diff --git a/.gitignore b/.gitignore index 46424bf616..bb412f760d 100644 --- a/.gitignore +++ b/.gitignore @@ -32,10 +32,30 @@ scratchpads_twitter.ini nohup.out docker-compose.dev.yml -# machine generated css and js +# machine generated css and jssites/all/libraries/vendor sites/default/files/advagg_css/ sites/default/files/advagg_js/ sites/default/files/css/ # files and assets sites/default/files + +# this library had to have code modified to be compatible with php 7.2 +# and therefore attempting to manage its git repp +# within the main scratchpads repo raised the question about where +# to store that modification. give that the modification is +# related to scratchpads' production server environment, +# the answer to that question is to store the change in +# scratchpads' repo. Moreover the original developer may not +# necessarily want to access a push up to their repo of this +# backwards compatible change to obsolete php version. +# Therefore with that decision to store in Scratchpads, that means +# disabling the project's own git (i.e. as a submodule), so the files +# will be removed and not tracked +sites/all/libraries/vendor/**/.git +# ^^^ not sure if this works +# +# discussion here: +# https://stackoverflow.com/questions/22685170/ignore-git-folder-in-sub-folder + + diff --git a/.htaccess b/.htaccess index 551b00eec9..c2aa6fc0dc 100644 --- a/.htaccess +++ b/.htaccess @@ -54,8 +54,8 @@ DirectoryIndex index.php index.html index.htm # Enable expirations. ExpiresActive On - # Cache all files for one month after access (A). - ExpiresDefault A2628000 + # Cache all files for 2 weeks after access (A). + ExpiresDefault A1209600 # Do not allow PHP scripts to be cached unless they explicitly send cache diff --git a/composer b/composer new file mode 120000 index 0000000000..73cdb9e23d --- /dev/null +++ b/composer @@ -0,0 +1 @@ +tools/phpcomposer/composer.phar \ No newline at end of file diff --git a/composer.json b/composer.json index 854db1a3b9..32c5aa15a1 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,8 @@ "require": { "knplabs/github-api": "^1.7", "michelf/php-markdown": "^1.8", - "php-http/guzzle6-adapter": "^1.1" + "php-http/guzzle6-adapter": "^1.1", + "jbroutier/iucn-api-client": "^1.0" }, "license": "GPL-2.0" } diff --git a/composer.lock b/composer.lock index 242e1f096c..76ec728776 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,121 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7cd35b3f391970a0c9ec23872e9716d0", + "content-hash": "7620fe7504dc7dd97e205e0c9216c484", "packages": [ + { + "name": "doctrine/collections", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "2b44dd4cbca8b5744327de78bafef5945c7e7b5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/2b44dd4cbca8b5744327de78bafef5945c7e7b5e", + "reference": "2b44dd4cbca8b5744327de78bafef5945c7e7b5e", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^0.5.3 || ^1", + "php": "^7.1.3 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0 || ^10.0", + "phpstan/phpstan": "^1.4.8", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.1.5", + "vimeo/psalm": "^4.22" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "keywords": [ + "array", + "collections", + "iterators", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/collections/issues", + "source": "https://github.com/doctrine/collections/tree/1.8.0" + }, + "time": "2022-09-01T20:12:10+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + }, + "time": "2022-05-02T15:47:09+00:00" + }, { "name": "guzzle/guzzle", "version": "v3.9.3", @@ -283,6 +396,60 @@ ], "time": "2017-03-20T17:10:46+00:00" }, + { + "name": "jbroutier/iucn-api-client", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/jbroutier/iucn-api-client.git", + "reference": "d2b95768b40d3c4606030a626e7c99393deef1de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jbroutier/iucn-api-client/zipball/d2b95768b40d3c4606030a626e7c99393deef1de", + "reference": "d2b95768b40d3c4606030a626e7c99393deef1de", + "shasum": "" + }, + "require": { + "doctrine/collections": "^1.7.2", + "php": "^7.4|^8.0", + "symfony/http-client": "^5.4|^6.0" + }, + "require-dev": { + "ekino/phpstan-banned-code": "^1.0.0", + "ext-json": "*", + "phpstan/extension-installer": "^1.1.0", + "phpstan/phpstan": "^1.8.4", + "phpstan/phpstan-deprecation-rules": "^1.0.0", + "phpstan/phpstan-phpunit": "^1.1.1", + "phpstan/phpstan-strict-rules": "^1.4.3", + "phpunit/phpunit": "^9.5.24" + }, + "type": "library", + "autoload": { + "psr-4": { + "IucnApi\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérémie BROUTIER", + "email": "jeremie.broutier@posteo.net", + "homepage": "https://github.com/jbroutier", + "role": "developer" + } + ], + "description": "A PHP client to retrieve data from The IUCN Red List of Threatened Species™.", + "support": { + "issues": "https://github.com/jbroutier/iucn-api-client/issues", + "source": "https://github.com/jbroutier/iucn-api-client/tree/1.0.0" + }, + "time": "2022-09-09T16:48:06+00:00" + }, { "name": "knplabs/github-api", "version": "1.7.1", @@ -557,6 +724,54 @@ ], "time": "2016-01-26T13:27:02+00:00" }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, { "name": "psr/http-message", "version": "1.0.1", @@ -607,6 +822,123 @@ ], "time": "2016-08-06T14:39:51+00:00" }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + }, + "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": "2022-01-02T09:53:40+00:00" + }, { "name": "symfony/event-dispatcher", "version": "v2.8.48", @@ -666,6 +998,416 @@ "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", "time": "2018-11-21T14:20:20+00:00" + }, + { + "name": "symfony/http-client", + "version": "v5.4.15", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "8f29b0f06c9ff48c8431e78eb90c8bd6f82cb12b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/8f29b0f06c9ff48c8431e78eb90c8bd6f82cb12b", + "reference": "8f29b0f06c9ff48c8431e78eb90c8bd6f82cb12b", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/http-client-contracts": "^2.4", + "symfony/polyfill-php73": "^1.11", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.0|^2|^3" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "2.4" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4.13|^5.1.5|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-client/tree/v5.4.15" + }, + "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": "2022-10-25T16:22:13+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "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": "2022-04-12T15:48:08+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "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": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "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": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "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": "2022-05-30T19:17:29+00:00" } ], "packages-dev": [], @@ -675,5 +1417,6 @@ "prefer-stable": false, "prefer-lowest": false, "platform": [], - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "2.3.0" } diff --git a/includes/authorize.inc b/includes/authorize.inc index 8360e132ce..1db3267832 100644 --- a/includes/authorize.inc +++ b/includes/authorize.inc @@ -104,11 +104,6 @@ function authorize_filetransfer_form($form, &$form_state) { // Start non-JS code. if (isset($form_state['values']['connection_settings']['authorize_filetransfer_default']) && $form_state['values']['connection_settings']['authorize_filetransfer_default'] == $name) { - // If the user switches from JS to non-JS, Drupal (and Batch API) will - // barf. This is a known bug: http://drupal.org/node/229825. - setcookie('has_js', '', time() - 3600, '/'); - unset($_COOKIE['has_js']); - // Change the submit button to the submit_process one. $form['submit_process']['#attributes'] = array(); unset($form['submit_connection']); diff --git a/includes/authorize.inc:Zone.Identifier b/includes/authorize.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/authorize.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/batch.inc b/includes/batch.inc index 4d4e504d5d..c98135bebf 100644 --- a/includes/batch.inc +++ b/includes/batch.inc @@ -72,7 +72,9 @@ function _batch_page() { $output = NULL; switch ($op) { case 'start': - $output = _batch_start(); + // Display the full progress page on startup and on each additional + // non-JavaScript iteration. + $output = _batch_progress_page(); break; case 'do': @@ -82,7 +84,7 @@ function _batch_page() { case 'do_nojs': // Non-JavaScript-based progress page. - $output = _batch_progress_page_nojs(); + $output = _batch_progress_page(); break; case 'finished': @@ -93,69 +95,12 @@ function _batch_page() { return $output; } -/** - * Initializes the batch processing. - * - * JavaScript-enabled clients are identified by the 'has_js' cookie set in - * drupal.js. If no JavaScript-enabled page has been visited during the current - * user's browser session, the non-JavaScript version is returned. - */ -function _batch_start() { - if (isset($_COOKIE['has_js']) && $_COOKIE['has_js']) { - return _batch_progress_page_js(); - } - else { - return _batch_progress_page_nojs(); - } -} - -/** - * Outputs a batch processing page with JavaScript support. - * - * This initializes the batch and error messages. Note that in JavaScript-based - * processing, the batch processing page is displayed only once and updated via - * AHAH requests, so only the first batch set gets to define the page title. - * Titles specified by subsequent batch sets are not displayed. - * - * @see batch_set() - * @see _batch_do() - */ -function _batch_progress_page_js() { - $batch = batch_get(); - - $current_set = _batch_current_set(); - drupal_set_title($current_set['title'], PASS_THROUGH); - - // Merge required query parameters for batch processing into those provided by - // batch_set() or hook_batch_alter(). - $batch['url_options']['query']['id'] = $batch['id']; - - $js_setting = array( - 'batch' => array( - 'errorMessage' => $current_set['error_message'] . '
' . $batch['error_message'], - 'initMessage' => $current_set['init_message'], - 'uri' => url($batch['url'], $batch['url_options']), - ), - ); - drupal_add_js($js_setting, 'setting'); - drupal_add_library('system', 'drupal.batch'); - - return '
'; -} - /** * Does one execution pass with JavaScript and returns progress to the browser. * - * @see _batch_progress_page_js() * @see _batch_process() */ function _batch_do() { - // HTTP POST required. - if ($_SERVER['REQUEST_METHOD'] != 'POST') { - drupal_set_message(t('HTTP POST is required.'), 'error'); - drupal_set_title(t('Error')); - return ''; - } // Perform actual processing. list($percentage, $message) = _batch_process(); @@ -164,11 +109,11 @@ function _batch_do() { } /** - * Outputs a batch processing page without JavaScript support. + * Outputs a batch processing page. * * @see _batch_process() */ -function _batch_progress_page_nojs() { +function _batch_progress_page() { $batch = &batch_get(); $current_set = _batch_current_set(); @@ -216,6 +161,9 @@ function _batch_progress_page_nojs() { $url = url($batch['url'], $batch['url_options']); $element = array( + // Redirect through a 'Refresh' meta tag if JavaScript is disabled. + '#prefix' => '', '#tag' => 'meta', '#attributes' => array( 'http-equiv' => 'Refresh', @@ -224,6 +172,17 @@ function _batch_progress_page_nojs() { ); drupal_add_html_head($element, 'batch_progress_meta_refresh'); + // Adds JavaScript code and settings for clients where JavaScript is enabled. + $js_setting = array( + 'batch' => array( + 'errorMessage' => $current_set['error_message'] . '
' . $batch['error_message'], + 'initMessage' => $current_set['init_message'], + 'uri' => $url, + ), + ); + drupal_add_js($js_setting, 'setting'); + drupal_add_library('system', 'drupal.batch'); + return theme('progress_bar', array('percent' => $percentage, 'message' => $message)); } diff --git a/includes/batch.inc:Zone.Identifier b/includes/batch.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/batch.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index bd81e7e594..6bf5ec52ad 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.82'); +define('VERSION', '7.92'); /** * Core API compatibility. @@ -359,6 +359,7 @@ abstract class DrupalCacheArray implements ArrayAccess { /** * Implements ArrayAccess::offsetExists(). */ + #[\ReturnTypeWillChange] public function offsetExists($offset) { return $this->offsetGet($offset) !== NULL; } @@ -366,6 +367,7 @@ abstract class DrupalCacheArray implements ArrayAccess { /** * Implements ArrayAccess::offsetGet(). */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { if (isset($this->storage[$offset]) || array_key_exists($offset, $this->storage)) { return $this->storage[$offset]; @@ -378,6 +380,7 @@ abstract class DrupalCacheArray implements ArrayAccess { /** * Implements ArrayAccess::offsetSet(). */ + #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { $this->storage[$offset] = $value; } @@ -385,6 +388,7 @@ abstract class DrupalCacheArray implements ArrayAccess { /** * Implements ArrayAccess::offsetUnset(). */ + #[\ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->storage[$offset]); } @@ -803,14 +807,17 @@ function drupal_settings_initialize() { // HTTP_HOST can be modified by a visitor, but we already sanitized it // in drupal_settings_initialize(). if (!empty($_SERVER['HTTP_HOST'])) { - $cookie_domain = $_SERVER['HTTP_HOST']; - // Strip leading periods, www., and port numbers from cookie domain. - $cookie_domain = ltrim($cookie_domain, '.'); - if (strpos($cookie_domain, 'www.') === 0) { - $cookie_domain = substr($cookie_domain, 4); - } - $cookie_domain = explode(':', $cookie_domain); - $cookie_domain = '.' . $cookie_domain[0]; + $cookie_domain = _drupal_get_cookie_domain($_SERVER['HTTP_HOST']); + } + + // Drupal 7.83 included a security improvement whereby www. is no longer + // stripped from the cookie domain. However, this can cause problems with + // existing session cookies where some users are left unable to login. In + // order to avoid that, prepend a leading dot to the session_name that was + // derived from the base_url when a www. subdomain is in use. + // @see https://www.drupal.org/project/drupal/issues/2522002 + if (strpos($session_name, 'www.') === 0) { + $session_name = '.' . $session_name; } } // Per RFC 2109, cookie domains must contain at least one dot other than the @@ -831,6 +838,24 @@ function drupal_settings_initialize() { session_name($prefix . substr(hash('sha256', $session_name), 0, 32)); } +/** + * Derive the cookie domain to use for session cookies. + * + * @param $host + * The value of the HTTP host name. + * + * @return + * The string to use as a cookie domain. + */ +function _drupal_get_cookie_domain($host) { + $cookie_domain = $host; + // Strip leading periods and port numbers from cookie domain. + $cookie_domain = ltrim($cookie_domain, '.'); + $cookie_domain = explode(':', $cookie_domain); + $cookie_domain = '.' . $cookie_domain[0]; + return $cookie_domain; +} + /** * Returns and optionally sets the filename for a system resource. * @@ -1157,6 +1182,31 @@ function _drupal_trigger_error_with_delayed_logging($error_msg, $error_type = E_ $delay_logging = FALSE; } +/** + * Invoke trigger_error() using a fatal error that will terminate the request. + * + * Normally, Drupal's error handler does not terminate script execution on + * user-level errors, even if the error is of type E_USER_ERROR. This function + * triggers an error of type E_USER_ERROR that is explicitly forced to be a + * fatal error which terminates script execution. + * + * @param string $error_msg + * The error message to trigger. As with trigger_error() itself, this is + * limited to 1024 bytes; additional characters beyond that will be removed. + * + * @see _drupal_error_handler_real() + */ +function drupal_trigger_fatal_error($error_msg) { + $fatal_error = &drupal_static(__FUNCTION__, FALSE); + $fatal_error = TRUE; + trigger_error($error_msg, E_USER_ERROR); + $fatal_error = FALSE; + // The standard Drupal error handler should have treated this as a fatal + // error and already ended the page request. But in case another error + // handler is being used, terminate execution explicitly here also. + exit; +} + /** * Writes the file scan cache to the persistent cache. * @@ -1552,7 +1602,7 @@ function drupal_page_header() { */ function drupal_serve_page_from_cache(stdClass $cache) { // Negotiate whether to use compression. - $page_compression = !empty($cache->data['page_compressed']); + $page_compression = !empty($cache->data['page_compressed']) && !empty($cache->data['body']); $return_compressed = $page_compression && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE; // Get headers set in hook_boot(). Keys are lower-case. @@ -1855,7 +1905,7 @@ function format_string($string, array $args = array()) { * @ingroup sanitization */ function check_plain($text) { - return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); + return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8'); } /** @@ -1883,7 +1933,7 @@ function check_plain($text) { * TRUE if the text is valid UTF-8, FALSE if not. */ function drupal_validate_utf8($text) { - if (strlen($text) == 0) { + if (strlen((string) $text) == 0) { return TRUE; } // With the PCRE_UTF8 modifier 'u', preg_match() fails silently on strings @@ -2265,7 +2315,7 @@ function drupal_random_bytes($count) { // $random_state does not use drupal_static as it stores random bytes. static $random_state, $bytes, $has_openssl; - $missing_bytes = $count - strlen($bytes); + $missing_bytes = $count - strlen((string) $bytes); if ($missing_bytes > 0) { // PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes() @@ -2298,7 +2348,7 @@ function drupal_random_bytes($count) { // the microtime() - is prepended rather than appended. This is to avoid // directly leaking $random_state via the $output stream, which could // allow for trivial prediction of further "random" numbers. - if (strlen($bytes) < $count) { + if (strlen((string) $bytes) < $count) { // Initialize on the first call. The contents of $_SERVER includes a mix of // user-specific and system information that varies a little with each page. if (!isset($random_state)) { diff --git a/includes/bootstrap.inc:Zone.Identifier b/includes/bootstrap.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/bootstrap.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/common.inc b/includes/common.inc index 2ca4fa06fd..0f6ced800d 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -633,7 +633,7 @@ function drupal_parse_url($url) { * The Drupal path to encode. */ function drupal_encode_path($path) { - return str_replace('%2F', '/', rawurlencode($path)); + return str_replace('%2F', '/', rawurlencode((string) $path)); } /** @@ -943,7 +943,7 @@ function drupal_http_request($url, array $options = array()) { // or PUT request. Some non-standard servers get confused by Content-Length in // at least HEAD/GET requests, and Squid always requires Content-Length in // POST/PUT requests. - $content_length = strlen($options['data']); + $content_length = strlen((string) $options['data']); if ($content_length > 0 || $options['method'] == 'POST' || $options['method'] == 'PUT') { $options['headers']['Content-Length'] = $content_length; } @@ -1019,7 +1019,7 @@ function drupal_http_request($url, array $options = array()) { $result->headers = array(); // Parse the response headers. - while ($line = trim(array_shift($response))) { + while ($line = trim((string) array_shift($response))) { list($name, $value) = explode(':', $line, 2); $name = strtolower($name); if (isset($result->headers[$name]) && $name == 'set-cookie') { @@ -1104,6 +1104,14 @@ function drupal_http_request($url, array $options = array()) { // Redirect to the new location. $options['max_redirects']--; + // Check if we need to remove any potentially sensitive headers before + // following the redirect. + // @see https://www.rfc-editor.org/rfc/rfc9110.html#name-redirection-3xx + if (_drupal_should_strip_sensitive_headers_on_http_redirect($url, $location)) { + unset($options['headers']['Cookie']); + unset($options['headers']['Authorization']); + } + // We need to unset the 'Host' header // as we are redirecting to a new location. unset($options['headers']['Host']); @@ -1122,6 +1130,36 @@ function drupal_http_request($url, array $options = array()) { return $result; } +/** + * Determine whether to strip sensitive headers from a request when redirected. + * + * @param string $url + * The url from the original outbound http request. + * + * @param string $location + * The location to which the request has been redirected. + * + * @return boolean + * Whether sensitive headers should be stripped from the request before + * following the redirect. + */ +function _drupal_should_strip_sensitive_headers_on_http_redirect($url, $location) { + $url_parsed = parse_url($url); + $location_parsed = parse_url($location); + if (!isset($location_parsed['host'])) { + return FALSE; + } + $strip_on_host_change = variable_get('drupal_http_request_strip_sensitive_headers_on_host_change', TRUE); + $strip_on_https_downgrade = variable_get('drupal_http_request_strip_sensitive_headers_on_https_downgrade', TRUE); + if ($strip_on_host_change && strcasecmp($url_parsed['host'], $location_parsed['host']) !== 0) { + return TRUE; + } + if ($strip_on_https_downgrade && $url_parsed['scheme'] !== $location_parsed['scheme'] && 'https' !== $location_parsed['scheme']) { + return TRUE; + } + return FALSE; +} + /** * Splits an HTTP response status line into components. * @@ -1500,7 +1538,7 @@ function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', // Store the text format. _filter_xss_split($allowed_tags, TRUE); // Remove NULL characters (ignored by some browsers). - $string = str_replace(chr(0), '', $string); + $string = str_replace(chr(0), '', (string) $string); // Remove Netscape 4 JS entities. $string = preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string); @@ -1916,7 +1954,7 @@ function format_plural($count, $singular, $plural, array $args = array(), array */ function parse_size($size) { $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size. - $size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size. + $size = (float) preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size. if ($unit) { // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by. return round($size * pow(DRUPAL_KILOBYTE, stripos('bkmgtpezy', $unit[0]))); @@ -1995,7 +2033,7 @@ function format_interval($interval, $granularity = 2, $langcode = NULL) { $key = explode('|', $key); if ($interval >= $value) { $output .= ($output ? ' ' : '') . format_plural(floor($interval / $value), $key[0], $key[1], array(), array('langcode' => $langcode)); - $interval %= $value; + $interval = (int) $interval % $value; $granularity--; } @@ -2308,7 +2346,7 @@ function url($path = NULL, array $options = array()) { // Strip leading slashes from internal paths to prevent them becoming external // URLs without protocol. /example.com should not be turned into // //example.com. - $path = ltrim($path, '/'); + $path = ltrim((string) $path, '/'); global $base_url, $base_secure_url, $base_insecure_url; @@ -2346,7 +2384,7 @@ function url($path = NULL, array $options = array()) { } $base = $options['absolute'] ? $options['base_url'] . '/' : base_path(); - $prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix']; + $prefix = empty($path) ? rtrim((string) $options['prefix'], '/') : $options['prefix']; // With Clean URLs. if (!empty($GLOBALS['conf']['clean_url'])) { @@ -2390,6 +2428,7 @@ function url($path = NULL, array $options = array()) { * Boolean TRUE or FALSE, where TRUE indicates an external path. */ function url_is_external($path) { + $path = (string) $path; $colonpos = strpos($path, ':'); // Some browsers treat \ as / so normalize to forward slashes. $path = str_replace('\\', '/', $path); @@ -2569,6 +2608,7 @@ function l($text, $path, array $options = array()) { $use_theme = FALSE; } } + $path = drupal_strip_dangerous_protocols((string) $path); if ($use_theme) { return theme('link', array('text' => $text, 'path' => $path, 'options' => $options)); } @@ -2695,6 +2735,7 @@ function drupal_deliver_html_page($page_callback_result) { if ($frame_options && is_null(drupal_get_http_header('X-Frame-Options'))) { drupal_add_http_header('X-Frame-Options', $frame_options); } + drupal_add_http_header('X-Content-Type-Options', 'nosniff'); if (variable_get('block_interest_cohort', TRUE)) { $permissions_policy = drupal_get_http_header('Permissions-Policy'); @@ -2944,12 +2985,12 @@ function base_path() { } /** - * Adds a LINK tag with a distinct 'rel' attribute to the page's HEAD. + * Adds a LINK tag with distinct attributes to the page's HEAD. * * This function can be called as long the HTML header hasn't been sent, which * on normal pages is up through the preprocess step of theme('html'). Adding - * a link will overwrite a prior link with the exact same 'rel' and 'href' - * attributes. + * a link will overwrite a prior link with the exact same 'rel', 'href' and + * 'hreflang' attributes. * * @param $attributes * Associative array of element attributes including 'href' and 'rel'. @@ -2965,12 +3006,12 @@ function drupal_add_html_head_link($attributes, $header = FALSE) { if ($header) { // Also add a HTTP header "Link:". - $href = '<' . check_plain($attributes['href']) . '>;'; + $href = '<' . $attributes['href'] . '>;'; unset($attributes['href']); $element['#attached']['drupal_add_http_header'][] = array('Link', $href . drupal_http_header_attributes($attributes), TRUE); } - drupal_add_html_head($element, 'drupal_add_html_head_link:' . $attributes['rel'] . ':' . $href); + drupal_add_html_head($element, 'drupal_add_html_head_link:' . $attributes['rel'] . ':' . (isset($attributes['hreflang']) ? "{$attributes['hreflang']}:" : '') . $href); } /** @@ -4342,6 +4383,7 @@ function drupal_add_js($data = NULL, $options = NULL) { 'data' => array( array('basePath' => base_path()), array('pathPrefix' => empty($prefix) ? '' : $prefix), + array('setHasJsCookie' => variable_get('set_has_js_cookie', FALSE) ? 1 : 0), ), 'type' => 'setting', 'scope' => 'header', @@ -6085,7 +6127,7 @@ function drupal_render_page($page) { */ function drupal_render(&$elements) { // Early-return nothing if user does not have access. - if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) { + if (empty($elements) || !is_array($elements) || (isset($elements['#access']) && !$elements['#access'])) { return ''; } @@ -6641,7 +6683,7 @@ function drupal_sort_title($a, $b) { * Checks if the key is a property. */ function element_property($key) { - return $key[0] == '#'; + return $key !== '' && is_string($key) && $key[0] == '#'; } /** @@ -8032,8 +8074,14 @@ function entity_extract_ids($entity_type, $entity) { $info = entity_get_info($entity_type); // Objects being created might not have id/vid yet. - $id = isset($entity->{$info['entity keys']['id']}) ? $entity->{$info['entity keys']['id']} : NULL; - $vid = ($info['entity keys']['revision'] && isset($entity->{$info['entity keys']['revision']})) ? $entity->{$info['entity keys']['revision']} : NULL; + if (!empty($info)) { + $id = isset($entity->{$info['entity keys']['id']}) ? $entity->{$info['entity keys']['id']} : NULL; + $vid = ($info['entity keys']['revision'] && isset($entity->{$info['entity keys']['revision']})) ? $entity->{$info['entity keys']['revision']} : NULL; + } + else { + $id = NULL; + $vid = NULL; + } if (!empty($info['entity keys']['bundle'])) { // Explicitly fail for malformed entities missing the bundle property. diff --git a/includes/common.inc:Zone.Identifier b/includes/common.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/common.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/database.inc b/includes/database/database.inc index 61ac44f783..36999e7e80 100644 --- a/includes/database/database.inc +++ b/includes/database/database.inc @@ -1924,6 +1924,11 @@ class DatabaseTransactionOutOfOrderException extends Exception { } */ class InvalidMergeQueryException extends Exception {} +/** + * Exception thrown if an invalid query condition is specified. + */ +class InvalidQueryConditionOperatorException extends Exception {} + /** * Exception thrown if an insert query specifies a field twice. * @@ -2257,6 +2262,7 @@ class DatabaseStatementBase extends PDOStatement implements DatabaseStatementInt $this->setFetchMode(PDO::FETCH_OBJ); } + #[\ReturnTypeWillChange] public function execute($args = array(), $options = array()) { if (isset($options['fetch'])) { if (is_string($options['fetch'])) { @@ -2394,23 +2400,27 @@ class DatabaseStatementEmpty implements Iterator, DatabaseStatementInterface { } /* Implementations of Iterator. */ - + #[\ReturnTypeWillChange] public function current() { return NULL; } + #[\ReturnTypeWillChange] public function key() { return NULL; } + #[\ReturnTypeWillChange] public function rewind() { // Nothing to do: our DatabaseStatement can't be rewound. } + #[\ReturnTypeWillChange] public function next() { // Do nothing, since this is an always-empty implementation. } + #[\ReturnTypeWillChange] public function valid() { return FALSE; } diff --git a/includes/database/database.inc:Zone.Identifier b/includes/database/database.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/database.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/log.inc:Zone.Identifier b/includes/database/log.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/log.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc index b836111987..8bb88d24f3 100644 --- a/includes/database/mysql/database.inc +++ b/includes/database/mysql/database.inc @@ -332,6 +332,11 @@ class DatabaseConnection_mysql extends DatabaseConnection { PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE, // Because MySQL's prepared statements skip the query cache, because it's dumb. PDO::ATTR_EMULATE_PREPARES => TRUE, + // Convert numeric values to strings when fetching. In PHP 8.1, + // PDO::ATTR_EMULATE_PREPARES now behaves the same way as non emulated + // prepares and returns integers. See https://externals.io/message/113294 + // for further discussion. + PDO::ATTR_STRINGIFY_FETCHES => TRUE, ); if (defined('PDO::MYSQL_ATTR_MULTI_STATEMENTS')) { // An added connection option in PHP 5.5.21+ to optionally limit SQL to a diff --git a/includes/database/mysql/database.inc:Zone.Identifier b/includes/database/mysql/database.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/mysql/database.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/mysql/install.inc:Zone.Identifier b/includes/database/mysql/install.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/mysql/install.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/mysql/query.inc:Zone.Identifier b/includes/database/mysql/query.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/mysql/query.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/mysql/schema.inc:Zone.Identifier b/includes/database/mysql/schema.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/mysql/schema.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/pgsql/database.inc b/includes/database/pgsql/database.inc index 96ffc1d3e4..7aa69a92a4 100644 --- a/includes/database/pgsql/database.inc +++ b/includes/database/pgsql/database.inc @@ -117,7 +117,8 @@ class DatabaseConnection_pgsql extends DatabaseConnection { case Database::RETURN_AFFECTED: return $stmt->rowCount(); case Database::RETURN_INSERT_ID: - return $this->connection->lastInsertId($options['sequence_name']); + $sequence_name = isset($options['sequence_name']) ? $options['sequence_name'] : NULL; + return $this->connection->lastInsertId($sequence_name); case Database::RETURN_NULL: return; default: diff --git a/includes/database/pgsql/database.inc:Zone.Identifier b/includes/database/pgsql/database.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/pgsql/database.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/pgsql/install.inc:Zone.Identifier b/includes/database/pgsql/install.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/pgsql/install.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/pgsql/query.inc b/includes/database/pgsql/query.inc index 9902b1643a..e2d587d5b7 100644 --- a/includes/database/pgsql/query.inc +++ b/includes/database/pgsql/query.inc @@ -30,7 +30,7 @@ class InsertQuery_pgsql extends InsertQuery { foreach ($this->insertFields as $idx => $field) { if (isset($table_information->blob_fields[$field])) { $blobs[$blob_count] = fopen('php://memory', 'a'); - fwrite($blobs[$blob_count], $insert_values[$idx]); + fwrite($blobs[$blob_count], (string) $insert_values[$idx]); rewind($blobs[$blob_count]); $stmt->bindParam(':db_insert_placeholder_' . $max_placeholder++, $blobs[$blob_count], PDO::PARAM_LOB); @@ -182,7 +182,7 @@ class UpdateQuery_pgsql extends UpdateQuery { if (isset($table_information->blob_fields[$field])) { $blobs[$blob_count] = fopen('php://memory', 'a'); - fwrite($blobs[$blob_count], $value); + fwrite($blobs[$blob_count], (string) $value); rewind($blobs[$blob_count]); $stmt->bindParam($placeholder, $blobs[$blob_count], PDO::PARAM_LOB); ++$blob_count; diff --git a/includes/database/pgsql/query.inc:Zone.Identifier b/includes/database/pgsql/query.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/pgsql/query.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/pgsql/schema.inc b/includes/database/pgsql/schema.inc index f5774de1c9..8d1b388c11 100644 --- a/includes/database/pgsql/schema.inc +++ b/includes/database/pgsql/schema.inc @@ -12,6 +12,13 @@ class DatabaseSchema_pgsql extends DatabaseSchema { + /** + * PostgreSQL's temporary namespace name. + * + * @var string + */ + protected $tempNamespaceName; + /** * A cache of information about blob columns and sequences of tables. * @@ -23,6 +30,64 @@ class DatabaseSchema_pgsql extends DatabaseSchema { */ protected $tableInformation = array(); + /** + * The maximum allowed length for index, primary key and constraint names. + * + * Value will usually be set to a 63 chars limit but PostgreSQL allows + * to higher this value before compiling, so we need to check for that. + * + * @var int + */ + protected $maxIdentifierLength; + + /** + * Make sure to limit identifiers according to PostgreSQL compiled in length. + * + * PostgreSQL allows in standard configuration identifiers no longer than 63 + * chars for table/relation names, indexes, primary keys, and constraints. So + * we map all identifiers that are too long to drupal_base64hash_tag, where + * tag is one of: + * - idx for indexes + * - key for constraints + * - pkey for primary keys + * - seq for sequences + * + * @param string $table_identifier_part + * The first argument used to build the identifier string. This usually + * refers to a table/relation name. + * @param string $column_identifier_part + * The second argument used to build the identifier string. This usually + * refers to one or more column names. + * @param string $tag + * The identifier tag. It can be one of 'idx', 'key', 'pkey' or 'seq'. + * + * @return string + * The index/constraint/pkey identifier. + */ + protected function ensureIdentifiersLength($table_identifier_part, $column_identifier_part, $tag) { + $info = $this->getPrefixInfo($table_identifier_part); + $table_identifier_part = $info['table']; + + // Filters out potentially empty $column_identifier_part to ensure + // compatibility with old naming convention (see prefixNonTable()). + $identifiers = array_filter(array($table_identifier_part, $column_identifier_part, $tag)); + $identifierName = implode('_', $identifiers); + + // Retrieve the max identifier length which is usually 63 characters + // but can be altered before PostgreSQL is compiled so we need to check. + if (empty($this->maxIdentifierLength)) { + $this->maxIdentifierLength = $this->connection->query("SHOW max_identifier_length")->fetchField(); + } + + if (strlen($identifierName) > $this->maxIdentifierLength) { + $saveIdentifier = 'drupal_' . $this->hashBase64($identifierName) . '_' . $tag; + } + else { + $saveIdentifier = $identifierName; + } + return $saveIdentifier; + } + /** * Fetch the list of blobs and sequences used on a table. * @@ -39,23 +104,47 @@ class DatabaseSchema_pgsql extends DatabaseSchema { public function queryTableInformation($table) { // Generate a key to reference this table's information on. $key = $this->connection->prefixTables('{' . $table . '}'); - if (!strpos($key, '.')) { + + // Take into account that temporary tables are stored in a different schema. + // \DatabaseConnection::generateTemporaryTableName() sets 'db_temporary_' + // prefix to all temporary tables. + if (strpos($key, '.') === FALSE && strpos($table, 'db_temporary_') === FALSE) { $key = 'public.' . $key; } + else { + $key = $this->getTempNamespaceName() . '.' . $key; + } if (!isset($this->tableInformation[$key])) { - // Split the key into schema and table for querying. - list($schema, $table_name) = explode('.', $key); $table_information = (object) array( 'blob_fields' => array(), 'sequences' => array(), ); - // Don't use {} around information_schema.columns table. - $result = $this->connection->query("SELECT column_name, data_type, column_default FROM information_schema.columns WHERE table_schema = :schema AND table_name = :table AND (data_type = 'bytea' OR (numeric_precision IS NOT NULL AND column_default LIKE :default))", array( - ':schema' => $schema, - ':table' => $table_name, - ':default' => '%nextval%', + + // The bytea columns and sequences for a table can be found in + // pg_attribute, which is significantly faster than querying the + // information_schema. The data type of a field can be found by lookup + // of the attribute ID, and the default value must be extracted from the + // node tree for the attribute definition instead of the historical + // human-readable column, adsrc. + $sql = <<<'EOD' +SELECT pg_attribute.attname AS column_name, format_type(pg_attribute.atttypid, pg_attribute.atttypmod) AS data_type, pg_get_expr(pg_attrdef.adbin, pg_attribute.attrelid) AS column_default +FROM pg_attribute +LEFT JOIN pg_attrdef ON pg_attrdef.adrelid = pg_attribute.attrelid AND pg_attrdef.adnum = pg_attribute.attnum +WHERE pg_attribute.attnum > 0 +AND NOT pg_attribute.attisdropped +AND pg_attribute.attrelid = :key::regclass +AND (format_type(pg_attribute.atttypid, pg_attribute.atttypmod) = 'bytea' +OR pg_get_expr(pg_attrdef.adbin, pg_attribute.attrelid) LIKE 'nextval%') +EOD; + $result = $this->connection->query($sql, array( + ':key' => $key, )); + + if (empty($result)) { + return $table_information; + } + foreach ($result as $column) { if ($column->data_type == 'bytea') { $table_information->blob_fields[$column->column_name] = TRUE; @@ -73,6 +162,19 @@ class DatabaseSchema_pgsql extends DatabaseSchema { return $this->tableInformation[$key]; } + /** + * Gets PostgreSQL's temporary namespace name. + * + * @return string + * PostgreSQL's temporary namespace anme. + */ + protected function getTempNamespaceName() { + if (!isset($this->tempNamespaceName)) { + $this->tempNamespaceName = $this->connection->query('SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema()')->fetchField(); + } + return $this->tempNamespaceName; + } + /** * Fetch the list of CHECK constraints used on a field. * @@ -124,11 +226,11 @@ class DatabaseSchema_pgsql extends DatabaseSchema { $sql_keys = array(); if (isset($table['primary key']) && is_array($table['primary key'])) { - $sql_keys[] = 'PRIMARY KEY (' . implode(', ', $table['primary key']) . ')'; + $sql_keys[] = 'CONSTRAINT ' . $this->ensureIdentifiersLength($name, '', 'pkey') . ' PRIMARY KEY (' . implode(', ', $table['primary key']) . ')'; } if (isset($table['unique keys']) && is_array($table['unique keys'])) { foreach ($table['unique keys'] as $key_name => $key) { - $sql_keys[] = 'CONSTRAINT ' . $this->prefixNonTable($name, $key_name, 'key') . ' UNIQUE (' . implode(', ', $key) . ')'; + $sql_keys[] = 'CONSTRAINT ' . $this->ensureIdentifiersLength($name, $key_name, 'key') . ' UNIQUE (' . implode(', ', $key) . ')'; } } @@ -312,6 +414,68 @@ class DatabaseSchema_pgsql extends DatabaseSchema { return implode(', ', $return); } + /** + * {@inheritdoc} + */ + public function tableExists($table) { + // In PostgreSQL "unquoted names are always folded to lower case." + // @see DatabaseSchema_pgsql::buildTableNameCondition(). + $prefixInfo = $this->getPrefixInfo(strtolower($table), TRUE); + + return (bool) $this->connection->query("SELECT 1 FROM pg_tables WHERE schemaname = :schema AND tablename = :table", array(':schema' => $prefixInfo['schema'], ':table' => $prefixInfo['table']))->fetchField(); + } + + /** + * {@inheritdoc} + */ + public function findTables($table_expression) { + $individually_prefixed_tables = $this->connection->getUnprefixedTablesMap(); + $default_prefix = $this->connection->tablePrefix(); + $default_prefix_length = strlen($default_prefix); + $tables = array(); + + // Load all the tables up front in order to take into account per-table + // prefixes. The actual matching is done at the bottom of the method. + $results = $this->connection->query("SELECT tablename FROM pg_tables WHERE schemaname = :schema", array(':schema' => $this->defaultSchema)); + foreach ($results as $table) { + // Take into account tables that have an individual prefix. + if (isset($individually_prefixed_tables[$table->tablename])) { + $prefix_length = strlen($this->connection->tablePrefix($individually_prefixed_tables[$table->tablename])); + } + elseif ($default_prefix && substr($table->tablename, 0, $default_prefix_length) !== $default_prefix) { + // This table name does not start the default prefix, which means that + // it is not managed by Drupal so it should be excluded from the result. + continue; + } + else { + $prefix_length = $default_prefix_length; + } + + // Remove the prefix from the returned tables. + $unprefixed_table_name = substr($table->tablename, $prefix_length); + + // The pattern can match a table which is the same as the prefix. That + // will become an empty string when we remove the prefix, which will + // probably surprise the caller, besides not being a prefixed table. So + // remove it. + if (!empty($unprefixed_table_name)) { + $tables[$unprefixed_table_name] = $unprefixed_table_name; + } + } + + // Need to use strtolower on the table name as it was used previously by + // DatabaseSchema_pgsql::buildTableNameCondition(). + // @see https://www.drupal.org/project/drupal/issues/3262341 + $table_expression = strtolower($table_expression); + + // Convert the table expression from its SQL LIKE syntax to a regular + // expression and escape the delimiter that will be used for matching. + $table_expression = str_replace(array('%', '_'), array('.*?', '.'), preg_quote($table_expression, '/')); + $tables = preg_grep('/^' . $table_expression . '$/i', $tables); + + return $tables; + } + function renameTable($table, $new_name) { if (!$this->tableExists($table)) { throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot rename @table to @table_new: table @table doesn't exist.", array('@table' => $table, '@table_new' => $new_name))); @@ -328,10 +492,31 @@ class DatabaseSchema_pgsql extends DatabaseSchema { // rename them when renaming the table. $indexes = $this->connection->query('SELECT indexname FROM pg_indexes WHERE schemaname = :schema AND tablename = :table', array(':schema' => $old_schema, ':table' => $old_table_name)); foreach ($indexes as $index) { - if (preg_match('/^' . preg_quote($old_full_name) . '_(.*)$/', $index->indexname, $matches)) { + // Get the index type by suffix, e.g. idx/key/pkey + $index_type = substr($index->indexname, strrpos($index->indexname, '_') + 1); + + // If the index is already rewritten by ensureIdentifiersLength() to not + // exceed the 63 chars limit of PostgreSQL, we need to take care of that. + // Example (drupal_Gk7Su_T1jcBHVuvSPeP22_I3Ni4GrVEgTYlIYnBJkro_idx). + if (strpos($index->indexname, 'drupal_') !== FALSE) { + preg_match('/^drupal_(.*)_' . preg_quote($index_type) . '/', $index->indexname, $matches); $index_name = $matches[1]; - $this->connection->query('ALTER INDEX ' . $index->indexname . ' RENAME TO {' . $new_name . '}_' . $index_name); } + else { + if ($index_type == 'pkey') { + // Primary keys do not have a specific name in D7. + $index_name = ''; + } + else { + // Make sure to remove the suffix from index names, because + // ensureIdentifiersLength() will add the suffix again and thus + // would result in a wrong index name. + preg_match('/^' . preg_quote($old_full_name) . '_(.*)_' . preg_quote($index_type) . '/', $index->indexname, $matches); + $index_name = $matches[1]; + } + } + + $this->connection->query('ALTER INDEX ' . $index->indexname . ' RENAME TO ' . $this->ensureIdentifiersLength($new_name, $index_name, $index_type)); } // Now rename the table. @@ -414,9 +599,20 @@ class DatabaseSchema_pgsql extends DatabaseSchema { $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" DROP DEFAULT'); } + /** + * {@inheritdoc} + */ + public function fieldExists($table, $column) { + // In PostgreSQL "unquoted names are always folded to lower case." + // @see DatabaseSchema_pgsql::buildTableNameCondition(). + $prefixInfo = $this->getPrefixInfo(strtolower($table)); + + return (bool) $this->connection->query("SELECT 1 FROM pg_attribute WHERE attrelid = :key::regclass AND attname = :column AND NOT attisdropped AND attnum > 0", array(':key' => $prefixInfo['schema'] . '.' . $prefixInfo['table'], ':column' => $column))->fetchField(); + } + public function indexExists($table, $name) { - // Details http://www.postgresql.org/docs/8.3/interactive/view-pg-indexes.html - $index_name = '{' . $table . '}_' . $name . '_idx'; + // Details https://www.postgresql.org/docs/10/view-pg-indexes.html + $index_name = $this->ensureIdentifiersLength($table, $name, 'idx'); return (bool) $this->connection->query("SELECT 1 FROM pg_indexes WHERE indexname = '$index_name'")->fetchField(); } @@ -429,7 +625,18 @@ class DatabaseSchema_pgsql extends DatabaseSchema { * The name of the constraint (typically 'pkey' or '[constraint]_key'). */ protected function constraintExists($table, $name) { - $constraint_name = '{' . $table . '}_' . $name; + // ensureIdentifiersLength() expects three parameters, thus we split our + // constraint name in a proper name and a suffix. + if ($name == 'pkey') { + $suffix = $name; + $name = ''; + } + else { + $pos = strrpos($name, '_'); + $suffix = substr($name, $pos + 1); + $name = substr($name, 0, $pos); + } + $constraint_name = $this->ensureIdentifiersLength($table, $name, $suffix); return (bool) $this->connection->query("SELECT 1 FROM pg_constraint WHERE conname = '$constraint_name'")->fetchField(); } @@ -441,7 +648,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema { throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table @table: primary key already exists.", array('@table' => $table))); } - $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . implode(',', $fields) . ')'); + $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT ' . $this->ensureIdentifiersLength($table, '', 'pkey') . ' PRIMARY KEY (' . implode(',', $fields) . ')'); } public function dropPrimaryKey($table) { @@ -449,7 +656,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema { return FALSE; } - $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT ' . $this->prefixNonTable($table, 'pkey')); + $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT ' . $this->ensureIdentifiersLength($table, '', 'pkey')); return TRUE; } @@ -461,7 +668,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema { throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key @name to table @table: unique key already exists.", array('@table' => $table, '@name' => $name))); } - $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT "' . $this->prefixNonTable($table, $name, 'key') . '" UNIQUE (' . implode(',', $fields) . ')'); + $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT "' . $this->ensureIdentifiersLength($table, $name, 'key') . '" UNIQUE (' . implode(',', $fields) . ')'); } public function dropUniqueKey($table, $name) { @@ -469,7 +676,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema { return FALSE; } - $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $this->prefixNonTable($table, $name, 'key') . '"'); + $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $this->ensureIdentifiersLength($table, $name, 'key') . '"'); return TRUE; } @@ -489,7 +696,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema { return FALSE; } - $this->connection->query('DROP INDEX ' . $this->prefixNonTable($table, $name, 'idx')); + $this->connection->query('DROP INDEX ' . $this->ensureIdentifiersLength($table, $name, 'idx')); return TRUE; } @@ -580,7 +787,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema { } protected function _createIndexSql($table, $name, $fields) { - $query = 'CREATE INDEX "' . $this->prefixNonTable($table, $name, 'idx') . '" ON {' . $table . '} ('; + $query = 'CREATE INDEX "' . $this->ensureIdentifiersLength($table, $name, 'idx') . '" ON {' . $table . '} ('; $query .= $this->_createKeySql($fields) . ')'; return $query; } @@ -614,4 +821,36 @@ class DatabaseSchema_pgsql extends DatabaseSchema { return $this->connection->query('SELECT obj_description(oid, ?) FROM pg_class WHERE relname = ?', array('pg_class', $info['table']))->fetchField(); } } + + /** + * Calculates a base-64 encoded, PostgreSQL-safe sha-256 hash per PostgreSQL + * documentation: 4.1. Lexical Structure. + * + * @param $data + * String to be hashed. + * + * @return string + * A base-64 encoded sha-256 hash, with + and / replaced with _ and any = + * padding characters removed. + */ + protected function hashBase64($data) { + // Ensure lowercase as D7's pgsql driver does not quote identifiers + // consistently, and they are therefore folded to lowercase by PostgreSQL. + $hash = strtolower(base64_encode(hash('sha256', $data, TRUE))); + // Modify the hash so it's safe to use in PostgreSQL identifiers. + return strtr($hash, array('+' => '_', '/' => '_', '=' => '')); + } + + /** + * Build a condition to match a table name against a standard information_schema. + * + * In PostgreSQL "unquoted names are always folded to lower case." The pgsql + * driver does not quote table names, so they are therefore always lowercase. + * + * @see https://www.postgresql.org/docs/14/sql-syntax-lexical.html + */ + protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) { + return parent::buildTableNameCondition(strtolower($table_name), $operator, $add_prefix); + } + } diff --git a/includes/database/pgsql/schema.inc:Zone.Identifier b/includes/database/pgsql/schema.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/pgsql/schema.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/pgsql/select.inc:Zone.Identifier b/includes/database/pgsql/select.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/pgsql/select.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/prefetch.inc b/includes/database/prefetch.inc index 3b36a4e102..2a0bd55ce1 100644 --- a/includes/database/prefetch.inc +++ b/includes/database/prefetch.inc @@ -268,6 +268,7 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface * @return * The current row formatted as requested. */ + #[\ReturnTypeWillChange] public function current() { if (isset($this->currentRow)) { switch ($this->fetchStyle) { @@ -285,7 +286,7 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface case PDO::FETCH_OBJ: return (object) $this->currentRow; case PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE: - $class_name = array_unshift($this->currentRow); + $class_name = array_shift($this->currentRow); // Deliberate no break. case PDO::FETCH_CLASS: if (!isset($class_name)) { @@ -320,14 +321,17 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface /* Implementations of Iterator. */ + #[\ReturnTypeWillChange] public function key() { return $this->currentKey; } + #[\ReturnTypeWillChange] public function rewind() { // Nothing to do: our DatabaseStatement can't be rewound. } + #[\ReturnTypeWillChange] public function next() { if (!empty($this->data)) { $this->currentRow = reset($this->data); @@ -339,6 +343,7 @@ class DatabaseStatementPrefetch implements Iterator, DatabaseStatementInterface } } + #[\ReturnTypeWillChange] public function valid() { return isset($this->currentRow); } diff --git a/includes/database/prefetch.inc:Zone.Identifier b/includes/database/prefetch.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/prefetch.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/query.inc b/includes/database/query.inc index 048c8a2654..7346fbc0bd 100644 --- a/includes/database/query.inc +++ b/includes/database/query.inc @@ -871,8 +871,14 @@ class DeleteQuery extends Query implements QueryConditionInterface { $query = $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '} '; if (count($this->condition)) { - - $this->condition->compile($this->connection, $this); + try { + $this->condition->compile($this->connection, $this); + } + // PHP does not allow exceptions to be thrown in __toString(), so trigger + // a fatal error instead. + catch (InvalidQueryConditionOperatorException $e) { + drupal_trigger_fatal_error($e->getMessage()); + } $query .= "\nWHERE " . $this->condition; } @@ -1204,7 +1210,14 @@ class UpdateQuery extends Query implements QueryConditionInterface { $query = $comments . 'UPDATE {' . $this->connection->escapeTable($this->table) . '} SET ' . implode(', ', $update_fields); if (count($this->condition)) { - $this->condition->compile($this->connection, $this); + try { + $this->condition->compile($this->connection, $this); + } + // PHP does not allow exceptions to be thrown in __toString(), so trigger + // a fatal error instead. + catch (InvalidQueryConditionOperatorException $e) { + drupal_trigger_fatal_error($e->getMessage()); + } // There is an implicit string cast on $this->condition. $query .= "\nWHERE " . $this->condition; } @@ -1697,6 +1710,7 @@ class DatabaseCondition implements QueryConditionInterface, Countable { * size of its conditional array minus one, because one element is the * conjunction. */ + #[\ReturnTypeWillChange] public function count() { return count($this->conditions) - 1; } @@ -1789,6 +1803,8 @@ class DatabaseCondition implements QueryConditionInterface, Countable { /** * Implements QueryConditionInterface::compile(). + * + * @throws InvalidQueryConditionOperatorException */ public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) { // Re-compile if this condition changed or if we are compiled against a @@ -1819,6 +1835,12 @@ class DatabaseCondition implements QueryConditionInterface, Countable { $arguments += $condition['field']->arguments(); } else { + // If the operator contains an invalid character, throw an + // exception to protect against SQL injection attempts. + if (stripos($condition['operator'], 'UNION') !== FALSE || strpbrk($condition['operator'], '[-\'"();') !== FALSE) { + throw new InvalidQueryConditionOperatorException('Invalid characters in query operator: ' . $condition['operator']); + } + // For simplicity, we treat all operators as the same data structure. // In the typical degenerate case, this won't get changed. $operator_defaults = array( @@ -1883,7 +1905,7 @@ class DatabaseCondition implements QueryConditionInterface, Countable { public function __toString() { // If the caller forgot to call compile() first, refuse to run. if ($this->changed) { - return NULL; + return ''; } return $this->stringVersion; } diff --git a/includes/database/query.inc:Zone.Identifier b/includes/database/query.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/query.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/schema.inc:Zone.Identifier b/includes/database/schema.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/schema.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/select.inc b/includes/database/select.inc index 674c6b53ad..fa3745609a 100644 --- a/includes/database/select.inc +++ b/includes/database/select.inc @@ -883,7 +883,7 @@ class SelectQuery extends Query implements SelectQueryInterface { * 'type' => $join_type (one of INNER, LEFT OUTER, RIGHT OUTER), * 'table' => $table, * 'alias' => $alias_of_the_table, - * 'condition' => $condition_clause_on_which_to_join, + * 'condition' => $join_condition (string or Condition object), * 'arguments' => $array_of_arguments_for_placeholders_in_the condition. * 'all_fields' => TRUE to SELECT $alias.*, FALSE or NULL otherwise. * ) @@ -891,6 +891,10 @@ class SelectQuery extends Query implements SelectQueryInterface { * If $table is a string, it is taken as the name of a table. If it is * a SelectQuery object, it is taken as a subquery. * + * If $join_condition is a Condition object, any arguments should be + * incorporated into the object; a separate array of arguments does not need + * to be provided. + * * @var array */ protected $tables = array(); @@ -1028,6 +1032,10 @@ class SelectQuery extends Query implements SelectQueryInterface { if ($table['table'] instanceof SelectQueryInterface) { $args += $table['table']->arguments(); } + // If the join condition is an object, grab its arguments recursively. + if (!empty($table['condition']) && $table['condition'] instanceof QueryConditionInterface) { + $args += $table['condition']->arguments(); + } } foreach ($this->expressions as $expression) { @@ -1079,6 +1087,10 @@ class SelectQuery extends Query implements SelectQueryInterface { if ($table['table'] instanceof SelectQueryInterface) { $table['table']->compile($connection, $queryPlaceholder); } + // Make sure join conditions are also compiled. + if (!empty($table['condition']) && $table['condition'] instanceof QueryConditionInterface) { + $table['condition']->compile($connection, $queryPlaceholder); + } } // If there are any dependent queries to UNION, compile it recursively. @@ -1099,6 +1111,11 @@ class SelectQuery extends Query implements SelectQueryInterface { return FALSE; } } + if (!empty($table['condition']) && $table['condition'] instanceof QueryConditionInterface) { + if (!$table['condition']->compiled()) { + return FALSE; + } + } } foreach ($this->union as $union) { @@ -1504,7 +1521,14 @@ class SelectQuery extends Query implements SelectQueryInterface { // the query will be executed, it will be recompiled using the proper // placeholder generator anyway. if (!$this->compiled()) { - $this->compile($this->connection, $this); + try { + $this->compile($this->connection, $this); + } + // PHP does not allow exceptions to be thrown in __toString(), so trigger + // a fatal error instead. + catch (InvalidQueryConditionOperatorException $e) { + drupal_trigger_fatal_error($e->getMessage()); + } } // Create a sanitized comment string to prepend to the query. @@ -1561,7 +1585,7 @@ class SelectQuery extends Query implements SelectQueryInterface { $query .= $table_string . ' ' . $this->connection->escapeAlias($table['alias']); if (!empty($table['condition'])) { - $query .= ' ON ' . $table['condition']; + $query .= ' ON ' . (string) $table['condition']; } } @@ -1582,6 +1606,14 @@ class SelectQuery extends Query implements SelectQueryInterface { $query .= "\nHAVING " . $this->having; } + // UNION is a little odd, as the select queries to combine are passed into + // this query, but syntactically they all end up on the same level. + if ($this->union) { + foreach ($this->union as $union) { + $query .= ' ' . $union['type'] . ' ' . (string) $union['query']; + } + } + // ORDER BY if ($this->order) { $query .= "\nORDER BY "; @@ -1601,14 +1633,6 @@ class SelectQuery extends Query implements SelectQueryInterface { $query .= "\nLIMIT " . (int) $this->range['length'] . " OFFSET " . (int) $this->range['start']; } - // UNION is a little odd, as the select queries to combine are passed into - // this query, but syntactically they all end up on the same level. - if ($this->union) { - foreach ($this->union as $union) { - $query .= ' ' . $union['type'] . ' ' . (string) $union['query']; - } - } - if ($this->forUpdate) { $query .= ' FOR UPDATE'; } @@ -1617,6 +1641,8 @@ class SelectQuery extends Query implements SelectQueryInterface { } public function __clone() { + parent::__clone(); + // On cloning, also clone the dependent objects. However, we do not // want to clone the database connection object as that would duplicate the // connection itself. @@ -1626,6 +1652,11 @@ class SelectQuery extends Query implements SelectQueryInterface { foreach ($this->union as $key => $aggregate) { $this->union[$key]['query'] = clone($aggregate['query']); } + foreach ($this->tables as $alias => $table) { + if ($table['table'] instanceof SelectQueryInterface) { + $this->tables[$alias]['table'] = clone $table['table']; + } + } } } diff --git a/includes/database/select.inc:Zone.Identifier b/includes/database/select.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/select.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/sqlite/database.inc:Zone.Identifier b/includes/database/sqlite/database.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/sqlite/database.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/sqlite/install.inc:Zone.Identifier b/includes/database/sqlite/install.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/sqlite/install.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/sqlite/query.inc:Zone.Identifier b/includes/database/sqlite/query.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/sqlite/query.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/sqlite/schema.inc b/includes/database/sqlite/schema.inc index 43ea6d61c5..9d9ec895eb 100644 --- a/includes/database/sqlite/schema.inc +++ b/includes/database/sqlite/schema.inc @@ -433,7 +433,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema { 'type' => $type, 'size' => $size, 'not null' => !empty($row->notnull), - 'default' => trim($row->dflt_value, "'"), + 'default' => trim((string) $row->dflt_value, "'"), ); if ($length) { $schema['fields'][$row->name]['length'] = $length; diff --git a/includes/database/sqlite/schema.inc:Zone.Identifier b/includes/database/sqlite/schema.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/sqlite/schema.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/database/sqlite/select.inc:Zone.Identifier b/includes/database/sqlite/select.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/database/sqlite/select.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/entity.inc b/includes/entity.inc index e80ce3b89f..2500e383cc 100644 --- a/includes/entity.inc +++ b/includes/entity.inc @@ -254,7 +254,10 @@ class DrupalDefaultEntityController implements DrupalEntityControllerInterface { * Callback for array_filter that removes non-integer IDs. */ protected function filterId($id) { - return is_numeric($id) && $id == (int) $id; + // ctype_digit() is used here instead of a strict comparison as sometimes + // the id is passed as a string containing '0' which may represent a bug + // elsewhere but would fail with a strict comparison. + return is_numeric($id) && $id == (int) $id && ctype_digit((string) $id); } /** diff --git a/includes/entity.inc:Zone.Identifier b/includes/entity.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/entity.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/errors.inc b/includes/errors.inc index 4401ebe87e..500b7b9618 100644 --- a/includes/errors.inc +++ b/includes/errors.inc @@ -59,7 +59,8 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line) { require_once DRUPAL_ROOT . '/includes/common.inc'; } - // We treat recoverable errors as fatal. + // We treat recoverable errors as fatal, and also allow fatal errors to be + // explicitly triggered by drupal_trigger_fatal_error(). _drupal_log_error(array( '%type' => isset($types[$error_level]) ? $severity_msg : 'Unknown error', // The standard PHP error handler considers that the error messages @@ -69,7 +70,7 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line) { '%file' => $caller['file'], '%line' => $caller['line'], 'severity_level' => $severity_level, - ), $error_level == E_RECOVERABLE_ERROR); + ), $error_level == E_RECOVERABLE_ERROR || drupal_static('drupal_trigger_fatal_error')); } } @@ -266,7 +267,7 @@ function _drupal_log_error($error, $fatal = FALSE) { function _drupal_get_last_caller($backtrace) { // Errors that occur inside PHP internal functions do not generate // information about file and line. Ignore black listed functions. - $blacklist = array('debug', '_drupal_error_handler', '_drupal_exception_handler'); + $blacklist = array('debug', '_drupal_error_handler', '_drupal_exception_handler', 'drupal_trigger_fatal_error'); while (($backtrace && !isset($backtrace[0]['line'])) || (isset($backtrace[1]['function']) && in_array($backtrace[1]['function'], $blacklist))) { array_shift($backtrace); diff --git a/includes/errors.inc:Zone.Identifier b/includes/errors.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/errors.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/file.inc b/includes/file.inc index 013c435cf3..b132b9c77c 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -197,7 +197,7 @@ function file_stream_wrapper_get_class($scheme) { * @see file_uri_target() */ function file_uri_scheme($uri) { - $position = strpos($uri, '://'); + $position = strpos((string) $uri, '://'); return $position ? substr($uri, 0, $position) : FALSE; } @@ -437,10 +437,10 @@ function file_prepare_directory(&$directory, $options = FILE_MODIFY_PERMISSIONS) // Check if directory exists. if (!is_dir($directory)) { - // Let mkdir() recursively create directories and use the default directory - // permissions. - if (($options & FILE_CREATE_DIRECTORY) && @drupal_mkdir($directory, NULL, TRUE)) { - return drupal_chmod($directory); + // Let drupal_mkdir() recursively create directories and use the default + // directory permissions. + if ($options & FILE_CREATE_DIRECTORY) { + return @drupal_mkdir($directory, NULL, TRUE); } return FALSE; } @@ -535,6 +535,10 @@ SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006 php_flag engine off +# From PHP 8 there is no number in the module name. + + php_flag engine off + EOF; if ($private) { @@ -2481,19 +2485,21 @@ function drupal_basename($uri, $suffix = NULL) { } /** - * Creates a directory using Drupal's default mode. + * Creates a directory, optionally creating missing components in the path to + * the directory. * - * PHP's mkdir() does not respect Drupal's default permissions mode. If a mode - * is not provided, this function will make sure that Drupal's is used. - * - * Compatibility: normal paths and stream wrappers. + * When PHP's mkdir() creates a directory, the requested mode is affected by the + * process's umask. This function overrides the umask and sets the mode + * explicitly for all directory components created. * * @param $uri * A URI or pathname. * @param $mode - * By default the Drupal mode is used. + * Mode given to created directories. Defaults to the directory mode + * configured in the Drupal installation. It must have a leading zero. * @param $recursive - * Default to FALSE. + * Create directories recursively, defaults to FALSE. Cannot work with a mode + * which denies writing or execution to the owner of the process. * @param $context * Refer to http://php.net/manual/ref.stream.php * @@ -2509,7 +2515,71 @@ function drupal_mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL) { $mode = variable_get('file_chmod_directory', 0775); } - if (!isset($context)) { + // If the URI has a scheme, don't override the umask - schemes can handle this + // issue in their own implementation. + if (file_uri_scheme($uri)) { + return _drupal_mkdir_call($uri, $mode, $recursive, $context); + } + + // If recursive, create each missing component of the parent directory + // individually and set the mode explicitly to override the umask. + if ($recursive) { + // Ensure the path is using DIRECTORY_SEPARATOR, and trim off any trailing + // slashes because they can throw off the loop when creating the parent + // directories. + $uri = rtrim(str_replace('/', DIRECTORY_SEPARATOR, $uri), DIRECTORY_SEPARATOR); + // Determine the components of the path. + $components = explode(DIRECTORY_SEPARATOR, $uri); + // If the filepath is absolute the first component will be empty as there + // will be nothing before the first slash. + if ($components[0] == '') { + $recursive_path = DIRECTORY_SEPARATOR; + // Get rid of the empty first component. + array_shift($components); + } + else { + $recursive_path = ''; + } + // Don't handle the top-level directory in this loop. + array_pop($components); + // Create each component if necessary. + foreach ($components as $component) { + $recursive_path .= $component; + + if (!file_exists($recursive_path)) { + $success = _drupal_mkdir_call($recursive_path, $mode, FALSE, $context); + // If the operation failed, check again if the directory was created + // by another process/server, only report a failure if not. + if (!$success && !file_exists($recursive_path)) { + return FALSE; + } + // Not necessary to use self::chmod() as there is no scheme. + if (!chmod($recursive_path, $mode)) { + return FALSE; + } + } + + $recursive_path .= DIRECTORY_SEPARATOR; + } + } + + // Do not check if the top-level directory already exists, as this condition + // must cause this function to fail. + if (!_drupal_mkdir_call($uri, $mode, FALSE, $context)) { + return FALSE; + } + // Not necessary to use drupal_chmod() as there is no scheme. + return chmod($uri, $mode); +} + +/** + * Helper function. Ensures we don't pass a NULL as a context resource to + * mkdir(). + * + * @see drupal_mkdir() + */ +function _drupal_mkdir_call($uri, $mode, $recursive, $context) { + if (is_null($context)) { return mkdir($uri, $mode, $recursive); } else { diff --git a/includes/file.inc:Zone.Identifier b/includes/file.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/file.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/filetransfer/filetransfer.inc b/includes/filetransfer/filetransfer.inc index cd420bd06a..2817b89d50 100644 --- a/includes/filetransfer/filetransfer.inc +++ b/includes/filetransfer/filetransfer.inc @@ -364,7 +364,7 @@ class FileTransferException extends Exception { public $arguments; function __construct($message, $code = 0, $arguments = array()) { - parent::__construct($message, $code); + parent::__construct($message, (int) $code); $this->arguments = $arguments; } } @@ -409,11 +409,13 @@ class SkipDotsRecursiveDirectoryIterator extends RecursiveDirectoryIterator { $this->skipdots(); } + #[\ReturnTypeWillChange] function rewind() { parent::rewind(); $this->skipdots(); } + #[\ReturnTypeWillChange] function next() { parent::next(); $this->skipdots(); diff --git a/includes/filetransfer/filetransfer.inc:Zone.Identifier b/includes/filetransfer/filetransfer.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/filetransfer/filetransfer.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/filetransfer/ftp.inc:Zone.Identifier b/includes/filetransfer/ftp.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/filetransfer/ftp.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/filetransfer/local.inc:Zone.Identifier b/includes/filetransfer/local.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/filetransfer/local.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/filetransfer/ssh.inc:Zone.Identifier b/includes/filetransfer/ssh.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/filetransfer/ssh.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/form.inc b/includes/form.inc index 3f6c7661ad..fe52b0afaa 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -1393,7 +1393,10 @@ function _form_validate(&$elements, &$form_state, $form_id = NULL) { // identical to the empty option's value, we reset the element's value // to NULL to trigger the regular #required handling below. // @see form_process_select() - elseif ($elements['#type'] == 'select' && !$elements['#multiple'] && $elements['#required'] && !isset($elements['#default_value']) && $elements['#value'] === $elements['#empty_value']) { + elseif ($elements['#type'] == 'select' && $elements['#required'] + && (!array_key_exists('#multiple', $elements) || !$elements['#multiple']) + && !isset($elements['#default_value']) + && $elements['#value'] === $elements['#empty_value']) { $elements['#value'] = NULL; form_set_value($elements, NULL, $form_state); } @@ -2084,7 +2087,7 @@ function _form_builder_handle_input_element($form_id, &$element, &$form_state) { // #access=FALSE on an element usually allow access for some users, so forms // submitted with drupal_form_submit() may bypass access restriction and be // treated as high-privilege users instead. - $process_input = empty($element['#disabled']) && (($form_state['programmed'] && $form_state['programmed_bypass_access_check']) || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access']))); + $process_input = empty($element['#disabled']) && ($element['#type'] !== 'value') && (($form_state['programmed'] && $form_state['programmed_bypass_access_check']) || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access']))); // Set the element's #value property. if (!isset($element['#value']) && !array_key_exists('#value', $element)) { @@ -4324,10 +4327,14 @@ function theme_form_required_marker($variables) { * required. That is especially important for screenreader users to know * which field is required. * + * To associate the label with a different field, set the #label_for property + * to the ID of the desired field. + * * @param $variables * An associative array containing: * - element: An associative array containing the properties of the element. - * Properties used: #required, #title, #id, #value, #description. + * Properties used: #required, #title, #id, #value, #description, + * #label_for. * * @ingroup themeable */ @@ -4356,7 +4363,14 @@ function theme_form_element_label($variables) { $attributes['class'] = 'element-invisible'; } - if (!empty($element['#id'])) { + // Use the element's ID as the default value of the "for" attribute (to + // associate the label with this form element), but allow this to be + // overridden in order to associate the label with a different form element + // instead. + if (!empty($element['#label_for'])) { + $attributes['for'] = $element['#label_for']; + } + elseif (!empty($element['#id'])) { $attributes['for'] = $element['#id']; } diff --git a/includes/form.inc:Zone.Identifier b/includes/form.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/form.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/install.core.inc b/includes/install.core.inc index b18d23d213..2e4c491a7f 100644 --- a/includes/install.core.inc +++ b/includes/install.core.inc @@ -1505,8 +1505,19 @@ function install_configure_form($form, &$form_state, &$install_state) { // especially out of place on the last page of the installer, where it would // distract from the message that the Drupal installation has completed // successfully.) - if (empty($_POST) && (!drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE) || !drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_dir, FILE_NOT_WRITABLE, 'dir'))) { - drupal_set_message(st('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the online handbook.', array('%dir' => $settings_dir, '%file' => $settings_file, '@handbook_url' => 'http://drupal.org/server-permissions')), 'warning'); + + $skip_permissions_hardening = variable_get('skip_permissions_hardening', FALSE); + // Allow system administrators to ignore permissions hardening for the site + // directory. This allows additional files in the site directory to be + // updated when they are managed in a version control system. + if (!$skip_permissions_hardening) { + if (empty($_POST) && (!drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_file, FILE_EXIST | FILE_READABLE | FILE_NOT_WRITABLE) || !drupal_verify_install_file(DRUPAL_ROOT . '/' . $settings_dir, FILE_NOT_WRITABLE, 'dir'))) { + drupal_set_message(st('All necessary changes to %dir and %file have been made, so you should remove write permissions to them now in order to avoid security risks. If you are unsure how to do so, consult the online handbook.', array( + '%dir' => $settings_dir, + '%file' => $settings_file, + '@handbook_url' => 'http://drupal.org/server-permissions' + )), 'warning'); + } } drupal_add_js(drupal_get_path('module', 'system') . '/system.js'); diff --git a/includes/install.core.inc:Zone.Identifier b/includes/install.core.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/install.core.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/install.inc b/includes/install.inc index b7db783586..8f9137be30 100644 --- a/includes/install.inc +++ b/includes/install.inc @@ -830,11 +830,14 @@ function drupal_uninstall_modules($module_list = array(), $uninstall_dependents * An optional bitmask created from various FILE_* constants. * @param $type * The type of file. Can be file (default), dir, or link. + * @param bool $autofix + * (optional) Determines whether to attempt fixing the permissions according + * to the provided $mask. Defaults to TRUE. * * @return * TRUE on success or FALSE on failure. A message is set for the latter. */ -function drupal_verify_install_file($file, $mask = NULL, $type = 'file') { +function drupal_verify_install_file($file, $mask = NULL, $type = 'file', $autofix = TRUE) { $return = TRUE; // Check for files that shouldn't be there. if (isset($mask) && ($mask & FILE_NOT_EXIST) && file_exists($file)) { @@ -856,7 +859,7 @@ function drupal_verify_install_file($file, $mask = NULL, $type = 'file') { switch ($current_mask) { case FILE_EXIST: if (!file_exists($file)) { - if ($type == 'dir') { + if ($type == 'dir' && $autofix) { drupal_install_mkdir($file, $mask); } if (!file_exists($file)) { @@ -865,32 +868,32 @@ function drupal_verify_install_file($file, $mask = NULL, $type = 'file') { } break; case FILE_READABLE: - if (!is_readable($file) && !drupal_install_fix_file($file, $mask)) { + if (!is_readable($file)) { $return = FALSE; } break; case FILE_WRITABLE: - if (!is_writable($file) && !drupal_install_fix_file($file, $mask)) { + if (!is_writable($file)) { $return = FALSE; } break; case FILE_EXECUTABLE: - if (!is_executable($file) && !drupal_install_fix_file($file, $mask)) { + if (!is_executable($file)) { $return = FALSE; } break; case FILE_NOT_READABLE: - if (is_readable($file) && !drupal_install_fix_file($file, $mask)) { + if (is_readable($file)) { $return = FALSE; } break; case FILE_NOT_WRITABLE: - if (is_writable($file) && !drupal_install_fix_file($file, $mask)) { + if (is_writable($file)) { $return = FALSE; } break; case FILE_NOT_EXECUTABLE: - if (is_executable($file) && !drupal_install_fix_file($file, $mask)) { + if (is_executable($file)) { $return = FALSE; } break; @@ -898,6 +901,9 @@ function drupal_verify_install_file($file, $mask = NULL, $type = 'file') { } } } + if (!$return && $autofix) { + return drupal_install_fix_file($file, $mask); + } return $return; } diff --git a/includes/install.inc:Zone.Identifier b/includes/install.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/install.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/iso.inc b/includes/iso.inc index 5cad329d9d..e15c35731e 100644 --- a/includes/iso.inc +++ b/includes/iso.inc @@ -327,7 +327,7 @@ function _locale_get_predefined_list() { 'da' => array('Danish', 'Dansk'), 'de' => array('German', 'Deutsch'), 'dv' => array('Maldivian'), - 'dz' => array('Bhutani'), + 'dz' => array('Dzongkha', 'རྫོང་ཁ'), 'ee' => array('Ewe', 'Ɛʋɛ'), 'el' => array('Greek', 'Ελληνικά'), 'en' => array('English'), diff --git a/includes/iso.inc:Zone.Identifier b/includes/iso.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/iso.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/locale.inc b/includes/locale.inc index 11f1413eec..48dbdce988 100644 --- a/includes/locale.inc +++ b/includes/locale.inc @@ -615,7 +615,7 @@ function locale_add_language($langcode, $name = NULL, $native = NULL, $direction 'direction' => $direction, 'domain' => $domain, 'prefix' => $prefix, - 'enabled' => $enabled, + 'enabled' => $enabled ? 1 : 0, )) ->execute(); @@ -1603,7 +1603,7 @@ function _locale_parse_js_file($filepath) { if ($source) { // We already have this source string and now have to add the location // to the location column, if this file is not yet present in there. - $locations = preg_split('~\s*;\s*~', $source->location); + $locations = preg_split('~\s*;\s*~', (string) $source->location); if (!in_array($filepath, $locations)) { $locations[] = $filepath; diff --git a/includes/locale.inc:Zone.Identifier b/includes/locale.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/locale.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/menu.inc b/includes/menu.inc index b979275110..519ce8af57 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -3203,7 +3203,7 @@ function menu_link_save(&$item, $existing_item = array(), $parent_candidates = a 'external' => $item['external'], 'has_children' => $item['has_children'], 'expanded' => $item['expanded'], - 'weight' => $item['weight'], + 'weight' => (int) $item['weight'], 'module' => $item['module'], 'link_title' => $item['link_title'], 'options' => serialize($item['options']), @@ -3267,7 +3267,7 @@ function menu_link_save(&$item, $existing_item = array(), $parent_candidates = a 'external' => $item['external'], 'has_children' => $item['has_children'], 'expanded' => $item['expanded'], - 'weight' => $item['weight'], + 'weight' => (int) $item['weight'], 'depth' => $item['depth'], 'p1' => $item['p1'], 'p2' => $item['p2'], @@ -3906,7 +3906,7 @@ function _menu_router_save($menu, $masks) { 'type' => $item['type'], 'description' => $item['description'], 'position' => $item['position'], - 'weight' => $item['weight'], + 'weight' => (int) $item['weight'], 'include_file' => $item['include file'], )); diff --git a/includes/menu.inc:Zone.Identifier b/includes/menu.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/menu.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/module.inc b/includes/module.inc index 4c2b3fbeeb..ab368b4b67 100644 --- a/includes/module.inc +++ b/includes/module.inc @@ -142,9 +142,10 @@ function system_list($type) { foreach ($bootstrap_list as $module) { drupal_get_filename('module', $module->name, $module->filename); } - // We only return the module names here since module_list() doesn't need - // the filename itself. - $lists['bootstrap'] = array_keys($bootstrap_list); + // Only return module names here since module_list() doesn't need the + // filename itself. Don't use drupal_map_assoc() as that requires common.inc. + $list = array_keys($bootstrap_list); + $lists['bootstrap'] = (!empty($list) ? array_combine($list, $list) : array()); } // Otherwise build the list for enabled modules and themes. elseif (!isset($lists['module_enabled'])) { diff --git a/includes/module.inc:Zone.Identifier b/includes/module.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/module.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/pager.inc b/includes/pager.inc index 316e17d5ad..48daa15e73 100644 --- a/includes/pager.inc +++ b/includes/pager.inc @@ -164,6 +164,21 @@ class PagerDefault extends SelectQueryExtender { } return $this; } + + /** + * Gets the element ID for this pager query. + * + * The element is used to differentiate different pager queries on the same + * page so that they may be operated independently. + * + * @return + * Element ID that is used to differentiate between different pager + * queries. + */ + public function getElement() { + $this->ensureElement(); + return $this->element; + } } /** diff --git a/includes/pager.inc:Zone.Identifier b/includes/pager.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/pager.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/path.inc b/includes/path.inc index 28d1146a5e..5ed4a4ce0f 100644 --- a/includes/path.inc +++ b/includes/path.inc @@ -417,6 +417,8 @@ function path_load($conditions) { } return $select ->fields('url_alias') + ->orderBy('pid', 'DESC') + ->range(0, 1) ->execute() ->fetchAssoc(); } diff --git a/includes/path.inc:Zone.Identifier b/includes/path.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/path.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/session.inc b/includes/session.inc index a4ce54b7d0..1f3c1773ba 100644 --- a/includes/session.inc +++ b/includes/session.inc @@ -106,7 +106,7 @@ function _drupal_session_read($sid) { // active user. if ($user && $user->uid > 0 && $user->status == 1) { // This is done to unserialize the data member of $user. - $user->data = unserialize($user->data); + $user->data = unserialize((string) $user->data); // Add roles element to $user. $user->roles = array(); diff --git a/includes/session.inc:Zone.Identifier b/includes/session.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/session.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/stream_wrappers.inc b/includes/stream_wrappers.inc index 232ff1437c..285621893b 100644 --- a/includes/stream_wrappers.inc +++ b/includes/stream_wrappers.inc @@ -405,6 +405,12 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface public function stream_open($uri, $mode, $options, &$opened_path) { $this->uri = $uri; $path = $this->getLocalPath(); + if ($path === FALSE) { + if ($options & STREAM_REPORT_ERRORS) { + trigger_error('stream_open() filename cannot be empty', E_USER_WARNING); + } + return FALSE; + } $this->handle = ($options & STREAM_REPORT_ERRORS) ? fopen($path, $mode) : @fopen($path, $mode); if ((bool) $this->handle && $options & STREAM_USE_PATH) { @@ -784,10 +790,10 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface $localpath = $this->getLocalPath($uri); } if ($options & STREAM_REPORT_ERRORS) { - return mkdir($localpath, $mode, $recursive); + return drupal_mkdir($localpath, $mode, $recursive); } else { - return @mkdir($localpath, $mode, $recursive); + return @drupal_mkdir($localpath, $mode, $recursive); } } @@ -928,6 +934,27 @@ class DrupalPublicStreamWrapper extends DrupalLocalStreamWrapper { $path = str_replace('\\', '/', $this->getTarget()); return $GLOBALS['base_url'] . '/' . self::getDirectoryPath() . '/' . drupal_encode_path($path); } + + /** + * {@inheritdoc} + */ + protected function getLocalPath($uri = NULL) { + $path = parent::getLocalPath($uri); + + if (variable_get('sa_core_2022_012_override', FALSE)) { + return $path; + } + + $private_path = variable_get('file_private_path', FALSE); + if ($private_path) { + $private_path = realpath($private_path); + if ($private_path && strpos($path, $private_path) === 0) { + return FALSE; + } + } + + return $path; + } } diff --git a/includes/stream_wrappers.inc:Zone.Identifier b/includes/stream_wrappers.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/stream_wrappers.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/includes/unicode.inc b/includes/unicode.inc index f9684a8973..4c61ce143e 100644 --- a/includes/unicode.inc +++ b/includes/unicode.inc @@ -589,6 +589,7 @@ function drupal_ucfirst($text) { */ function drupal_substr($text, $start, $length = NULL) { global $multibyte; + $text = (string) $text; if ($multibyte == UNICODE_MULTIBYTE) { return $length === NULL ? mb_substr($text, $start) : mb_substr($text, $start, $length); } diff --git a/includes/unicode.inc:Zone.Identifier b/includes/unicode.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/includes/unicode.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/misc/batch.js b/misc/batch.js index fee71a52fd..998879e4a5 100644 --- a/misc/batch.js +++ b/misc/batch.js @@ -7,6 +7,9 @@ Drupal.behaviors.batch = { attach: function (context, settings) { $('#progress', context).once('batch', function () { var holder = $(this); + // Remove HTML from no-js progress bar. The JS progress bar is created + // later on. + holder.empty(); // Success: redirect to the summary. var updateCallback = function (progress, status, pb) { diff --git a/misc/batch.js:Zone.Identifier b/misc/batch.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/misc/batch.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/misc/drupal.js b/misc/drupal.js index 7a3f5f5926..07692fcbc7 100644 --- a/misc/drupal.js +++ b/misc/drupal.js @@ -588,8 +588,12 @@ Drupal.ajaxError = function (xmlhttp, uri, customMessage) { // Class indicating that JS is enabled; used for styling purpose. $('html').addClass('js'); -// 'js enabled' cookie. -document.cookie = 'has_js=1; path=/'; +$(function () { + if (Drupal.settings.setHasJsCookie === 1) { + // 'js enabled' cookie. + document.cookie = 'has_js=1; path=/; SameSite=Lax'; + } +}); /** * Additions to jQuery.support. diff --git a/misc/drupal.js:Zone.Identifier b/misc/drupal.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/misc/drupal.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/misc/machine-name.js b/misc/machine-name.js index 4678e0b534..45c146b4f4 100644 --- a/misc/machine-name.js +++ b/misc/machine-name.js @@ -27,7 +27,7 @@ Drupal.behaviors.machineName = { attach: function (context, settings) { var self = this; $.each(settings.machineName, function (source_id, options) { - var $source = $(source_id, context).addClass('machine-name-source'); + var $source = $(source_id, context).addClass('machine-name-source').once('machine-name'); var $target = $(options.target, context).addClass('machine-name-target'); var $suffix = $(options.suffix, context); var $wrapper = $target.closest('.form-item'); diff --git a/misc/machine-name.js:Zone.Identifier b/misc/machine-name.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/misc/machine-name.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/misc/ui/jquery.ui.datepicker-1.13.0-backport.js b/misc/ui/jquery.ui.datepicker-1.13.0-backport.js new file mode 100644 index 0000000000..9cb92b0236 --- /dev/null +++ b/misc/ui/jquery.ui.datepicker-1.13.0-backport.js @@ -0,0 +1,36 @@ +/** + * Backport of security fixes from: + * https://github.com/jquery/jquery-ui/pull/1953 + * https://github.com/jquery/jquery-ui/pull/1954 + */ + +(function ($, Drupal) { + + // No backport is needed if we're already on jQuery UI 1.13 or higher. + var versionParts = $.ui.datepicker.version.split('.'); + var majorVersion = parseInt(versionParts[0]); + var minorVersion = parseInt(versionParts[1]); + if ( (majorVersion > 1) || (majorVersion === 1 && minorVersion >= 13) ) { + return; + } + + var fnOriginalGet = $.datepicker._get; + $.extend($.datepicker, { + + _get: function( inst, name ) { + var val = fnOriginalGet.call(this, inst, name); + + // @see https://github.com/jquery/jquery-ui/pull/1954 + if (name === 'altField') { + val = $(document).find(val); + } + // @see https://github.com/jquery/jquery-ui/pull/1953 + else if ($.inArray(name, ['appendText', 'buttonText', 'prevText', 'currentText', 'nextText', 'closeText']) !== -1) { + val = Drupal.checkPlain(val); + } + + return val; + } + + }) +})(jQuery, Drupal); diff --git a/misc/ui/jquery.ui.datepicker-1.13.0-backport.js:Zone.Identifier b/misc/ui/jquery.ui.datepicker-1.13.0-backport.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/misc/ui/jquery.ui.datepicker-1.13.0-backport.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/misc/ui/jquery.ui.dialog-1.13.0-backport.js b/misc/ui/jquery.ui.dialog-1.13.0-backport.js new file mode 100644 index 0000000000..564092d9ea --- /dev/null +++ b/misc/ui/jquery.ui.dialog-1.13.0-backport.js @@ -0,0 +1,58 @@ +/** + * Backport of security fixes from: + * https://bugs.jqueryui.com/ticket/6016 + * https://github.com/jquery/jquery-ui/pull/1635/files + */ + +(function ($) { + + // Parts of this backport differ by jQuery version. + var versionParts = $.ui.dialog.version.split('.'); + var majorVersion = parseInt(versionParts[0]); + var minorVersion = parseInt(versionParts[1]); + + if (majorVersion === 1 && minorVersion < 13) { + var _originalSetOption = $.ui.dialog.prototype._setOption; + var _originalCreateTitlebar = $.ui.dialog.prototype._createTitlebar; + + $.extend($.ui.dialog.prototype, { + + _createTitlebar: function () { + if (this.options.closeText) { + this.options.closeText = Drupal.checkPlain(this.options.closeText); + } + _originalCreateTitlebar.apply(this, arguments); + }, + + _setOption: function (key, value) { + if (key === 'title' || key == 'closeText') { + if (value) { + value = Drupal.checkPlain(value); + } + } + _originalSetOption.apply(this, [key, value]); + } + }); + + if (majorVersion === 1 && minorVersion < 10) { + var _originalCreate = $.ui.dialog.prototype._create; + + $.extend($.ui.dialog.prototype, { + + _create: function () { + if (!this.options.title) { + var defaultTitle = this.element.attr('title'); + // .attr() might return a DOMElement + if (typeof defaultTitle !== "string") { + defaultTitle = ""; + } + this.options.title = defaultTitle; + } + this.options.title = Drupal.checkPlain(this.options.title); + _originalCreate.apply(this, arguments); + }, + }); + } + } + +})(jQuery); diff --git a/misc/ui/jquery.ui.dialog-1.13.0-backport.js:Zone.Identifier b/misc/ui/jquery.ui.dialog-1.13.0-backport.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/misc/ui/jquery.ui.dialog-1.13.0-backport.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/misc/ui/jquery.ui.position-1.13.0-backport.js b/misc/ui/jquery.ui.position-1.13.0-backport.js new file mode 100644 index 0000000000..6567e5e2fe --- /dev/null +++ b/misc/ui/jquery.ui.position-1.13.0-backport.js @@ -0,0 +1,33 @@ +/** + * Backport of security fix from: + * https://github.com/jquery/jquery-ui/pull/1955/files + */ + +(function ($) { + + // No backport is needed if we're already on jQuery UI 1.13 or higher. + var versionParts = $.ui.version.split('.'); + var majorVersion = parseInt(versionParts[0]); + var minorVersion = parseInt(versionParts[1]); + if ( (majorVersion > 1) || (majorVersion === 1 && minorVersion >= 13) ) { + return; + } + + var fnOriginalPosition = $.fn.position; + $.fn.extend({ + 'position': function (options) { + if (typeof options === 'undefined') { + return fnOriginalPosition.call(this); + } + + // Make sure string options are treated as CSS selectors + var target = typeof options.of === "string" ? + $(document).find(options.of) : + $(options.of); + + options.of = (target[0] === undefined) ? null : target; + return fnOriginalPosition.call(this, options); + } + }); + +})(jQuery); diff --git a/misc/ui/jquery.ui.position-1.13.0-backport.js:Zone.Identifier b/misc/ui/jquery.ui.position-1.13.0-backport.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/misc/ui/jquery.ui.position-1.13.0-backport.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator-feed-source.tpl.php:Zone.Identifier b/modules/aggregator/aggregator-feed-source.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator-feed-source.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator-item.tpl.php:Zone.Identifier b/modules/aggregator/aggregator-item.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator-item.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator-rtl.css:Zone.Identifier b/modules/aggregator/aggregator-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator-summary-item.tpl.php:Zone.Identifier b/modules/aggregator/aggregator-summary-item.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator-summary-item.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator-summary-items.tpl.php:Zone.Identifier b/modules/aggregator/aggregator-summary-items.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator-summary-items.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator-wrapper.tpl.php:Zone.Identifier b/modules/aggregator/aggregator-wrapper.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator-wrapper.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.admin.inc:Zone.Identifier b/modules/aggregator/aggregator.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.api.php:Zone.Identifier b/modules/aggregator/aggregator.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.css:Zone.Identifier b/modules/aggregator/aggregator.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.fetcher.inc:Zone.Identifier b/modules/aggregator/aggregator.fetcher.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.fetcher.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.info b/modules/aggregator/aggregator.info index cdf7864b4a..b696670c21 100644 --- a/modules/aggregator/aggregator.info +++ b/modules/aggregator/aggregator.info @@ -7,7 +7,7 @@ files[] = aggregator.test configure = admin/config/services/aggregator/settings stylesheets[all][] = aggregator.css -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/aggregator/aggregator.info:Zone.Identifier b/modules/aggregator/aggregator.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.install:Zone.Identifier b/modules/aggregator/aggregator.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.module:Zone.Identifier b/modules/aggregator/aggregator.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.pages.inc:Zone.Identifier b/modules/aggregator/aggregator.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.parser.inc:Zone.Identifier b/modules/aggregator/aggregator.parser.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.parser.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.processor.inc:Zone.Identifier b/modules/aggregator/aggregator.processor.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.processor.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/aggregator.test:Zone.Identifier b/modules/aggregator/aggregator.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/aggregator.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/tests/aggregator_test.info b/modules/aggregator/tests/aggregator_test.info index 8569ca1aac..c63f62eac7 100644 --- a/modules/aggregator/tests/aggregator_test.info +++ b/modules/aggregator/tests/aggregator_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/aggregator/tests/aggregator_test.info:Zone.Identifier b/modules/aggregator/tests/aggregator_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/tests/aggregator_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/tests/aggregator_test.module:Zone.Identifier b/modules/aggregator/tests/aggregator_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/tests/aggregator_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/tests/aggregator_test_atom.xml:Zone.Identifier b/modules/aggregator/tests/aggregator_test_atom.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/tests/aggregator_test_atom.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/tests/aggregator_test_rss091.xml:Zone.Identifier b/modules/aggregator/tests/aggregator_test_rss091.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/tests/aggregator_test_rss091.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/aggregator/tests/aggregator_test_title_entities.xml:Zone.Identifier b/modules/aggregator/tests/aggregator_test_title_entities.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/aggregator/tests/aggregator_test_title_entities.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block-admin-display-form.tpl.php:Zone.Identifier b/modules/block/block-admin-display-form.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block-admin-display-form.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block.admin.inc:Zone.Identifier b/modules/block/block.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block.api.php:Zone.Identifier b/modules/block/block.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block.css:Zone.Identifier b/modules/block/block.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block.info b/modules/block/block.info index 346fb701f5..d043c4a441 100644 --- a/modules/block/block.info +++ b/modules/block/block.info @@ -6,7 +6,7 @@ core = 7.x files[] = block.test configure = admin/structure/block -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/block/block.info:Zone.Identifier b/modules/block/block.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block.install:Zone.Identifier b/modules/block/block.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block.js:Zone.Identifier b/modules/block/block.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block.module:Zone.Identifier b/modules/block/block.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block.test:Zone.Identifier b/modules/block/block.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/block.tpl.php:Zone.Identifier b/modules/block/block.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/block.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/tests/block_test.info b/modules/block/tests/block_test.info index abb024f78b..a680bffc15 100644 --- a/modules/block/tests/block_test.info +++ b/modules/block/tests/block_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/block/tests/block_test.info:Zone.Identifier b/modules/block/tests/block_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/tests/block_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/tests/block_test.module:Zone.Identifier b/modules/block/tests/block_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/tests/block_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/tests/themes/block_test_theme/block_test_theme.info b/modules/block/tests/themes/block_test_theme/block_test_theme.info index 3eaf9c065a..a3cdefbf4a 100644 --- a/modules/block/tests/themes/block_test_theme/block_test_theme.info +++ b/modules/block/tests/themes/block_test_theme/block_test_theme.info @@ -13,7 +13,7 @@ regions[footer] = Footer regions[highlighted] = Highlighted regions[help] = Help -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/block/tests/themes/block_test_theme/block_test_theme.info:Zone.Identifier b/modules/block/tests/themes/block_test_theme/block_test_theme.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/tests/themes/block_test_theme/block_test_theme.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/block/tests/themes/block_test_theme/page.tpl.php:Zone.Identifier b/modules/block/tests/themes/block_test_theme/page.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/block/tests/themes/block_test_theme/page.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/blog/blog.info b/modules/blog/blog.info index 775e032ad8..95bdd0c92a 100644 --- a/modules/blog/blog.info +++ b/modules/blog/blog.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = blog.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/blog/blog.info:Zone.Identifier b/modules/blog/blog.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/blog/blog.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/blog/blog.install:Zone.Identifier b/modules/blog/blog.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/blog/blog.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/blog/blog.module:Zone.Identifier b/modules/blog/blog.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/blog/blog.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/blog/blog.pages.inc:Zone.Identifier b/modules/blog/blog.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/blog/blog.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/blog/blog.test:Zone.Identifier b/modules/blog/blog.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/blog/blog.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book-all-books-block.tpl.php:Zone.Identifier b/modules/book/book-all-books-block.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book-all-books-block.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book-export-html.tpl.php:Zone.Identifier b/modules/book/book-export-html.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book-export-html.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book-navigation.tpl.php:Zone.Identifier b/modules/book/book-navigation.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book-navigation.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book-node-export-html.tpl.php:Zone.Identifier b/modules/book/book-node-export-html.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book-node-export-html.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book-rtl.css:Zone.Identifier b/modules/book/book-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book.admin.inc:Zone.Identifier b/modules/book/book.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book.css:Zone.Identifier b/modules/book/book.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book.info b/modules/book/book.info index 37a7b3d230..be6bf9b1ce 100644 --- a/modules/book/book.info +++ b/modules/book/book.info @@ -7,7 +7,7 @@ files[] = book.test configure = admin/content/book/settings stylesheets[all][] = book.css -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/book/book.info:Zone.Identifier b/modules/book/book.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book.install:Zone.Identifier b/modules/book/book.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book.js:Zone.Identifier b/modules/book/book.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book.module:Zone.Identifier b/modules/book/book.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book.pages.inc:Zone.Identifier b/modules/book/book.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/book/book.test:Zone.Identifier b/modules/book/book.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/book/book.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/color-rtl.css:Zone.Identifier b/modules/color/color-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/color-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/color.css:Zone.Identifier b/modules/color/color.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/color.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/color.info b/modules/color/color.info index 0e6287e95d..2254f09768 100644 --- a/modules/color/color.info +++ b/modules/color/color.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = color.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/color/color.info:Zone.Identifier b/modules/color/color.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/color.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/color.install:Zone.Identifier b/modules/color/color.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/color.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/color.js:Zone.Identifier b/modules/color/color.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/color.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/color.module b/modules/color/color.module index 45acd788ff..583a203228 100644 --- a/modules/color/color.module +++ b/modules/color/color.module @@ -724,7 +724,7 @@ function _color_blend($img, $hex1, $hex2, $alpha) { $in2 = _color_unpack($hex2); $out = array($img); for ($i = 0; $i < 3; ++$i) { - $out[] = $in1[$i] + ($in2[$i] - $in1[$i]) * $alpha; + $out[] = (int) ($in1[$i] + ($in2[$i] - $in1[$i]) * $alpha); } return call_user_func_array('imagecolorallocate', $out); @@ -752,7 +752,7 @@ function _color_unpack($hex, $normalize = FALSE) { function _color_pack($rgb, $normalize = FALSE) { $out = 0; foreach ($rgb as $k => $v) { - $out |= (($v * ($normalize ? 255 : 1)) << (16 - $k * 8)); + $out |= (((int) ($v * ($normalize ? 255 : 1))) << (16 - $k * 8)); } return '#' . str_pad(dechex($out), 6, 0, STR_PAD_LEFT); diff --git a/modules/color/color.module:Zone.Identifier b/modules/color/color.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/color.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/color.test b/modules/color/color.test index f29c0c2679..bac17a8476 100644 --- a/modules/color/color.test +++ b/modules/color/color.test @@ -131,3 +131,53 @@ class ColorTestCase extends DrupalWebTestCase { } } } + +/** + * Unit tests for the color.module + */ +class ColorUnitTestCase extends DrupalUnitTestCase { + + protected $test_values; + + /** + * {@inheritdoc} + */ + public static function getInfo() { + return array( + 'name' => 'Color module unit tests', + 'description' => 'Test color.module functionality.', + 'group' => 'Color', + ); + } + + /** + * Set up the test environment. + */ + public function setUp() { + drupal_load('module', 'color'); + parent::setUp(); + + $this->test_values = array( + array(array(0.2, 0.4, 0.8), TRUE, '#3366cc'), + array(array(51, 102, 204), FALSE, '#3366cc'), + array(array(6, 120, 190), FALSE, '#0678be'), + array(array(192, 192, 192), FALSE, '#c0c0c0'), + array(array(255, 255, 0), FALSE, '#ffff00'), + array(array(128, 0, 128), FALSE, '#800080'), + array(array(0.6, 0.8, 1), TRUE, '#99ccff'), + array(array(221, 72, 20), FALSE, '#dd4814'), + ); + } + + public function testColorPack() { + foreach ($this->test_values as $test) { + $this->assertEqual(_color_pack($test[0], $test[1]), $test[2], __FUNCTION__ . ' hex: ' . $test[2] . ' normalize: ' . ($test[1] ? 'TRUE' : 'FALSE')); + } + } + + public function testColorUnpack() { + foreach ($this->test_values as $test) { + $this->assertEqual(_color_unpack($test[2], $test[1]), $test[0], __FUNCTION__ . ' hex: ' . $test[2] . ' normalize: ' . ($test[1] ? 'TRUE' : 'FALSE')); + } + } +} diff --git a/modules/color/color.test:Zone.Identifier b/modules/color/color.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/color.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/images/hook-rtl.png:Zone.Identifier b/modules/color/images/hook-rtl.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/images/hook-rtl.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/images/hook.png:Zone.Identifier b/modules/color/images/hook.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/images/hook.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/images/lock.png:Zone.Identifier b/modules/color/images/lock.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/images/lock.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/preview.html:Zone.Identifier b/modules/color/preview.html:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/preview.html:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/color/preview.js:Zone.Identifier b/modules/color/preview.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/color/preview.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment-node-form.js:Zone.Identifier b/modules/comment/comment-node-form.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment-node-form.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment-rtl.css:Zone.Identifier b/modules/comment/comment-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment-wrapper.tpl.php:Zone.Identifier b/modules/comment/comment-wrapper.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment-wrapper.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.admin.inc:Zone.Identifier b/modules/comment/comment.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.api.php:Zone.Identifier b/modules/comment/comment.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.css:Zone.Identifier b/modules/comment/comment.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.info b/modules/comment/comment.info index 19a4bcd25c..77e8cfcd38 100644 --- a/modules/comment/comment.info +++ b/modules/comment/comment.info @@ -9,7 +9,7 @@ files[] = comment.test configure = admin/content/comment stylesheets[all][] = comment.css -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/comment/comment.info:Zone.Identifier b/modules/comment/comment.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.install:Zone.Identifier b/modules/comment/comment.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.module b/modules/comment/comment.module index 6f0df6cae1..786be42de9 100644 --- a/modules/comment/comment.module +++ b/modules/comment/comment.module @@ -1515,7 +1515,7 @@ function comment_save($comment) { // by retrieving the maximum thread level. $max = db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid))->fetchField(); // Strip the "/" from the end of the thread. - $max = rtrim($max, '/'); + $max = rtrim((string) $max, '/'); // We need to get the value at the correct depth. $parts = explode('.', $max); $firstsegment = $parts[0]; @@ -1918,7 +1918,6 @@ function comment_form($form, &$form_state, $comment) { if ($is_admin) { $author = (!$comment->uid && $comment->name ? $comment->name : $comment->registered_name); $status = (isset($comment->status) ? $comment->status : COMMENT_NOT_PUBLISHED); - $date = (!empty($comment->date) ? $comment->date : format_date($comment->created, 'custom', 'Y-m-d H:i O')); } else { if ($user->uid) { @@ -1928,7 +1927,11 @@ function comment_form($form, &$form_state, $comment) { $author = ($comment->name ? $comment->name : ''); } $status = (user_access('skip comment approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED); - $date = ''; + } + + $date = ''; + if ($comment->cid) { + $date = !empty($comment->date) ? $comment->date : format_date($comment->created, 'custom', 'Y-m-d H:i:s O'); } // Add the author name field depending on the current user. @@ -2176,7 +2179,7 @@ function comment_submit($comment) { if (empty($comment->date)) { $comment->date = 'now'; } - $comment->created = strtotime($comment->date); + $comment->created = strtotime($comment->date, REQUEST_TIME); $comment->changed = REQUEST_TIME; // If the comment was posted by a registered user, assign the author's ID. diff --git a/modules/comment/comment.module:Zone.Identifier b/modules/comment/comment.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.pages.inc:Zone.Identifier b/modules/comment/comment.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.test b/modules/comment/comment.test index b70fa26c38..f87560bdf9 100644 --- a/modules/comment/comment.test +++ b/modules/comment/comment.test @@ -1003,7 +1003,7 @@ class CommentPreviewTest extends CommentHelperCase { */ function testCommentEditPreviewSave() { $langcode = LANGUAGE_NONE; - $web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'skip comment approval')); + $web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'skip comment approval', 'edit own comments')); $this->drupalLogin($this->admin_user); $this->setCommentPreview(DRUPAL_OPTIONAL); $this->setCommentForm(TRUE); @@ -1017,7 +1017,7 @@ class CommentPreviewTest extends CommentHelperCase { $edit['date'] = '2008-03-02 17:23 +0300'; $raw_date = strtotime($edit['date']); $expected_text_date = format_date($raw_date); - $expected_form_date = format_date($raw_date, 'custom', 'Y-m-d H:i O'); + $expected_form_date = format_date($raw_date, 'custom', 'Y-m-d H:i:s O'); $comment = $this->postComment($this->node, $edit['subject'], $edit['comment_body[' . $langcode . '][0][value]'], TRUE); $this->drupalPost('comment/' . $comment->id . '/edit', $edit, t('Preview')); @@ -1059,7 +1059,16 @@ class CommentPreviewTest extends CommentHelperCase { $this->assertEqual($comment_loaded->comment_body[$langcode][0]['value'], $edit['comment_body[' . $langcode . '][0][value]'], 'Comment body loaded.'); $this->assertEqual($comment_loaded->name, $edit['name'], 'Name loaded.'); $this->assertEqual($comment_loaded->created, $raw_date, 'Date loaded.'); + $this->drupalLogout(); + // Check that the date and time of the comment are correct when edited by + // non-admin users. + $user_edit = array(); + $expected_created_time = $comment_loaded->created; + $this->drupalLogin($web_user); + $this->drupalPost('comment/' . $comment->id . '/edit', $user_edit, t('Save')); + $comment_loaded = comment_load($comment->id, TRUE); + $this->assertEqual($comment_loaded->created, $expected_created_time, 'Expected date and time for comment edited.'); } } diff --git a/modules/comment/comment.test:Zone.Identifier b/modules/comment/comment.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.tokens.inc:Zone.Identifier b/modules/comment/comment.tokens.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.tokens.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/comment/comment.tpl.php:Zone.Identifier b/modules/comment/comment.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/comment/comment.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contact/contact.admin.inc:Zone.Identifier b/modules/contact/contact.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contact/contact.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contact/contact.info b/modules/contact/contact.info index 1d0e483e47..0a8c6b1c95 100644 --- a/modules/contact/contact.info +++ b/modules/contact/contact.info @@ -6,7 +6,7 @@ core = 7.x files[] = contact.test configure = admin/structure/contact -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/contact/contact.info:Zone.Identifier b/modules/contact/contact.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contact/contact.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contact/contact.install:Zone.Identifier b/modules/contact/contact.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contact/contact.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contact/contact.module:Zone.Identifier b/modules/contact/contact.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contact/contact.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contact/contact.pages.inc:Zone.Identifier b/modules/contact/contact.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contact/contact.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contact/contact.test:Zone.Identifier b/modules/contact/contact.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contact/contact.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contextual/contextual-rtl.css:Zone.Identifier b/modules/contextual/contextual-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contextual/contextual-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contextual/contextual.api.php:Zone.Identifier b/modules/contextual/contextual.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contextual/contextual.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contextual/contextual.css:Zone.Identifier b/modules/contextual/contextual.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contextual/contextual.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contextual/contextual.info b/modules/contextual/contextual.info index 73c478e632..5d97a68913 100644 --- a/modules/contextual/contextual.info +++ b/modules/contextual/contextual.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = contextual.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/contextual/contextual.info:Zone.Identifier b/modules/contextual/contextual.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contextual/contextual.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contextual/contextual.js:Zone.Identifier b/modules/contextual/contextual.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contextual/contextual.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contextual/contextual.module:Zone.Identifier b/modules/contextual/contextual.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contextual/contextual.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contextual/contextual.test:Zone.Identifier b/modules/contextual/contextual.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contextual/contextual.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/contextual/images/gear-select.png:Zone.Identifier b/modules/contextual/images/gear-select.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/contextual/images/gear-select.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dashboard/dashboard-rtl.css:Zone.Identifier b/modules/dashboard/dashboard-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dashboard/dashboard-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dashboard/dashboard.api.php:Zone.Identifier b/modules/dashboard/dashboard.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dashboard/dashboard.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dashboard/dashboard.css:Zone.Identifier b/modules/dashboard/dashboard.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dashboard/dashboard.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dashboard/dashboard.info b/modules/dashboard/dashboard.info index 983f918655..562059672d 100644 --- a/modules/dashboard/dashboard.info +++ b/modules/dashboard/dashboard.info @@ -7,7 +7,7 @@ files[] = dashboard.test dependencies[] = block configure = admin/dashboard/customize -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/dashboard/dashboard.info:Zone.Identifier b/modules/dashboard/dashboard.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dashboard/dashboard.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dashboard/dashboard.install:Zone.Identifier b/modules/dashboard/dashboard.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dashboard/dashboard.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dashboard/dashboard.js:Zone.Identifier b/modules/dashboard/dashboard.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dashboard/dashboard.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dashboard/dashboard.module:Zone.Identifier b/modules/dashboard/dashboard.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dashboard/dashboard.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dashboard/dashboard.test:Zone.Identifier b/modules/dashboard/dashboard.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dashboard/dashboard.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dblog/dblog-rtl.css:Zone.Identifier b/modules/dblog/dblog-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dblog/dblog-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dblog/dblog.admin.inc b/modules/dblog/dblog.admin.inc index f8a00c26bb..df9f6a8719 100644 --- a/modules/dblog/dblog.admin.inc +++ b/modules/dblog/dblog.admin.inc @@ -286,13 +286,19 @@ function theme_dblog_message($variables) { $event = $variables['event']; // Check for required properties. if (isset($event->message) && isset($event->variables)) { + $event_variables = @unserialize($event->variables); // Messages without variables or user specified text. - if ($event->variables === 'N;') { + if ($event_variables === NULL) { $output = $event->message; } + elseif (!is_array($event_variables)) { + $output = t('Log data is corrupted and cannot be unserialized: @message', array( + '@message' => $event->message, + )); + } // Message to translate with injected variables. else { - $output = t($event->message, unserialize($event->variables)); + $output = t($event->message, $event_variables); } // If the output is expected to be a link, strip all the tags and // special characters by using filter_xss() without any allowed tags. diff --git a/modules/dblog/dblog.admin.inc:Zone.Identifier b/modules/dblog/dblog.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dblog/dblog.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dblog/dblog.css:Zone.Identifier b/modules/dblog/dblog.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dblog/dblog.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dblog/dblog.info b/modules/dblog/dblog.info index 6466d9bc01..1e043dea21 100644 --- a/modules/dblog/dblog.info +++ b/modules/dblog/dblog.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = dblog.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/dblog/dblog.info:Zone.Identifier b/modules/dblog/dblog.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dblog/dblog.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dblog/dblog.install:Zone.Identifier b/modules/dblog/dblog.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dblog/dblog.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dblog/dblog.module:Zone.Identifier b/modules/dblog/dblog.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dblog/dblog.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/dblog/dblog.test b/modules/dblog/dblog.test index b0a58ba454..9c266656fd 100644 --- a/modules/dblog/dblog.test +++ b/modules/dblog/dblog.test @@ -58,12 +58,42 @@ class DBLogTestCase extends DrupalWebTestCase { $this->verifyCron($row_limit); $this->verifyEvents(); $this->verifyReports(); + $this->testDBLogCorrupted(); // Login the regular user. $this->drupalLogin($this->any_user); $this->verifyReports(403); } + /** + * Tests corrupted log entries can still display available data. + */ + private function testDBLogCorrupted() { + global $base_root; + + // Prepare the fields to be logged + $log = array( + 'type' => 'custom', + 'message' => 'Log entry added to test the unserialize failure.', + 'variables' => 'BAD SERIALIZED DATA', + 'severity' => WATCHDOG_NOTICE, + 'link' => '', + 'user' => $this->big_user, + 'uid' => isset($this->big_user->uid) ? $this->big_user->uid : 0, + 'request_uri' => $base_root . request_uri(), + 'referer' => $_SERVER['HTTP_REFERER'], + 'ip' => ip_address(), + 'timestamp' => REQUEST_TIME, + ); + dblog_watchdog($log); + + // View the database log report page. + $this->drupalGet('admin/reports/dblog'); + $this->assertResponse(200); + $output = truncate_utf8(filter_xss(t('Log data is corrupted and cannot be unserialized: Log entry added to test unserialize failure.'), array()), 56, TRUE, TRUE); + $this->assertText($output, 'Log data is corrupted and cannot be unserialized.'); + } + /** * Verifies setting of the database log row limit. * diff --git a/modules/dblog/dblog.test:Zone.Identifier b/modules/dblog/dblog.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/dblog/dblog.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.api.php:Zone.Identifier b/modules/field/field.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.attach.inc:Zone.Identifier b/modules/field/field.attach.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.attach.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.crud.inc b/modules/field/field.crud.inc index 7c0e3a154a..3673128d08 100644 --- a/modules/field/field.crud.inc +++ b/modules/field/field.crud.inc @@ -733,6 +733,7 @@ function field_read_instances($params = array(), $include_additional = array()) } $instances = array(); + $query->orderBy('fci.id'); $results = $query->execute(); foreach ($results as $record) { diff --git a/modules/field/field.crud.inc:Zone.Identifier b/modules/field/field.crud.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.crud.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.default.inc:Zone.Identifier b/modules/field/field.default.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.default.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.form.inc:Zone.Identifier b/modules/field/field.form.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.form.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.info b/modules/field/field.info index 2b570ad58a..9cd7e0d76b 100644 --- a/modules/field/field.info +++ b/modules/field/field.info @@ -11,7 +11,7 @@ dependencies[] = field_sql_storage required = TRUE stylesheets[all][] = theme/field.css -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/field/field.info.class.inc b/modules/field/field.info.class.inc index 772cd451f3..03dad67741 100644 --- a/modules/field/field.info.class.inc +++ b/modules/field/field.info.class.inc @@ -138,7 +138,7 @@ class FieldInfo { $map = array(); - $query = db_query('SELECT fc.type, fci.field_name, fci.entity_type, fci.bundle FROM {field_config_instance} fci INNER JOIN {field_config} fc ON fc.id = fci.field_id WHERE fc.active = 1 AND fc.storage_active = 1 AND fc.deleted = 0 AND fci.deleted = 0'); + $query = db_query('SELECT fc.type, fci.field_name, fci.entity_type, fci.bundle FROM {field_config_instance} fci INNER JOIN {field_config} fc ON fc.id = fci.field_id WHERE fc.active = 1 AND fc.storage_active = 1 AND fc.deleted = 0 AND fci.deleted = 0 ORDER BY bundle, entity_type'); foreach ($query as $row) { $map[$row->field_name]['bundles'][$row->entity_type][] = $row->bundle; $map[$row->field_name]['type'] = $row->type; diff --git a/modules/field/field.info.class.inc:Zone.Identifier b/modules/field/field.info.class.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.info.class.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.info.inc:Zone.Identifier b/modules/field/field.info.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.info.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.info:Zone.Identifier b/modules/field/field.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.install:Zone.Identifier b/modules/field/field.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.module:Zone.Identifier b/modules/field/field.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/field.multilingual.inc:Zone.Identifier b/modules/field/field.multilingual.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/field.multilingual.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.info b/modules/field/modules/field_sql_storage/field_sql_storage.info index 3b80c0bf10..3390ada1e5 100644 --- a/modules/field/modules/field_sql_storage/field_sql_storage.info +++ b/modules/field/modules/field_sql_storage/field_sql_storage.info @@ -7,7 +7,7 @@ dependencies[] = field files[] = field_sql_storage.test required = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.info:Zone.Identifier b/modules/field/modules/field_sql_storage/field_sql_storage.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/field_sql_storage/field_sql_storage.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.install:Zone.Identifier b/modules/field/modules/field_sql_storage/field_sql_storage.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/field_sql_storage/field_sql_storage.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.module b/modules/field/modules/field_sql_storage/field_sql_storage.module index deb08d0dac..63161ab7d1 100644 --- a/modules/field/modules/field_sql_storage/field_sql_storage.module +++ b/modules/field/modules/field_sql_storage/field_sql_storage.module @@ -212,6 +212,18 @@ function _field_sql_storage_schema($field) { ), ); + // If the target entity type uses a string for its entity ID then update + // the fields entity_id and revision_id columns from INT to VARCHAR. + if (!empty($field['entity_id_type']) && $field['entity_id_type'] === 'string') { + $current['fields']['entity_id']['type'] = 'varchar'; + $current['fields']['entity_id']['length'] = 128; + unset($current['fields']['entity_id']['unsigned']); + + $current['fields']['revision_id']['type'] = 'varchar'; + $current['fields']['revision_id']['length'] = 128; + unset($current['fields']['revision_id']['unsigned']); + } + $field += array('columns' => array(), 'indexes' => array(), 'foreign keys' => array()); // Add field columns. foreach ($field['columns'] as $column_name => $attributes) { diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.module:Zone.Identifier b/modules/field/modules/field_sql_storage/field_sql_storage.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/field_sql_storage/field_sql_storage.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.test b/modules/field/modules/field_sql_storage/field_sql_storage.test index e46677be9c..ad8d74926b 100644 --- a/modules/field/modules/field_sql_storage/field_sql_storage.test +++ b/modules/field/modules/field_sql_storage/field_sql_storage.test @@ -104,6 +104,29 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase { $this->assertFalse(array_key_exists($unavailable_language, $entity->{$this->field_name}), 'Field translation in an unavailable language ignored'); } + /** + * Tests adding a field with an entity ID type of string. + */ + function testFieldSqlSchemaForEntityWithStringIdentifier() { + // Test programmatically adding field with string ID. + $field_name = 'string_id_example'; + $field = array('field_name' => $field_name, 'type' => 'text', 'settings' => array('max_length' => 255), 'entity_id_type' => 'string'); + field_create_field($field); + $schema = drupal_get_schema('field_data_' . $field_name); + + $this->assertEqual($schema['fields']['entity_id']['type'], 'varchar'); + $this->assertEqual($schema['fields']['revision_id']['type'], 'varchar'); + + // Test programmatically adding field with default ID(int). + $field_name = 'default_id_example'; + $field = array('field_name' => $field_name, 'type' => 'text', 'settings' => array('max_length' => 255)); + field_create_field($field); + $schema = drupal_get_schema('field_data_' . $field_name); + + $this->assertEqual($schema['fields']['entity_id']['type'], 'int'); + $this->assertEqual($schema['fields']['revision_id']['type'], 'int'); + } + /** * Reads mysql to verify correct data is * written when using insert and update. diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.test:Zone.Identifier b/modules/field/modules/field_sql_storage/field_sql_storage.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/field_sql_storage/field_sql_storage.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/list/list.info b/modules/field/modules/list/list.info index d79eb626dd..3ca656359f 100644 --- a/modules/field/modules/list/list.info +++ b/modules/field/modules/list/list.info @@ -7,7 +7,7 @@ dependencies[] = field dependencies[] = options files[] = tests/list.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/field/modules/list/list.info:Zone.Identifier b/modules/field/modules/list/list.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/list/list.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/list/list.install:Zone.Identifier b/modules/field/modules/list/list.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/list/list.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/list/list.module b/modules/field/modules/list/list.module index 634c134886..47544be681 100644 --- a/modules/field/modules/list/list.module +++ b/modules/field/modules/list/list.module @@ -67,7 +67,7 @@ function list_field_settings_form($field, $instance, $has_data) { $form['allowed_values'] = array( '#type' => 'textarea', '#title' => t('Allowed values list'), - '#default_value' => list_allowed_values_string($settings['allowed_values']), + '#default_value' => empty($settings['allowed_values_function']) ? list_allowed_values_string($settings['allowed_values']) : array(), '#rows' => 10, '#element_validate' => array('list_allowed_values_setting_validate'), '#field_has_data' => $has_data, @@ -388,7 +388,8 @@ function _list_values_in_use($field, $values) { * - 'list_illegal_value': The value is not part of the list of allowed values. */ function list_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) { - $allowed_values = list_allowed_values($field, $instance, $entity_type, $entity); + // Flatten the array before validating to account for optgroups. + $allowed_values = options_array_flatten(list_allowed_values($field, $instance, $entity_type, $entity)); foreach ($items as $delta => $item) { if (!empty($item['value'])) { if (!empty($allowed_values) && !isset($allowed_values[$item['value']])) { diff --git a/modules/field/modules/list/list.module:Zone.Identifier b/modules/field/modules/list/list.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/list/list.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/list/tests/list.test b/modules/field/modules/list/tests/list.test index b476b5aad1..7c3aec0c4a 100644 --- a/modules/field/modules/list/tests/list.test +++ b/modules/field/modules/list/tests/list.test @@ -406,18 +406,36 @@ class ListFieldUITestCase extends FieldTestCase { $this->assertFalse(isset($field['settings']['off']), 'The off value is not saved into settings'); } + /** + * List (text) : test 'allowed values function' input. + */ + function testDynamicListAllowedValuesText() { + $this->field_name = 'field_list_text'; + $this->createListField('list_text', array( + 'allowed_values_function' => 'list_test_dynamic_values_callback', + 'allowed_values' => '', + )); + $this->drupalGet($this->admin_path); + } + /** * Helper function to create list field of a given type. * * @param string $type * 'list_integer', 'list_float', 'list_text' or 'list_boolean' + * @param array $settings + * + * @throws \FieldException */ - protected function createListField($type) { + protected function createListField($type, $settings = array()) { // Create a test field and instance. $field = array( 'field_name' => $this->field_name, 'type' => $type, ); + if (!empty($settings)) { + $field['settings'] = $settings; + } field_create_field($field); $instance = array( 'field_name' => $this->field_name, diff --git a/modules/field/modules/list/tests/list.test:Zone.Identifier b/modules/field/modules/list/tests/list.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/list/tests/list.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/list/tests/list_test.info b/modules/field/modules/list/tests/list_test.info index e61332db98..f40208c070 100644 --- a/modules/field/modules/list/tests/list_test.info +++ b/modules/field/modules/list/tests/list_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/field/modules/list/tests/list_test.info:Zone.Identifier b/modules/field/modules/list/tests/list_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/list/tests/list_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/list/tests/list_test.module:Zone.Identifier b/modules/field/modules/list/tests/list_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/list/tests/list_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/number/number.info b/modules/field/modules/number/number.info index 064d07d130..7bd9574f0c 100644 --- a/modules/field/modules/number/number.info +++ b/modules/field/modules/number/number.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = field files[] = number.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/field/modules/number/number.info:Zone.Identifier b/modules/field/modules/number/number.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/number/number.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/number/number.install:Zone.Identifier b/modules/field/modules/number/number.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/number/number.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/number/number.module:Zone.Identifier b/modules/field/modules/number/number.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/number/number.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/number/number.test:Zone.Identifier b/modules/field/modules/number/number.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/number/number.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/options/options.api.php:Zone.Identifier b/modules/field/modules/options/options.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/options/options.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/options/options.info b/modules/field/modules/options/options.info index 1c9c437eef..25ce8fcd09 100644 --- a/modules/field/modules/options/options.info +++ b/modules/field/modules/options/options.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = field files[] = options.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/field/modules/options/options.info:Zone.Identifier b/modules/field/modules/options/options.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/options/options.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/options/options.module:Zone.Identifier b/modules/field/modules/options/options.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/options/options.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/options/options.test b/modules/field/modules/options/options.test index 321c2a4b5d..67110960ff 100644 --- a/modules/field/modules/options/options.test +++ b/modules/field/modules/options/options.test @@ -311,6 +311,11 @@ class OptionsWidgetsTestCase extends FieldTestCase { $edit = array("card_1[$langcode]" => '_none'); $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save')); $this->assertFieldValues($entity_init, 'card_1', $langcode, array()); + + // Submit form: select the option from optgroup. + $edit = array("card_1[$langcode]" => 2); + $this->drupalPost(NULL, $edit, t('Save')); + $this->assertFieldValues($entity_init, 'card_1', $langcode, array(2)); } /** diff --git a/modules/field/modules/options/options.test:Zone.Identifier b/modules/field/modules/options/options.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/options/options.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/text/text.info b/modules/field/modules/text/text.info index 57c5cb74fb..07c2e3d301 100644 --- a/modules/field/modules/text/text.info +++ b/modules/field/modules/text/text.info @@ -7,7 +7,7 @@ dependencies[] = field files[] = text.test required = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/field/modules/text/text.info:Zone.Identifier b/modules/field/modules/text/text.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/text/text.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/text/text.install:Zone.Identifier b/modules/field/modules/text/text.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/text/text.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/text/text.js:Zone.Identifier b/modules/field/modules/text/text.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/text/text.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/text/text.module b/modules/field/modules/text/text.module index bf0d29d5a1..d64eef9a68 100644 --- a/modules/field/modules/text/text.module +++ b/modules/field/modules/text/text.module @@ -348,6 +348,11 @@ function _text_sanitize($instance, $langcode, $item, $column) { */ function text_summary($text, $format = NULL, $size = NULL) { + // If the input text is NULL, return unchanged. + if (is_null($text)) { + return NULL; + } + if (!isset($size)) { // What used to be called 'teaser' is now called 'summary', but // the variable 'teaser_length' is preserved for backwards compatibility. diff --git a/modules/field/modules/text/text.module:Zone.Identifier b/modules/field/modules/text/text.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/text/text.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/modules/text/text.test b/modules/field/modules/text/text.test index ad803cf46d..0802c71194 100644 --- a/modules/field/modules/text/text.test +++ b/modules/field/modules/text/text.test @@ -378,6 +378,14 @@ class TextSummaryTestCase extends DrupalWebTestCase { } } + /** + * Test for the NULL value. + */ + function testNullSentence() { + $summary = text_summary(NULL); + $this->assertNull($summary, 'text_summary() casts returned null'); + } + /** * Calls text_summary() and asserts that the expected teaser is returned. */ diff --git a/modules/field/modules/text/text.test:Zone.Identifier b/modules/field/modules/text/text.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/modules/text/text.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test index 5312f2d455..c334661aa1 100644 --- a/modules/field/tests/field.test +++ b/modules/field/tests/field.test @@ -3788,4 +3788,16 @@ class EntityPropertiesTestCase extends FieldTestCase { } } } + + /** + * Tests entity_extract_ids() with an empty entity info. + */ + function testEntityKeys(){ + $entity_type = 'test_entity2'; + $entity = field_test_create_stub_entity(); + list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity); + + $this->assertNull($id, 'Entity id for test_entity2 returned NULL.'); + $this->assertNull($vid, 'Entity vid for test_entity2 returned NULL.'); + } } diff --git a/modules/field/tests/field.test:Zone.Identifier b/modules/field/tests/field.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/tests/field.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/tests/field_test.entity.inc:Zone.Identifier b/modules/field/tests/field_test.entity.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/tests/field_test.entity.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/tests/field_test.field.inc:Zone.Identifier b/modules/field/tests/field_test.field.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/tests/field_test.field.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/tests/field_test.info b/modules/field/tests/field_test.info index 1baa8717d7..a823922406 100644 --- a/modules/field/tests/field_test.info +++ b/modules/field/tests/field_test.info @@ -6,7 +6,7 @@ files[] = field_test.entity.inc version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/field/tests/field_test.info:Zone.Identifier b/modules/field/tests/field_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/tests/field_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/tests/field_test.install:Zone.Identifier b/modules/field/tests/field_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/tests/field_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/tests/field_test.module:Zone.Identifier b/modules/field/tests/field_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/tests/field_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/tests/field_test.storage.inc:Zone.Identifier b/modules/field/tests/field_test.storage.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/tests/field_test.storage.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/theme/field-rtl.css:Zone.Identifier b/modules/field/theme/field-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/theme/field-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/theme/field.css:Zone.Identifier b/modules/field/theme/field.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/theme/field.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field/theme/field.tpl.php:Zone.Identifier b/modules/field/theme/field.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field/theme/field.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field_ui/field_ui-rtl.css:Zone.Identifier b/modules/field_ui/field_ui-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field_ui/field_ui-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc index 1bdaa45ddc..8ae489f303 100644 --- a/modules/field_ui/field_ui.admin.inc +++ b/modules/field_ui/field_ui.admin.inc @@ -795,6 +795,14 @@ function field_ui_field_overview_form_submit($form, &$form_state) { $destinations = array(); + // Check if the target entity uses a non numeric ID. + $entity_info = entity_get_info($entity_type); + if (!empty($entity_info['entity_id_type']) && $entity_info['entity_id_type'] === 'string') { + $entity_id_type = 'string'; + } else { + $entity_id_type = NULL; + } + // Create new field. $field = array(); if (!empty($form_values['_add_new_field']['field_name'])) { @@ -804,6 +812,7 @@ function field_ui_field_overview_form_submit($form, &$form_state) { 'field_name' => $values['field_name'], 'type' => $values['type'], 'translatable' => $values['translatable'], + 'entity_id_type' => $entity_id_type, ); $instance = array( 'field_name' => $field['field_name'], diff --git a/modules/field_ui/field_ui.admin.inc:Zone.Identifier b/modules/field_ui/field_ui.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field_ui/field_ui.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field_ui/field_ui.api.php:Zone.Identifier b/modules/field_ui/field_ui.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field_ui/field_ui.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field_ui/field_ui.css:Zone.Identifier b/modules/field_ui/field_ui.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field_ui/field_ui.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field_ui/field_ui.info b/modules/field_ui/field_ui.info index 6dd468a060..d960343ddb 100644 --- a/modules/field_ui/field_ui.info +++ b/modules/field_ui/field_ui.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = field files[] = field_ui.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/field_ui/field_ui.info:Zone.Identifier b/modules/field_ui/field_ui.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field_ui/field_ui.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field_ui/field_ui.js:Zone.Identifier b/modules/field_ui/field_ui.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field_ui/field_ui.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field_ui/field_ui.module:Zone.Identifier b/modules/field_ui/field_ui.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field_ui/field_ui.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/field_ui/field_ui.test:Zone.Identifier b/modules/field_ui/field_ui.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/field_ui/field_ui.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/file.api.php:Zone.Identifier b/modules/file/file.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/file.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/file.css:Zone.Identifier b/modules/file/file.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/file.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/file.field.inc b/modules/file/file.field.inc index ddb4f841fd..706e01ceed 100644 --- a/modules/file/file.field.inc +++ b/modules/file/file.field.inc @@ -20,7 +20,7 @@ function file_field_info() { ), 'instance_settings' => array( 'file_extensions' => 'txt', - 'file_directory' => '', + 'file_directory' => '[date:custom:Y]-[date:custom:m]', 'max_filesize' => '', 'description_field' => 0, ), @@ -184,7 +184,7 @@ function file_field_load($entity_type, $entities, $field, $instances, $langcode, foreach ($items[$id] as $delta => $item) { // If the file does not exist, mark the entire item as empty. if (empty($item['fid']) || !isset($files[$item['fid']])) { - $items[$id][$delta] = NULL; + unset($items[$id][$delta]); } else { $items[$id][$delta] = array_merge((array) $files[$item['fid']], $item); @@ -943,7 +943,7 @@ function theme_file_upload_help($variables) { $descriptions = array(); - if (strlen($description)) { + if (!empty($description)) { $descriptions[] = $description; } if (isset($upload_validators['file_validate_size'])) { diff --git a/modules/file/file.field.inc:Zone.Identifier b/modules/file/file.field.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/file.field.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/file.info b/modules/file/file.info index ad5266c0cc..8a2810c393 100644 --- a/modules/file/file.info +++ b/modules/file/file.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = field files[] = tests/file.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/file/file.info:Zone.Identifier b/modules/file/file.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/file.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/file.install b/modules/file/file.install index 47ee4fd001..e0d33a04e2 100644 --- a/modules/file/file.install +++ b/modules/file/file.install @@ -53,18 +53,34 @@ function file_requirements($phase) { // Check the server's ability to indicate upload progress. if ($phase == 'runtime') { - $implementation = file_progress_implementation(); - $apache = strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== FALSE; - $fastcgi = strpos($_SERVER['SERVER_SOFTWARE'], 'mod_fastcgi') !== FALSE || strpos($_SERVER["SERVER_SOFTWARE"], 'mod_fcgi') !== FALSE; $description = NULL; - if (!$apache) { + $implementation = file_progress_implementation(); + // Test the web server identity. + $server_software = $_SERVER['SERVER_SOFTWARE']; + if (preg_match("/Nginx/i", $server_software)) { + $is_nginx = TRUE; + $is_apache = FALSE; + $fastcgi = FALSE; + } + elseif (preg_match("/Apache/i", $server_software)) { + $is_nginx = FALSE; + $is_apache = TRUE; + $fastcgi = strpos($server_software, 'mod_fastcgi') !== FALSE || strpos($server_software, 'mod_fcgi') !== FALSE; + } + else { + $is_nginx = FALSE; + $is_apache = FALSE; + $fastcgi = FALSE; + } + + if (!$is_apache && !$is_nginx) { $value = t('Not enabled'); - $description = t('Your server is not capable of displaying file upload progress. File upload progress requires an Apache server running PHP with mod_php.'); + $description = t('Your server is not capable of displaying file upload progress. File upload progress requires an Apache server running PHP with mod_php or Nginx with PHP-FPM.'); $severity = REQUIREMENT_INFO; } elseif ($fastcgi) { $value = t('Not enabled'); - $description = t('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php and not as FastCGI.'); + $description = t('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php or PHP-FPM and not as FastCGI.'); $severity = REQUIREMENT_INFO; } elseif (!$implementation && extension_loaded('apc')) { diff --git a/modules/file/file.install:Zone.Identifier b/modules/file/file.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/file.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/file.js:Zone.Identifier b/modules/file/file.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/file.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/file.module b/modules/file/file.module index 1f1d594475..4db60669e5 100644 --- a/modules/file/file.module +++ b/modules/file/file.module @@ -246,7 +246,15 @@ function file_ajax_upload() { // Invalid request. drupal_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error'); $commands = array(); - $commands[] = ajax_command_replace(NULL, theme('status_messages')); + $commands[] = ajax_command_prepend(NULL, theme('status_messages')); + + // Unset the problematic file from the input so that user can submit the + // form without reloading the page. + // @see https://www.drupal.org/project/drupal/issues/2749245 + $field_name = (string) reset($form_parents); + $wrapper_id = drupal_html_id('edit-' . $field_name); + $commands[] = ajax_command_invoke('#' . $wrapper_id . ' .form-type-managed-file input[type="file"]', 'val', array('')); + return array('#type' => 'ajax', '#commands' => $commands); } @@ -256,7 +264,7 @@ function file_ajax_upload() { // Invalid form_build_id. drupal_set_message(t('An unrecoverable error occurred. Use of this form has expired. Try reloading the page and submitting again.'), 'error'); $commands = array(); - $commands[] = ajax_command_replace(NULL, theme('status_messages')); + $commands[] = ajax_command_prepend(NULL, theme('status_messages')); return array('#type' => 'ajax', '#commands' => $commands); } @@ -363,10 +371,6 @@ function file_file_delete($file) { * support for a default value. */ function file_managed_file_process($element, &$form_state, $form) { - // Append the '-upload' to the #id so the field label's 'for' attribute - // corresponds with the file element. - $original_id = $element['#id']; - $element['#id'] .= '-upload'; $fid = isset($element['#value']['fid']) ? $element['#value']['fid'] : 0; // Set some default element properties. @@ -376,7 +380,7 @@ function file_managed_file_process($element, &$form_state, $form) { $ajax_settings = array( 'path' => 'file/ajax/' . implode('/', $element['#array_parents']) . '/' . $form['form_build_id']['#value'], - 'wrapper' => $original_id . '-ajax-wrapper', + 'wrapper' => $element['#id'] . '-ajax-wrapper', 'effect' => 'fade', 'progress' => array( 'type' => $element['#progress_indicator'], @@ -450,13 +454,26 @@ function file_managed_file_process($element, &$form_state, $form) { $element['upload'] = array( '#name' => 'files[' . implode('_', $element['#parents']) . ']', '#type' => 'file', + // This #title will not actually be used as the upload field's HTML label, + // since the theme function for upload fields never passes the element + // through theme('form_element'). Instead the parent element's #title is + // used as the label (see below). That is usually a more meaningful label + // anyway. '#title' => t('Choose a file'), '#title_display' => 'invisible', + // Set the ID manually so the desired field label can be associated with it + // below. Use the same method for setting the ID that the form API + // autogenerator does. + '#id' => drupal_html_id('edit-' . implode('-', array_merge($element['#parents'], array('upload')))), '#size' => $element['#size'], '#theme_wrappers' => array(), '#weight' => -10, ); + // Indicate that $element['#title'] should be used as the HTML label for the + // file upload field. + $element['#label_for'] = $element['upload']['#id']; + if ($fid && $element['#file']) { $element['filename'] = array( '#type' => 'markup', @@ -482,13 +499,13 @@ function file_managed_file_process($element, &$form_state, $form) { $element['upload']['#attached']['js'] = array( array( 'type' => 'setting', - 'data' => array('file' => array('elements' => array('#' . $element['#id'] => $extension_list))) + 'data' => array('file' => array('elements' => array('#' . $element['upload']['#id'] => $extension_list))) ) ); } // Prefix and suffix used for Ajax replacement. - $element['#prefix'] = '
'; + $element['#prefix'] = '
'; $element['#suffix'] = '
'; return $element; diff --git a/modules/file/file.module:Zone.Identifier b/modules/file/file.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/file.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/application-octet-stream.png:Zone.Identifier b/modules/file/icons/application-octet-stream.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/application-octet-stream.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/application-pdf.png:Zone.Identifier b/modules/file/icons/application-pdf.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/application-pdf.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/application-x-executable.png:Zone.Identifier b/modules/file/icons/application-x-executable.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/application-x-executable.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/audio-x-generic.png:Zone.Identifier b/modules/file/icons/audio-x-generic.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/audio-x-generic.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/image-x-generic.png:Zone.Identifier b/modules/file/icons/image-x-generic.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/image-x-generic.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/package-x-generic.png:Zone.Identifier b/modules/file/icons/package-x-generic.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/package-x-generic.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/text-html.png:Zone.Identifier b/modules/file/icons/text-html.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/text-html.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/text-plain.png:Zone.Identifier b/modules/file/icons/text-plain.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/text-plain.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/text-x-generic.png:Zone.Identifier b/modules/file/icons/text-x-generic.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/text-x-generic.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/text-x-script.png:Zone.Identifier b/modules/file/icons/text-x-script.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/text-x-script.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/video-x-generic.png:Zone.Identifier b/modules/file/icons/video-x-generic.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/video-x-generic.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/x-office-document.png:Zone.Identifier b/modules/file/icons/x-office-document.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/x-office-document.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/x-office-presentation.png:Zone.Identifier b/modules/file/icons/x-office-presentation.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/x-office-presentation.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/icons/x-office-spreadsheet.png:Zone.Identifier b/modules/file/icons/x-office-spreadsheet.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/icons/x-office-spreadsheet.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/tests/file.test b/modules/file/tests/file.test index c8264349d4..782d3a2fce 100644 --- a/modules/file/tests/file.test +++ b/modules/file/tests/file.test @@ -381,6 +381,20 @@ class FileManagedFileElementTestCase extends FileFieldTestCase { ); } + public function setUp() { + parent::setUp(); + + // Disable the displaying of errors, so that the AJAX responses are not + // contaminated with error messages about exceeding the maximum POST size. + $this->originalDisplayErrorsValue = ini_set('display_errors', '0'); + } + + public function tearDown() { + ini_set('display_errors', $this->originalDisplayErrorsValue); + + parent::tearDown(); + } + /** * Tests the managed_file element type. */ @@ -389,6 +403,9 @@ class FileManagedFileElementTestCase extends FileFieldTestCase { $this->drupalGet('file/test'); $this->assertFieldByXpath('//input[@name="files[nested_file]" and @size="13"]', NULL, 'The custom #size attribute is passed to the child upload element.'); + // Check that the file fields don't contain duplicate HTML IDs. + $this->assertNoDuplicateIds('There are no duplicate IDs'); + // Perform the tests with all permutations of $form['#tree'] and // $element['#extended']. foreach (array(0, 1) as $tree) { @@ -470,6 +487,43 @@ class FileManagedFileElementTestCase extends FileFieldTestCase { } } } + + /** + * Tests uploading a file that exceeds the maximum file size. + */ + function testManagedFileExceedMaximumFileSize() { + $path = 'file/test/0/0'; + $this->drupalGet($path); + + // Create a test file that exceeds the maximum POST size with 1 kilobyte. + $post_max_size = $this->_postMaxSizeToInteger(ini_get('post_max_size')); + $filename = 'text-exceeded'; + simpletest_generate_file($filename, ceil(($post_max_size + 1024) / 1024), 1024, 'text'); + $uri = 'public://' . $filename . '.txt'; + $input_base_name = 'file'; + $edit = array('files[' . $input_base_name . ']' => drupal_realpath($uri)); + $this->drupalPostAJAX(NULL, $edit, $input_base_name . '_upload_button'); + $this->assertFieldByXpath('//input[@type="submit"]', t('Upload'), 'After uploading a file that exceeds the maximum file size, the "Upload" button is displayed.'); + $this->drupalPost($path, array(), t('Save')); + $this->assertRaw(t('The file id is %fid.', array('%fid' => 0)), 'Submitted without a file.'); + } + + /** + * Converts php.ini post_max_size value to integer. + * + * @param $string + * The value from php.ini. + * + * @return int + * Converted value. + */ + protected function _postMaxSizeToInteger($string) { + sscanf($string, '%u%c', $number, $suffix); + if (isset($suffix)) { + $number = $number * pow(1024, strpos(' KMG', strtoupper($suffix))); + } + return $number; + } } /** @@ -749,6 +803,23 @@ class FileFieldWidgetTestCase extends FileFieldTestCase { foreach (array($field_name2, $field_name) as $each_field_name) { for ($delta = 0; $delta < 3; $delta++) { $edit = array('files[' . $each_field_name . '_' . LANGUAGE_NONE . '_' . $delta . ']' => drupal_realpath($test_file->uri)); + // drupalPost() takes a $submit parameter that is the value of the + // button whose click we want to emulate. Since we have multiple + // buttons with the value "Upload", and want to control which one we + // use, we change the value of the other ones to something else. + // Since non-clicked buttons aren't included in the submitted POST + // data, and since drupalPost() will result in $this being updated + // with a newly rebuilt form, this doesn't cause problems. Note that + // $buttons is an array of SimpleXMLElement objects passed by + // reference so modifications to each button will affect + // \DrupalWebTestCase::handleForm(). + $buttons = $this->xpath('//input[@type="submit" and @value="Upload"]'); + $button_name = $each_field_name . '_' . LANGUAGE_NONE . '_' . $delta . '_upload_button'; + foreach ($buttons as $button) { + if ($button['name'] != $button_name) { + $button['value'] = 'DUMMY'; + } + } // If the Upload button doesn't exist, drupalPost() will automatically // fail with an assertion message. $this->drupalPost(NULL, $edit, t('Upload')); @@ -786,13 +857,8 @@ class FileFieldWidgetTestCase extends FileFieldTestCase { $button_name = $current_field_name . '_' . LANGUAGE_NONE . '_' . $delta . '_remove_button'; switch ($type) { case 'nojs': - // drupalPost() takes a $submit parameter that is the value of the - // button whose click we want to emulate. Since we have multiple - // buttons with the value "Remove", and want to control which one we - // use, we change the value of the other ones to something else. - // Since non-clicked buttons aren't included in the submitted POST - // data, and since drupalPost() will result in $this being updated - // with a newly rebuilt form, this doesn't cause problems. + // Same workaround for multiple buttons with the value "Remove" as + // we did for the "Upload" buttons above. foreach ($buttons as $button) { if ($button['name'] != $button_name) { $button['value'] = 'DUMMY'; @@ -1354,10 +1420,11 @@ class FileFieldPathTestCase extends FileFieldTestCase { // Create a new node. $nid = $this->uploadNodeFile($test_file, $field_name, $type_name); - // Check that the file was uploaded to the file root. + // Check that the file was uploaded to the correct location. $node = node_load($nid, NULL, TRUE); $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0]; - $this->assertPathMatch('public://' . $test_file->filename, $node_file->uri, format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->uri))); + $expected_path = 'public://' . date('Y', REQUEST_TIME) . '-' . date('m', REQUEST_TIME) . '/' . $test_file->filename; + $this->assertPathMatch($expected_path, $node_file->uri, format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->uri))); // Change the path to contain multiple subdirectories. $field = $this->updateFileField($field_name, $type_name, array('file_directory' => 'foo/bar/baz')); @@ -1932,3 +1999,26 @@ class FileScanDirectory extends FileFieldTestCase { } } + +/** + * Test theme implementations declared in file_theme(). + */ +class FileThemeImplementationsTestCase extends DrupalUnitTestCase { + + public static function getInfo() { + return array( + 'name' => 'Theme implementations declared in file_theme()', + 'description' => 'Unit tests theme functions in the file module.', + 'group' => 'File', + ); + } + + function testThemeFileUploadHelp() { + $variables = array( + 'description' => NULL, + 'upload_validators' => NULL, + ); + $this->assertEqual('', theme_file_upload_help($variables), 'Empty string returned by theme_file_upload_help() with NULL inputs.'); + } + +} diff --git a/modules/file/tests/file.test:Zone.Identifier b/modules/file/tests/file.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/tests/file.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/tests/file_module_test.info b/modules/file/tests/file_module_test.info index 7fc368f295..2fe8034b66 100644 --- a/modules/file/tests/file_module_test.info +++ b/modules/file/tests/file_module_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/file/tests/file_module_test.info:Zone.Identifier b/modules/file/tests/file_module_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/tests/file_module_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/tests/file_module_test.module:Zone.Identifier b/modules/file/tests/file_module_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/tests/file_module_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/tests/fixtures/file_scan_ignore/a.txt:Zone.Identifier b/modules/file/tests/fixtures/file_scan_ignore/a.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/tests/fixtures/file_scan_ignore/a.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/b.txt:Zone.Identifier b/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/b.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/b.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/c.txt:Zone.Identifier b/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/c.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/file/tests/fixtures/file_scan_ignore/frontend_framework/c.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.admin.inc:Zone.Identifier b/modules/filter/filter.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.admin.js:Zone.Identifier b/modules/filter/filter.admin.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.admin.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.api.php:Zone.Identifier b/modules/filter/filter.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.css:Zone.Identifier b/modules/filter/filter.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.info b/modules/filter/filter.info index 7ac8efbbd9..afefe2c3fd 100644 --- a/modules/filter/filter.info +++ b/modules/filter/filter.info @@ -7,7 +7,7 @@ files[] = filter.test required = TRUE configure = admin/config/content/formats -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/filter/filter.info:Zone.Identifier b/modules/filter/filter.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.install:Zone.Identifier b/modules/filter/filter.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.js:Zone.Identifier b/modules/filter/filter.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.module b/modules/filter/filter.module index e9fd01d388..6b911cb8a0 100644 --- a/modules/filter/filter.module +++ b/modules/filter/filter.module @@ -785,7 +785,7 @@ function check_markup($text, $format_id = NULL, $langcode = '', $cache = FALSE) // Convert all Windows and Mac newlines to a single newline, so filters only // need to deal with one possibility. - $text = str_replace(array("\r\n", "\r"), "\n", $text); + $text = str_replace(array("\r\n", "\r"), "\n", (string) $text); // Get a complete list of filters, ordered properly. $filters = filter_list_format($format->format); @@ -1661,7 +1661,7 @@ function _filter_url_trim($text, $length = NULL) { } // Use +3 for '...' string length. - if ($_length && strlen($text) > $_length + 3) { + if ($_length && strlen((string) $text) > $_length + 3) { $text = substr($text, 0, $_length) . '...'; } diff --git a/modules/filter/filter.module:Zone.Identifier b/modules/filter/filter.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.pages.inc:Zone.Identifier b/modules/filter/filter.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/filter.test:Zone.Identifier b/modules/filter/filter.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/filter.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/tests/filter.url-input.txt:Zone.Identifier b/modules/filter/tests/filter.url-input.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/tests/filter.url-input.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/filter/tests/filter.url-output.txt:Zone.Identifier b/modules/filter/tests/filter.url-output.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/filter/tests/filter.url-output.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum-icon.tpl.php:Zone.Identifier b/modules/forum/forum-icon.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum-icon.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum-list.tpl.php:Zone.Identifier b/modules/forum/forum-list.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum-list.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum-rtl.css:Zone.Identifier b/modules/forum/forum-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum-submitted.tpl.php:Zone.Identifier b/modules/forum/forum-submitted.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum-submitted.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum-topic-list.tpl.php:Zone.Identifier b/modules/forum/forum-topic-list.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum-topic-list.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum.admin.inc:Zone.Identifier b/modules/forum/forum.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum.css:Zone.Identifier b/modules/forum/forum.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum.info b/modules/forum/forum.info index 213e59ecd6..258baee2fa 100644 --- a/modules/forum/forum.info +++ b/modules/forum/forum.info @@ -9,7 +9,7 @@ files[] = forum.test configure = admin/structure/forum stylesheets[all][] = forum.css -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/forum/forum.info:Zone.Identifier b/modules/forum/forum.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum.install:Zone.Identifier b/modules/forum/forum.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum.module:Zone.Identifier b/modules/forum/forum.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum.pages.inc:Zone.Identifier b/modules/forum/forum.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forum.test:Zone.Identifier b/modules/forum/forum.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forum.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/forum/forums.tpl.php:Zone.Identifier b/modules/forum/forums.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/forum/forums.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/help/help-rtl.css:Zone.Identifier b/modules/help/help-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/help/help-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/help/help.admin.inc:Zone.Identifier b/modules/help/help.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/help/help.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/help/help.css:Zone.Identifier b/modules/help/help.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/help/help.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/help/help.info b/modules/help/help.info index 96c2f05b07..367b0f19c7 100644 --- a/modules/help/help.info +++ b/modules/help/help.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = help.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/help/help.info:Zone.Identifier b/modules/help/help.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/help/help.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/help/help.module:Zone.Identifier b/modules/help/help.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/help/help.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/help/help.test:Zone.Identifier b/modules/help/help.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/help/help.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image-rtl.css:Zone.Identifier b/modules/image/image-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.admin.css:Zone.Identifier b/modules/image/image.admin.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.admin.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.admin.inc:Zone.Identifier b/modules/image/image.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.api.php:Zone.Identifier b/modules/image/image.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.css:Zone.Identifier b/modules/image/image.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.effects.inc b/modules/image/image.effects.inc index 35a6a74c7a..cbdb13609b 100644 --- a/modules/image/image.effects.inc +++ b/modules/image/image.effects.inc @@ -259,7 +259,7 @@ function image_rotate_effect(&$image, $data) { ); // Convert short #FFF syntax to full #FFFFFF syntax. - if (strlen($data['bgcolor']) == 4) { + if (strlen((string) $data['bgcolor']) == 4) { $c = $data['bgcolor']; $data['bgcolor'] = $c[0] . $c[1] . $c[1] . $c[2] . $c[2] . $c[3] . $c[3]; } diff --git a/modules/image/image.effects.inc:Zone.Identifier b/modules/image/image.effects.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.effects.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.field.inc b/modules/image/image.field.inc index 6d1867cb02..f0dbf27184 100644 --- a/modules/image/image.field.inc +++ b/modules/image/image.field.inc @@ -19,7 +19,7 @@ function image_field_info() { ), 'instance_settings' => array( 'file_extensions' => 'png gif jpg jpeg', - 'file_directory' => '', + 'file_directory' => '[date:custom:Y]-[date:custom:m]', 'max_filesize' => '', 'alt_field' => 0, 'title_field' => 0, diff --git a/modules/image/image.field.inc:Zone.Identifier b/modules/image/image.field.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.field.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.info b/modules/image/image.info index d9c0820a73..b56252d5e8 100644 --- a/modules/image/image.info +++ b/modules/image/image.info @@ -7,7 +7,7 @@ dependencies[] = file files[] = image.test configure = admin/config/media/image-styles -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/image/image.info:Zone.Identifier b/modules/image/image.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.install:Zone.Identifier b/modules/image/image.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.module b/modules/image/image.module index dab88361a2..cfb25713a9 100644 --- a/modules/image/image.module +++ b/modules/image/image.module @@ -583,8 +583,18 @@ function image_styles() { $style['storage'] = IMAGE_STORAGE_DEFAULT; foreach ($style['effects'] as $key => $effect) { $definition = image_effect_definition_load($effect['name']); - $effect = array_merge($definition, $effect); - $style['effects'][$key] = $effect; + if ($definition) { + $effect = array_merge($definition, $effect); + $style['effects'][$key] = $effect; + } + else { + watchdog('image', 'Image style %style_name has an effect %effect_name with no definition.', + array( + '%style_name' => $style_name, + '%effect_name' => $effect['name'], + ), + WATCHDOG_ERROR); + } } $styles[$style_name] = $style; } @@ -804,22 +814,25 @@ function image_style_options($include_empty = TRUE, $output = CHECK_PLAIN) { * @param $scheme * The file scheme, for example 'public' for public files. */ -function image_style_deliver($style, $scheme) { +function image_style_deliver($style, $scheme = NULL) { $args = func_get_args(); array_shift($args); array_shift($args); $target = implode('/', $args); - // Check that the style is defined, the scheme is valid, and the image - // derivative token is valid. (Sites which require image derivatives to be - // generated without a token can set the 'image_allow_insecure_derivatives' + // Check that the style is defined, the scheme is valid. + $valid = !empty($style) && !empty($scheme) && file_stream_wrapper_valid_scheme($scheme); + + // Also validate the derivative token. Sites which require image derivatives + // to be generated without a token can set the 'image_allow_insecure_derivatives' // variable to TRUE to bypass the latter check, but this will increase the // site's vulnerability to denial-of-service attacks. To prevent this // variable from leaving the site vulnerable to the most serious attacks, a // token is always required when a derivative of a derivative is requested.) - $valid = !empty($style) && file_stream_wrapper_valid_scheme($scheme); + $token = isset($_GET[IMAGE_DERIVATIVE_TOKEN]) ? $_GET[IMAGE_DERIVATIVE_TOKEN] : ''; + $token_is_valid = $token === image_style_path_token($style['name'], $scheme . '://' . $target); if (!variable_get('image_allow_insecure_derivatives', FALSE) || strpos(ltrim($target, '\/'), 'styles/') === 0) { - $valid = $valid && isset($_GET[IMAGE_DERIVATIVE_TOKEN]) && $_GET[IMAGE_DERIVATIVE_TOKEN] === image_style_path_token($style['name'], $scheme . '://' . $target); + $valid = $valid && $token_is_valid; } if (!$valid) { return MENU_ACCESS_DENIED; @@ -827,28 +840,33 @@ function image_style_deliver($style, $scheme) { $image_uri = $scheme . '://' . $target; $derivative_uri = image_style_path($style['name'], $image_uri); + $derivative_scheme = file_uri_scheme($derivative_uri); - // If using the private scheme, let other modules provide headers and - // control access to the file. - if ($scheme == 'private') { - if (file_exists($derivative_uri)) { - file_download($scheme, file_uri_target($derivative_uri)); - } - else { - $headers = file_download_headers($image_uri); - if (empty($headers)) { - return MENU_ACCESS_DENIED; - } - if (count($headers)) { - foreach ($headers as $name => $value) { - drupal_add_http_header($name, $value); - } - } + if ($token_is_valid) { + $is_public = ($scheme !== 'private'); + } + else { + $core_schemes = array('public', 'private', 'temporary'); + $additional_public_schemes = array_diff(variable_get('file_additional_public_schemes', array()), $core_schemes); + $public_schemes = array_merge(array('public'), $additional_public_schemes); + $is_public = in_array($derivative_scheme, $public_schemes, TRUE); + } + + if ($scheme == 'private' && file_exists($derivative_uri)) { + file_download($scheme, file_uri_target($derivative_uri)); + } + + $headers = array(); + + if (!$is_public) { + $headers = file_download_headers($image_uri); + if (empty($headers)) { + return MENU_ACCESS_DENIED; } } // Confirm that the original source image exists before trying to process it. - if (!is_file($image_uri)) { + if (!_image_source_image_exists($image_uri, $token_is_valid)) { watchdog('image', 'Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', array('%source_image_path' => $image_uri, '%derivative_path' => $derivative_uri)); return MENU_NOT_FOUND; } @@ -879,7 +897,11 @@ function image_style_deliver($style, $scheme) { if ($success) { $image = image_load($derivative_uri); - file_transfer($image->source, array('Content-Type' => $image->info['mime_type'], 'Content-Length' => $image->info['file_size'])); + $headers += array( + 'Content-Type' => $image->info['mime_type'], + 'Content-Length' => $image->info['file_size'] + ); + file_transfer($image->source, $headers); } else { watchdog('image', 'Unable to generate the derived image located at %path.', array('%path' => $derivative_uri)); @@ -890,6 +912,48 @@ function image_style_deliver($style, $scheme) { } } +/** + * Checks whether the provided source image exists. + * + * When a valid token is provided for the image URI, this function is + * equivalent to calling file_exists($image_uri). + * + * @param string $image_uri + * The URI for the source image. + * @param bool $token_is_valid + * Whether a valid image token was supplied. + * + * @return bool + * Whether the source image exists. + */ +function _image_source_image_exists($image_uri, $token_is_valid) { + $exists = file_exists($image_uri); + + // If the file doesn't exist, we can stop here. + if (!$exists) { + return FALSE; + } + + if ($token_is_valid) { + return TRUE; + } + + if (file_uri_scheme($image_uri) !== 'public') { + return TRUE; + } + + $image_path = drupal_realpath($image_uri); + $private_path = variable_get('file_private_path', FALSE); + if ($private_path) { + $private_path = realpath($private_path); + if ($private_path && strpos($image_path, $private_path) === 0) { + return FALSE; + } + } + + return TRUE; +} + /** * Creates a new image derivative based on an image style. * diff --git a/modules/image/image.module:Zone.Identifier b/modules/image/image.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/image.test b/modules/image/image.test index 22edcaa064..f569bec028 100644 --- a/modules/image/image.test +++ b/modules/image/image.test @@ -31,7 +31,12 @@ class ImageFieldTestCase extends DrupalWebTestCase { protected $admin_user; function setUp() { - parent::setUp('image'); + $modules = func_get_args(); + if (isset($modules[0]) && is_array($modules[0])) { + $modules = $modules[0]; + } + $modules[] = 'image'; + parent::setUp($modules); $this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'create article content', 'edit any article content', 'delete any article content', 'administer image styles', 'administer fields')); $this->drupalLogin($this->admin_user); } @@ -378,6 +383,11 @@ class ImageStylesPathAndUrlTestCase extends DrupalWebTestCase { $directory = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/' . $this->randomName(); $this->drupalGet(file_create_url($directory . '/' . $this->randomName())); $this->assertFalse(file_exists($directory), 'New directory was not created in the filesystem when requesting an unauthorized image.'); + + // Check that requesting a partial image style path returns access denied. + $partial_url = $scheme . '://styles/' . $this->style_name . '/'; + $this->drupalGet(file_create_url($partial_url) . '/'); + $this->assertResponse(403, 'Access was denied to a partial image style path.'); } } @@ -568,6 +578,10 @@ class ImageAdminStylesUnitTest extends ImageFieldTestCase { ); } + function setUp() { + parent::setUp('image_module_test', 'image_module_styles_test'); + } + /** * Given an image style, generate an image. */ @@ -888,6 +902,18 @@ class ImageAdminStylesUnitTest extends ImageFieldTestCase { $this->drupalGet('node/' . $nid); $this->assertRaw(check_plain(image_style_url('thumbnail', $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), format_string('Image displayed using style replacement style.')); } + + /** + * Test disabling a module providing an effect in use by an image style. + */ + function testOrphanedEffect() { + // This will not check whether anything depends on the module. + module_disable(array('image_module_test'), FALSE); + $this->drupalGet('admin/config/media/image-styles'); + $this->assertText('Test Image Style', 'Image style with an orphaned effect displayed in the list of styles.'); + $image_log = db_query_range('SELECT message FROM {watchdog} WHERE type = :type ORDER BY wid DESC', 0, 1, array(':type' => 'image'))->fetchField(); + $this->assertEqual('Image style %style_name has an effect %effect_name with no definition.', $image_log, 'A watchdog message was logged for the broken image style effect'); + } } /** @@ -1165,6 +1191,36 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase { $this->drupalGet('node/' . $node->nid); $this->assertRaw($default_output, 'Default private image displayed when no user supplied image is present.'); } + + /** + * Tests the display of image field with the missing FID. + */ + function testMissingImageFieldDisplay() { + $field_name = strtolower($this->randomName()); + $type_name = 'article'; + $field_settings = array( + 'display_field' => '1', + 'display_default' => '1', + ); + $instance_settings = array( + 'description_field' => '1', + ); + $widget_settings = array(); + $this->createImageField($field_name, $type_name, $field_settings, $instance_settings, $widget_settings); + $images = $this->drupalGetTestFiles('image'); + + // Create a new node with the uploaded file. + $nid = $this->uploadNodeImage($images[1], $field_name, 'article'); + // Delete uploaded file from file_managed table. + $max_fid_after = db_query('SELECT MAX(fid) AS fid FROM {file_managed}')->fetchField(); + $uploaded_file = file_load($max_fid_after); + file_delete($uploaded_file, TRUE); + // Clear field cache. + field_cache_clear(); + // Check the node detail if the file is loaded. + $this->drupalGet('node/' . $nid); + $this->assertResponse(200); + } } /** diff --git a/modules/image/image.test:Zone.Identifier b/modules/image/image.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/image.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/sample.png:Zone.Identifier b/modules/image/sample.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/sample.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/tests/image_module_styles_test.info b/modules/image/tests/image_module_styles_test.info new file mode 100644 index 0000000000..795e19f17d --- /dev/null +++ b/modules/image/tests/image_module_styles_test.info @@ -0,0 +1,13 @@ +name = Image Styles test +description = Provides additional hook implementations for testing Image Styles functionality. +package = Core +version = VERSION +core = 7.x +files[] = image_module_styles_test.module +dependencies[] = image_module_test +hidden = TRUE + +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" +project = "drupal" +datestamp = "1662554078" diff --git a/modules/image/tests/image_module_styles_test.info:Zone.Identifier b/modules/image/tests/image_module_styles_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/tests/image_module_styles_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/tests/image_module_styles_test.module b/modules/image/tests/image_module_styles_test.module new file mode 100644 index 0000000000..79929d9399 --- /dev/null +++ b/modules/image/tests/image_module_styles_test.module @@ -0,0 +1,29 @@ + 'Test Image Style', + 'effects' => array( + array( + 'name' => 'image_scale', + 'data' => array('width' => 100, 'height' => 100, 'upscale' => 1), + 'weight' => 0, + ), + array( + 'name' => 'image_module_test_null', + ), + ) + ); + + return $styles; +} diff --git a/modules/image/tests/image_module_styles_test.module:Zone.Identifier b/modules/image/tests/image_module_styles_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/tests/image_module_styles_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/tests/image_module_test.info b/modules/image/tests/image_module_test.info index 4daeb380cc..460cdc5669 100644 --- a/modules/image/tests/image_module_test.info +++ b/modules/image/tests/image_module_test.info @@ -6,7 +6,7 @@ core = 7.x files[] = image_module_test.module hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/image/tests/image_module_test.info:Zone.Identifier b/modules/image/tests/image_module_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/tests/image_module_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/image/tests/image_module_test.module b/modules/image/tests/image_module_test.module index fc66d9b8b7..e7ae716e7a 100644 --- a/modules/image/tests/image_module_test.module +++ b/modules/image/tests/image_module_test.module @@ -20,7 +20,8 @@ function image_module_test_file_download($uri) { function image_module_test_image_effect_info() { $effects = array( 'image_module_test_null' => array( - 'effect callback' => 'image_module_test_null_effect', + 'label' => 'image_module_test_null', + 'effect callback' => 'image_module_test_null_effect', ), ); @@ -38,7 +39,7 @@ function image_module_test_image_effect_info() { * @return * TRUE */ -function image_module_test_null_effect(array &$image, array $data) { +function image_module_test_null_effect(&$image, array $data) { return TRUE; } diff --git a/modules/image/tests/image_module_test.module:Zone.Identifier b/modules/image/tests/image_module_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/image/tests/image_module_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/locale-rtl.css:Zone.Identifier b/modules/locale/locale-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/locale-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/locale.admin.inc:Zone.Identifier b/modules/locale/locale.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/locale.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/locale.api.php:Zone.Identifier b/modules/locale/locale.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/locale.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/locale.css:Zone.Identifier b/modules/locale/locale.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/locale.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/locale.datepicker.js:Zone.Identifier b/modules/locale/locale.datepicker.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/locale.datepicker.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/locale.info b/modules/locale/locale.info index ed5488a66e..f3c6336632 100644 --- a/modules/locale/locale.info +++ b/modules/locale/locale.info @@ -6,7 +6,7 @@ core = 7.x files[] = locale.test configure = admin/config/regional/language -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/locale/locale.info:Zone.Identifier b/modules/locale/locale.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/locale.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/locale.install:Zone.Identifier b/modules/locale/locale.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/locale.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/locale.module b/modules/locale/locale.module index 93a4657f0c..0d7e080d57 100644 --- a/modules/locale/locale.module +++ b/modules/locale/locale.module @@ -555,6 +555,8 @@ function locale_language_types_info() { 'fixed' => array(LOCALE_LANGUAGE_NEGOTIATION_INTERFACE), ), LANGUAGE_TYPE_URL => array( + 'name' => t('URL'), + 'description' => t('Order of language detection methods for URLs. The detected language will be used as the default when generating URLs for internal links on the site.'), 'fixed' => array(LOCALE_LANGUAGE_NEGOTIATION_URL, LOCALE_LANGUAGE_NEGOTIATION_URL_FALLBACK), ), ); diff --git a/modules/locale/locale.module:Zone.Identifier b/modules/locale/locale.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/locale.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/locale.test b/modules/locale/locale.test index b890b06147..1709996d80 100644 --- a/modules/locale/locale.test +++ b/modules/locale/locale.test @@ -297,6 +297,28 @@ class LocaleJavascriptTranslationTest extends DrupalWebTestCase { $this->assertEqual(count($source_strings), count($test_strings), 'Found correct number of source strings.'); } + + /** + * Test handling of null values in JS parsing for PHP8.0+ deprecations. + */ + function testNullValuesLocalesSource() { + db_insert('locales_source') + ->fields(array( + 'location' => NULL, + 'source' => 'Standard Call t', + 'context' => '', + 'textgroup' => 'default', + )) + ->execute(); + + $filename = drupal_get_path('module', 'locale_test') . '/locale_test.js'; + + // Parse the file to look for source strings. + _locale_parse_js_file($filename); + + $num_records = db_select('locales_source')->fields(NULL, array('lid'))->countQuery()->execute()->fetchField(); + $this->assertEqual($num_records, 32, 'Correct number of strings parsed from JS file'); + } } /** * Functional test for string translation and validation. @@ -1642,6 +1664,14 @@ class LocaleLanguageSwitchingFunctionalTest extends DrupalWebTestCase { $this->assertIdentical($links, array('active' => array('en'), 'inactive' => array('fr')), 'Only the current language list item is marked as active on the language switcher block.'); $this->assertIdentical($anchors, array('active' => array('en'), 'inactive' => array('fr')), 'Only the current language anchor is marked as active on the language switcher block.'); } + + /** + * Tests that languages can be added as disabled. + */ + function testNewDisabledLanguage() { + // Add new language which will be disabled. + locale_add_language('de', 'German', 'Deutsch', LANGUAGE_LTR, '', '', FALSE, FALSE); + } } /** diff --git a/modules/locale/locale.test:Zone.Identifier b/modules/locale/locale.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/locale.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/tests/locale_test.info b/modules/locale/tests/locale_test.info index 916403fd96..e4dee0eda3 100644 --- a/modules/locale/tests/locale_test.info +++ b/modules/locale/tests/locale_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/locale/tests/locale_test.info:Zone.Identifier b/modules/locale/tests/locale_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/tests/locale_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/tests/locale_test.js:Zone.Identifier b/modules/locale/tests/locale_test.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/tests/locale_test.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/tests/locale_test.module:Zone.Identifier b/modules/locale/tests/locale_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/tests/locale_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/locale/tests/translations/test.xx.po:Zone.Identifier b/modules/locale/tests/translations/test.xx.po:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/locale/tests/translations/test.xx.po:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/menu/menu.admin.inc b/modules/menu/menu.admin.inc index 4d0a792dda..4be6be84ed 100644 --- a/modules/menu/menu.admin.inc +++ b/modules/menu/menu.admin.inc @@ -481,6 +481,7 @@ function menu_edit_menu($form, &$form_state, $type, $menu = array()) { '#default_value' => $menu['menu_name'], '#maxlength' => MENU_MAX_MENU_NAME_LENGTH_UI, '#description' => t('A unique name to construct the URL for the menu. It must only contain lowercase letters, numbers and hyphens.'), + '#field_prefix' => empty($menu['old_name']) ? 'menu-' : '', '#machine_name' => array( 'exists' => 'menu_edit_menu_name_exists', 'source' => array('title'), diff --git a/modules/menu/menu.admin.inc:Zone.Identifier b/modules/menu/menu.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/menu/menu.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/menu/menu.admin.js:Zone.Identifier b/modules/menu/menu.admin.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/menu/menu.admin.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/menu/menu.api.php:Zone.Identifier b/modules/menu/menu.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/menu/menu.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/menu/menu.css:Zone.Identifier b/modules/menu/menu.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/menu/menu.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/menu/menu.info b/modules/menu/menu.info index 339fd3fc26..77ac90b98b 100644 --- a/modules/menu/menu.info +++ b/modules/menu/menu.info @@ -6,7 +6,7 @@ core = 7.x files[] = menu.test configure = admin/structure/menu -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/menu/menu.info:Zone.Identifier b/modules/menu/menu.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/menu/menu.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/menu/menu.install:Zone.Identifier b/modules/menu/menu.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/menu/menu.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/menu/menu.js:Zone.Identifier b/modules/menu/menu.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/menu/menu.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/menu/menu.module b/modules/menu/menu.module index 9578f59271..c6cb548b1e 100644 --- a/modules/menu/menu.module +++ b/modules/menu/menu.module @@ -659,7 +659,7 @@ function _menu_get_menu_weight_delta($menu_names, $max_delta = NULL) { $weight_info = db_query("SELECT MAX(weight) AS max_weight, MIN(weight) as min_weight FROM {menu_links} WHERE menu_name IN (:menu_names)", array(':menu_names' => $menu_names))->fetchObject(); - $delta = max(abs($weight_info->min_weight), abs($weight_info->max_weight)) + 1; + $delta = max(abs((int) $weight_info->min_weight), abs((int) $weight_info->max_weight)) + 1; // Honor max param, if given. if (!is_null($max_delta) && $delta > $max_delta) { diff --git a/modules/menu/menu.module:Zone.Identifier b/modules/menu/menu.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/menu/menu.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/menu/menu.test:Zone.Identifier b/modules/menu/menu.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/menu/menu.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/content_types.inc:Zone.Identifier b/modules/node/content_types.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/content_types.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/content_types.js:Zone.Identifier b/modules/node/content_types.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/content_types.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.admin.inc:Zone.Identifier b/modules/node/node.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.api.php b/modules/node/node.api.php index c8176a7d32..1a0c3a99fd 100644 --- a/modules/node/node.api.php +++ b/modules/node/node.api.php @@ -747,10 +747,10 @@ function hook_node_update_index($node) { /** * Perform node validation before a node is created or updated. * - * This hook is invoked from node_validate(), after a user has has finished - * editing the node and is previewing or submitting it. It is invoked at the - * end of all the standard validation steps, and after the type-specific - * hook_validate() is invoked. + * This hook is invoked from node_validate(), after a user has finished editing + * the node and is previewing or submitting it. It is invoked at the end of all + * the standard validation steps, and after the type-specific hook_validate() is + * invoked. * * To indicate a validation error, use form_set_error(). * diff --git a/modules/node/node.api.php:Zone.Identifier b/modules/node/node.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.css:Zone.Identifier b/modules/node/node.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.info b/modules/node/node.info index 8fda3d748b..3a780271f0 100644 --- a/modules/node/node.info +++ b/modules/node/node.info @@ -9,7 +9,7 @@ required = TRUE configure = admin/structure/types stylesheets[all][] = node.css -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/node/node.info:Zone.Identifier b/modules/node/node.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.install:Zone.Identifier b/modules/node/node.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.js:Zone.Identifier b/modules/node/node.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.module:Zone.Identifier b/modules/node/node.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.pages.inc:Zone.Identifier b/modules/node/node.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.test b/modules/node/node.test index f0ff8e7d6e..96c927b28f 100644 --- a/modules/node/node.test +++ b/modules/node/node.test @@ -666,8 +666,17 @@ class NodeCreationTestCase extends DrupalWebTestCase { } // Check that the rollback error was logged. - $records = db_query("SELECT wid FROM {watchdog} WHERE variables LIKE '%Test exception for rollback.%'")->fetchAll(); - $this->assertTrue(count($records) > 0, 'Rollback explanatory error logged to watchdog.'); + // PostgreSQL doesn't support bytea LIKE queries, so we need to unserialize + // first to check for the rollback exception message. + $matches = array(); + $records = db_query("SELECT wid, variables FROM {watchdog}")->fetchAll(); + foreach ($records as $record) { + $variables = (array) unserialize($record->variables); + if (isset($variables['!message']) && $variables['!message'] === 'Test exception for rollback.') { + $matches[] = $record->wid; + } + } + $this->assertTrue(count($matches) > 0, 'Rollback explanatory error logged to watchdog.'); } /** @@ -2545,6 +2554,26 @@ class NodeTokenReplaceTestCase extends DrupalWebTestCase { $this->assertEqual($output, $expected, format_string('Sanitized node token %token replaced.', array('%token' => $input))); } + // Test if the node without nid gets correct tokens (e.g. unsaved node). + $new_node_without_nid = clone $node; + unset($new_node_without_nid->nid); + + // Update tokens values which should be empty + $tests['[node:nid]'] = ''; + $tests['[node:url]'] = ''; + $tests['[node:edit-url]'] = ''; + + // Generate and test sanitized tokens. + foreach ($tests as $input => $expected) { + $output = token_replace($input, array('node' => $new_node_without_nid), array('language' => $language)); + $this->assertEqual($output, $expected, format_string('Sanitized node token %token replaced.', array('%token' => $input))); + } + + // Revert tokens values + $tests['[node:nid]'] = $node->nid; + $tests['[node:url]'] = url('node/' . $node->nid, $url_options); + $tests['[node:edit-url]'] = url('node/' . $node->nid . '/edit', $url_options); + // Generate and test unsanitized tokens. $tests['[node:title]'] = $node->title; $tests['[node:body]'] = $node->body[$langcode][0]['value']; diff --git a/modules/node/node.test:Zone.Identifier b/modules/node/node.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.tokens.inc b/modules/node/node.tokens.inc index e63c751d6c..63b3273359 100644 --- a/modules/node/node.tokens.inc +++ b/modules/node/node.tokens.inc @@ -109,7 +109,7 @@ function node_tokens($type, $tokens, array $data = array(), array $options = arr switch ($name) { // Simple key values on the node. case 'nid': - $replacements[$original] = $node->nid; + $replacements[$original] = isset($node->nid) ? $node->nid : ''; break; case 'vid': @@ -168,11 +168,11 @@ function node_tokens($type, $tokens, array $data = array(), array $options = arr break; case 'url': - $replacements[$original] = url('node/' . $node->nid, $url_options); + $replacements[$original] = isset($node->nid) ? url('node/' . $node->nid, $url_options) : ''; break; case 'edit-url': - $replacements[$original] = url('node/' . $node->nid . '/edit', $url_options); + $replacements[$original] = isset($node->nid) ? url('node/' . $node->nid . '/edit', $url_options) : ''; break; // Default values for the chained tokens handled below. diff --git a/modules/node/node.tokens.inc:Zone.Identifier b/modules/node/node.tokens.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.tokens.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/node.tpl.php:Zone.Identifier b/modules/node/node.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/node.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/tests/node_access_test.info b/modules/node/tests/node_access_test.info index ab458804df..6a53bb99f8 100644 --- a/modules/node/tests/node_access_test.info +++ b/modules/node/tests/node_access_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/node/tests/node_access_test.info:Zone.Identifier b/modules/node/tests/node_access_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/tests/node_access_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/tests/node_access_test.install:Zone.Identifier b/modules/node/tests/node_access_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/tests/node_access_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/tests/node_access_test.module:Zone.Identifier b/modules/node/tests/node_access_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/tests/node_access_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/tests/node_test.info b/modules/node/tests/node_test.info index bf4e8261c6..c93b1853f0 100644 --- a/modules/node/tests/node_test.info +++ b/modules/node/tests/node_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/node/tests/node_test.info:Zone.Identifier b/modules/node/tests/node_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/tests/node_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/tests/node_test.module:Zone.Identifier b/modules/node/tests/node_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/tests/node_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/tests/node_test_exception.info b/modules/node/tests/node_test_exception.info index cf5a939a7b..547d4fcf46 100644 --- a/modules/node/tests/node_test_exception.info +++ b/modules/node/tests/node_test_exception.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/node/tests/node_test_exception.info:Zone.Identifier b/modules/node/tests/node_test_exception.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/tests/node_test_exception.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/node/tests/node_test_exception.module:Zone.Identifier b/modules/node/tests/node_test_exception.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/node/tests/node_test_exception.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/login-bg.png:Zone.Identifier b/modules/openid/login-bg.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/login-bg.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid-rtl.css:Zone.Identifier b/modules/openid/openid-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid.api.php:Zone.Identifier b/modules/openid/openid.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid.css:Zone.Identifier b/modules/openid/openid.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc index 4ca7471645..87a0d4d75a 100644 --- a/modules/openid/openid.inc +++ b/modules/openid/openid.inc @@ -445,7 +445,7 @@ function _openid_signature($association, $message_array, $keys_to_sign) { } $message = _openid_create_message($sign_data); - $secret = base64_decode($association->mac_key); + $secret = base64_decode((string) $association->mac_key); $signature = _openid_hmac($secret, $message); return base64_encode($signature); diff --git a/modules/openid/openid.inc:Zone.Identifier b/modules/openid/openid.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid.info b/modules/openid/openid.info index 2908a9a4e8..702ad5bc78 100644 --- a/modules/openid/openid.info +++ b/modules/openid/openid.info @@ -5,7 +5,7 @@ package = Core core = 7.x files[] = openid.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/openid/openid.info:Zone.Identifier b/modules/openid/openid.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid.install:Zone.Identifier b/modules/openid/openid.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid.js:Zone.Identifier b/modules/openid/openid.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid.module:Zone.Identifier b/modules/openid/openid.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid.pages.inc:Zone.Identifier b/modules/openid/openid.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/openid.test:Zone.Identifier b/modules/openid/openid.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/openid.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/tests/openid_test.info b/modules/openid/tests/openid_test.info index 7935fac905..6e3c149342 100644 --- a/modules/openid/tests/openid_test.info +++ b/modules/openid/tests/openid_test.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = openid hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/openid/tests/openid_test.info:Zone.Identifier b/modules/openid/tests/openid_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/tests/openid_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/tests/openid_test.install:Zone.Identifier b/modules/openid/tests/openid_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/tests/openid_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/openid/tests/openid_test.module:Zone.Identifier b/modules/openid/tests/openid_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/openid/tests/openid_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/images/background.png:Zone.Identifier b/modules/overlay/images/background.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/images/background.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/images/close-rtl.png:Zone.Identifier b/modules/overlay/images/close-rtl.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/images/close-rtl.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/images/close.png:Zone.Identifier b/modules/overlay/images/close.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/images/close.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay-child-rtl.css:Zone.Identifier b/modules/overlay/overlay-child-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay-child-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay-child.css:Zone.Identifier b/modules/overlay/overlay-child.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay-child.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay-child.js:Zone.Identifier b/modules/overlay/overlay-child.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay-child.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay-parent.css:Zone.Identifier b/modules/overlay/overlay-parent.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay-parent.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay-parent.js:Zone.Identifier b/modules/overlay/overlay-parent.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay-parent.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay.api.php:Zone.Identifier b/modules/overlay/overlay.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay.info b/modules/overlay/overlay.info index 0feb6d9ee9..82e87b9f61 100644 --- a/modules/overlay/overlay.info +++ b/modules/overlay/overlay.info @@ -4,7 +4,7 @@ package = Core version = VERSION core = 7.x -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/overlay/overlay.info:Zone.Identifier b/modules/overlay/overlay.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay.install:Zone.Identifier b/modules/overlay/overlay.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay.module:Zone.Identifier b/modules/overlay/overlay.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/overlay/overlay.tpl.php:Zone.Identifier b/modules/overlay/overlay.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/overlay/overlay.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/path/path.admin.inc:Zone.Identifier b/modules/path/path.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/path/path.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/path/path.api.php:Zone.Identifier b/modules/path/path.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/path/path.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/path/path.info b/modules/path/path.info index 60c1b6a62e..6158000b4e 100644 --- a/modules/path/path.info +++ b/modules/path/path.info @@ -6,7 +6,7 @@ core = 7.x files[] = path.test configure = admin/config/search/path -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/path/path.info:Zone.Identifier b/modules/path/path.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/path/path.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/path/path.js:Zone.Identifier b/modules/path/path.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/path/path.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/path/path.module:Zone.Identifier b/modules/path/path.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/path/path.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/path/path.test:Zone.Identifier b/modules/path/path.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/path/path.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/php/php.info b/modules/php/php.info index 0a6c967da7..0fe0aa9fe1 100644 --- a/modules/php/php.info +++ b/modules/php/php.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = php.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/php/php.info:Zone.Identifier b/modules/php/php.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/php/php.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/php/php.install:Zone.Identifier b/modules/php/php.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/php/php.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/php/php.module:Zone.Identifier b/modules/php/php.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/php/php.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/php/php.test:Zone.Identifier b/modules/php/php.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/php/php.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll-bar--block.tpl.php:Zone.Identifier b/modules/poll/poll-bar--block.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll-bar--block.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll-bar.tpl.php:Zone.Identifier b/modules/poll/poll-bar.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll-bar.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll-results--block.tpl.php:Zone.Identifier b/modules/poll/poll-results--block.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll-results--block.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll-results.tpl.php:Zone.Identifier b/modules/poll/poll-results.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll-results.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll-rtl.css:Zone.Identifier b/modules/poll/poll-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll-vote.tpl.php:Zone.Identifier b/modules/poll/poll-vote.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll-vote.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll.css:Zone.Identifier b/modules/poll/poll.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll.info b/modules/poll/poll.info index 10d53de1f5..5dbe7df803 100644 --- a/modules/poll/poll.info +++ b/modules/poll/poll.info @@ -6,7 +6,7 @@ core = 7.x files[] = poll.test stylesheets[all][] = poll.css -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/poll/poll.info:Zone.Identifier b/modules/poll/poll.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll.install:Zone.Identifier b/modules/poll/poll.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll.module:Zone.Identifier b/modules/poll/poll.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll.pages.inc:Zone.Identifier b/modules/poll/poll.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll.test b/modules/poll/poll.test index e24032d5a7..1e15848bc9 100644 --- a/modules/poll/poll.test +++ b/modules/poll/poll.test @@ -216,7 +216,7 @@ class PollCreateTestCase extends PollTestCase { $vote_count = '2000'; $node->choice[] = array( - 'chid' => '', + 'chid' => NULL, 'chtext' => $new_option, 'chvotes' => (int) $vote_count, 'weight' => 1000, diff --git a/modules/poll/poll.test:Zone.Identifier b/modules/poll/poll.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/poll/poll.tokens.inc:Zone.Identifier b/modules/poll/poll.tokens.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/poll/poll.tokens.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile-block.tpl.php:Zone.Identifier b/modules/profile/profile-block.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile-block.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile-listing.tpl.php:Zone.Identifier b/modules/profile/profile-listing.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile-listing.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile-wrapper.tpl.php:Zone.Identifier b/modules/profile/profile-wrapper.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile-wrapper.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile.admin.inc:Zone.Identifier b/modules/profile/profile.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile.css:Zone.Identifier b/modules/profile/profile.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile.info b/modules/profile/profile.info index 12b56ca89f..4ef85a3c3f 100644 --- a/modules/profile/profile.info +++ b/modules/profile/profile.info @@ -11,7 +11,7 @@ configure = admin/config/people/profile ; See user_system_info_alter(). hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/profile/profile.info:Zone.Identifier b/modules/profile/profile.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile.install:Zone.Identifier b/modules/profile/profile.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile.js:Zone.Identifier b/modules/profile/profile.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile.module:Zone.Identifier b/modules/profile/profile.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile.pages.inc:Zone.Identifier b/modules/profile/profile.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/profile/profile.test:Zone.Identifier b/modules/profile/profile.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/profile/profile.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/rdf/rdf.api.php:Zone.Identifier b/modules/rdf/rdf.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/rdf/rdf.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/rdf/rdf.info b/modules/rdf/rdf.info index 04fd0616c1..9236080cb4 100644 --- a/modules/rdf/rdf.info +++ b/modules/rdf/rdf.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x files[] = rdf.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/rdf/rdf.info:Zone.Identifier b/modules/rdf/rdf.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/rdf/rdf.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/rdf/rdf.install:Zone.Identifier b/modules/rdf/rdf.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/rdf/rdf.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/rdf/rdf.module:Zone.Identifier b/modules/rdf/rdf.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/rdf/rdf.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/rdf/rdf.test:Zone.Identifier b/modules/rdf/rdf.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/rdf/rdf.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/rdf/tests/rdf_test.info b/modules/rdf/tests/rdf_test.info index ca0be33df4..66c17f9d53 100644 --- a/modules/rdf/tests/rdf_test.info +++ b/modules/rdf/tests/rdf_test.info @@ -6,7 +6,7 @@ core = 7.x hidden = TRUE dependencies[] = blog -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/rdf/tests/rdf_test.info:Zone.Identifier b/modules/rdf/tests/rdf_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/rdf/tests/rdf_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/rdf/tests/rdf_test.install:Zone.Identifier b/modules/rdf/tests/rdf_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/rdf/tests/rdf_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/rdf/tests/rdf_test.module:Zone.Identifier b/modules/rdf/tests/rdf_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/rdf/tests/rdf_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search-block-form.tpl.php:Zone.Identifier b/modules/search/search-block-form.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search-block-form.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search-result.tpl.php:Zone.Identifier b/modules/search/search-result.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search-result.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search-results.tpl.php:Zone.Identifier b/modules/search/search-results.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search-results.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search-rtl.css:Zone.Identifier b/modules/search/search-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search.admin.inc:Zone.Identifier b/modules/search/search.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search.api.php:Zone.Identifier b/modules/search/search.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search.css:Zone.Identifier b/modules/search/search.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search.extender.inc:Zone.Identifier b/modules/search/search.extender.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search.extender.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search.info b/modules/search/search.info index b7e6532df3..ac35612a9e 100644 --- a/modules/search/search.info +++ b/modules/search/search.info @@ -8,7 +8,7 @@ files[] = search.test configure = admin/config/search/settings stylesheets[all][] = search.css -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/search/search.info:Zone.Identifier b/modules/search/search.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search.install:Zone.Identifier b/modules/search/search.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search.module:Zone.Identifier b/modules/search/search.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search.pages.inc:Zone.Identifier b/modules/search/search.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/search.test:Zone.Identifier b/modules/search/search.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/search.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/tests/UnicodeTest.txt:Zone.Identifier b/modules/search/tests/UnicodeTest.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/tests/UnicodeTest.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/tests/search_embedded_form.info b/modules/search/tests/search_embedded_form.info index f342d817d4..d007729388 100644 --- a/modules/search/tests/search_embedded_form.info +++ b/modules/search/tests/search_embedded_form.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/search/tests/search_embedded_form.info:Zone.Identifier b/modules/search/tests/search_embedded_form.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/tests/search_embedded_form.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/tests/search_embedded_form.module:Zone.Identifier b/modules/search/tests/search_embedded_form.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/tests/search_embedded_form.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/tests/search_extra_type.info b/modules/search/tests/search_extra_type.info index 89cc171e08..36f449def4 100644 --- a/modules/search/tests/search_extra_type.info +++ b/modules/search/tests/search_extra_type.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/search/tests/search_extra_type.info:Zone.Identifier b/modules/search/tests/search_extra_type.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/tests/search_extra_type.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/tests/search_extra_type.module:Zone.Identifier b/modules/search/tests/search_extra_type.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/tests/search_extra_type.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/tests/search_node_tags.info b/modules/search/tests/search_node_tags.info index fd009deb38..b0f696a958 100644 --- a/modules/search/tests/search_node_tags.info +++ b/modules/search/tests/search_node_tags.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/search/tests/search_node_tags.info:Zone.Identifier b/modules/search/tests/search_node_tags.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/tests/search_node_tags.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/search/tests/search_node_tags.module:Zone.Identifier b/modules/search/tests/search_node_tags.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/search/tests/search_node_tags.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut-rtl.css:Zone.Identifier b/modules/shortcut/shortcut-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.admin.css:Zone.Identifier b/modules/shortcut/shortcut.admin.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.admin.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.admin.inc:Zone.Identifier b/modules/shortcut/shortcut.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.admin.js:Zone.Identifier b/modules/shortcut/shortcut.admin.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.admin.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.api.php:Zone.Identifier b/modules/shortcut/shortcut.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.css:Zone.Identifier b/modules/shortcut/shortcut.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.info b/modules/shortcut/shortcut.info index 8f10d16312..d6cec7a20a 100644 --- a/modules/shortcut/shortcut.info +++ b/modules/shortcut/shortcut.info @@ -6,7 +6,7 @@ core = 7.x files[] = shortcut.test configure = admin/config/user-interface/shortcut -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/shortcut/shortcut.info:Zone.Identifier b/modules/shortcut/shortcut.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.install:Zone.Identifier b/modules/shortcut/shortcut.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.module:Zone.Identifier b/modules/shortcut/shortcut.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.png:Zone.Identifier b/modules/shortcut/shortcut.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/shortcut/shortcut.test:Zone.Identifier b/modules/shortcut/shortcut.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/shortcut/shortcut.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php index e2dc2322de..a3bd3730cc 100644 --- a/modules/simpletest/drupal_web_test_case.php +++ b/modules/simpletest/drupal_web_test_case.php @@ -1536,7 +1536,7 @@ protected function storeSetupCache($cache_key_prefix = '') { // Inform others that this cache is usable now. $cache_file = $this->originalFileDirectory . '/simpletest/' . $cache_key . '/simpletest-cache-setup'; - file_put_contents($cache_file, time(NULL)); + file_put_contents($cache_file, time()); lock_release($lock_key); return TRUE; diff --git a/modules/simpletest/drupal_web_test_case.php:Zone.Identifier b/modules/simpletest/drupal_web_test_case.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/drupal_web_test_case.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/README.txt:Zone.Identifier b/modules/simpletest/files/README.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/README.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/comment_hacks.css.optimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/comment_hacks.css.unoptimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/comment_hacks.css.unoptimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/comment_hacks.css.unoptimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/comment_hacks.css:Zone.Identifier b/modules/simpletest/files/css_test_files/comment_hacks.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/comment_hacks.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/css_input_with_import.css.optimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/css_input_with_import.css.unoptimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/css_input_with_import.css.unoptimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/css_input_with_import.css.unoptimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/css_input_with_import.css:Zone.Identifier b/modules/simpletest/files/css_test_files/css_input_with_import.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/css_input_with_import.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/css_input_without_import.css.optimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/css_input_without_import.css.unoptimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/css_input_without_import.css.unoptimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/css_input_without_import.css.unoptimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/css_input_without_import.css:Zone.Identifier b/modules/simpletest/files/css_test_files/css_input_without_import.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/css_input_without_import.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.optimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.optimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.optimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.unoptimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.unoptimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css.unoptimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css:Zone.Identifier b/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/css_subfolder/css_input_with_import.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/import1.css:Zone.Identifier b/modules/simpletest/files/css_test_files/import1.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/import1.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/import2.css:Zone.Identifier b/modules/simpletest/files/css_test_files/import2.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/import2.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/quotes.css.optimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/quotes.css.optimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/quotes.css.optimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/quotes.css.unoptimized.css:Zone.Identifier b/modules/simpletest/files/css_test_files/quotes.css.unoptimized.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/quotes.css.unoptimized.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/css_test_files/quotes.css:Zone.Identifier b/modules/simpletest/files/css_test_files/quotes.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/css_test_files/quotes.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/html-1.txt:Zone.Identifier b/modules/simpletest/files/html-1.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/html-1.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/html-2.html:Zone.Identifier b/modules/simpletest/files/html-2.html:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/html-2.html:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/image-1.png:Zone.Identifier b/modules/simpletest/files/image-1.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/image-1.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/image-2.jpg:Zone.Identifier b/modules/simpletest/files/image-2.jpg:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/image-2.jpg:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/image-test-no-transparency.gif:Zone.Identifier b/modules/simpletest/files/image-test-no-transparency.gif:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/image-test-no-transparency.gif:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/image-test-transparent-out-of-range.gif:Zone.Identifier b/modules/simpletest/files/image-test-transparent-out-of-range.gif:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/image-test-transparent-out-of-range.gif:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/image-test.gif:Zone.Identifier b/modules/simpletest/files/image-test.gif:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/image-test.gif:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/image-test.jpg:Zone.Identifier b/modules/simpletest/files/image-test.jpg:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/image-test.jpg:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/image-test.png:Zone.Identifier b/modules/simpletest/files/image-test.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/image-test.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/javascript-1.txt:Zone.Identifier b/modules/simpletest/files/javascript-1.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/javascript-1.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/javascript-2.script:Zone.Identifier b/modules/simpletest/files/javascript-2.script:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/javascript-2.script:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/phar-1.phar:Zone.Identifier b/modules/simpletest/files/phar-1.phar:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/phar-1.phar:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/php-1.txt:Zone.Identifier b/modules/simpletest/files/php-1.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/php-1.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/php-2.php:Zone.Identifier b/modules/simpletest/files/php-2.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/php-2.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/sql-1.txt:Zone.Identifier b/modules/simpletest/files/sql-1.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/sql-1.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/files/sql-2.sql:Zone.Identifier b/modules/simpletest/files/sql-2.sql:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/files/sql-2.sql:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php:Zone.Identifier b/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/lib/Drupal/simpletest/Tests/PSR0WebTest.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/simpletest.api.php:Zone.Identifier b/modules/simpletest/simpletest.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/simpletest.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/simpletest.css:Zone.Identifier b/modules/simpletest/simpletest.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/simpletest.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/simpletest.info b/modules/simpletest/simpletest.info index da1e2d056a..3c6ded7b44 100644 --- a/modules/simpletest/simpletest.info +++ b/modules/simpletest/simpletest.info @@ -58,7 +58,7 @@ files[] = tests/upgrade/update.trigger.test files[] = tests/upgrade/update.field.test files[] = tests/upgrade/update.user.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/simpletest.info:Zone.Identifier b/modules/simpletest/simpletest.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/simpletest.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/simpletest.install b/modules/simpletest/simpletest.install index 6c6f5694de..d92f70d17f 100644 --- a/modules/simpletest/simpletest.install +++ b/modules/simpletest/simpletest.install @@ -20,7 +20,6 @@ function simpletest_requirements($phase) { $has_curl = function_exists('curl_init'); $has_hash = function_exists('hash_hmac'); $has_domdocument = method_exists('DOMDocument', 'loadHTML'); - $open_basedir = ini_get('open_basedir'); $requirements['curl'] = array( 'title' => $t('cURL'), @@ -48,18 +47,6 @@ function simpletest_requirements($phase) { $requirements['php_domdocument']['description'] = $t('The testing framework requires the DOMDocument class to be available. Check the configure command at the PHP info page.', array('@link-phpinfo' => url('admin/reports/status/php'))); } - // SimpleTest currently needs 2 cURL options which are incompatible with - // having PHP's open_basedir restriction set. - // See http://drupal.org/node/674304. - $requirements['php_open_basedir'] = array( - 'title' => $t('PHP open_basedir restriction'), - 'value' => $open_basedir ? $t('Enabled') : $t('Disabled'), - ); - if ($open_basedir) { - $requirements['php_open_basedir']['severity'] = REQUIREMENT_ERROR; - $requirements['php_open_basedir']['description'] = $t('The testing framework requires the PHP open_basedir restriction to be disabled. Check your webserver configuration or contact your web host.', array('@open_basedir-url' => 'http://php.net/manual/en/ini.core.php#ini.open-basedir')); - } - // Check the current memory limit. If it is set too low, SimpleTest will fail // to load all tests and throw a fatal error. $memory_limit = ini_get('memory_limit'); diff --git a/modules/simpletest/simpletest.install:Zone.Identifier b/modules/simpletest/simpletest.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/simpletest.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/simpletest.js:Zone.Identifier b/modules/simpletest/simpletest.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/simpletest.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/simpletest.module:Zone.Identifier b/modules/simpletest/simpletest.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/simpletest.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/simpletest.pages.inc:Zone.Identifier b/modules/simpletest/simpletest.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/simpletest.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/simpletest.test:Zone.Identifier b/modules/simpletest/simpletest.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/simpletest.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/src/Tests/PSR4WebTest.php:Zone.Identifier b/modules/simpletest/src/Tests/PSR4WebTest.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/src/Tests/PSR4WebTest.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/actions.test:Zone.Identifier b/modules/simpletest/tests/actions.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/actions.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/actions_loop_test.info b/modules/simpletest/tests/actions_loop_test.info index c879eb92ae..2624231216 100644 --- a/modules/simpletest/tests/actions_loop_test.info +++ b/modules/simpletest/tests/actions_loop_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/actions_loop_test.info:Zone.Identifier b/modules/simpletest/tests/actions_loop_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/actions_loop_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/actions_loop_test.install:Zone.Identifier b/modules/simpletest/tests/actions_loop_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/actions_loop_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/actions_loop_test.module:Zone.Identifier b/modules/simpletest/tests/actions_loop_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/actions_loop_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/ajax.test:Zone.Identifier b/modules/simpletest/tests/ajax.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/ajax.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/ajax_forms_test.info b/modules/simpletest/tests/ajax_forms_test.info index 7a1151833b..da452a4868 100644 --- a/modules/simpletest/tests/ajax_forms_test.info +++ b/modules/simpletest/tests/ajax_forms_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/ajax_forms_test.info:Zone.Identifier b/modules/simpletest/tests/ajax_forms_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/ajax_forms_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/ajax_forms_test.module:Zone.Identifier b/modules/simpletest/tests/ajax_forms_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/ajax_forms_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/ajax_test.info b/modules/simpletest/tests/ajax_test.info index ccf249bdd9..de20a4149e 100644 --- a/modules/simpletest/tests/ajax_test.info +++ b/modules/simpletest/tests/ajax_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/ajax_test.info:Zone.Identifier b/modules/simpletest/tests/ajax_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/ajax_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/ajax_test.module:Zone.Identifier b/modules/simpletest/tests/ajax_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/ajax_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/batch.test:Zone.Identifier b/modules/simpletest/tests/batch.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/batch.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/batch_test.callbacks.inc:Zone.Identifier b/modules/simpletest/tests/batch_test.callbacks.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/batch_test.callbacks.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/batch_test.info b/modules/simpletest/tests/batch_test.info index 599081c816..819c7c674d 100644 --- a/modules/simpletest/tests/batch_test.info +++ b/modules/simpletest/tests/batch_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/batch_test.info:Zone.Identifier b/modules/simpletest/tests/batch_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/batch_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/batch_test.module:Zone.Identifier b/modules/simpletest/tests/batch_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/batch_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/boot.test:Zone.Identifier b/modules/simpletest/tests/boot.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/boot.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/boot_test_1.info b/modules/simpletest/tests/boot_test_1.info index bbd2619f04..43d9427187 100644 --- a/modules/simpletest/tests/boot_test_1.info +++ b/modules/simpletest/tests/boot_test_1.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/boot_test_1.info:Zone.Identifier b/modules/simpletest/tests/boot_test_1.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/boot_test_1.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/boot_test_1.module:Zone.Identifier b/modules/simpletest/tests/boot_test_1.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/boot_test_1.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/boot_test_2.info b/modules/simpletest/tests/boot_test_2.info index 9624ba945f..f1b72fd0bb 100644 --- a/modules/simpletest/tests/boot_test_2.info +++ b/modules/simpletest/tests/boot_test_2.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/boot_test_2.info:Zone.Identifier b/modules/simpletest/tests/boot_test_2.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/boot_test_2.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/boot_test_2.module:Zone.Identifier b/modules/simpletest/tests/boot_test_2.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/boot_test_2.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test index 61caf53cae..6bee03e12f 100644 --- a/modules/simpletest/tests/bootstrap.test +++ b/modules/simpletest/tests/bootstrap.test @@ -187,6 +187,7 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase { $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=0', 'Cache-Control header was sent.'); $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.'); $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.'); + $this->assertEqual($this->drupalGetHeader('X-Content-Type-Options'), 'nosniff', 'X-Content-Type-Options header was sent.'); // Check replacing default headers. $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Expires', 'value' => 'Fri, 19 Nov 2008 05:00:00 GMT'))); @@ -236,6 +237,9 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase { $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), 'Site title matches.'); $this->assertRaw('', 'Page was not compressed.'); + // Verify that an empty page doesn't throw an error when being decompressed. + $this->drupalGet('system-test/empty-page'); + // Disable compression mode. variable_set('page_compression', FALSE); @@ -248,6 +252,27 @@ class BootstrapPageCacheTestCase extends DrupalWebTestCase { $this->drupalGet(''); $this->assertRaw('', 'Page was delivered after compression mode is changed (compression support disabled).'); } + + /** + * Test page cache headers. + */ + function testPageCacheHeaders() { + variable_set('cache', 1); + // First request should store a response in the page cache. + $this->drupalGet('system-test/page-cache-headers'); + + // The test callback should remove the query string leaving the same path + // as the previous request, which we'll try to retrieve from cache_page. + $this->drupalGet('system-test/page-cache-headers', array('query' => array('return_headers' => 'TRUE'))); + + $headers = json_decode($this->drupalGetHeader('Page-Cache-Headers'), TRUE); + if (is_null($headers)) { + $this->fail('No headers were retrieved from the page cache.'); + } + else { + $this->assertEqual($headers['X-Content-Type-Options'], 'nosniff', 'X-Content-Type-Options header retrieved from response in the page cache.'); + } + } } class BootstrapVariableTestCase extends DrupalWebTestCase { diff --git a/modules/simpletest/tests/bootstrap.test:Zone.Identifier b/modules/simpletest/tests/bootstrap.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/bootstrap.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/cache.test:Zone.Identifier b/modules/simpletest/tests/cache.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/cache.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test index f5b85bad0b..fde70b1385 100644 --- a/modules/simpletest/tests/common.test +++ b/modules/simpletest/tests/common.test @@ -91,6 +91,12 @@ class CommonURLUnitTest extends DrupalWebTestCase { $link = l($text, $path); $sanitized_path = check_url(url($path)); $this->assertTrue(strpos($link, $sanitized_path) !== FALSE, format_string('XSS attack @path was filtered', array('@path' => $path))); + + // Verify that a dangerous protocol is sanitized. + $text = $this->randomName(); + $path = "javascript:alert('XSS')"; + $link = l($text, $path, array('external' => TRUE)); + $this->assertTrue(strpos($link, 'javascript:') === FALSE, 'Dangerous protocol javascript: was sanitized.'); } /* @@ -480,6 +486,15 @@ class CommonXssUnitTest extends DrupalUnitTestCase { * Check that invalid multi-byte sequences are rejected. */ function testInvalidMultiByte() { + // Ignore PHP 8.0+ null deprecations. + $text = check_plain(NULL); + $this->assertEqual($text, '', 'check_plain() casts null to string'); + $text = check_plain(FALSE); + $this->assertEqual($text, '', 'check_plain() casts boolean to string'); + $text = filter_xss(NULL); + $this->assertEqual($text, '', 'filter_xss() casts null to string'); + $text = filter_xss(FALSE); + $this->assertEqual($text, '', 'filter_xss() casts boolean to string'); // Ignore PHP 5.3+ invalid multibyte sequence warning. $text = @check_plain("Foo\xC0barbaz"); $this->assertEqual($text, '', 'check_plain() rejects invalid sequence "Foo\xC0barbaz"'); @@ -1182,6 +1197,10 @@ class DrupalHTTPRequestTestCase extends DrupalWebTestCase { $redirect_301 = drupal_http_request(url('system-test/redirect/301', array('absolute' => TRUE)), array('max_redirects' => 0)); $this->assertFalse(isset($redirect_301->redirect_code), 'drupal_http_request does not follow 301 redirect if max_redirects = 0.'); + $redirect_invalid = drupal_http_request(url('system-test/redirect-protocol-relative', array('absolute' => TRUE)), array('max_redirects' => 1)); + $this->assertEqual($redirect_invalid->code, -1002, format_string('301 redirect to protocol-relative URL returned with error code !error.', array('!error' => $redirect_invalid->error))); + $this->assertEqual($redirect_invalid->error, 'missing schema', format_string('301 redirect to protocol-relative URL returned with error message "!error".', array('!error' => $redirect_invalid->error))); + $redirect_invalid = drupal_http_request(url('system-test/redirect-noscheme', array('absolute' => TRUE)), array('max_redirects' => 1)); $this->assertEqual($redirect_invalid->code, -1002, format_string('301 redirect to invalid URL returned with error code !error.', array('!error' => $redirect_invalid->error))); $this->assertEqual($redirect_invalid->error, 'missing schema', format_string('301 redirect to invalid URL returned with error message "!error".', array('!error' => $redirect_invalid->error))); @@ -1231,6 +1250,44 @@ class DrupalHTTPRequestTestCase extends DrupalWebTestCase { } } +/** + * Unit tests for processing of http redirects. + */ +class DrupalHTTPRedirectTest extends DrupalUnitTestCase { + + public static function getInfo() { + return array( + 'name' => 'Drupal HTTP redirect processing', + 'description' => 'Perform unit tests on processing of http redirects.', + 'group' => 'System', + ); + } + + public function testHttpsDowngrade() { + $url = 'https://example.com/foo'; + $location = 'http://example.com/bar'; + $this->assertTrue(_drupal_should_strip_sensitive_headers_on_http_redirect($url, $location), 'Sensitive headers are stripped on HTTPS downgrade.'); + } + + public function testNoHttpsDowngrade() { + $url = 'https://example.com/foo'; + $location = 'https://example.com/bar'; + $this->assertFalse(_drupal_should_strip_sensitive_headers_on_http_redirect($url, $location), 'Sensitive headers are not stripped without HTTPS downgrade.'); + } + + public function testHostChange() { + $url = 'https://example.com/foo'; + $location = 'https://www.example.com/bar'; + $this->assertTrue(_drupal_should_strip_sensitive_headers_on_http_redirect($url, $location), 'Sensitive headers are stripped on change of host.'); + } + + public function testNoHostChange() { + $url = 'http://example.com/foo'; + $location = 'http://example.com/bar'; + $this->assertFalse(_drupal_should_strip_sensitive_headers_on_http_redirect($url, $location), 'Sensitive headers are not stripped without change of host.'); + } +} + /** * Tests parsing of the HTTP response status line. */ @@ -1484,8 +1541,8 @@ class JavaScriptTestCase extends DrupalWebTestCase { */ function testAddSetting() { $javascript = drupal_add_js(array('drupal' => 'rocks', 'dries' => 280342800), 'setting'); - $this->assertEqual(280342800, $javascript['settings']['data'][2]['dries'], 'JavaScript setting is set correctly.'); - $this->assertEqual('rocks', $javascript['settings']['data'][2]['drupal'], 'The other JavaScript setting is set correctly.'); + $this->assertEqual(280342800, $javascript['settings']['data'][3]['dries'], 'JavaScript setting is set correctly.'); + $this->assertEqual('rocks', $javascript['settings']['data'][3]['drupal'], 'The other JavaScript setting is set correctly.'); } /** @@ -1923,6 +1980,18 @@ class JavaScriptTestCase extends DrupalWebTestCase { $this->assertRaw(drupal_get_path('module', 'node') . '/node.js?' . $query_string, 'Query string was appended correctly to js.'); } + /** + * Tests that the set_has_js_cookie variable is reflected in Drupal.settings. + */ + function testSetHasJsCookie() { + $this->drupalGet(''); + $this->assertRaw('"setHasJsCookie":0', 'setHasJsCookie set to 0 by default.'); + + variable_set('set_has_js_cookie', TRUE); + $this->drupalGet(''); + $this->assertRaw('"setHasJsCookie":1', 'setHasJsCookie set to 1 when set_has_js_cookie is set to TRUE.'); + } + /** * Resets static variables related to adding JavaScript to a page. */ @@ -1968,6 +2037,11 @@ class DrupalRenderTestCase extends DrupalWebTestCase { 'value' => '', 'expected' => '', ), + array( + 'name' => 'not a render array', + 'value' => 'this is not an array', + 'expected' => '', + ), array( 'name' => 'no access', 'value' => array( @@ -3297,3 +3371,48 @@ class BlockInterestCohortTest extends DrupalWebTestCase { } } + +/** + * Test for drupal_add_html_head_link(). + */ +class DrupalAddHtmlHeadLinkTest extends DrupalWebTestCase { + + /** + * {@inheritdoc} + */ + public static function getInfo() { + return array( + 'name' => 'Add HTML head link', + 'description' => 'Test for drupal_add_html_head_link().', + 'group' => 'System', + ); + } + + /** + * {@inheritdoc} + */ + function setUp() { + parent::setUp('common_test'); + } + + /** + * Tests drupal_add_html_head_link(). + */ + function testDrupalAddHtmlHeadLink() { + $this->drupalGet('common-test/html_head_link'); + $expected_link_header = implode(',', array( + '; rel="alternate"', + '; hreflang="nl"; rel="alternate"', + '; hreflang="de"; rel="alternate"', + '; hreflang="en"; rel="alternate"', + )); + $this->assertEqual($this->drupalGetHeader('Link'), $expected_link_header); + + // Check that duplicate alternate URLs with different hreflangs are allowed. + $test_link = $this->xpath('//head/link[@rel="alternate"][@href="/foo/bar"]'); + $this->assertEqual(count($test_link), 2, 'Duplicate alternate URLs are allowed.'); + // Check that link element attributes are HTML-encoded. + $this->assertRaw(''); + } + +} diff --git a/modules/simpletest/tests/common.test:Zone.Identifier b/modules/simpletest/tests/common.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/common.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/common_test.css:Zone.Identifier b/modules/simpletest/tests/common_test.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/common_test.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/common_test.info b/modules/simpletest/tests/common_test.info index f1fc039563..e9c6bcccdf 100644 --- a/modules/simpletest/tests/common_test.info +++ b/modules/simpletest/tests/common_test.info @@ -7,7 +7,7 @@ stylesheets[all][] = common_test.css stylesheets[print][] = common_test.print.css hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/common_test.info:Zone.Identifier b/modules/simpletest/tests/common_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/common_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/common_test.module b/modules/simpletest/tests/common_test.module index d7b97bc892..863d6b02f5 100644 --- a/modules/simpletest/tests/common_test.module +++ b/modules/simpletest/tests/common_test.module @@ -64,6 +64,12 @@ function common_test_menu() { 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); + $items['common-test/html_head_link'] = array( + 'title' => 'Test HTML head link', + 'page callback' => 'common_test_html_head_link', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); return $items; } @@ -314,3 +320,33 @@ function existing_permissions_policy_header() { drupal_add_http_header('Permissions-Policy', 'geolocation=()'); print __FUNCTION__; } + +/** + * Page callback. + */ +function common_test_html_head_link() { + drupal_add_html_head_link(array( + 'href' => '/foo?bar=baz', + 'rel' => 'alternate', + ), TRUE); + drupal_add_html_head_link(array( + 'href' => '/not-added-to-http-headers', + 'rel' => 'alternate', + ), FALSE); + drupal_add_html_head_link(array( + 'href' => '/foo/bar', + 'hreflang' => 'nl', + 'rel' => 'alternate', + ), TRUE); + drupal_add_html_head_link(array( + 'href' => '/foo/bar', + 'hreflang' => 'de', + 'rel' => 'alternate', + ), TRUE); + drupal_add_html_head_link(array( + 'href' => '/foo?bar=baz&baz=false', + 'hreflang' => 'en', + 'rel' => 'alternate', + ), TRUE); + return ''; +} diff --git a/modules/simpletest/tests/common_test.module:Zone.Identifier b/modules/simpletest/tests/common_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/common_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/common_test.print.css:Zone.Identifier b/modules/simpletest/tests/common_test.print.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/common_test.print.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/common_test_cron_helper.info b/modules/simpletest/tests/common_test_cron_helper.info index c012d8879f..f9cff27bc7 100644 --- a/modules/simpletest/tests/common_test_cron_helper.info +++ b/modules/simpletest/tests/common_test_cron_helper.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/common_test_cron_helper.info:Zone.Identifier b/modules/simpletest/tests/common_test_cron_helper.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/common_test_cron_helper.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/common_test_cron_helper.module:Zone.Identifier b/modules/simpletest/tests/common_test_cron_helper.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/common_test_cron_helper.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/common_test_info.txt:Zone.Identifier b/modules/simpletest/tests/common_test_info.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/common_test_info.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/database_test.info b/modules/simpletest/tests/database_test.info index 8df294b023..a9dac596b8 100644 --- a/modules/simpletest/tests/database_test.info +++ b/modules/simpletest/tests/database_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/database_test.info:Zone.Identifier b/modules/simpletest/tests/database_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/database_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/database_test.install b/modules/simpletest/tests/database_test.install index 44ed5ee0a4..ad19430d8b 100644 --- a/modules/simpletest/tests/database_test.install +++ b/modules/simpletest/tests/database_test.install @@ -54,6 +54,44 @@ function database_test_schema() { ), ); + $schema['test_classtype'] = array( + 'description' => 'A duplicate version of the test table, used for fetch_style PDO::FETCH_CLASSTYPE tests.', + 'fields' => array( + 'classname' => array( + 'description' => "A custom class name", + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'name' => array( + 'description' => "A person's name", + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'age' => array( + 'description' => "The person's age", + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'job' => array( + 'description' => "The person's job", + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + ), + 'primary key' => array('job'), + 'indexes' => array( + 'ages' => array('age'), + ), + ); + // This is an alternate version of the same table that is structured the same // but has a non-serial Primary Key. $schema['test_people'] = array( @@ -236,5 +274,7 @@ function database_test_schema() { 'primary key' => array('id'), ); + $schema['TEST_UPPERCASE'] = $schema['test']; + return $schema; } diff --git a/modules/simpletest/tests/database_test.install:Zone.Identifier b/modules/simpletest/tests/database_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/database_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/database_test.module:Zone.Identifier b/modules/simpletest/tests/database_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/database_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test index 0f0d2c3209..310178e1bb 100644 --- a/modules/simpletest/tests/database_test.test +++ b/modules/simpletest/tests/database_test.test @@ -22,11 +22,13 @@ class DatabaseTestCase extends DrupalWebTestCase { parent::setUp('database_test'); $schema['test'] = drupal_get_schema('test'); + $schema['test_classtype'] = drupal_get_schema('test_classtype'); $schema['test_people'] = drupal_get_schema('test_people'); $schema['test_people_copy'] = drupal_get_schema('test_people_copy'); $schema['test_one_blob'] = drupal_get_schema('test_one_blob'); $schema['test_two_blobs'] = drupal_get_schema('test_two_blobs'); $schema['test_task'] = drupal_get_schema('test_task'); + $schema['TEST_UPPERCASE'] = drupal_get_schema('TEST_UPPERCASE'); $this->installTables($schema); @@ -117,6 +119,15 @@ class DatabaseTestCase extends DrupalWebTestCase { )) ->execute(); + db_insert('test_classtype') + ->fields(array( + 'classname' => 'FakeRecord', + 'name' => 'Kay', + 'age' => 26, + 'job' => 'Web Developer', + )) + ->execute(); + db_insert('test_people') ->fields(array( 'name' => 'Meredith', @@ -314,6 +325,10 @@ class DatabaseSelectCloneTest extends DatabaseTestCase { $query->condition('id', $subquery, 'IN'); $clone = clone $query; + + // Cloned query should have a different unique identifier. + $this->assertNotEqual($query->uniqueIdentifier(), $clone->uniqueIdentifier()); + // Cloned query should not be altered by the following modification // happening on original query. $subquery->condition('age', 25, '>'); @@ -325,6 +340,33 @@ class DatabaseSelectCloneTest extends DatabaseTestCase { $this->assertEqual(3, $clone_result, 'The cloned query returns the expected number of rows'); $this->assertEqual(2, $query_result, 'The query returns the expected number of rows'); } + + /** + * Tests that nested SELECT queries are cloned properly. + */ + public function testNestedQueryCloning() { + $sub_query = db_select('test', 't'); + $sub_query->addField('t', 'id', 'id'); + $sub_query->condition('age', 28, '<'); + + $query = db_select($sub_query, 't'); + + $clone = clone $query; + + // Cloned query should have a different unique identifier. + $this->assertNotEqual($query->uniqueIdentifier(), $clone->uniqueIdentifier()); + + // Cloned query should not be altered by the following modification + // happening on original query. + $sub_query->condition('age', 25, '>'); + + $clone_result = $clone->countQuery()->execute()->fetchField(); + $query_result = $query->countQuery()->execute()->fetchField(); + + // Make sure the cloned query has not been modified. + $this->assertEqual(3, $clone_result, 'The cloned query returns the expected number of rows'); + $this->assertEqual(2, $query_result, 'The query returns the expected number of rows'); + } } /** @@ -406,6 +448,27 @@ class DatabaseFetchTestCase extends DatabaseTestCase { $this->assertIdentical(count($records), 1, 'There is only one record.'); } + + /** + * Confirms that we can fetch a record into a new instance of a custom class. + * The name of the class is determined from a value of the first column. + * + * @see FakeRecord + */ + function testQueryFetchClasstype() { + $records = array(); + $result = db_query('SELECT classname, name, job FROM {test_classtype} WHERE age = :age', array(':age' => 26), array('fetch' => PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE)); + foreach ($result as $record) { + $records[] = $record; + if ($this->assertTrue($record instanceof FakeRecord, 'Record is an object of class FakeRecord.')) { + $this->assertIdentical($record->name, 'Kay', 'Kay is found.'); + $this->assertIdentical($record->job, 'Web Developer', 'A 26 year old Web Developer.'); + } + $this->assertFalse(isset($record->classname), 'Classname field not found, as intended.'); + } + + $this->assertIdentical(count($records), 1, 'There is only one record.'); + } } /** @@ -867,28 +930,30 @@ class DatabaseUpdateTestCase extends DatabaseTestCase { ->fields(array('age' => 1)) ->execute(); - // Ensure that expressions are handled properly. This should set every - // record's age to a square of itself, which will change only three of the - // four records in the table since 1*1 = 1. That means only three records - // are modified, so we should get back 3, not 4, from execute(). + // Ensure that expressions are handled properly. This should set every + // record's age to a square of itself. The number of affected rows returned + // by db_update() will vary across different database engines and versions: + // - MySQL / InnoDB: changed rows only + // - MySQL / MyISAM: changed rows only + // - PostgreSQL: all rows matched by the query + // - SQLite: changed rows only (see workaround in UpdateQuery_sqlite) + // All database engines will change only three of the four records in the + // table since 1*1 = 1. However, the pgsql driver will return the number of + // rows matched rather than the number changed. + // @see https://www.drupal.org/project/drupal/issues/805858 + // @see https://www.drupal.org/project/drupal/issues/3264471 + $connection = Database::getConnection()->getConnectionOptions(); + $expected_rows = 3; + if ($connection['driver'] === 'pgsql') { + $expected_rows ++; + } $num_rows = db_update('test') ->expression('age', 'age * age') ->execute(); - $this->assertIdentical($num_rows, 3, 'Number of affected rows are returned.'); - } - - /** - * Confirm that we can update the primary key of a record successfully. - */ - function testPrimaryKeyUpdate() { - $num_updated = db_update('test') - ->fields(array('id' => 42, 'name' => 'John')) - ->condition('id', 1) - ->execute(); - $this->assertIdentical($num_updated, 1, 'Updated 1 record.'); + $this->assertIdentical($num_rows, $expected_rows, 'Number of affected rows are returned.'); - $saved_name= db_query('SELECT name FROM {test} WHERE id = :id', array(':id' => 42))->fetchField(); - $this->assertIdentical($saved_name, 'John', 'Updated primary key successfully.'); + $saved_name = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => pow(26, 2)))->fetchField(); + $this->assertIdentical('Paul', $saved_name, 'Successfully updated values using an algebraic expression.'); } } @@ -1605,7 +1670,7 @@ class DatabaseSelectTestCase extends DatabaseTestCase { /** * Test that we can UNION multiple Select queries together. This is - * semantically equal to UNION DISTINCT, so we don't explicity test that. + * semantically equal to UNION DISTINCT, so we don't explicitly test that. */ function testUnion() { $query_1 = db_select('test', 't') @@ -1614,7 +1679,8 @@ class DatabaseSelectTestCase extends DatabaseTestCase { $query_2 = db_select('test', 't') ->fields('t', array('name')) - ->condition('age', 28); + ->condition('age', 28) + ->orderBy('name'); $query_1->union($query_2); @@ -1651,6 +1717,64 @@ class DatabaseSelectTestCase extends DatabaseTestCase { $this->assertEqual($names[2], 'Ringo', 'Third query returned correct name.'); } + /** + * Tests that we can UNION multiple Select queries together and set the ORDER. + */ + function testUnionOrder() { + // This gives George and Ringo. + $query_1 = db_select('test', 't') + ->fields('t', array('name')) + ->condition('age', array(27, 28), 'IN'); + + // This gives Paul. + $query_2 = db_select('test', 't') + ->fields('t', array('name')) + ->condition('age', 26); + + $query_1->union($query_2); + $query_1->orderBy('name', 'DESC'); + + $names = $query_1->execute()->fetchCol(); + + // Ensure we get all 3 records. + $this->assertEqual(count($names), 3, 'UNION returned rows from both queries.'); + + // Ensure that the names are in the correct reverse alphabetical order, + // regardless of which query they came from. + $this->assertEqual($names[0], 'Ringo', 'First query returned correct name.'); + $this->assertEqual($names[1], 'Paul', 'Second query returned correct name.'); + $this->assertEqual($names[2], 'George', 'Third query returned correct name.'); + } + + /** + * Tests that we can UNION multiple Select queries together with a LIMIT. + */ + function testUnionOrderLimit() { + // This gives George and Ringo. + $query_1 = db_select('test', 't') + ->fields('t', array('name')) + ->condition('age', array(27, 28), 'IN'); + + // This gives Paul. + $query_2 = db_select('test', 't') + ->fields('t', array('name')) + ->condition('age', 26); + + $query_1->union($query_2); + $query_1->orderBy('name', 'DESC'); + $query_1->range(0, 2); + + $names = $query_1->execute()->fetchCol(); + + // Ensure we get only 2 of the 3 records. + $this->assertEqual(count($names), 2, 'UNION with a limit returned rows from both queries.'); + + // Ensure that the names are in the correct reverse alphabetical order, + // regardless of which query they came from. + $this->assertEqual($names[0], 'Ringo', 'First query returned correct name.'); + $this->assertEqual($names[1], 'Paul', 'Second query returned correct name.'); + } + /** * Test that random ordering of queries works. * @@ -2316,6 +2440,51 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase { $this->assertNotEqual($crowded_job->name, $crowded_job->othername, 'Correctly joined same table twice.'); } + /** + * Test that join conditions can use Condition objects. + */ + function testJoinConditionObject() { + // Same test as testDefaultJoin, but with a Condition object. + $query = db_select('test_task', 't'); + $join_cond = db_and()->where('t.pid = p.id'); + $people_alias = $query->join('test', 'p', $join_cond); + $name_field = $query->addField($people_alias, 'name', 'name'); + $query->addField('t', 'task', 'task'); + $priority_field = $query->addField('t', 'priority', 'priority'); + + $query->orderBy($priority_field); + $result = $query->execute(); + + $num_records = 0; + $last_priority = 0; + foreach ($result as $record) { + $num_records++; + $this->assertTrue($record->$priority_field >= $last_priority, 'Results returned in correct order.'); + $this->assertNotEqual($record->$name_field, 'Ringo', 'Taskless person not selected.'); + $last_priority = $record->$priority_field; + } + + $this->assertEqual($num_records, 7, 'Returned the correct number of rows.'); + + // Test a condition object that creates placeholders. + $t1_name = 'John'; + $t2_name = 'George'; + $join_cond = db_and() + ->condition('t1.name', $t1_name) + ->condition('t2.name', $t2_name); + $query = db_select('test', 't1'); + $query->innerJoin('test', 't2', $join_cond); + $query->addField('t1', 'name', 't1_name'); + $query->addField('t2', 'name', 't2_name'); + + $num_records = $query->countQuery()->execute()->fetchField(); + $this->assertEqual($num_records, 1, 'Query expected to return 1 row. Actual: ' . $num_records); + if ($num_records == 1) { + $record = $query->execute()->fetchObject(); + $this->assertEqual($record->t1_name, $t1_name, 'Query expected to retrieve name ' . $t1_name . ' from table t1. Actual: ' . $record->t1_name); + $this->assertEqual($record->t2_name, $t2_name, 'Query expected to retrieve name ' . $t2_name . ' from table t2. Actual: ' . $record->t2_name); + } + } } /** @@ -2507,32 +2676,32 @@ class DatabaseSelectPagerDefaultTestCase extends DatabaseTestCase { function testElementNumbers() { $_GET['page'] = '3, 2, 1, 0'; - $name = db_select('test', 't')->extend('PagerDefault') - ->element(2) + $query = db_select('test', 't')->extend('PagerDefault'); + $query->element(2) ->fields('t', array('name')) ->orderBy('age') - ->limit(1) - ->execute() - ->fetchField(); + ->limit(1); + $this->assertEqual(2, $query->getElement()); + $name = $query->execute()->fetchField(); $this->assertEqual($name, 'Paul', 'Pager query #1 with a specified element ID returned the correct results.'); // Setting an element smaller than the previous one // should not overwrite the pager $maxElement with a smaller value. - $name = db_select('test', 't')->extend('PagerDefault') - ->element(1) + $query = db_select('test', 't')->extend('PagerDefault'); + $query->element(1) ->fields('t', array('name')) ->orderBy('age') - ->limit(1) - ->execute() - ->fetchField(); + ->limit(1); + $this->assertEqual(1, $query->getElement()); + $name = $query->execute()->fetchField(); $this->assertEqual($name, 'George', 'Pager query #2 with a specified element ID returned the correct results.'); - $name = db_select('test', 't')->extend('PagerDefault') - ->fields('t', array('name')) + $query = db_select('test', 't')->extend('PagerDefault'); + $query->fields('t', array('name')) ->orderBy('age') - ->limit(1) - ->execute() - ->fetchField(); + ->limit(1); + $this->assertEqual(3, $query->getElement()); + $name = $query->execute()->fetchField(); $this->assertEqual($name, 'John', 'Pager query #3 with a generated element ID returned the correct results.'); unset($_GET['page']); @@ -3463,6 +3632,67 @@ class DatabaseQueryTestCase extends DatabaseTestCase { ->fetchField(); $this->assertFalse($result, 'SQL injection attempt did not result in a row being inserted in the database table.'); } + + /** + * Tests SQL injection via condition operator. + */ + public function testConditionOperatorArgumentsSQLInjection() { + + $injection = "IS NOT NULL); INSERT INTO {test} (name) VALUES ('test12345678'); -- "; + try { + $result = db_select('test', 't') + ->fields('t') + ->condition('name', 1, $injection) + ->execute(); + $this->fail('Should not be able to attempt SQL injection via condition operator.'); + } + catch (InvalidQueryConditionOperatorException $e) { + $this->pass('SQL injection attempt via condition arguments should result in a database exception.'); + } + + // Test that the insert query that was used in the SQL injection attempt did + // not result in a row being inserted in the database. + $result = db_select('test') + ->condition('name', 'test12345678') + ->countQuery() + ->execute() + ->fetchField(); + $this->assertFalse($result, 'SQL injection attempt did not result in a row being inserted in the database table.'); + + // Attempt SQLi via union query with no unsafe characters. + db_insert('test') + ->fields(array('name' => '123456')) + ->execute(); + + $injection = "= 1 UNION ALL SELECT password FROM user WHERE uid ="; + try { + $result = db_select('test', 't') + ->fields('t', array('name', 'name')) + ->condition('name', 1, $injection) + ->execute(); + $this->fail('Should not be able to attempt SQL injection via operator.'); + } + catch (InvalidQueryConditionOperatorException $e) { + $this->pass('SQL injection attempt via condition arguments should result in a database exception.'); + } + + // Attempt SQLi via union query - uppercase tablename. + db_insert('TEST_UPPERCASE') + ->fields(array('name' => 'secrets')) + ->execute(); + + $injection = "IS NOT NULL) UNION ALL SELECT name FROM {TEST_UPPERCASE} -- "; + try { + $result = db_select('test', 't') + ->fields('t', array('name')) + ->condition('name', 1, $injection) + ->execute(); + $this->fail('Should not be able to attempt SQL injection via operator.'); + } + catch (InvalidQueryConditionOperatorException $e) { + $this->pass('SQL injection attempt via condition arguments should result in a database exception.'); + } + } } /** @@ -4293,6 +4523,13 @@ class DatabaseReservedKeywordTestCase extends DatabaseTestCase { } else { $database = $connection['database']; + + if ($connection['driver'] === 'pgsql') { + // database.scheme.table for PostgreSQL + // @see https://www.postgresql.org/docs/14/ddl-schemas.html + $database .= '.public'; + } + // Test db_query with schema.{table} pattern db_query('SELECT * FROM ' . $database . '.{system} LIMIT 1')->fetchObject(); $this->assertTrue(isset($record->filename), 'Successfully queried the schema.{system} table.'); @@ -4416,6 +4653,13 @@ class DatabaseTablePrefixTestCase extends DatabaseTestCase { } $db_name = $connection_options['database']; + + if ($connection_options['driver'] === 'pgsql') { + // database.scheme.table for PostgreSQL + // @see https://www.postgresql.org/docs/14/ddl-schemas.html + $db_name .= '.public'; + } + // This prefix is usually something like simpletest12345 $test_prefix = $connection_options['prefix']['default']; diff --git a/modules/simpletest/tests/database_test.test:Zone.Identifier b/modules/simpletest/tests/database_test.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/database_test.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info index 0b077fc068..1db5a80b5f 100644 --- a/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info +++ b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info @@ -7,7 +7,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info:Zone.Identifier b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.module:Zone.Identifier b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test_class.inc:Zone.Identifier b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test_class.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test_class.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test_interface.inc:Zone.Identifier b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test_interface.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test_interface.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test_trait.sh:Zone.Identifier b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test_trait.sh:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test_trait.sh:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index 8eb87b206e..0c9ca69460 100644 --- a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info:Zone.Identifier b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module:Zone.Identifier b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index 5939450452..eb38a64f96 100644 --- a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info:Zone.Identifier b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module:Zone.Identifier b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_cache_test.info b/modules/simpletest/tests/entity_cache_test.info index 1688292117..05fe08084d 100644 --- a/modules/simpletest/tests/entity_cache_test.info +++ b/modules/simpletest/tests/entity_cache_test.info @@ -6,7 +6,7 @@ core = 7.x dependencies[] = entity_cache_test_dependency hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/entity_cache_test.info:Zone.Identifier b/modules/simpletest/tests/entity_cache_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_cache_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_cache_test.module:Zone.Identifier b/modules/simpletest/tests/entity_cache_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_cache_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_cache_test_dependency.info b/modules/simpletest/tests/entity_cache_test_dependency.info index 32234c4a62..b9feaf393e 100644 --- a/modules/simpletest/tests/entity_cache_test_dependency.info +++ b/modules/simpletest/tests/entity_cache_test_dependency.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/entity_cache_test_dependency.info:Zone.Identifier b/modules/simpletest/tests/entity_cache_test_dependency.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_cache_test_dependency.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_cache_test_dependency.module:Zone.Identifier b/modules/simpletest/tests/entity_cache_test_dependency.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_cache_test_dependency.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_crud.test b/modules/simpletest/tests/entity_crud.test index be15977902..c7d66509a2 100644 --- a/modules/simpletest/tests/entity_crud.test +++ b/modules/simpletest/tests/entity_crud.test @@ -46,4 +46,16 @@ class EntityLoadTestCase extends DrupalWebTestCase { $this->assertIdentical($nodes_loaded[$node_2->nid], $all_nodes[$node_2->nid], 'Loaded node 2 is identical to cached node.'); $this->assertIdentical($nodes_loaded[$node_3->nid], $all_nodes[$node_3->nid], 'Loaded node 3 is identical to cached node.'); } + + public function testEntityLoadIds() { + $this->drupalCreateNode(array('title' => 'Node 1')); + $this->drupalCreateNode(array('title' => 'Node 2')); + + $nodes_loaded = entity_load('node', array('1', '2')); + $this->assertEqual(count($nodes_loaded), 2); + + // Ensure that an id with a trailing decimal place is ignored. + $nodes_loaded = entity_load('node', array('1.', '2')); + $this->assertEqual(count($nodes_loaded), 1); + } } diff --git a/modules/simpletest/tests/entity_crud.test:Zone.Identifier b/modules/simpletest/tests/entity_crud.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_crud.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_crud_hook_test.info b/modules/simpletest/tests/entity_crud_hook_test.info index ea7a78a5f8..9b95541e70 100644 --- a/modules/simpletest/tests/entity_crud_hook_test.info +++ b/modules/simpletest/tests/entity_crud_hook_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/entity_crud_hook_test.info:Zone.Identifier b/modules/simpletest/tests/entity_crud_hook_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_crud_hook_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_crud_hook_test.module:Zone.Identifier b/modules/simpletest/tests/entity_crud_hook_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_crud_hook_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_crud_hook_test.test:Zone.Identifier b/modules/simpletest/tests/entity_crud_hook_test.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_crud_hook_test.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_query.test:Zone.Identifier b/modules/simpletest/tests/entity_query.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_query.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_query_access_test.info b/modules/simpletest/tests/entity_query_access_test.info index 1444a0b3d8..baa7aedd2d 100644 --- a/modules/simpletest/tests/entity_query_access_test.info +++ b/modules/simpletest/tests/entity_query_access_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/entity_query_access_test.info:Zone.Identifier b/modules/simpletest/tests/entity_query_access_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_query_access_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/entity_query_access_test.module:Zone.Identifier b/modules/simpletest/tests/entity_query_access_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/entity_query_access_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/error.test:Zone.Identifier b/modules/simpletest/tests/error.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/error.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/error_test.info b/modules/simpletest/tests/error_test.info index 5620431ce4..5b6af5bcf9 100644 --- a/modules/simpletest/tests/error_test.info +++ b/modules/simpletest/tests/error_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/error_test.info:Zone.Identifier b/modules/simpletest/tests/error_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/error_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/error_test.module:Zone.Identifier b/modules/simpletest/tests/error_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/error_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/file.test b/modules/simpletest/tests/file.test index 57b315fb0e..ff8cb2f7a6 100644 --- a/modules/simpletest/tests/file.test +++ b/modules/simpletest/tests/file.test @@ -108,6 +108,7 @@ class FileTestCase extends DrupalWebTestCase { // Mask out all but the last three octets. $actual_mode = fileperms($filepath) & 0777; + $expected_mode = $expected_mode & 0777; // PHP on Windows has limited support for file permissions. Usually each of // "user", "group" and "other" use one octal digit (3 bits) to represent the @@ -143,6 +144,7 @@ class FileTestCase extends DrupalWebTestCase { // Mask out all but the last three octets. $actual_mode = fileperms($directory) & 0777; + $expected_mode = $expected_mode & 0777; // PHP on Windows has limited support for file permissions. Usually each of // "user", "group" and "other" use one octal digit (3 bits) to represent the @@ -1055,6 +1057,39 @@ class FileDirectoryTest extends FileTestCase { ); } + /** + * Test local directory handling functions. + */ + function testFileCheckLocalDirectoryHandling() { + $directory = file_default_scheme() . '://'; + + // Check a new recursively created local directory for correct file system + // permissions. + $parent = $this->randomName(); + $child = $this->randomName(); + + // Files directory already exists. + $this->assertTrue(is_dir($directory), 'Files directory already exists.', 'File'); + // Make files directory writable only. + $old_mode = fileperms($directory); + + // Create the directories. + $parent_path = $directory . DIRECTORY_SEPARATOR . $parent; + $child_path = $parent_path . DIRECTORY_SEPARATOR . $child; + $this->assertTrue(drupal_mkdir($child_path, 0775, TRUE), 'No error reported when creating new local directories.', 'File'); + + // Ensure new directories also exist. + $this->assertTrue(is_dir($parent_path), 'New parent directory actually exists.', 'File'); + $this->assertTrue(is_dir($child_path), 'New child directory actually exists.', 'File'); + + // Check that new directory permissions were set properly. + $this->assertDirectoryPermissions($parent_path, 0775); + $this->assertDirectoryPermissions($child_path, 0775); + + // Check that existing directory permissions were not modified. + $this->assertDirectoryPermissions($directory, $old_mode); + } + /** * Test directory handling functions. */ diff --git a/modules/simpletest/tests/file.test:Zone.Identifier b/modules/simpletest/tests/file.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/file.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/file_test.info b/modules/simpletest/tests/file_test.info index ad2dc10187..51d51cecff 100644 --- a/modules/simpletest/tests/file_test.info +++ b/modules/simpletest/tests/file_test.info @@ -6,7 +6,7 @@ core = 7.x files[] = file_test.module hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/file_test.info:Zone.Identifier b/modules/simpletest/tests/file_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/file_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/file_test.module:Zone.Identifier b/modules/simpletest/tests/file_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/file_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/filetransfer.test b/modules/simpletest/tests/filetransfer.test index 905d23cab7..617e6cc021 100644 --- a/modules/simpletest/tests/filetransfer.test +++ b/modules/simpletest/tests/filetransfer.test @@ -114,7 +114,7 @@ class TestFileTransfer extends FileTransfer { $parts = explode(':', $this->hostname); $port = (count($parts) == 2) ? $parts[1] : $this->port; $this->connection = new MockTestConnection(); - $this->connection->connectionString = 'test://' . urlencode($this->username) . ':' . urlencode($this->password) . "@$this->host:$this->port/"; + $this->connection->connectionString = 'test://' . urlencode((string) $this->username) . ':' . urlencode((string) $this->password) . "@$this->host:$this->port/"; } function copyFileJailed($source, $destination) { diff --git a/modules/simpletest/tests/filetransfer.test:Zone.Identifier b/modules/simpletest/tests/filetransfer.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/filetransfer.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/filter_test.info b/modules/simpletest/tests/filter_test.info index 5e54e1d2fe..3eee6e431a 100644 --- a/modules/simpletest/tests/filter_test.info +++ b/modules/simpletest/tests/filter_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/filter_test.info:Zone.Identifier b/modules/simpletest/tests/filter_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/filter_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/filter_test.module:Zone.Identifier b/modules/simpletest/tests/filter_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/filter_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/form.test:Zone.Identifier b/modules/simpletest/tests/form.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/form.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/form_test.file.inc:Zone.Identifier b/modules/simpletest/tests/form_test.file.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/form_test.file.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/form_test.info b/modules/simpletest/tests/form_test.info index b871932c7c..99a4bd0db2 100644 --- a/modules/simpletest/tests/form_test.info +++ b/modules/simpletest/tests/form_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/form_test.info:Zone.Identifier b/modules/simpletest/tests/form_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/form_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/form_test.module:Zone.Identifier b/modules/simpletest/tests/form_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/form_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/graph.test:Zone.Identifier b/modules/simpletest/tests/graph.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/graph.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/http.php:Zone.Identifier b/modules/simpletest/tests/http.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/http.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/https.php:Zone.Identifier b/modules/simpletest/tests/https.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/https.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/image.test:Zone.Identifier b/modules/simpletest/tests/image.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/image.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/image_test.info b/modules/simpletest/tests/image_test.info index 4e3f8acde7..f2d612da8c 100644 --- a/modules/simpletest/tests/image_test.info +++ b/modules/simpletest/tests/image_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/image_test.info:Zone.Identifier b/modules/simpletest/tests/image_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/image_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/image_test.module:Zone.Identifier b/modules/simpletest/tests/image_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/image_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/lock.test:Zone.Identifier b/modules/simpletest/tests/lock.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/lock.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/mail.test:Zone.Identifier b/modules/simpletest/tests/mail.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/mail.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/menu.test b/modules/simpletest/tests/menu.test index f5d7d290fc..daea9f09ec 100644 --- a/modules/simpletest/tests/menu.test +++ b/modules/simpletest/tests/menu.test @@ -1738,3 +1738,41 @@ class MenuTrailTestCase extends MenuWebTestCase { } } } + +/** + * Tests value integrity. + */ +class MenuDataIntegrityTestCase extends MenuWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Menu item array integrity', + 'description' => 'Tests the values passed on to menu items array.', + 'group' => 'Menu', + ); + } + + /** + * Tests for null/casting weight parameter. + */ + public function testNullMenuWeight() { + $base_options = array( + 'link_title' => 'Menu link test', + 'module' => 'menu_test', + 'menu_name' => 'menu_test', + 'weight' => NULL, + 'link_path' => 'menu-test/parent', + ); + + try { + menu_link_save($base_options); + } + catch (PDOException $exception) { + $this->fail('Menu weight is not being cast properly.'); + return; + } + + $this->pass('Menu weight is being cast properly.'); + } + +} diff --git a/modules/simpletest/tests/menu.test:Zone.Identifier b/modules/simpletest/tests/menu.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/menu.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/menu_test.info b/modules/simpletest/tests/menu_test.info index 8576ac8368..4f0c3c1de9 100644 --- a/modules/simpletest/tests/menu_test.info +++ b/modules/simpletest/tests/menu_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/menu_test.info:Zone.Identifier b/modules/simpletest/tests/menu_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/menu_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/menu_test.module:Zone.Identifier b/modules/simpletest/tests/menu_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/menu_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/module.test b/modules/simpletest/tests/module.test index eea3b51e9c..617c8f3f38 100644 --- a/modules/simpletest/tests/module.test +++ b/modules/simpletest/tests/module.test @@ -66,6 +66,12 @@ class ModuleUnitTest extends DrupalWebTestCase { // Reset the module list. module_list(TRUE); $this->assertModuleList($module_list, t('After reset')); + + // Verify that the module_list() returns correct bootstrap modules. + $bootstrap_module_list = module_list(TRUE, TRUE); + $expected_bootstrap_modules = db_query("SELECT name, filename FROM {system} WHERE status = 1 AND bootstrap = 1 AND type = 'module' ORDER BY weight ASC, name ASC")->fetchAllAssoc('name'); + $expected_bootstrap_module_list = array_combine(array_keys($expected_bootstrap_modules), array_keys($expected_bootstrap_modules)); + $this->assertIdentical($expected_bootstrap_module_list, $bootstrap_module_list, 'module_list() returns correct bootstrap modules.'); } /** @@ -110,6 +116,31 @@ class ModuleUnitTest extends DrupalWebTestCase { $this->assertEqual($static['test_hook']['module_test'], 'file', 'Include file detected.'); } + /** + * Test system_modules() with a module with a dependency with a null version. + */ + function testSystemModulesNullVersion() { + module_enable(array('system_requires_null_version_test'), FALSE); + $this->resetAll(); + $admin = $this->drupalCreateUser(array('administer modules')); + $this->drupalLogin($admin); + $this->drupalGet('admin/modules'); + $this->assertText('System null version test', 'Module admin UI listed dependency with null version successfully.'); + } + + /** + * Test system_modules() with a module with a broken configure path. + */ + function testSystemModulesBrokenConfigure() { + module_enable(array('system_admin_test')); + $this->resetAll(); + $admin = $this->drupalCreateUser(array('administer modules')); + $this->drupalLogin($admin); + $this->drupalGet('admin/modules'); + $module_log = db_query_range('SELECT message FROM {watchdog} WHERE type = :type ORDER BY wid DESC', 0, 1, array(':type' => 'system'))->fetchField(); + $this->assertEqual('Module %module specifies an invalid path for configuration: %configure', $module_log, 'An error was logged for the module\'s broken configure path.'); + } + /** * Test that module_invoke() can load a hook defined in hook_hook_info(). */ diff --git a/modules/simpletest/tests/module.test:Zone.Identifier b/modules/simpletest/tests/module.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/module.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/module_test.file.inc:Zone.Identifier b/modules/simpletest/tests/module_test.file.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/module_test.file.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/module_test.implementations.inc:Zone.Identifier b/modules/simpletest/tests/module_test.implementations.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/module_test.implementations.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/module_test.info b/modules/simpletest/tests/module_test.info index 301fdd20a2..600dbe9f4e 100644 --- a/modules/simpletest/tests/module_test.info +++ b/modules/simpletest/tests/module_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/module_test.info:Zone.Identifier b/modules/simpletest/tests/module_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/module_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/module_test.install:Zone.Identifier b/modules/simpletest/tests/module_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/module_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/module_test.module:Zone.Identifier b/modules/simpletest/tests/module_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/module_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/pager.test b/modules/simpletest/tests/pager.test index 432edbf456..1a00472166 100644 --- a/modules/simpletest/tests/pager.test +++ b/modules/simpletest/tests/pager.test @@ -169,6 +169,6 @@ class PagerFunctionalWebTestCase extends DrupalWebTestCase { if (!isset($message)) { $message = "Class .$class not found."; } - $this->assertTrue(strpos($element['class'], $class) === FALSE, $message); + $this->assertTrue(strpos((string) $element['class'], $class) === FALSE, $message); } } diff --git a/modules/simpletest/tests/pager.test:Zone.Identifier b/modules/simpletest/tests/pager.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/pager.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/password.test:Zone.Identifier b/modules/simpletest/tests/password.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/password.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/path.test b/modules/simpletest/tests/path.test index b8b3c93c81..5473bab7c9 100644 --- a/modules/simpletest/tests/path.test +++ b/modules/simpletest/tests/path.test @@ -331,6 +331,17 @@ class PathLookupTest extends DrupalWebTestCase { ); path_save($path); $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Newer alias record is returned when comparing two LANGUAGE_NONE paths with the same alias.'); + + // Test if the alias returned by drupal_lookup_path() is the same as the + // alias returned by path_load(). + $path = array( + 'source' => 'user/' . $account2->uid, + 'alias' => 'bar2', + ); + path_save($path); + $this->assertEqual(drupal_lookup_path('alias', $path['source']), 'bar2', 'Newer alias record is returned when using drupal_lookup_path() on paths with multiple aliases.'); + $loaded_path = path_load(array('source' => $path['source'])); + $this->assertEqual($loaded_path['alias'], 'bar2', 'Newer alias record is returned when using path_load() on paths with multiple aliases.'); } } diff --git a/modules/simpletest/tests/path.test:Zone.Identifier b/modules/simpletest/tests/path.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/path.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/path_test.info b/modules/simpletest/tests/path_test.info index d9d2ff8f6f..fcfd79f1f0 100644 --- a/modules/simpletest/tests/path_test.info +++ b/modules/simpletest/tests/path_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/path_test.info:Zone.Identifier b/modules/simpletest/tests/path_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/path_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/path_test.module:Zone.Identifier b/modules/simpletest/tests/path_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/path_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/ExampleTest.php:Zone.Identifier b/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/ExampleTest.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/ExampleTest.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php:Zone.Identifier b/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/psr_0_test/psr_0_test.info b/modules/simpletest/tests/psr_0_test/psr_0_test.info index af851e1190..637b2f2020 100644 --- a/modules/simpletest/tests/psr_0_test/psr_0_test.info +++ b/modules/simpletest/tests/psr_0_test/psr_0_test.info @@ -5,7 +5,7 @@ core = 7.x hidden = TRUE package = Testing -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/psr_0_test/psr_0_test.info:Zone.Identifier b/modules/simpletest/tests/psr_0_test/psr_0_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/psr_0_test/psr_0_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/psr_0_test/psr_0_test.module:Zone.Identifier b/modules/simpletest/tests/psr_0_test/psr_0_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/psr_0_test/psr_0_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/psr_4_test/psr_4_test.info b/modules/simpletest/tests/psr_4_test/psr_4_test.info index 274fe3a006..2283f3a727 100644 --- a/modules/simpletest/tests/psr_4_test/psr_4_test.info +++ b/modules/simpletest/tests/psr_4_test/psr_4_test.info @@ -5,7 +5,7 @@ core = 7.x hidden = TRUE package = Testing -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/psr_4_test/psr_4_test.info:Zone.Identifier b/modules/simpletest/tests/psr_4_test/psr_4_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/psr_4_test/psr_4_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/psr_4_test/psr_4_test.module:Zone.Identifier b/modules/simpletest/tests/psr_4_test/psr_4_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/psr_4_test/psr_4_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/psr_4_test/src/Tests/ExampleTest.php:Zone.Identifier b/modules/simpletest/tests/psr_4_test/src/Tests/ExampleTest.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/psr_4_test/src/Tests/ExampleTest.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/psr_4_test/src/Tests/Nested/NestedExampleTest.php:Zone.Identifier b/modules/simpletest/tests/psr_4_test/src/Tests/Nested/NestedExampleTest.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/psr_4_test/src/Tests/Nested/NestedExampleTest.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/registry.test:Zone.Identifier b/modules/simpletest/tests/registry.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/registry.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/request_sanitizer.test:Zone.Identifier b/modules/simpletest/tests/request_sanitizer.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/request_sanitizer.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/requirements1_test.info b/modules/simpletest/tests/requirements1_test.info index 4ed711c706..b980e5325f 100644 --- a/modules/simpletest/tests/requirements1_test.info +++ b/modules/simpletest/tests/requirements1_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/requirements1_test.info:Zone.Identifier b/modules/simpletest/tests/requirements1_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/requirements1_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/requirements1_test.install:Zone.Identifier b/modules/simpletest/tests/requirements1_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/requirements1_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/requirements1_test.module:Zone.Identifier b/modules/simpletest/tests/requirements1_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/requirements1_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/requirements2_test.info b/modules/simpletest/tests/requirements2_test.info index 721caeb6a2..a036bbf0c0 100644 --- a/modules/simpletest/tests/requirements2_test.info +++ b/modules/simpletest/tests/requirements2_test.info @@ -7,7 +7,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/requirements2_test.info:Zone.Identifier b/modules/simpletest/tests/requirements2_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/requirements2_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/requirements2_test.module:Zone.Identifier b/modules/simpletest/tests/requirements2_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/requirements2_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/schema.test:Zone.Identifier b/modules/simpletest/tests/schema.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/schema.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/session.test b/modules/simpletest/tests/session.test index 5632d44e4d..b309546f14 100644 --- a/modules/simpletest/tests/session.test +++ b/modules/simpletest/tests/session.test @@ -773,3 +773,123 @@ class SessionHttpsTestCase extends DrupalWebTestCase { } } +/** + * Unit tests for session handling. + */ +class SessionUnitTestCase extends DrupalUnitTestCase { + + /** + * {@inheritdoc} + */ + public static function getInfo() { + return array( + 'name' => 'Session unit tests', + 'description' => 'Test session handling functionality.', + 'group' => 'Session', + ); + } + + function testCookieDomain() { + $tests = array( + array('example.com', '.example.com'), + array('www.example.com', '.www.example.com'), + array('subdomain.example.com', '.subdomain.example.com'), + ); + + foreach ($tests as $test) { + $this->assertEqual(_drupal_get_cookie_domain($test[0]), $test[1], 'Correct $cookie_domain for host ' . $test[0]); + } + } + + /** + * Unit test drupal_settings_initialize(). + */ + function testSessionInitialization() { + global $base_url, $cookie_domain; + + $tests = array( + array( + 'http_host' => 'example.com', + 'script_name' => '/index.php', + 'session_name' => 'SESSa379a6f6eeafb9a55e378c118034e275', + 'base_url' => 'http://example.com', + 'cookie_domain' => '.example.com', + ), + array( + 'http_host' => 'example.com', + 'script_name' => '/foo/index.php', + 'session_name' => 'SESS76f699faa11e8fbe9a70d933651df90f', + 'base_url' => 'http://example.com/foo', + 'cookie_domain' => '.example.com', + ), + array( + 'http_host' => 'one.two.example.com', + 'script_name' => '/index.php', + 'session_name' => 'SESSc0cc73483118b575693f5c255faeb739', + 'base_url' => 'http://one.two.example.com', + 'cookie_domain' => '.one.two.example.com', + ), + array( + 'http_host' => 'www.sub.example.com', + 'script_name' => '/index.php', + 'session_name' => 'SESSdc70980beaa5d571d3c9785cf9246c96', + 'base_url' => 'http://www.sub.example.com', + 'cookie_domain' => '.www.sub.example.com', + ), + array( + 'http_host' => 'example.com', + 'script_name' => '/foo/bar/index.php', + 'session_name' => 'SESSdbf7edcf4f2656b247021ceb4752f7f9', + 'base_url' => 'http://example.com/foo/bar', + 'cookie_domain' => '.example.com', + ), + array( + 'http_host' => 'www.sub.example.com', + 'script_name' => '/baz/index.php', + 'session_name' => 'SESS63543f965940db9e8a79801aa6d52423', + 'base_url' => 'http://www.sub.example.com/baz', + 'cookie_domain' => '.www.sub.example.com', + ), + array( + 'http_host' => 'sub.example.com', + 'script_name' => '/index.php', + 'session_name' => 'SESS005c4a974d8b94af421206f9ef34efeb', + 'base_url' => 'http://sub.example.com', + 'cookie_domain' => '.sub.example.com', + ), + array( + 'http_host' => 'www.example.com', + 'script_name' => '/index.php', + 'session_name' => 'SESS0e9f0e2600e4d8f26827597c5e324261', + 'base_url' => 'http://www.example.com', + 'cookie_domain' => '.www.example.com', + ), + array( + 'http_host' => 'www.example.com', + 'script_name' => '/foo/index.php', + 'session_name' => 'SESS0ddd0afc0bece848c840cdcd7b8ed9c9', + 'base_url' => 'http://www.example.com/foo', + 'cookie_domain' => '.www.example.com', + ), + array( + 'http_host' => 'www.example.com', + 'script_name' => '/bar/index.php', + 'session_name' => 'SESS22f2cd08599536cb4363fcd09e29d264', + 'base_url' => 'http://www.example.com/bar', + 'cookie_domain' => '.www.example.com', + ), + ); + + foreach ($tests as $test) { + $_SERVER['HTTP_HOST'] = $test['http_host']; + $_SERVER['SCRIPT_NAME'] = $test['script_name']; + $cookie_domain = NULL; + $base_url = NULL; + drupal_settings_initialize(); + $this->assertEqual(session_name(), $test['session_name'], 'Correct session_name for ' . $test['http_host'] . $test['script_name']); + $this->assertEqual($base_url, $test['base_url'], 'Correct base_url for ' . $test['http_host'] . $test['script_name']); + $this->assertEqual($cookie_domain, $test['cookie_domain'], 'Correct cookie_domain for ' . $test['http_host'] . $test['script_name']); + } + + } +} diff --git a/modules/simpletest/tests/session.test:Zone.Identifier b/modules/simpletest/tests/session.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/session.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/session_test.info b/modules/simpletest/tests/session_test.info index aaaf84cff3..28b4019d4d 100644 --- a/modules/simpletest/tests/session_test.info +++ b/modules/simpletest/tests/session_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/session_test.info:Zone.Identifier b/modules/simpletest/tests/session_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/session_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/session_test.module:Zone.Identifier b/modules/simpletest/tests/session_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/session_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/system.base.css:Zone.Identifier b/modules/simpletest/tests/system.base.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/system.base.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/system_admin_test.info b/modules/simpletest/tests/system_admin_test.info new file mode 100644 index 0000000000..b3c01d64d0 --- /dev/null +++ b/modules/simpletest/tests/system_admin_test.info @@ -0,0 +1,12 @@ +name = System Admin Test +description = 'Support module for testing system.admin.inc.' +package = Only For Testing +version = VERSION +core = 7.x +hidden = FALSE +configure = config/broken + +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" +project = "drupal" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/system_admin_test.info:Zone.Identifier b/modules/simpletest/tests/system_admin_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/system_admin_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/system_admin_test.module b/modules/simpletest/tests/system_admin_test.module new file mode 100644 index 0000000000..ae61e74951 --- /dev/null +++ b/modules/simpletest/tests/system_admin_test.module @@ -0,0 +1,6 @@ +2.0) -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info:Zone.Identifier b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module:Zone.Identifier b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/system_incompatible_module_version_test.info b/modules/simpletest/tests/system_incompatible_module_version_test.info index 27a7d791ac..827c96c897 100644 --- a/modules/simpletest/tests/system_incompatible_module_version_test.info +++ b/modules/simpletest/tests/system_incompatible_module_version_test.info @@ -5,7 +5,7 @@ version = 1.0 core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/system_incompatible_module_version_test.info:Zone.Identifier b/modules/simpletest/tests/system_incompatible_module_version_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_module_version_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/system_incompatible_module_version_test.module:Zone.Identifier b/modules/simpletest/tests/system_incompatible_module_version_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_module_version_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/system_null_version_test.info b/modules/simpletest/tests/system_null_version_test.info new file mode 100644 index 0000000000..2f5297f9a2 --- /dev/null +++ b/modules/simpletest/tests/system_null_version_test.info @@ -0,0 +1,10 @@ +name = "System null version test" +description = "Support module for testing with a null version." +package = Only For Testing +core = 7.x +hidden = FALSE + +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" +project = "drupal" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/system_null_version_test.info:Zone.Identifier b/modules/simpletest/tests/system_null_version_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/system_null_version_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/system_null_version_test.module b/modules/simpletest/tests/system_null_version_test.module new file mode 100644 index 0000000000..b3d9bbc7f3 --- /dev/null +++ b/modules/simpletest/tests/system_null_version_test.module @@ -0,0 +1 @@ + array('access content'), 'type' => MENU_CALLBACK, ); + $items['system-test/redirect-protocol-relative'] = array( + 'page callback' => 'system_test_redirect_protocol_relative', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); $items['system-test/redirect-noparse'] = array( 'page callback' => 'system_test_redirect_noparse', 'access arguments' => array('access content'), @@ -141,6 +146,19 @@ function system_test_menu() { 'type' => MENU_CALLBACK, ); + $items['system-test/empty-page'] = array( + 'title' => 'Test page cache with empty page.', + 'page callback' => 'system_test_empty_page', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + + $items['system-test/page-cache-headers'] = array( + 'page callback' => 'system_test_page_cache_headers', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + return $items; } @@ -213,6 +231,11 @@ function system_test_redirect_noscheme() { exit; } +function system_test_redirect_protocol_relative() { + header("Location: //example.com/path", TRUE, 301); + exit; +} + function system_test_redirect_noparse() { header("Location: http:///path", TRUE, 301); exit; @@ -223,6 +246,28 @@ function system_test_redirect_invalid_scheme() { exit; } +/** + * Menu callback to test headers stored in the page cache. + */ +function system_test_page_cache_headers() { + if (!isset($_GET['return_headers'])) { + return t('Content to store in the page cache if it is enabled.'); + } + global $base_root; + // Remove the test query param but try to preserve any remaining query string. + $url = parse_url($base_root . request_uri()); + $query_parts = explode('&', $url['query']); + $query_string = implode('&', array_diff($query_parts, array('return_headers=TRUE'))); + $request_uri = $url['path'] . '?' . $query_string; + $cache = cache_get($base_root . $request_uri, 'cache_page'); + // If there are any headers stored in the cache, output them. + if (isset($cache->data['headers'])) { + drupal_add_http_header('Page-Cache-Headers', json_encode($cache->data['headers'])); + return 'Headers from cache_page returned in the Page-Cache-Headers http response header.'; + } + return 'No headers retrieved from cache_page.'; +} + /** * Implements hook_modules_installed(). */ @@ -532,6 +577,12 @@ function system_test_drupal_get_filename_with_schema_rebuild() { return ''; } +/** + * Page callback to output an empty page. + */ +function system_test_empty_page() { +} + /** * Implements hook_watchdog(). */ @@ -566,6 +617,6 @@ function system_test_module_implements_alter(&$implementations, $hook) { $group = $implementations['system_test']; unset($implementations['system_test']); $count = count($implementations); - $implementations = array_merge(array_slice($implementations, 0, $count / 2, TRUE), array('system_test' => $group), array_slice($implementations, $count / 2, NULL, TRUE)); + $implementations = array_merge(array_slice($implementations, 0, (int) ($count / 2), TRUE), array('system_test' => $group), array_slice($implementations, (int) ($count / 2), NULL, TRUE)); } } diff --git a/modules/simpletest/tests/system_test.module:Zone.Identifier b/modules/simpletest/tests/system_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/system_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/tablesort.test:Zone.Identifier b/modules/simpletest/tests/tablesort.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/tablesort.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/taxonomy_nodes_test.info b/modules/simpletest/tests/taxonomy_nodes_test.info new file mode 100644 index 0000000000..a23ae1a4a5 --- /dev/null +++ b/modules/simpletest/tests/taxonomy_nodes_test.info @@ -0,0 +1,11 @@ +name = "Taxonomy module node list tests" +description = "Support module for taxonomy node list related testing." +package = Testing +version = VERSION +core = 7.x +hidden = TRUE + +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" +project = "drupal" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/taxonomy_nodes_test.info:Zone.Identifier b/modules/simpletest/tests/taxonomy_nodes_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/taxonomy_nodes_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/taxonomy_nodes_test.module b/modules/simpletest/tests/taxonomy_nodes_test.module new file mode 100644 index 0000000000..3d5035d271 --- /dev/null +++ b/modules/simpletest/tests/taxonomy_nodes_test.module @@ -0,0 +1,26 @@ +getTables() as $alias => $table) { + if ($table['table'] == 'taxonomy_index') { + $taxonomy_index = TRUE; + } + } + + if ($taxonomy_index) { + // Verify that additional data can be added to the default + // taxonomy_select_nodes() query by altering it. + $query->leftJoin('taxonomy_term_data', 'ttd', 'ttd.tid = t.tid'); + } + } +} diff --git a/modules/simpletest/tests/taxonomy_nodes_test.module:Zone.Identifier b/modules/simpletest/tests/taxonomy_nodes_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/taxonomy_nodes_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/taxonomy_test.info b/modules/simpletest/tests/taxonomy_test.info index 9d7234c08e..6a9e4e6f5d 100644 --- a/modules/simpletest/tests/taxonomy_test.info +++ b/modules/simpletest/tests/taxonomy_test.info @@ -6,7 +6,7 @@ core = 7.x hidden = TRUE dependencies[] = taxonomy -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/taxonomy_test.info:Zone.Identifier b/modules/simpletest/tests/taxonomy_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/taxonomy_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/taxonomy_test.install:Zone.Identifier b/modules/simpletest/tests/taxonomy_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/taxonomy_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/taxonomy_test.module b/modules/simpletest/tests/taxonomy_test.module index f414438013..16b571ecdc 100644 --- a/modules/simpletest/tests/taxonomy_test.module +++ b/modules/simpletest/tests/taxonomy_test.module @@ -139,3 +139,14 @@ function taxonomy_test_query_taxonomy_term_access_alter(QueryAlterableInterface variable_set(__FUNCTION__, ++$value); } } + +/** + * Test controller class for taxonomy terms. + * + * The main purpose is to make cacheGet() method available for testing. + */ +class TestTaxonomyTermController extends TaxonomyTermController { + public function loadFromCache($ids, $conditions = array()) { + return parent::cacheGet($ids, $conditions); + } +} diff --git a/modules/simpletest/tests/taxonomy_test.module:Zone.Identifier b/modules/simpletest/tests/taxonomy_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/taxonomy_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/theme.test:Zone.Identifier b/modules/simpletest/tests/theme.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/theme.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/theme_test.inc:Zone.Identifier b/modules/simpletest/tests/theme_test.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/theme_test.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/theme_test.info b/modules/simpletest/tests/theme_test.info index bd2eb34af7..b3ea77cd55 100644 --- a/modules/simpletest/tests/theme_test.info +++ b/modules/simpletest/tests/theme_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/theme_test.info:Zone.Identifier b/modules/simpletest/tests/theme_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/theme_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/theme_test.module:Zone.Identifier b/modules/simpletest/tests/theme_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/theme_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/theme_test.template_test.tpl.php:Zone.Identifier b/modules/simpletest/tests/theme_test.template_test.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/theme_test.template_test.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/themes/engines/nyan_cat/nyan_cat.engine:Zone.Identifier b/modules/simpletest/tests/themes/engines/nyan_cat/nyan_cat.engine:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/themes/engines/nyan_cat/nyan_cat.engine:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info index c535122ec4..26fc997547 100644 --- a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info +++ b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info @@ -6,7 +6,7 @@ hidden = TRUE settings[basetheme_only] = base theme value settings[subtheme_override] = base theme value -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info:Zone.Identifier b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info index 4cb573a2cd..1a629be1c6 100644 --- a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info +++ b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info @@ -6,7 +6,7 @@ hidden = TRUE settings[subtheme_override] = subtheme value -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info:Zone.Identifier b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/themes/test_theme/template.php:Zone.Identifier b/modules/simpletest/tests/themes/test_theme/template.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/themes/test_theme/template.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/themes/test_theme/templates/node--1.tpl.php:Zone.Identifier b/modules/simpletest/tests/themes/test_theme/templates/node--1.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/themes/test_theme/templates/node--1.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/themes/test_theme/test_theme.info b/modules/simpletest/tests/themes/test_theme/test_theme.info index dfe3943042..bfd1ee6e32 100644 --- a/modules/simpletest/tests/themes/test_theme/test_theme.info +++ b/modules/simpletest/tests/themes/test_theme/test_theme.info @@ -17,7 +17,7 @@ stylesheets[all][] = system.base.css settings[theme_test_setting] = default value -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/themes/test_theme/test_theme.info:Zone.Identifier b/modules/simpletest/tests/themes/test_theme/test_theme.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/themes/test_theme/test_theme.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/themes/test_theme/theme-settings.php:Zone.Identifier b/modules/simpletest/tests/themes/test_theme/theme-settings.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/themes/test_theme/theme-settings.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/themes/test_theme_nyan_cat/templates/theme_test_template_test.nyan-cat.html:Zone.Identifier b/modules/simpletest/tests/themes/test_theme_nyan_cat/templates/theme_test_template_test.nyan-cat.html:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/themes/test_theme_nyan_cat/templates/theme_test_template_test.nyan-cat.html:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info b/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info index eb57839a15..4f121ee1d0 100644 --- a/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info +++ b/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info @@ -4,7 +4,7 @@ core = 7.x hidden = TRUE engine = nyan_cat -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info:Zone.Identifier b/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/unicode.test:Zone.Identifier b/modules/simpletest/tests/unicode.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/unicode.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update.test:Zone.Identifier b/modules/simpletest/tests/update.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_script_test.info b/modules/simpletest/tests/update_script_test.info index 279f899541..10b6596128 100644 --- a/modules/simpletest/tests/update_script_test.info +++ b/modules/simpletest/tests/update_script_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/update_script_test.info:Zone.Identifier b/modules/simpletest/tests/update_script_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_script_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_script_test.install:Zone.Identifier b/modules/simpletest/tests/update_script_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_script_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_script_test.module:Zone.Identifier b/modules/simpletest/tests/update_script_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_script_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_test_1.info b/modules/simpletest/tests/update_test_1.info index afb06f08b5..4c38b10f77 100644 --- a/modules/simpletest/tests/update_test_1.info +++ b/modules/simpletest/tests/update_test_1.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/update_test_1.info:Zone.Identifier b/modules/simpletest/tests/update_test_1.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_test_1.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_test_1.install:Zone.Identifier b/modules/simpletest/tests/update_test_1.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_test_1.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_test_1.module:Zone.Identifier b/modules/simpletest/tests/update_test_1.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_test_1.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_test_2.info b/modules/simpletest/tests/update_test_2.info index afb06f08b5..4c38b10f77 100644 --- a/modules/simpletest/tests/update_test_2.info +++ b/modules/simpletest/tests/update_test_2.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/update_test_2.info:Zone.Identifier b/modules/simpletest/tests/update_test_2.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_test_2.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_test_2.install:Zone.Identifier b/modules/simpletest/tests/update_test_2.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_test_2.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_test_2.module:Zone.Identifier b/modules/simpletest/tests/update_test_2.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_test_2.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_test_3.info b/modules/simpletest/tests/update_test_3.info index afb06f08b5..4c38b10f77 100644 --- a/modules/simpletest/tests/update_test_3.info +++ b/modules/simpletest/tests/update_test_3.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/update_test_3.info:Zone.Identifier b/modules/simpletest/tests/update_test_3.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_test_3.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_test_3.install:Zone.Identifier b/modules/simpletest/tests/update_test_3.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_test_3.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/update_test_3.module:Zone.Identifier b/modules/simpletest/tests/update_test_3.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/update_test_3.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.bare.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.bare.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.bare.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.comments.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.comments.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.comments.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.duplicate-permission.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.duplicate-permission.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.duplicate-permission.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.filled.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.filled.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.filled.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.forum.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.forum.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.forum.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.locale.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.locale.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.locale.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.menu.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.menu.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.menu.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.node_type_broken.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.node_type_broken.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.node_type_broken.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.translatable.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.translatable.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.translatable.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.trigger.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.trigger.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.trigger.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.upload.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.upload.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.upload.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.user-no-password-token.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.user-no-password-token.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.user-no-password-token.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-6.user-password-token.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-6.user-password-token.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.user-password-token.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-7.aggregator.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-7.aggregator.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.aggregator.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-7.bare.minimal.database.php.gz:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-7.bare.minimal.database.php.gz:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.bare.minimal.database.php.gz:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-7.bare.standard_all.database.php.gz:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-7.bare.standard_all.database.php.gz:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.bare.standard_all.database.php.gz:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-7.field.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-7.field.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.field.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-7.filled.minimal.database.php.gz:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-7.filled.minimal.database.php.gz:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.filled.minimal.database.php.gz:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gz:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gz:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gz:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/drupal-7.trigger.database.php:Zone.Identifier b/modules/simpletest/tests/upgrade/drupal-7.trigger.database.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.trigger.database.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/update.aggregator.test b/modules/simpletest/tests/upgrade/update.aggregator.test index d4135774e7..9f5bcaa254 100644 --- a/modules/simpletest/tests/upgrade/update.aggregator.test +++ b/modules/simpletest/tests/upgrade/update.aggregator.test @@ -36,6 +36,7 @@ class AggregatorUpdatePathTestCase extends UpdatePathTestCase { $query ->fields('af', array('url', 'link')) ->fields('ai', array('link', 'guid')); + $query->orderBy('ai.iid'); $pre_update_data = $query->execute()->fetchAll(); $this->assertTrue($this->performUpgrade(), 'The update was completed successfully.'); diff --git a/modules/simpletest/tests/upgrade/update.aggregator.test:Zone.Identifier b/modules/simpletest/tests/upgrade/update.aggregator.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/update.aggregator.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/update.field.test:Zone.Identifier b/modules/simpletest/tests/upgrade/update.field.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/update.field.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/update.trigger.test:Zone.Identifier b/modules/simpletest/tests/upgrade/update.trigger.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/update.trigger.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/update.user.test:Zone.Identifier b/modules/simpletest/tests/upgrade/update.user.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/update.user.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.comment.test b/modules/simpletest/tests/upgrade/upgrade.comment.test index 40d893a845..84551c3c0e 100644 --- a/modules/simpletest/tests/upgrade/upgrade.comment.test +++ b/modules/simpletest/tests/upgrade/upgrade.comment.test @@ -27,6 +27,9 @@ class CommentUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ public function testCommentUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); } } diff --git a/modules/simpletest/tests/upgrade/upgrade.comment.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.comment.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.comment.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.filter.test b/modules/simpletest/tests/upgrade/upgrade.filter.test index 584f4d9461..6d805122f2 100644 --- a/modules/simpletest/tests/upgrade/upgrade.filter.test +++ b/modules/simpletest/tests/upgrade/upgrade.filter.test @@ -28,6 +28,9 @@ class FilterFormatUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ function testFilterFormatUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); $format = filter_format_load('1'); diff --git a/modules/simpletest/tests/upgrade/upgrade.filter.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.filter.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.filter.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.forum.test b/modules/simpletest/tests/upgrade/upgrade.forum.test index b0bbd4ed78..7551445368 100644 --- a/modules/simpletest/tests/upgrade/upgrade.forum.test +++ b/modules/simpletest/tests/upgrade/upgrade.forum.test @@ -27,6 +27,9 @@ class ForumUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade (no negotiation). */ public function testForumUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // Work around http://drupal.org/node/931512 diff --git a/modules/simpletest/tests/upgrade/upgrade.forum.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.forum.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.forum.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.locale.test b/modules/simpletest/tests/upgrade/upgrade.locale.test index f7b0038d64..a13499d015 100644 --- a/modules/simpletest/tests/upgrade/upgrade.locale.test +++ b/modules/simpletest/tests/upgrade/upgrade.locale.test @@ -27,6 +27,9 @@ class LocaleUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade (no negotiation). */ public function testLocaleUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // The home page should be in French. @@ -43,6 +46,9 @@ class LocaleUpgradePathTestCase extends UpgradePathTestCase { * Test an upgrade with path-based negotiation. */ public function testLocaleUpgradePathDefault() { + if ($this->skipUpgradeTest) { + return; + } // LANGUAGE_NEGOTIATION_PATH_DEFAULT. $this->variable_set('language_negotiation', 1); @@ -66,6 +72,9 @@ class LocaleUpgradePathTestCase extends UpgradePathTestCase { * Test an upgrade with path-based (with fallback) negotiation. */ public function testLocaleUpgradePathFallback() { + if ($this->skipUpgradeTest) { + return; + } // LANGUAGE_NEGOTIATION_PATH. $this->variable_set('language_negotiation', 2); @@ -92,6 +101,9 @@ class LocaleUpgradePathTestCase extends UpgradePathTestCase { * Test an upgrade with domain-based negotiation. */ public function testLocaleUpgradeDomain() { + if ($this->skipUpgradeTest) { + return; + } // LANGUAGE_NEGOTIATION_DOMAIN. $this->variable_set('language_negotiation', 3); diff --git a/modules/simpletest/tests/upgrade/upgrade.locale.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.locale.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.locale.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.menu.test b/modules/simpletest/tests/upgrade/upgrade.menu.test index d9ae6c1b77..a9dfd4fa4b 100644 --- a/modules/simpletest/tests/upgrade/upgrade.menu.test +++ b/modules/simpletest/tests/upgrade/upgrade.menu.test @@ -27,6 +27,9 @@ class MenuUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ public function testMenuUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // Test the migration of "Default menu for content" setting to individual diff --git a/modules/simpletest/tests/upgrade/upgrade.menu.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.menu.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.menu.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.node.test b/modules/simpletest/tests/upgrade/upgrade.node.test index 4ac14c5745..7986bab69c 100644 --- a/modules/simpletest/tests/upgrade/upgrade.node.test +++ b/modules/simpletest/tests/upgrade/upgrade.node.test @@ -26,6 +26,9 @@ class NodeBodyUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ public function testNodeBodyUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); $instance = field_info_instance('node', 'body', 'story'); @@ -77,6 +80,9 @@ class DisabledNodeTypeTestCase extends UpgradePathTestCase { * Tests a successful upgrade. */ public function testDisabledNodeTypeUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); $this->assertTrue(field_info_instance('comment', 'comment_body', 'comment_node_broken'), 'Comment body field instance was created for comments attached to the disabled broken node type'); } @@ -114,6 +120,9 @@ class PollUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ public function testPollUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // Check modules page for poll diff --git a/modules/simpletest/tests/upgrade/upgrade.node.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.node.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.node.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.poll.test b/modules/simpletest/tests/upgrade/upgrade.poll.test index ac4ea4365d..85c4ffd757 100644 --- a/modules/simpletest/tests/upgrade/upgrade.poll.test +++ b/modules/simpletest/tests/upgrade/upgrade.poll.test @@ -32,6 +32,9 @@ class PollUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ public function testPollUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // Check modules page for poll diff --git a/modules/simpletest/tests/upgrade/upgrade.poll.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.poll.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.poll.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.taxonomy.test b/modules/simpletest/tests/upgrade/upgrade.taxonomy.test index 51402ed760..bde2691fbe 100644 --- a/modules/simpletest/tests/upgrade/upgrade.taxonomy.test +++ b/modules/simpletest/tests/upgrade/upgrade.taxonomy.test @@ -46,6 +46,9 @@ class UpgradePathTaxonomyTestCase extends UpgradePathTestCase { * Basic tests for the taxonomy upgrade. */ public function testTaxonomyUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // Visit the front page to assert for PHP warning and errors. diff --git a/modules/simpletest/tests/upgrade/upgrade.taxonomy.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.taxonomy.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.taxonomy.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.test b/modules/simpletest/tests/upgrade/upgrade.test index 784a091787..68eec60cef 100644 --- a/modules/simpletest/tests/upgrade/upgrade.test +++ b/modules/simpletest/tests/upgrade/upgrade.test @@ -37,6 +37,11 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { */ var $pendingUpdates = TRUE; + /** + * Flag to indicate whether to skip upgrade tests. + */ + var $skipUpgradeTest = FALSE; + /** * Constructs an UpgradePathTestCase object. * @@ -46,6 +51,8 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { */ function __construct($test_id = NULL) { parent::__construct($test_id); + $connection_info = Database::getConnectionInfo(); + $this->skipUpgradeTest = (bool) ($connection_info['default']['driver'] == 'pgsql'); $this->zlibInstalled = function_exists('gzopen'); } @@ -355,6 +362,9 @@ class BasicUpgradePath extends UpgradePathTestCase { * Test a failed upgrade, and verify that the failure is reported. */ public function testFailedUpgrade() { + if ($this->skipUpgradeTest) { + return; + } // Destroy a table that the upgrade process needs. db_drop_table('access'); // Assert that the upgrade fails. @@ -365,6 +375,9 @@ class BasicUpgradePath extends UpgradePathTestCase { * Test a successful upgrade. */ public function testBasicUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // Hit the frontpage. @@ -579,7 +592,24 @@ class BasicMinimalUpdatePath extends UpdatePathTestCase { $this->assertText(t('Custom date format added.')); // Verify that the unique key on {date_formats}.format still exists. - $this->assertTrue(db_index_exists('date_formats', 'formats'), 'Unique key on {date_formats} exists'); + try { + // The PostgreSQL driver appends suffixes to keys/indexes according to + // their types. A unique key is a key (not an index), so it has a _key + // suffix. It is not possible to call db_index_exists() as this function + // will check the index name with _idx suffix, so it will never succeed on + // PostgreSQL. An attempt to create a new unique key when it exists should + // fail and the thrown exception will confirm that the unique key exists. + // MySQL and SQLite are not affected by this change, as they do not append + // suffixes to keys/indexes names. + db_add_unique_key('date_formats', 'formats', array('formats')); + // This is executed if no exception has been thrown and the unique key + // did not already exist. + $this->fail('Unique key on {date_formats} does not exist'); + } + catch (DatabaseSchemaObjectExistsException $e) { + // Exception confirms that the unique key already existed. + $this->pass('Unique key on {date_formats} exists'); + } } } diff --git a/modules/simpletest/tests/upgrade/upgrade.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.translatable.test b/modules/simpletest/tests/upgrade/upgrade.translatable.test index 6fefb0ff07..c4f7161a67 100644 --- a/modules/simpletest/tests/upgrade/upgrade.translatable.test +++ b/modules/simpletest/tests/upgrade/upgrade.translatable.test @@ -28,6 +28,9 @@ class TranslatableUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade (no negotiation). */ public function testTranslatableUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); // The D6 database contains the english node "First translatable page" with diff --git a/modules/simpletest/tests/upgrade/upgrade.translatable.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.translatable.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.translatable.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.trigger.test b/modules/simpletest/tests/upgrade/upgrade.trigger.test index ef2394142d..79cb63e3b9 100644 --- a/modules/simpletest/tests/upgrade/upgrade.trigger.test +++ b/modules/simpletest/tests/upgrade/upgrade.trigger.test @@ -29,6 +29,9 @@ class UpgradePathTriggerTestCase extends UpgradePathTestCase { * Basic tests for the trigger upgrade. */ public function testTaxonomyUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); $this->drupalGet('admin/structure/trigger/node'); $this->assertRaw(''. t('Make post sticky') .''); diff --git a/modules/simpletest/tests/upgrade/upgrade.trigger.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.trigger.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.trigger.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.upload.test b/modules/simpletest/tests/upgrade/upgrade.upload.test index dfa94a008b..6e0668cc3b 100644 --- a/modules/simpletest/tests/upgrade/upgrade.upload.test +++ b/modules/simpletest/tests/upgrade/upgrade.upload.test @@ -29,6 +29,9 @@ class UploadUpgradePathTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ public function testUploadUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); $query = new EntityFieldQuery(); $query->entityCondition('entity_type', 'node'); diff --git a/modules/simpletest/tests/upgrade/upgrade.upload.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.upload.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.upload.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/upgrade/upgrade.user.test b/modules/simpletest/tests/upgrade/upgrade.user.test index d33234e431..605a43dcfb 100644 --- a/modules/simpletest/tests/upgrade/upgrade.user.test +++ b/modules/simpletest/tests/upgrade/upgrade.user.test @@ -24,6 +24,9 @@ class UserUpgradePathPasswordTokenTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ public function testUserUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); $this->assertEqual(variable_get('user_mail_register_no_approval_required_body'), ', [user:name], [site:name], [site:url], [site:url-brief], [user:mail], [date:medium], [site:login-url], [user:edit-url], [user:one-time-login-url].', 'Existing email templates have been modified (password token involved).'); // Check that a non-md5 hash was untouched. @@ -57,6 +60,9 @@ class UserUpgradePathNoPasswordTokenTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ public function testUserUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); $this->assertEqual(variable_get('user_mail_register_no_approval_required_body'), '[user:name], [site:name], [site:url], [site:url-brief], [user:mail], [date:medium], [site:login-url], [user:edit-url], [user:one-time-login-url].', 'Existing email templates have been modified (password token not involved).'); } @@ -87,6 +93,9 @@ class UserUpgradePathDuplicatedPermissionTestCase extends UpgradePathTestCase { * Test a successful upgrade. */ public function testUserUpgrade() { + if ($this->skipUpgradeTest) { + return; + } $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.'); } } diff --git a/modules/simpletest/tests/upgrade/upgrade.user.test:Zone.Identifier b/modules/simpletest/tests/upgrade/upgrade.user.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/upgrade/upgrade.user.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/url_alter_test.info b/modules/simpletest/tests/url_alter_test.info index dfdd63b707..b827b85598 100644 --- a/modules/simpletest/tests/url_alter_test.info +++ b/modules/simpletest/tests/url_alter_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/url_alter_test.info:Zone.Identifier b/modules/simpletest/tests/url_alter_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/url_alter_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/url_alter_test.install:Zone.Identifier b/modules/simpletest/tests/url_alter_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/url_alter_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/url_alter_test.module b/modules/simpletest/tests/url_alter_test.module index 9287ff5230..bdc3167a81 100644 --- a/modules/simpletest/tests/url_alter_test.module +++ b/modules/simpletest/tests/url_alter_test.module @@ -57,7 +57,7 @@ function url_alter_test_url_inbound_alter(&$path, $original_path, $path_language */ function url_alter_test_url_outbound_alter(&$path, &$options, $original_path) { // Rewrite user/uid to user/username. - if (preg_match('!^user/([0-9]+)(/.*)?!', $path, $matches)) { + if (preg_match('!^user/([0-9]+)(/.*)?!', (string) $path, $matches)) { if ($account = user_load($matches[1])) { $matches += array(2 => ''); $path = 'user/' . $account->name . $matches[2]; @@ -65,7 +65,7 @@ function url_alter_test_url_outbound_alter(&$path, &$options, $original_path) { } // Rewrite forum/ to community/. - if ($path == 'forum' || strpos($path, 'forum/') === 0) { + if ($path == 'forum' || strpos((string) $path, 'forum/') === 0) { $path = 'community' . substr($path, 5); } } diff --git a/modules/simpletest/tests/url_alter_test.module:Zone.Identifier b/modules/simpletest/tests/url_alter_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/url_alter_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/xmlrpc.test:Zone.Identifier b/modules/simpletest/tests/xmlrpc.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/xmlrpc.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/xmlrpc_test.info b/modules/simpletest/tests/xmlrpc_test.info index b8201c78bf..4408a46c0b 100644 --- a/modules/simpletest/tests/xmlrpc_test.info +++ b/modules/simpletest/tests/xmlrpc_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/simpletest/tests/xmlrpc_test.info:Zone.Identifier b/modules/simpletest/tests/xmlrpc_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/xmlrpc_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/simpletest/tests/xmlrpc_test.module:Zone.Identifier b/modules/simpletest/tests/xmlrpc_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/simpletest/tests/xmlrpc_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/statistics/statistics.admin.inc:Zone.Identifier b/modules/statistics/statistics.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/statistics/statistics.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/statistics/statistics.info b/modules/statistics/statistics.info index 9e6e78dc5c..d14bd216ff 100644 --- a/modules/statistics/statistics.info +++ b/modules/statistics/statistics.info @@ -6,7 +6,7 @@ core = 7.x files[] = statistics.test configure = admin/config/system/statistics -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/statistics/statistics.info:Zone.Identifier b/modules/statistics/statistics.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/statistics/statistics.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/statistics/statistics.install:Zone.Identifier b/modules/statistics/statistics.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/statistics/statistics.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/statistics/statistics.js:Zone.Identifier b/modules/statistics/statistics.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/statistics/statistics.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/statistics/statistics.module:Zone.Identifier b/modules/statistics/statistics.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/statistics/statistics.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/statistics/statistics.pages.inc:Zone.Identifier b/modules/statistics/statistics.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/statistics/statistics.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/statistics/statistics.php:Zone.Identifier b/modules/statistics/statistics.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/statistics/statistics.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/statistics/statistics.test:Zone.Identifier b/modules/statistics/statistics.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/statistics/statistics.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/statistics/statistics.tokens.inc:Zone.Identifier b/modules/statistics/statistics.tokens.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/statistics/statistics.tokens.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/syslog/syslog.info b/modules/syslog/syslog.info index e60284a523..d240d2327a 100644 --- a/modules/syslog/syslog.info +++ b/modules/syslog/syslog.info @@ -6,7 +6,7 @@ core = 7.x files[] = syslog.test configure = admin/config/development/logging -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/syslog/syslog.info:Zone.Identifier b/modules/syslog/syslog.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/syslog/syslog.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/syslog/syslog.install:Zone.Identifier b/modules/syslog/syslog.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/syslog/syslog.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/syslog/syslog.module b/modules/syslog/syslog.module index af3eb0a0f0..32193a18dd 100644 --- a/modules/syslog/syslog.module +++ b/modules/syslog/syslog.module @@ -111,8 +111,8 @@ function syslog_watchdog(array $log_entry) { '!request_uri' => $log_entry['request_uri'], '!referer' => $log_entry['referer'], '!uid' => $log_entry['uid'], - '!link' => strip_tags($log_entry['link']), - '!message' => strip_tags(!isset($log_entry['variables']) ? $log_entry['message'] : strtr($log_entry['message'], $log_entry['variables'])), + '!link' => strip_tags((string) $log_entry['link']), + '!message' => strip_tags((string) (!isset($log_entry['variables']) ? $log_entry['message'] : strtr($log_entry['message'], $log_entry['variables']))), )); syslog($log_entry['severity'], $message); diff --git a/modules/syslog/syslog.module:Zone.Identifier b/modules/syslog/syslog.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/syslog/syslog.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/syslog/syslog.test:Zone.Identifier b/modules/syslog/syslog.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/syslog/syslog.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/form.api.php:Zone.Identifier b/modules/system/form.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/form.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/html.tpl.php:Zone.Identifier b/modules/system/html.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/html.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/image.gd.inc b/modules/system/image.gd.inc index 3d0797e424..bcc02cf06b 100644 --- a/modules/system/image.gd.inc +++ b/modules/system/image.gd.inc @@ -204,9 +204,11 @@ function image_gd_rotate(stdClass $image, $degrees, $background = NULL) { * @see image_crop() */ function image_gd_crop(stdClass $image, $x, $y, $width, $height) { + $width = (int) $width; + $height = (int) $height; $res = image_gd_create_tmp($image, $width, $height); - if (!imagecopyresampled($res, $image->resource, 0, 0, $x, $y, $width, $height, $width, $height)) { + if (!imagecopyresampled($res, $image->resource, 0, 0, (int) $x, (int) $y, $width, $height, $width, $height)) { return FALSE; } diff --git a/modules/system/image.gd.inc:Zone.Identifier b/modules/system/image.gd.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/image.gd.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/language.api.php:Zone.Identifier b/modules/system/language.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/language.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/maintenance-page.tpl.php:Zone.Identifier b/modules/system/maintenance-page.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/maintenance-page.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/page.tpl.php:Zone.Identifier b/modules/system/page.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/page.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/region.tpl.php:Zone.Identifier b/modules/system/region.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/region.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.admin-rtl.css:Zone.Identifier b/modules/system/system.admin-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.admin-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.admin.css:Zone.Identifier b/modules/system/system.admin.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.admin.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc index b7e6fc9e70..bf3abb67d6 100644 --- a/modules/system/system.admin.inc +++ b/modules/system/system.admin.inc @@ -839,7 +839,7 @@ function system_modules($form, $form_state = array()) { elseif (isset($visible_files[$requires])) { $requires_name = $files[$requires]->info['name']; // Disable this module if it is incompatible with the dependency's version. - if ($incompatible_version = drupal_check_incompatibility($v, str_replace(DRUPAL_CORE_COMPATIBILITY . '-', '', $files[$requires]->info['version']))) { + if ($incompatible_version = drupal_check_incompatibility($v, str_replace(DRUPAL_CORE_COMPATIBILITY . '-', '', (string) $files[$requires]->info['version']))) { $extra['requires'][$requires] = t('@module (incompatible with version @version)', array( '@module' => $requires_name . $incompatible_version, '@version' => $files[$requires]->info['version'], @@ -886,7 +886,13 @@ function system_modules($form, $form_state = array()) { // one. if ($module->status && isset($module->info['configure'])) { $configure_link = menu_get_item($module->info['configure']); - if ($configure_link['access']) { + if ($configure_link === FALSE) { + watchdog('system', 'Module %module specifies an invalid path for configuration: %configure', array( + '%module' => $module->info['name'], + '%configure' => $module->info['configure'], + )); + } + else if ($configure_link['access']) { $extra['links']['configure'] = array( '#type' => 'link', '#title' => t('Configure'), @@ -929,6 +935,8 @@ function system_modules($form, $form_state = array()) { ), // Ensure that the "Core" package fieldset comes first. '#weight' => $package == 'Core' ? -10 : NULL, + // Hide this package unless we're running a test. + '#access' => !($package == 'Only For Testing' && !drupal_valid_test_ua()), ); } @@ -2358,6 +2366,10 @@ function system_status($check = FALSE) { * Menu callback: run cron manually. */ function system_run_cron() { + if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'run-cron')) { + return MENU_ACCESS_DENIED; + } + // Run cron manually if (drupal_cron_run()) { drupal_set_message(t('Cron ran successfully.')); @@ -2386,6 +2398,7 @@ function system_batch_page() { if ($output === FALSE) { drupal_access_denied(); + drupal_exit(); } elseif (isset($output)) { // Force a page without blocks or messages to diff --git a/modules/system/system.admin.inc:Zone.Identifier b/modules/system/system.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.api.php b/modules/system/system.api.php index d5de102405..3a14738906 100644 --- a/modules/system/system.api.php +++ b/modules/system/system.api.php @@ -3175,7 +3175,7 @@ function hook_requirements($phase) { ); } - $requirements['cron']['description'] .= ' ' . $t('You can run cron manually.', array('@cron' => url('admin/reports/status/run-cron'))); + $requirements['cron']['description'] .= ' ' . $t('You can run cron manually.', array('@cron' => url('admin/reports/status/run-cron', array('query' => array('token' => drupal_get_token('run-cron')))))); $requirements['cron']['title'] = $t('Cron maintenance tasks'); } diff --git a/modules/system/system.api.php:Zone.Identifier b/modules/system/system.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.archiver.inc:Zone.Identifier b/modules/system/system.archiver.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.archiver.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.base-rtl.css:Zone.Identifier b/modules/system/system.base-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.base-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.base.css:Zone.Identifier b/modules/system/system.base.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.base.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.cron.js:Zone.Identifier b/modules/system/system.cron.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.cron.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.info b/modules/system/system.info index 5f8b0388a6..b904ea725a 100644 --- a/modules/system/system.info +++ b/modules/system/system.info @@ -12,7 +12,7 @@ files[] = system.test required = TRUE configure = admin/config/system -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/system/system.info:Zone.Identifier b/modules/system/system.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.install b/modules/system/system.install index 01b0af474d..147f61c3ae 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -236,20 +236,36 @@ function system_requirements($phase) { // Test settings.php file writability if ($phase == 'runtime') { - $conf_dir = drupal_verify_install_file(conf_path(), FILE_NOT_WRITABLE, 'dir'); - $conf_file = drupal_verify_install_file(conf_path() . '/settings.php', FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE); - if (!$conf_dir || !$conf_file) { + $conf_errors = array(); + // Allow system administrators to ignore permissions hardening for the site + // directory. This allows additional files in the site directory to be + // updated when they are managed in a version control system. + $skip_permissions_hardening = variable_get('skip_permissions_hardening', FALSE); + + if ($skip_permissions_hardening) { + $error_value = t('Protection disabled'); + // If permissions hardening is disabled, then only show a warning for a + // writable file, as a reminder, rather than an error. + $file_protection_severity = REQUIREMENT_WARNING; + } + else { + $error_value = t('Not protected'); + // In normal operation, writable files or directories are an error. + $file_protection_severity = REQUIREMENT_ERROR; + if (!drupal_verify_install_file(conf_path(), FILE_NOT_WRITABLE, 'dir')) { + $conf_errors[] = $t('The directory %file is not protected from modifications and poses a security risk. You must change the directory\'s permissions to be non-writable. ', array('%file' => conf_path())); + } + } + if (!drupal_verify_install_file(conf_path() . '/settings.php', FILE_EXIST | FILE_READABLE | FILE_NOT_WRITABLE, 'file', !$skip_permissions_hardening)) { + $conf_errors[] = $t('The file %file is not protected from modifications and poses a security risk. You must change the file\'s permissions to be non-writable.', array('%file' => conf_path() . '/settings.php')); + } + + if (!empty($conf_errors)) { $requirements['settings.php'] = array( - 'value' => $t('Not protected'), - 'severity' => REQUIREMENT_ERROR, - 'description' => '', + 'value' => $error_value, + 'severity' => $file_protection_severity, + 'description' => implode('
', $conf_errors), ); - if (!$conf_dir) { - $requirements['settings.php']['description'] .= $t('The directory %file is not protected from modifications and poses a security risk. You must change the directory\'s permissions to be non-writable. ', array('%file' => conf_path())); - } - if (!$conf_file) { - $requirements['settings.php']['description'] .= $t('The file %file is not protected from modifications and poses a security risk. You must change the file\'s permissions to be non-writable.', array('%file' => conf_path() . '/settings.php')); - } } else { $requirements['settings.php'] = array( @@ -323,7 +339,7 @@ function system_requirements($phase) { $description = $t('Cron has not run recently.') . ' ' . $help; } - $description .= ' ' . $t('You can run cron manually.', array('@cron' => url('admin/reports/status/run-cron'))); + $description .= ' ' . $t('You can run cron manually.', array('@cron' => url('admin/reports/status/run-cron', array('query' => array('token' => drupal_get_token('run-cron')))))); $description .= '
' . $t('To run cron from outside the site, go to !cron', array('!cron' => url($base_url . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => variable_get('cron_key', 'drupal')))))); $requirements['cron'] = array( @@ -473,7 +489,7 @@ function system_requirements($phase) { // Check for an incompatible version. $required_file = $files[$required_module]; $required_name = $required_file->info['name']; - $version = str_replace(DRUPAL_CORE_COMPATIBILITY . '-', '', $required_file->info['version']); + $version = str_replace(DRUPAL_CORE_COMPATIBILITY . '-', '', (string) $required_file->info['version']); $compatibility = drupal_check_incompatibility($requirement, $version); if ($compatibility) { $compatibility = rtrim(substr($compatibility, 2), ')'); @@ -522,7 +538,7 @@ function system_requirements($phase) { // Warning for httpoxy on IIS with affected PHP versions. // @see https://www.drupal.org/node/2783079 - if (strpos($software, 'Microsoft-IIS') !== FALSE && (version_compare(PHP_VERSION, '5.5.38', '<') + if (strpos((string) $software, 'Microsoft-IIS') !== FALSE && (version_compare(PHP_VERSION, '5.5.38', '<') || (version_compare(PHP_VERSION, '5.6.0', '>=') && version_compare(PHP_VERSION, '5.6.24', '<')) || (version_compare(PHP_VERSION, '7.0.0', '>=') && version_compare(PHP_VERSION, '7.0.9', '<')) )) { diff --git a/modules/system/system.install:Zone.Identifier b/modules/system/system.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.js:Zone.Identifier b/modules/system/system.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.mail.inc:Zone.Identifier b/modules/system/system.mail.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.mail.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.maintenance.css:Zone.Identifier b/modules/system/system.maintenance.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.maintenance.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.menus-rtl.css:Zone.Identifier b/modules/system/system.menus-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.menus-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.menus.css:Zone.Identifier b/modules/system/system.menus.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.menus.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.messages-rtl.css:Zone.Identifier b/modules/system/system.messages-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.messages-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.messages.css:Zone.Identifier b/modules/system/system.messages.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.messages.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.module b/modules/system/system.module index 02785ef575..ba5da73f7a 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -1328,6 +1328,7 @@ function system_library() { 'version' => '1.8.7', 'js' => array( 'misc/ui/jquery.ui.datepicker.min.js' => array(), + 'misc/ui/jquery.ui.datepicker-1.13.0-backport.js' => array(), ), 'css' => array( 'misc/ui/jquery.ui.datepicker.css' => array(), @@ -1341,7 +1342,8 @@ function system_library() { 'website' => 'http://jqueryui.com/demos/dialog/', 'version' => '1.8.7', 'js' => array( - 'misc/ui/jquery.ui.dialog.min.js' => array(), + 'misc/ui/jquery.ui.dialog.min.js' => array(), + 'misc/ui/jquery.ui.dialog-1.13.0-backport.js' => array(), ), 'css' => array( 'misc/ui/jquery.ui.dialog.css' => array(), @@ -1397,6 +1399,7 @@ function system_library() { 'version' => '1.8.7', 'js' => array( 'misc/ui/jquery.ui.position.min.js' => array(), + 'misc/ui/jquery.ui.position-1.13.0-backport.js' => array(), ), ); $libraries['ui.progressbar'] = array( @@ -4085,3 +4088,21 @@ function system_admin_paths() { ); return $paths; } + +/** + * Implements hook_file_download(). + */ +function system_file_download($uri) { + $core_schemes = array('public', 'private', 'temporary'); + $additional_public_schemes = array_diff(variable_get('file_additional_public_schemes', array()), $core_schemes); + if ($additional_public_schemes) { + $scheme = file_uri_scheme($uri); + if (in_array($scheme, $additional_public_schemes, TRUE)) { + return array( + // Returning any header grants access, and setting the 'Cache-Control' + // header is appropriate for public files. + 'Cache-Control' => 'public', + ); + } + } +} diff --git a/modules/system/system.module:Zone.Identifier b/modules/system/system.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.queue.inc:Zone.Identifier b/modules/system/system.queue.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.queue.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.tar.inc b/modules/system/system.tar.inc index 505f2c0ba7..0b26f9cb76 100644 --- a/modules/system/system.tar.inc +++ b/modules/system/system.tar.inc @@ -41,7 +41,7 @@ /** * Note on Drupal 7 porting. - * This file origin is Tar.php, release 1.4.9 (stable) with some code + * This file origin is Tar.php, release 1.4.14 (stable) with some code * from PEAR.php, release 1.10.10 (stable) both at http://pear.php.net. * To simplify future porting from pear of this file, you should not * do cosmetic or other non significant changes to this file. @@ -792,7 +792,7 @@ class Archive_Tar */ public function setIgnoreList($list) { - $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list); + $list = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list); $regexp = '#/' . join('$|/', $list) . '#'; $this->setIgnoreRegexp($regexp); } @@ -1336,7 +1336,7 @@ class Archive_Tar while (($v_buffer = fread($v_file, $this->buffer_length)) != '') { $buffer_length = strlen("$v_buffer"); if ($buffer_length != $this->buffer_length) { - $pack_size = ((int)($buffer_length / 512) + 1) * 512; + $pack_size = ((int)($buffer_length / 512) + ($buffer_length % 512 !== 0 ? 1 : 0)) * 512; $pack_format = sprintf('a%d', $pack_size); } else { $pack_format = sprintf('a%d', $this->buffer_length); @@ -1465,11 +1465,13 @@ class Archive_Tar $userinfo = posix_getpwuid($v_info[4]); $groupinfo = posix_getgrgid($v_info[5]); - $v_uname = $userinfo['name']; - $v_gname = $groupinfo['name']; - } else { - $v_uname = ''; - $v_gname = ''; + if (isset($userinfo['name'])) { + $v_uname = $userinfo['name']; + } + + if (isset($groupinfo['name'])) { + $v_gname = $groupinfo['name']; + } } $v_devmajor = ''; @@ -1578,8 +1580,13 @@ class Archive_Tar $userinfo = posix_getpwuid($p_uid); $groupinfo = posix_getgrgid($p_gid); - $v_uname = $userinfo['name']; - $v_gname = $groupinfo['name']; + if ($userinfo === false || $groupinfo === false) { + $v_uname = ''; + $v_gname = ''; + } else { + $v_uname = $userinfo['name']; + $v_gname = $groupinfo['name']; + } } else { $v_uname = ''; $v_gname = ''; diff --git a/modules/system/system.tar.inc:Zone.Identifier b/modules/system/system.tar.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.tar.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.test b/modules/system/system.test index 45c6648c43..0d6a9e76aa 100644 --- a/modules/system/system.test +++ b/modules/system/system.test @@ -925,6 +925,22 @@ class CronRunTestCase extends DrupalWebTestCase { $this->assertEqual($result, 'success', 'Cron correctly handles exceptions thrown during hook_cron() invocations.'); } + /** + * Ensure that the manual cron run is working. + */ + function testManualCron() { + $admin_user = $this->drupalCreateUser(array('administer site configuration')); + $this->drupalLogin($admin_user); + + $this->drupalGet('admin/reports/status/run-cron'); + $this->assertResponse(403); + + $this->drupalGet('admin/reports/status'); + $this->clickLink(t('run cron manually')); + $this->assertResponse(200); + $this->assertText(t('Cron ran successfully.')); + } + /** * Tests that hook_flush_caches() is not invoked on every single cron run. * @@ -1101,6 +1117,16 @@ class AccessDeniedTestCase extends DrupalWebTestCase { // Check that we're still on the same page. $this->assertText(t('Site information')); + + // Check batch page response. + $query_parameters = array( + ':type' => 'php', + ':severity' => WATCHDOG_WARNING, + ); + $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND severity = :severity', $query_parameters)->fetchField(), 0, 'No warning message appears in the logs before accessing the batch page.'); + $this->drupalGet('batch'); + $this->assertResponse(403); + $this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND severity = :severity', $query_parameters)->fetchField(), 0, 'No warning message appears in the logs after accessing the batch page.'); } } @@ -3096,3 +3122,192 @@ class ConfirmFormTest extends DrupalWebTestCase { return $this->assertTrue(isset($links[0]), $message, $group); } } + +/** + * Test case for Archiver classes. + * + * Cannot be a DrupalUnitTestCase as it requires access to the db and files. + */ +class SystemArchiverTest extends DrupalWebTestCase +{ + + public static function getInfo() + { + return array( + 'name' => 'Archiver tests', + 'description' => 'Test the Archiver classes.', + 'group' => 'System', + ); + } + + /** + * Tests interacting with a tarball archive. + */ + public function testArchiverTarball() { + $src_tarball = DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/tests/system_test_archive.tar.gz'; + $tmp = file_directory_temp(); + $tarball = $tmp . '/' . basename($src_tarball); + file_unmanaged_copy($src_tarball, $tarball); + try { + $archiver = archiver_get_archiver($tarball); + } + catch (Exception $e) { + // The file's not there (this is not part of the test). + $this->assertTrue(FALSE, $e); + return; + } + + // Test \ArchiverTar::listContents + $listing = $archiver->listContents(); + $this->assertEqual(count($listing), 4, 'Tarball listing has 4 entries.'); + $this->assertTrue((strpos(implode(',', $listing), 'tarball.module') !== FALSE), 'Tarball listing includes tarball.module'); + + // Test \ArchiverTar::extract + $extract_dir = file_directory_temp() . '/testArchiverTarball'; + $archiver->extract($extract_dir); + $this->assertTrue(file_exists($extract_dir . '/system_test_archive/test.txt'), 'test.txt extracted from tarball'); + $this->assertEqual(count(glob($extract_dir . '/system_test_archive/*')), 3, '3 files extracted from tarball'); + + // Test \ArchiverTar::add + $extra_file = DRUPAL_ROOT . '/misc/druplicon.png'; + $archiver->add($extra_file); + $new_listing = $archiver->listContents(); + // \ArchiverTar::add probably should not add the new file with its absolute + // path. However that's how \Archive_Tar::add works. If we wanted to modify + // the file path within the archive, we could call \Archive_Tar::addModify + // directly and use its additional parameters. That could be done using + // \ArchiverTar::getArchive like in _testArchiverOutOfPath() which calls + // \Archive_Tar::extract directly. + $this->assertTrue(in_array($extra_file, $new_listing), 'Druplicon added to tarball'); + } + + /** + * Tests out-of-path extraction protection. + */ + public function testArchiverOutOfPath() { + $this->_testArchiverOutOfPath('system_test_archive_rel.tar', 'Relative out-of-path extraction caught'); + $this->_testArchiverOutOfPath('system_test_archive_abs.tgz', 'Absolute out-of-path extraction caught'); + } + + /** + * Helper to test out-of-path extraction protection. + */ + public function _testArchiverOutOfPath($archive, $message) { + $src_tarball = DRUPAL_ROOT . '/modules/system/tests/' . $archive; + $tarball = file_directory_temp() . '/' . $archive; + file_unmanaged_copy($src_tarball, $tarball); + try { + $archiver = archiver_get_archiver($tarball); + } catch (Exception $e) { + // The file's not there (this is not part of the test). + $this->assertTrue(FALSE, $e); + return; + } + + $extract_dir = file_directory_temp() . '/testArchiverTarball'; + $caught_exception = FALSE; + try { + // Drupal's \ArchiverTar::extract() doesn't support symlinks, so we have + // to access the underlying Archive_Tar object. + $archiver->getArchive()->extract($extract_dir, FALSE, TRUE); + } + catch (Exception $e) { + $caught_exception = (strpos($e->getMessage(), 'Out-of-path file extraction') !== FALSE); + } + $this->assertTrue($caught_exception, $message); + } +} + +/** + * Tests .htaccess is working correctly. + */ +class HtaccessTest extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => '.htaccess tests', + 'description' => 'Tests .htaccess is working correctly.', + 'group' => 'System', + ); + } + + /** + * Get an array of file paths for access testing. + */ + protected function getProtectedFiles() { + $path = drupal_get_path('module', 'system') . '/tests/fixtures/HtaccessTest'; + + // Tests the FilesMatch directive which denies access to certain file + // extensions. + $file_exts_to_deny = array( + 'engine', + 'inc', + 'info', + 'install', + 'make', + 'module', + 'module~', + 'module.bak', + 'module.orig', + 'module.save', + 'module.swo', + 'module.swp', + 'php~', + 'php.bak', + 'php.orig', + 'php.save', + 'php.swo', + 'php.swp', + 'profile', + 'po', + 'sh', + 'sql', + 'test', + 'theme', + 'tpl.php', + 'xtmpl', + ); + + foreach ($file_exts_to_deny as $file_ext) { + $file_paths["$path/access_test.$file_ext"] = 403; + } + + // Test extensions that should be permitted. + $file_exts_to_allow = array( + 'php-info.txt', + ); + + foreach ($file_exts_to_allow as $file_ext) { + $file_paths["$path/access_test.$file_ext"] = 200; + } + + // Ensure web server configuration files cannot be accessed. + $file_paths["$path/.htaccess"] = 403; + $file_paths["$path/web.config"] = 403; + + return $file_paths; + } + + /** + * Iterates over protected files and calls assertNoFileAccess(). + */ + function testFileAccess() { + foreach ($this->getProtectedFiles() as $file => $response_code) { + $this->assertFileAccess($file, $response_code); + } + } + + /** + * Asserts that a file exists and requesting it returns a specific response. + * + * @param string $path + * Path to file. Without leading slash. + * @param int $response_code + * The expected response code. For example: 200, 403 or 404. + */ + protected function assertFileAccess($path, $response_code) { + global $base_url; + $this->assertTrue(file_exists(DRUPAL_ROOT . '/' . $path), format_string('@filename exists.', array('@filename' => $path))); + $this->drupalGet($base_url . '/' . $path, array('external' => TRUE)); + $this->assertResponse($response_code, "Response code to $path should be $response_code"); + } +} diff --git a/modules/system/system.test:Zone.Identifier b/modules/system/system.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.theme-rtl.css:Zone.Identifier b/modules/system/system.theme-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.theme-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.theme.css:Zone.Identifier b/modules/system/system.theme.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.theme.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.tokens.inc:Zone.Identifier b/modules/system/system.tokens.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.tokens.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/system.updater.inc:Zone.Identifier b/modules/system/system.updater.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/system.updater.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/cron_queue_test.info b/modules/system/tests/cron_queue_test.info index c231dc1609..f8618a1fbc 100644 --- a/modules/system/tests/cron_queue_test.info +++ b/modules/system/tests/cron_queue_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/system/tests/cron_queue_test.info:Zone.Identifier b/modules/system/tests/cron_queue_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/cron_queue_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/cron_queue_test.module:Zone.Identifier b/modules/system/tests/cron_queue_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/cron_queue_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/.htaccess b/modules/system/tests/fixtures/HtaccessTest/.htaccess new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/.htaccess:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/.htaccess:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/.htaccess:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.engine b/modules/system/tests/fixtures/HtaccessTest/access_test.engine new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.engine:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.engine:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.engine:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.inc b/modules/system/tests/fixtures/HtaccessTest/access_test.inc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.inc:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.info b/modules/system/tests/fixtures/HtaccessTest/access_test.info new file mode 100644 index 0000000000..e6c15a82b3 --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.info @@ -0,0 +1,5 @@ + +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" +project = "drupal" +datestamp = "1662554078" diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.info:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.install b/modules/system/tests/fixtures/HtaccessTest/access_test.install new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.install:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.make b/modules/system/tests/fixtures/HtaccessTest/access_test.make new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.make:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.make:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.make:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module b/modules/system/tests/fixtures/HtaccessTest/access_test.module new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.bak b/modules/system/tests/fixtures/HtaccessTest/access_test.module.bak new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.bak:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.module.bak:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.module.bak:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.orig b/modules/system/tests/fixtures/HtaccessTest/access_test.module.orig new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.orig:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.module.orig:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.module.orig:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.save b/modules/system/tests/fixtures/HtaccessTest/access_test.module.save new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.save:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.module.save:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.module.save:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.swo b/modules/system/tests/fixtures/HtaccessTest/access_test.module.swo new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.swo:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.module.swo:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.module.swo:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.swp b/modules/system/tests/fixtures/HtaccessTest/access_test.module.swp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module.swp:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.module.swp:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.module.swp:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module~ b/modules/system/tests/fixtures/HtaccessTest/access_test.module~ new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.module~:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.module~:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.module~:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php-info.txt b/modules/system/tests/fixtures/HtaccessTest/access_test.php-info.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php-info.txt:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.php-info.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.php-info.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.bak b/modules/system/tests/fixtures/HtaccessTest/access_test.php.bak new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.bak:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.php.bak:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.php.bak:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.orig b/modules/system/tests/fixtures/HtaccessTest/access_test.php.orig new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.orig:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.php.orig:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.php.orig:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.save b/modules/system/tests/fixtures/HtaccessTest/access_test.php.save new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.save:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.php.save:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.php.save:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.swo b/modules/system/tests/fixtures/HtaccessTest/access_test.php.swo new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.swo:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.php.swo:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.php.swo:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.swp b/modules/system/tests/fixtures/HtaccessTest/access_test.php.swp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php.swp:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.php.swp:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.php.swp:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php~ b/modules/system/tests/fixtures/HtaccessTest/access_test.php~ new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.php~:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.php~:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.php~:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.po b/modules/system/tests/fixtures/HtaccessTest/access_test.po new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.po:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.po:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.po:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.profile b/modules/system/tests/fixtures/HtaccessTest/access_test.profile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.profile:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.profile:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.profile:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.sh b/modules/system/tests/fixtures/HtaccessTest/access_test.sh new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.sh:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.sh:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.sh:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.sql:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.sql:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.sql:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.test b/modules/system/tests/fixtures/HtaccessTest/access_test.test new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.test:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.theme b/modules/system/tests/fixtures/HtaccessTest/access_test.theme new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.theme:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.theme:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.theme:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.tpl.php b/modules/system/tests/fixtures/HtaccessTest/access_test.tpl.php new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.tpl.php:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.xtmpl b/modules/system/tests/fixtures/HtaccessTest/access_test.xtmpl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/access_test.xtmpl:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/access_test.xtmpl:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/access_test.xtmpl:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/fixtures/HtaccessTest/web.config b/modules/system/tests/fixtures/HtaccessTest/web.config new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/system/tests/fixtures/HtaccessTest/web.config:Zone.Identifier b/modules/system/tests/fixtures/HtaccessTest/web.config:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/fixtures/HtaccessTest/web.config:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/system_cron_test.info b/modules/system/tests/system_cron_test.info index 7136292ab8..1d9572b9b7 100644 --- a/modules/system/tests/system_cron_test.info +++ b/modules/system/tests/system_cron_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/system/tests/system_cron_test.info:Zone.Identifier b/modules/system/tests/system_cron_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/system_cron_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/system_cron_test.module:Zone.Identifier b/modules/system/tests/system_cron_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/system_cron_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/system_test_archive.tar.gz b/modules/system/tests/system_test_archive.tar.gz new file mode 100644 index 0000000000..603baea01d Binary files /dev/null and b/modules/system/tests/system_test_archive.tar.gz differ diff --git a/modules/system/tests/system_test_archive.tar.gz:Zone.Identifier b/modules/system/tests/system_test_archive.tar.gz:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/system_test_archive.tar.gz:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/system_test_archive_abs.tgz b/modules/system/tests/system_test_archive_abs.tgz new file mode 100644 index 0000000000..bf4a3ff416 Binary files /dev/null and b/modules/system/tests/system_test_archive_abs.tgz differ diff --git a/modules/system/tests/system_test_archive_abs.tgz:Zone.Identifier b/modules/system/tests/system_test_archive_abs.tgz:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/system_test_archive_abs.tgz:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/tests/system_test_archive_rel.tar b/modules/system/tests/system_test_archive_rel.tar new file mode 100644 index 0000000000..b528d681a5 Binary files /dev/null and b/modules/system/tests/system_test_archive_rel.tar differ diff --git a/modules/system/tests/system_test_archive_rel.tar:Zone.Identifier b/modules/system/tests/system_test_archive_rel.tar:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/tests/system_test_archive_rel.tar:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/system/theme.api.php:Zone.Identifier b/modules/system/theme.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/system/theme.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy-term.tpl.php:Zone.Identifier b/modules/taxonomy/taxonomy-term.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy-term.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.admin.inc b/modules/taxonomy/taxonomy.admin.inc index 828fde0ab2..b44128ed81 100644 --- a/modules/taxonomy/taxonomy.admin.inc +++ b/modules/taxonomy/taxonomy.admin.inc @@ -826,8 +826,8 @@ function taxonomy_form_term_submit($form, &$form_state) { break; } - $current_parent_count = count($form_state['values']['parent']); - $previous_parent_count = count($form['#term']['parent']); + $current_parent_count = empty($form_state['values']['parent']) ? 0 : count((array) $form_state['values']['parent']); + $previous_parent_count = empty($form['#term']['parent']) ? 0 : count((array) $form['#term']['parent']); // Root doesn't count if it's the only parent. if ($current_parent_count == 1 && isset($form_state['values']['parent'][0])) { $current_parent_count = 0; diff --git a/modules/taxonomy/taxonomy.admin.inc:Zone.Identifier b/modules/taxonomy/taxonomy.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.api.php:Zone.Identifier b/modules/taxonomy/taxonomy.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.css:Zone.Identifier b/modules/taxonomy/taxonomy.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.info b/modules/taxonomy/taxonomy.info index d2d0cace78..cbd5c8e1ab 100644 --- a/modules/taxonomy/taxonomy.info +++ b/modules/taxonomy/taxonomy.info @@ -8,7 +8,7 @@ files[] = taxonomy.module files[] = taxonomy.test configure = admin/structure/taxonomy -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/taxonomy/taxonomy.info:Zone.Identifier b/modules/taxonomy/taxonomy.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.install:Zone.Identifier b/modules/taxonomy/taxonomy.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.js:Zone.Identifier b/modules/taxonomy/taxonomy.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module index e3ee48e0cf..d94e165ad6 100644 --- a/modules/taxonomy/taxonomy.module +++ b/modules/taxonomy/taxonomy.module @@ -207,7 +207,7 @@ function taxonomy_select_nodes($tid, $pager = TRUE, $limit = FALSE, $order = arr } $query = db_select('taxonomy_index', 't'); $query->addTag('node_access'); - $query->condition('tid', $tid); + $query->condition('t.tid', $tid); if ($pager) { $count_query = clone $query; $count_query->addExpression('COUNT(t.nid)'); @@ -1274,7 +1274,7 @@ class TaxonomyTermController extends DrupalDefaultEntityController { // LOWER() and drupal_strtolower() may return different results. foreach ($terms as $term) { $term_values = (array) $term; - if (isset($conditions['name']) && drupal_strtolower($conditions['name'] != drupal_strtolower($term_values['name']))) { + if (isset($conditions['name']) && drupal_strtolower($conditions['name']) != drupal_strtolower($term_values['name'])) { unset($terms[$term->tid]); } } @@ -1513,7 +1513,7 @@ function taxonomy_field_validate($entity_type, $entity, $field, $instance, $lang // Build an array of existing term IDs so they can be loaded with // taxonomy_term_load_multiple(); foreach ($items as $delta => $item) { - if (!empty($item['tid']) && $item['tid'] != 'autocreate') { + if (!empty($item['tid']) && $item['tid'] !== 'autocreate') { $tids[] = $item['tid']; } } @@ -1524,7 +1524,7 @@ function taxonomy_field_validate($entity_type, $entity, $field, $instance, $lang // allowed values for this field. foreach ($items as $delta => $item) { $validate = TRUE; - if (!empty($item['tid']) && $item['tid'] != 'autocreate') { + if (!empty($item['tid']) && $item['tid'] !== 'autocreate') { $validate = FALSE; foreach ($field['settings']['allowed_values'] as $settings) { // If no parent is specified, check if the term is in the vocabulary. @@ -1600,7 +1600,7 @@ function taxonomy_field_formatter_view($entity_type, $entity, $field, $instance, switch ($display['type']) { case 'taxonomy_term_reference_link': foreach ($items as $delta => $item) { - if ($item['tid'] == 'autocreate') { + if ($item['tid'] === 'autocreate') { $element[$delta] = array( '#markup' => check_plain($item['name']), ); @@ -1620,7 +1620,7 @@ function taxonomy_field_formatter_view($entity_type, $entity, $field, $instance, case 'taxonomy_term_reference_plain': foreach ($items as $delta => $item) { - $name = ($item['tid'] != 'autocreate' ? $item['taxonomy_term']->name : $item['name']); + $name = ($item['tid'] !== 'autocreate' ? $item['taxonomy_term']->name : $item['name']); $element[$delta] = array( '#markup' => check_plain($name), ); @@ -1631,9 +1631,9 @@ function taxonomy_field_formatter_view($entity_type, $entity, $field, $instance, foreach ($items as $delta => $item) { $entity->rss_elements[] = array( 'key' => 'category', - 'value' => $item['tid'] != 'autocreate' ? $item['taxonomy_term']->name : $item['name'], + 'value' => $item['tid'] !== 'autocreate' ? $item['taxonomy_term']->name : $item['name'], 'attributes' => array( - 'domain' => $item['tid'] != 'autocreate' ? url('taxonomy/term/' . $item['tid'], array('absolute' => TRUE)) : '', + 'domain' => $item['tid'] !== 'autocreate' ? url('taxonomy/term/' . $item['tid'], array('absolute' => TRUE)) : '', ), ); } @@ -1678,7 +1678,7 @@ function taxonomy_field_formatter_prepare_view($entity_type, $entities, $field, foreach ($entities as $id => $entity) { foreach ($items[$id] as $delta => $item) { // Force the array key to prevent duplicates. - if ($item['tid'] != 'autocreate') { + if ($item['tid'] !== 'autocreate') { $tids[$item['tid']] = $item['tid']; } } @@ -1697,7 +1697,7 @@ function taxonomy_field_formatter_prepare_view($entity_type, $entities, $field, $items[$id][$delta]['taxonomy_term'] = $terms[$item['tid']]; } // Terms to be created are not in $terms, but are still legitimate. - elseif ($item['tid'] == 'autocreate') { + elseif ($item['tid'] === 'autocreate') { // Leave the item in place. } // Otherwise, unset the instance value, since the term does not exist. @@ -1901,7 +1901,7 @@ function taxonomy_rdf_mapping() { */ function taxonomy_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) { foreach ($items as $delta => $item) { - if ($item['tid'] == 'autocreate') { + if ($item['tid'] === 'autocreate') { $term = (object) $item; unset($term->tid); taxonomy_term_save($term); @@ -2061,3 +2061,12 @@ function taxonomy_entity_query_alter($query) { unset($conditions['bundle']); } } + +/** + * Implements hook_file_download_access(). + */ +function taxonomy_file_download_access($field, $entity_type, $entity) { + if ($entity_type == 'taxonomy_term') { + return user_access('access content'); + } +} diff --git a/modules/taxonomy/taxonomy.module:Zone.Identifier b/modules/taxonomy/taxonomy.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.pages.inc:Zone.Identifier b/modules/taxonomy/taxonomy.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test index a4b7ee833e..6188d8be5c 100644 --- a/modules/taxonomy/taxonomy.test +++ b/modules/taxonomy/taxonomy.test @@ -1008,6 +1008,29 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase { $this->assertEqual(count($terms), 0, 'No terms loaded when restricted by a non-existing vocabulary.'); } + /** + * Tests that taxonomy term detail page is working even after the default + * taxonomy_select_nodes() query is altered. + */ + public function testTaxonomySelectNodesAlter() { + // Create a new term. + $term = $this->createTerm($this->vocabulary); + + // Create an article. + $settings = array( + 'type' => 'article', + $this->instance['field_name'] => array(LANGUAGE_NONE => array(array('tid' => $term->tid))), + ); + $this->drupalCreateNode($settings); + + // Check if the taxonomy term detail page is working. + module_enable(array('taxonomy_nodes_test')); + variable_set('taxonomy_nodes_test_query_node_access_alter', TRUE); + $this->drupalGet('taxonomy/term/' . $term->tid); + $this->assertResponse(200, 'The taxonomy term page is working.'); + variable_set('taxonomy_nodes_test_query_node_access_alter', FALSE); + } + } /** @@ -1610,6 +1633,21 @@ class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase { $this->assertEqual($allowed_values[2]['vocabulary'], 'foo', 'Index 2: Machine name was left untouched.'); } + /** + * Test empty taxonomy term reference field. + */ + function testEmptyTaxonomyTermReferenceField() { + // Test if an empty value in the taxonomy reference field would trigger + // autocreate or if the value would be saved correctly. + $langcode = LANGUAGE_NONE; + $entity = field_test_create_stub_entity(NULL, NULL); + $entity->{$this->field_name}[$langcode][0]['tid'] = 0; + field_test_entity_save($entity); + $entity = field_test_entity_test_load($entity->ftid); + field_test_entity_save($entity); + $this->pass('Empty term ID does not trigger autocreate.'); + } + } /** @@ -2093,3 +2131,114 @@ class TaxonomyQueryAlterTestCase extends TaxonomyWebTestCase { } } + +/** + * Tests for taxonomy terms cache usage. + */ +class TaxonomyTermCacheUsageTestCase extends TaxonomyWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Taxonomy term cache usage', + 'description' => 'Tests for taxonomy term cache usage.', + 'group' => 'Taxonomy', + ); + } + + function setUp() { + parent::setUp('taxonomy', 'taxonomy_test'); + } + + /** + * Test taxonomy_get_term_by_name() cache usage. + */ + function testTaxonomyGetTermByNameCacheUsage() { + // Create vocabulary and term. + $new_vocabulary = $this->createVocabulary(); + $new_term = new stdClass(); + $new_term->name = 'MixedCaseTerm'; + $new_term->vid = $new_vocabulary->vid; + taxonomy_term_save($new_term); + + // Try to load term with mixed case letters from the cache. + $taxonomy_controller = new TestTaxonomyTermController('taxonomy_term'); + // First load to warm the cache. + $terms = $taxonomy_controller->load(array(), array('name' => $new_term->name)); + $this->assertTrue(isset($terms[$new_term->tid]), 'Term loaded using exact name and vocabulary machine name.'); + // Second load should load the $new_term from the cache. + $terms = $taxonomy_controller->loadFromCache(array(), array('name' => $new_term->name)); + $this->assertTrue(isset($terms[$new_term->tid]), 'Term loaded using the cache.'); + } + +} + +/** + * Tests appropriate access control to private file fields on a term. + */ +class TaxonomyPrivateFileTestCase extends TaxonomyWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Taxonomy term private file access', + 'description' => 'Verifies private files on terms have appropriate access control.', + 'group' => 'Taxonomy', + ); + } + + public function setUp() { + parent::setUp('taxonomy_test'); + + // Remove access content permission from registered users. + user_role_revoke_permissions(DRUPAL_AUTHENTICATED_RID, array('access content')); + + $this->vocabulary = $this->createVocabulary(); + // Add a field instance to the vocabulary. + $field = array( + 'field_name' => 'field_test', + 'type' => 'image', + 'settings' => array( + 'uri_scheme' => 'private' + ), + ); + field_create_field($field); + $instance = array( + 'field_name' => 'field_test', + 'entity_type' => 'taxonomy_term', + 'label' => 'test', + 'bundle' => $this->vocabulary->machine_name, + 'widget' => array( + 'type' => 'image_image', + 'settings' => array(), + ), + ); + field_create_instance($instance); + } + + /** + * Tests access to a private file on a taxonomy term entity. + */ + public function testTaxonomyImageAccess() { + $user = $this->drupalCreateUser(array('administer site configuration', 'administer taxonomy', 'access user profiles')); + $this->drupalLogin($user); + + // Create a term and upload the image. + $term = $this->createTerm($this->vocabulary); + $files = $this->drupalGetTestFiles('image'); + $image = array_pop($files); + $edit['files[field_test_' . LANGUAGE_NONE . '_0]'] = drupal_realpath($image->uri); + $this->drupalPost('taxonomy/term/' . $term->tid . '/edit', $edit, t('Save')); + $term = taxonomy_term_load($term->tid); + $this->assertText(t('Updated term @name.', array('@name' => $term->name))); + + // Create a user that should have access to the file and one that doesn't. + $access_user = $this->drupalCreateUser(array('access content')); + $no_access_user = $this->drupalCreateUser(); + $image = file_load($term->field_test[LANGUAGE_NONE][0]['fid']); + $image_url = file_create_url($image->uri); + $this->drupalLogin($access_user); + $this->drupalGet($image_url); + $this->assertResponse(200, 'Private image on term is accessible with right permission'); + + $this->drupalLogin($no_access_user); + $this->drupalGet($image_url); + $this->assertResponse(403, 'Private image on term not accessible without right permission'); + } +} diff --git a/modules/taxonomy/taxonomy.test:Zone.Identifier b/modules/taxonomy/taxonomy.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/taxonomy/taxonomy.tokens.inc:Zone.Identifier b/modules/taxonomy/taxonomy.tokens.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/taxonomy/taxonomy.tokens.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/toolbar/toolbar-print.css:Zone.Identifier b/modules/toolbar/toolbar-print.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/toolbar/toolbar-print.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/toolbar/toolbar-rtl.css:Zone.Identifier b/modules/toolbar/toolbar-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/toolbar/toolbar-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/toolbar/toolbar.css:Zone.Identifier b/modules/toolbar/toolbar.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/toolbar/toolbar.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/toolbar/toolbar.info b/modules/toolbar/toolbar.info index ebb5cd8dac..b02a0abe1e 100644 --- a/modules/toolbar/toolbar.info +++ b/modules/toolbar/toolbar.info @@ -4,7 +4,7 @@ core = 7.x package = Core version = VERSION -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/toolbar/toolbar.info:Zone.Identifier b/modules/toolbar/toolbar.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/toolbar/toolbar.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/toolbar/toolbar.js:Zone.Identifier b/modules/toolbar/toolbar.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/toolbar/toolbar.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/toolbar/toolbar.module:Zone.Identifier b/modules/toolbar/toolbar.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/toolbar/toolbar.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/toolbar/toolbar.png:Zone.Identifier b/modules/toolbar/toolbar.png:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/toolbar/toolbar.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/toolbar/toolbar.tpl.php:Zone.Identifier b/modules/toolbar/toolbar.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/toolbar/toolbar.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/tracker/tracker.css:Zone.Identifier b/modules/tracker/tracker.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/tracker/tracker.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/tracker/tracker.info b/modules/tracker/tracker.info index 4fc73a4fd7..e671674548 100644 --- a/modules/tracker/tracker.info +++ b/modules/tracker/tracker.info @@ -6,7 +6,7 @@ version = VERSION core = 7.x files[] = tracker.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/tracker/tracker.info:Zone.Identifier b/modules/tracker/tracker.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/tracker/tracker.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/tracker/tracker.install:Zone.Identifier b/modules/tracker/tracker.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/tracker/tracker.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/tracker/tracker.module:Zone.Identifier b/modules/tracker/tracker.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/tracker/tracker.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/tracker/tracker.pages.inc:Zone.Identifier b/modules/tracker/tracker.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/tracker/tracker.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/tracker/tracker.test:Zone.Identifier b/modules/tracker/tracker.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/tracker/tracker.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/translation/tests/translation_test.info b/modules/translation/tests/translation_test.info index 08492c01ac..71ebebfcfb 100644 --- a/modules/translation/tests/translation_test.info +++ b/modules/translation/tests/translation_test.info @@ -5,7 +5,7 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/translation/tests/translation_test.info:Zone.Identifier b/modules/translation/tests/translation_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/translation/tests/translation_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/translation/tests/translation_test.module:Zone.Identifier b/modules/translation/tests/translation_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/translation/tests/translation_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/translation/translation.info b/modules/translation/translation.info index 60990920ee..600668d5b6 100644 --- a/modules/translation/translation.info +++ b/modules/translation/translation.info @@ -6,7 +6,7 @@ version = VERSION core = 7.x files[] = translation.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/translation/translation.info:Zone.Identifier b/modules/translation/translation.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/translation/translation.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/translation/translation.module:Zone.Identifier b/modules/translation/translation.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/translation/translation.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/translation/translation.pages.inc:Zone.Identifier b/modules/translation/translation.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/translation/translation.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/translation/translation.test:Zone.Identifier b/modules/translation/translation.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/translation/translation.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/trigger/tests/trigger_test.info b/modules/trigger/tests/trigger_test.info index cf85753142..a5351b80d2 100644 --- a/modules/trigger/tests/trigger_test.info +++ b/modules/trigger/tests/trigger_test.info @@ -4,7 +4,7 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/trigger/tests/trigger_test.info:Zone.Identifier b/modules/trigger/tests/trigger_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/trigger/tests/trigger_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/trigger/tests/trigger_test.module:Zone.Identifier b/modules/trigger/tests/trigger_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/trigger/tests/trigger_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/trigger/trigger.admin.inc:Zone.Identifier b/modules/trigger/trigger.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/trigger/trigger.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/trigger/trigger.api.php:Zone.Identifier b/modules/trigger/trigger.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/trigger/trigger.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/trigger/trigger.info b/modules/trigger/trigger.info index 03b43f15ef..c62794b351 100644 --- a/modules/trigger/trigger.info +++ b/modules/trigger/trigger.info @@ -6,7 +6,7 @@ core = 7.x files[] = trigger.test configure = admin/structure/trigger -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/trigger/trigger.info:Zone.Identifier b/modules/trigger/trigger.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/trigger/trigger.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/trigger/trigger.install:Zone.Identifier b/modules/trigger/trigger.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/trigger/trigger.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/trigger/trigger.module:Zone.Identifier b/modules/trigger/trigger.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/trigger/trigger.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/trigger/trigger.test:Zone.Identifier b/modules/trigger/trigger.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/trigger/trigger.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/aaa_update_test.1_0.xml:Zone.Identifier b/modules/update/tests/aaa_update_test.1_0.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/aaa_update_test.1_0.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/aaa_update_test.info b/modules/update/tests/aaa_update_test.info index 92df754514..d0c897cc2c 100644 --- a/modules/update/tests/aaa_update_test.info +++ b/modules/update/tests/aaa_update_test.info @@ -4,7 +4,7 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/update/tests/aaa_update_test.info:Zone.Identifier b/modules/update/tests/aaa_update_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/aaa_update_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/aaa_update_test.module:Zone.Identifier b/modules/update/tests/aaa_update_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/aaa_update_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/aaa_update_test.no-releases.xml:Zone.Identifier b/modules/update/tests/aaa_update_test.no-releases.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/aaa_update_test.no-releases.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/aaa_update_test.tar.gz:Zone.Identifier b/modules/update/tests/aaa_update_test.tar.gz:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/aaa_update_test.tar.gz:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/bbb_update_test.1_0.xml:Zone.Identifier b/modules/update/tests/bbb_update_test.1_0.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/bbb_update_test.1_0.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/bbb_update_test.info b/modules/update/tests/bbb_update_test.info index 9c5d5f18e5..22eb3384ff 100644 --- a/modules/update/tests/bbb_update_test.info +++ b/modules/update/tests/bbb_update_test.info @@ -4,7 +4,7 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/update/tests/bbb_update_test.info:Zone.Identifier b/modules/update/tests/bbb_update_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/bbb_update_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/bbb_update_test.module:Zone.Identifier b/modules/update/tests/bbb_update_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/bbb_update_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/ccc_update_test.1_0.xml:Zone.Identifier b/modules/update/tests/ccc_update_test.1_0.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/ccc_update_test.1_0.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/ccc_update_test.info b/modules/update/tests/ccc_update_test.info index ec3badc4bc..35a601c9bc 100644 --- a/modules/update/tests/ccc_update_test.info +++ b/modules/update/tests/ccc_update_test.info @@ -4,7 +4,7 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/update/tests/ccc_update_test.info:Zone.Identifier b/modules/update/tests/ccc_update_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/ccc_update_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/ccc_update_test.module:Zone.Identifier b/modules/update/tests/ccc_update_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/ccc_update_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/drupal.0.xml:Zone.Identifier b/modules/update/tests/drupal.0.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/drupal.0.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/drupal.1.xml:Zone.Identifier b/modules/update/tests/drupal.1.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/drupal.1.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/drupal.2-sec.xml:Zone.Identifier b/modules/update/tests/drupal.2-sec.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/drupal.2-sec.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/drupal.dev.xml:Zone.Identifier b/modules/update/tests/drupal.dev.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/drupal.dev.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info b/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info index c7bcefc7b6..f3799feb71 100644 --- a/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info +++ b/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info @@ -3,7 +3,7 @@ description = Test theme which is used as admin theme. core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info:Zone.Identifier b/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info b/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info index 6d5ab97dc6..a84e02b1a2 100644 --- a/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info +++ b/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info @@ -3,7 +3,7 @@ description = Test theme which acts as a base theme for other test subthemes. core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info:Zone.Identifier b/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info b/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info index 2efff4d327..3259dcff3f 100644 --- a/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info +++ b/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info @@ -4,7 +4,7 @@ core = 7.x base theme = update_test_basetheme hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info:Zone.Identifier b/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/update_test.info b/modules/update/tests/update_test.info index f0bec43f09..b829dd6bab 100644 --- a/modules/update/tests/update_test.info +++ b/modules/update/tests/update_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/update/tests/update_test.info:Zone.Identifier b/modules/update/tests/update_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/update_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/update_test.module:Zone.Identifier b/modules/update/tests/update_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/update_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/update_test_basetheme.1_1-sec.xml:Zone.Identifier b/modules/update/tests/update_test_basetheme.1_1-sec.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/update_test_basetheme.1_1-sec.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/tests/update_test_subtheme.1_0.xml:Zone.Identifier b/modules/update/tests/update_test_subtheme.1_0.xml:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/tests/update_test_subtheme.1_0.xml:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update-rtl.css:Zone.Identifier b/modules/update/update-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.api.php:Zone.Identifier b/modules/update/update.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.authorize.inc:Zone.Identifier b/modules/update/update.authorize.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.authorize.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.compare.inc:Zone.Identifier b/modules/update/update.compare.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.compare.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.css:Zone.Identifier b/modules/update/update.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.fetch.inc:Zone.Identifier b/modules/update/update.fetch.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.fetch.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.info b/modules/update/update.info index 9c6ab9ba53..0b28d0ee0c 100644 --- a/modules/update/update.info +++ b/modules/update/update.info @@ -6,7 +6,7 @@ core = 7.x files[] = update.test configure = admin/reports/updates/settings -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/update/update.info:Zone.Identifier b/modules/update/update.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.install:Zone.Identifier b/modules/update/update.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.manager.inc:Zone.Identifier b/modules/update/update.manager.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.manager.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.module b/modules/update/update.module index a59c7d7f91..67f832cbc5 100644 --- a/modules/update/update.module +++ b/modules/update/update.module @@ -367,8 +367,9 @@ function update_cache_clear_submit($form, &$form_state) { */ function _update_no_data() { $destination = drupal_get_destination(); + $cron_token = array('token' => drupal_get_token('run-cron')); return t('No update information available. Run cron or check manually.', array( - '@run_cron' => url('admin/reports/status/run-cron', array('query' => $destination)), + '@run_cron' => url('admin/reports/status/run-cron', array('query' => $cron_token + $destination)), '@check_manually' => url('admin/reports/updates/check', array('query' => $destination)), )); } diff --git a/modules/update/update.module:Zone.Identifier b/modules/update/update.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.report.inc:Zone.Identifier b/modules/update/update.report.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.report.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.settings.inc:Zone.Identifier b/modules/update/update.settings.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.settings.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/update/update.test:Zone.Identifier b/modules/update/update.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/update/update.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/tests/user_flood_test.info b/modules/user/tests/user_flood_test.info index 895cfff5f4..be30b610f7 100644 --- a/modules/user/tests/user_flood_test.info +++ b/modules/user/tests/user_flood_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/user/tests/user_flood_test.info:Zone.Identifier b/modules/user/tests/user_flood_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/tests/user_flood_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/tests/user_flood_test.module:Zone.Identifier b/modules/user/tests/user_flood_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/tests/user_flood_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/tests/user_form_test.info b/modules/user/tests/user_form_test.info index e15a70b353..7b48bab23f 100644 --- a/modules/user/tests/user_form_test.info +++ b/modules/user/tests/user_form_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/user/tests/user_form_test.info:Zone.Identifier b/modules/user/tests/user_form_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/tests/user_form_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/tests/user_form_test.module:Zone.Identifier b/modules/user/tests/user_form_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/tests/user_form_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/tests/user_session_test.info b/modules/user/tests/user_session_test.info index df6510db6d..00221d1978 100644 --- a/modules/user/tests/user_session_test.info +++ b/modules/user/tests/user_session_test.info @@ -5,7 +5,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/user/tests/user_session_test.info:Zone.Identifier b/modules/user/tests/user_session_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/tests/user_session_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/tests/user_session_test.module:Zone.Identifier b/modules/user/tests/user_session_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/tests/user_session_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user-picture.tpl.php:Zone.Identifier b/modules/user/user-picture.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user-picture.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user-profile-category.tpl.php:Zone.Identifier b/modules/user/user-profile-category.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user-profile-category.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user-profile-item.tpl.php:Zone.Identifier b/modules/user/user-profile-item.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user-profile-item.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user-profile.tpl.php:Zone.Identifier b/modules/user/user-profile.tpl.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user-profile.tpl.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user-rtl.css:Zone.Identifier b/modules/user/user-rtl.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user-rtl.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc index 0db7efb1a1..7a6adf2f2e 100644 --- a/modules/user/user.admin.inc +++ b/modules/user/user.admin.inc @@ -167,6 +167,7 @@ function user_admin_account() { 'status' => array('data' => t('Status'), 'field' => 'u.status'), 'roles' => array('data' => t('Roles')), 'member_for' => array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'), + 'changed' => array('data' => t('Last changed'), 'field' => 'u.changed', 'sort' => 'desc'), 'access' => array('data' => t('Last access'), 'field' => 'u.access'), 'operations' => array('data' => t('Operations')), ); @@ -180,7 +181,7 @@ function user_admin_account() { $query = $query->extend('PagerDefault')->extend('TableSort'); $query - ->fields('u', array('uid', 'name', 'status', 'created', 'access')) + ->fields('u', array('uid', 'name', 'status', 'created', 'changed', 'access')) ->limit(50) ->orderByHeader($header) ->setCountQuery($count_query); @@ -226,6 +227,7 @@ function user_admin_account() { 'status' => $status[$account->status], 'roles' => theme('item_list', array('items' => $users_roles)), 'member_for' => format_interval(REQUEST_TIME - $account->created), + 'changed' => t('@time ago', array('@time' => format_interval(REQUEST_TIME - $account->changed))), 'access' => $account->access ? t('@time ago', array('@time' => format_interval(REQUEST_TIME - $account->access))) : t('never'), 'operations' => array('data' => array('#type' => 'link', '#title' => t('edit'), '#href' => "user/$account->uid/edit", '#options' => array('query' => $destination))), ); @@ -437,6 +439,18 @@ function user_admin_settings() { '#description' => t("This text is displayed at the picture upload form in addition to the default guidelines. It's useful for helping or instructing your users."), ); + $form['privacy'] = array( + '#type' => 'fieldset', + '#title' => t('Privacy'), + ); + $form['privacy']['user_password_reset_text'] = array( + '#type' => 'textarea', + '#title' => t('Password reset text'), + '#default_value' => variable_get('user_password_reset_text', t('If %identifier is a valid account, an email will be sent with instructions to reset your password.')), + '#description' => t('The text that appears when a user successfully submits the password reset form. Due to privacy concerns, it should not contain any information about previously registered users. %identifier will be replaced with what the user entered into the form field.'), + '#required' => TRUE, + ); + $form['email_title'] = array( '#type' => 'item', '#title' => t('E-mails'), @@ -843,27 +857,26 @@ function theme_user_permission_description($variables) { */ function user_admin_roles($form, $form_state) { $roles = user_roles(); + $role_weights = db_query('SELECT r.rid, r.weight FROM {role} r')->fetchAllKeyed(); $form['roles'] = array( '#tree' => TRUE, ); - $order = 0; foreach ($roles as $rid => $name) { $form['roles'][$rid]['#role'] = (object) array( 'rid' => $rid, 'name' => $name, - 'weight' => $order, + 'weight' => $role_weights[$rid], ); - $form['roles'][$rid]['#weight'] = $order; + $form['roles'][$rid]['#weight'] = $role_weights[$rid]; $form['roles'][$rid]['weight'] = array( '#type' => 'textfield', '#title' => t('Weight for @title', array('@title' => $name)), '#title_display' => 'invisible', '#size' => 4, - '#default_value' => $order, + '#default_value' => $role_weights[$rid], '#attributes' => array('class' => array('role-weight')), ); - $order++; } $form['name'] = array( diff --git a/modules/user/user.admin.inc:Zone.Identifier b/modules/user/user.admin.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.admin.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.api.php:Zone.Identifier b/modules/user/user.api.php:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.api.php:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.css:Zone.Identifier b/modules/user/user.css:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.css:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.info b/modules/user/user.info index 9e206e7090..5412df8183 100644 --- a/modules/user/user.info +++ b/modules/user/user.info @@ -9,7 +9,7 @@ required = TRUE configure = admin/config/people stylesheets[all][] = user.css -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/modules/user/user.info:Zone.Identifier b/modules/user/user.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.install b/modules/user/user.install index 7a74766a1e..43afb19a42 100644 --- a/modules/user/user.install +++ b/modules/user/user.install @@ -182,6 +182,12 @@ function user_schema() { 'default' => 0, 'description' => 'Timestamp for when user was created.', ), + 'changed' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'Timestamp for when user was changed.', + ), 'access' => array( 'type' => 'int', 'not null' => TRUE, @@ -238,6 +244,7 @@ function user_schema() { 'indexes' => array( 'access' => array('access'), 'created' => array('created'), + 'changed' => array('changed'), 'mail' => array('mail'), 'picture' => array('picture'), ), @@ -312,6 +319,7 @@ function user_install() { 'name' => 'placeholder-for-uid-1', 'mail' => 'placeholder-for-uid-1', 'created' => REQUEST_TIME, + 'changed' => REQUEST_TIME, 'status' => 1, 'data' => NULL, )) @@ -922,6 +930,45 @@ function user_update_7019() { db_add_index('authmap', 'uid_module', array('uid', 'module')); } } + +/** + * Add changed field to users table. + */ +function user_update_7020() { + // The "changed" column was renamed to "access" in system_update_136(), and + // the "changed" index on "access" column may persist on old MySQL databases. + if (db_index_exists('users', 'changed')) { + if (!db_index_exists('users', 'access')) { + db_add_index('users', 'access', array('access')); + } + db_drop_index('users', 'changed'); + } + + $spec = array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'Timestamp for when user was changed.', + ); + $keys = array( + 'indexes' => array( + 'changed' => array('changed'), + ), + ); + // In some cases sites have added the changed field themselves e.g. via a + // contrib or custom module. Ensure the field uses core's new schema. + if (db_field_exists('users', 'changed')) { + db_change_field('users', 'changed', 'changed', $spec, $keys); + } + else { + db_add_field('users', 'changed', $spec, $keys); + // Set the initial value for existing users. + db_update('users') + ->expression('changed', 'created') + ->execute(); + } + +} /** * @} End of "addtogroup updates-7.x-extra". */ diff --git a/modules/user/user.install:Zone.Identifier b/modules/user/user.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.js:Zone.Identifier b/modules/user/user.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.module b/modules/user/user.module index dfa05978cb..9f99980c55 100644 --- a/modules/user/user.module +++ b/modules/user/user.module @@ -304,7 +304,7 @@ class UserController extends DrupalDefaultEntityController { $picture_fids = array(); foreach ($queried_users as $key => $record) { $picture_fids[] = $record->picture; - $queried_users[$key]->data = unserialize($record->data); + $queried_users[$key]->data = unserialize((string) $record->data); $queried_users[$key]->roles = array(); if ($record->uid) { $queried_users[$record->uid]->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user'; @@ -322,7 +322,7 @@ class UserController extends DrupalDefaultEntityController { // Add the full file objects for user pictures if enabled. if (!empty($picture_fids) && variable_get('user_pictures', 0)) { - $pictures = file_load_multiple($picture_fids); + $pictures = file_load_multiple(array_filter($picture_fids)); foreach ($queried_users as $account) { if (!empty($account->picture) && isset($pictures[$account->picture])) { $account->picture = $pictures[$account->picture]; @@ -506,6 +506,8 @@ function user_save($account, $edit = array(), $category = 'account') { // Do not allow 'uid' to be changed. $account->uid = $account->original->uid; + // Save current time as last changed time. + $account->changed = REQUEST_TIME; // Save changes to the user table. $success = drupal_write_record('users', $account, 'uid'); // Restore the picture object. @@ -577,6 +579,8 @@ function user_save($account, $edit = array(), $category = 'account') { if (!isset($account->created)) { $account->created = REQUEST_TIME; } + // Save current time as last changed time. + $account->changed = REQUEST_TIME; $success = drupal_write_record('users', $account); if ($success === FALSE) { // On a failed INSERT some other existing user's uid may be returned. diff --git a/modules/user/user.module:Zone.Identifier b/modules/user/user.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.pages.inc b/modules/user/user.pages.inc index 937f7a31e4..1266bbfb59 100644 --- a/modules/user/user.pages.inc +++ b/modules/user/user.pages.inc @@ -107,9 +107,6 @@ function user_pass_validate($form, &$form_state) { flood_register_event('pass_reset_user', $user_pass_reset_user_window, $identifier); form_set_value(array('#parents' => array('account')), $account, $form_state); } - else { - form_set_error('name', t('Sorry, %name is not recognized as a user name or an e-mail address.', array('%name' => $name))); - } } /** @@ -120,14 +117,21 @@ function user_pass_validate($form, &$form_state) { function user_pass_submit($form, &$form_state) { global $language; - $account = $form_state['values']['account']; - // Mail one time login URL and instructions using current language. - $mail = _user_mail_notify('password_reset', $account, $language); - if (!empty($mail)) { - watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail)); - drupal_set_message(t('Further instructions have been sent to your e-mail address.')); + $name = $form_state['values']['name']; + if (isset($form_state['values']['account'])) { + $account = $form_state['values']['account']; + // Mail one time login URL and instructions using current language. + $mail = _user_mail_notify('password_reset', $account, $language); + if (!empty($mail)) { + watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail)); + } + } + else { + watchdog('user', 'Password reset form was submitted with an unknown or inactive account: %name.', array('%name' => $name)); } + $password_reset_text = variable_get('user_password_reset_text', t('If %identifier is a valid account, an email will be sent with instructions to reset your password.')); + drupal_set_message(format_string($password_reset_text, array('%identifier' => $name))); $form_state['redirect'] = 'user'; return; } diff --git a/modules/user/user.pages.inc:Zone.Identifier b/modules/user/user.pages.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.pages.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.permissions.js:Zone.Identifier b/modules/user/user.permissions.js:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.permissions.js:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.test b/modules/user/user.test index ec2f90d6f1..4cfb5162e6 100644 --- a/modules/user/user.test +++ b/modules/user/user.test @@ -164,6 +164,7 @@ class UserRegistrationTestCase extends DrupalWebTestCase { $this->assertEqual($new_user->theme, '', 'Correct theme field.'); $this->assertEqual($new_user->signature, '', 'Correct signature field.'); $this->assertTrue(($new_user->created > REQUEST_TIME - 20 ), 'Correct creation time.'); + $this->assertEqual($new_user->changed, $new_user->created, 'Correct changed time.'); $this->assertEqual($new_user->status, variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS ? 1 : 0, 'Correct status field.'); $this->assertEqual($new_user->timezone, variable_get('date_default_timezone'), 'Correct time zone field.'); $this->assertEqual($new_user->language, '', 'Correct language field.'); @@ -534,11 +535,20 @@ class UserPasswordResetTestCase extends DrupalWebTestCase { // Attempt to reset password. $edit = array('name' => $account->name); $this->drupalPost('user/password', $edit, t('E-mail new password')); - // Confirm the password reset. - $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.'); + // Ensure the correct message is shown for a valid user name. + $password_reset_text = variable_get('user_password_reset_text', t('If %identifier is a valid account, an email will be sent with instructions to reset your password.')); + $this->assertRaw(format_string($password_reset_text, array('%identifier' => $account->name)), 'Password reset instructions mailed message displayed for a valid user.'); + // Ensure that flood control was not triggered. $this->assertNoText(t('is temporarily blocked. Try again later'), 'Flood control was not triggered by single password reset.'); + // Ensure the correct message is shown for a non-existent user name. + $name = $this->randomName(); + $edit = array('name' => $name); + $this->drupalPost('user/password', $edit, t('E-mail new password')); + $password_reset_text = variable_get('user_password_reset_text', t('If %identifier is a valid account, an email will be sent with instructions to reset your password.')); + $this->assertRaw(format_string($password_reset_text, array('%identifier' => $name)), 'Password reset instructions mailed message displayed for a non-existent user.'); + // Create an image field to enable an Ajax request on the user profile page. $field = array( 'field_name' => 'field_avatar', @@ -619,7 +629,8 @@ class UserPasswordResetTestCase extends DrupalWebTestCase { for ($i = 0; $i < 2; $i++) { $this->drupalPost('user/password', $edit, t('E-mail new password')); // Confirm the password reset. - $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.'); + $password_reset_text = variable_get('user_password_reset_text', t('If %identifier is a valid account, an email will be sent with instructions to reset your password.')); + $this->assertRaw(format_string($password_reset_text, array('%identifier' => $account->name)), 'Password reset instructions mailed message displayed.'); // Ensure that flood control was not triggered. $this->assertNoText(t('is temporarily blocked. Try again later'), 'Flood control was not triggered by password reset.'); } @@ -636,7 +647,8 @@ class UserPasswordResetTestCase extends DrupalWebTestCase { for ($i = 0; $i < 2; $i++) { $this->drupalPost('user/password', $edit, t('E-mail new password')); // Confirm the password reset. - $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.'); + $password_reset_text = variable_get('user_password_reset_text', t('If %identifier is a valid account, an email will be sent with instructions to reset your password.')); + $this->assertRaw(format_string($password_reset_text, array('%identifier' => $account->name)), 'Password reset instructions mailed message displayed.'); // Ensure that flood control was not triggered. $this->assertNoText(t('is temporarily blocked. Try again later'), 'Flood control was not triggered by password reset.'); } @@ -661,9 +673,9 @@ class UserPasswordResetTestCase extends DrupalWebTestCase { $name = $this->randomName(); $edit = array('name' => $name); $this->drupalPost('user/password', $edit, t('E-mail new password')); - // Confirm the password reset was not blocked. Note that @name is used - // instead of %name as assertText() works with plain text not HTML. - $this->assertText(t('Sorry, @name is not recognized as a user name or an e-mail address.', array('@name' => $name)), 'User name not recognized message displayed.'); + // Confirm the password reset was not blocked. + $password_reset_text = variable_get('user_password_reset_text', t('If %identifier is a valid account, an email will be sent with instructions to reset your password.')); + $this->assertRaw(format_string($password_reset_text, array('%identifier' => $name)), 'Password reset instructions mailed message displayed.'); // Ensure that flood control was not triggered. $this->assertNoText(t('is temporarily blocked. Try again later'), 'Flood control was not triggered by password reset.'); } @@ -1358,7 +1370,7 @@ class UserPictureTestCase extends DrupalWebTestCase { $this->assertRaw($text, 'File size cited as reason for failure.'); // Check if file is not uploaded. - $this->assertFalse(is_file($pic_path), 'File was not uploaded.'); + $this->assertFalse(is_file((string) $pic_path), 'File was not uploaded.'); } } @@ -2486,6 +2498,10 @@ class UserRoleAdminTestCase extends DrupalWebTestCase { $role = user_role_load($rid); $new_weight = $role->weight; $this->assertTrue(($old_weight + 1) == $new_weight, 'Role weight updated successfully.'); + + // Check if the updated weight is displayed on the roles settings page. + $this->drupalGet('admin/people/permissions/roles'); + $this->assertFieldByXPath("//input[@name='roles[$rid][weight]']", $new_weight, 'The role weight is displayed correctly.'); } } @@ -2532,6 +2548,8 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase { $tests['[user:last-login:short]'] = format_date($account->login, 'short', '', NULL, $language->language); $tests['[user:created]'] = format_date($account->created, 'medium', '', NULL, $language->language); $tests['[user:created:short]'] = format_date($account->created, 'short', '', NULL, $language->language); + $tests['[user:changed]'] = format_date($account->changed, 'medium', '', NULL, $language->language); + $tests['[user:changed:short]'] = format_date($account->changed, 'short', '', NULL, $language->language); $tests['[current-user:name]'] = check_plain(format_username($global_account)); // Test to make sure that we generated something for each token. @@ -2552,6 +2570,25 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase { $this->assertEqual($output, $expected, format_string('Unsanitized user token %token replaced.', array('%token' => $input))); } } + + /** + * Uses an anonymous user, then tests the tokens generated from it. + */ + function testAnonymousUserTokenReplacement() { + global $language; + + // Load anonymous user data. + $account = drupal_anonymous_user(); + + // Generate and test sanitized tokens. + $tests = array(); + $tests['[user:mail]'] = ''; + + foreach ($tests as $input => $expected) { + $output = token_replace($input, array('user' => $account), array('language' => $language)); + $this->assertEqual($output, $expected, format_string('Sanitized user token %token replaced.', array('%token' => $input))); + } + } } /** diff --git a/modules/user/user.test:Zone.Identifier b/modules/user/user.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/modules/user/user.tokens.inc b/modules/user/user.tokens.inc index 8dcea4b597..a372696da4 100644 --- a/modules/user/user.tokens.inc +++ b/modules/user/user.tokens.inc @@ -52,6 +52,12 @@ function user_token_info() { 'type' => 'date', ); + $user['changed'] = array( + 'name' => t("Changed"), + 'description' => t("The date the user account was changed."), + 'type' => 'date', + ); + return array( 'types' => $types, 'tokens' => array('user' => $user), @@ -90,7 +96,12 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr break; case 'mail': - $replacements[$original] = $sanitize ? check_plain($account->mail) : $account->mail; + if (empty($account->mail)) { + $replacements[$original] = ''; + } + else { + $replacements[$original] = $sanitize ? check_plain($account->mail) : $account->mail; + } break; case 'url': @@ -110,6 +121,11 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr // In the case of user_presave the created date may not yet be set. $replacements[$original] = !empty($account->created) ? format_date($account->created, 'medium', '', NULL, $language_code) : t('not yet created'); break; + + case 'changed': + // In the case of user_presave the created date may not yet be set. + $replacements[$original] = !empty($account->changed) ? format_date($account->changed, 'medium', '', NULL, $language_code) : t('not yet created'); + break; } } @@ -120,6 +136,10 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr if ($registered_tokens = token_find_with_prefix($tokens, 'created')) { $replacements += token_generate('date', $registered_tokens, array('date' => $account->created), $options); } + + if ($changed_tokens = token_find_with_prefix($tokens, 'changed')) { + $replacements += token_generate('date', $changed_tokens, array('date' => $account->changed), $options); + } } if ($type == 'current-user') { diff --git a/modules/user/user.tokens.inc:Zone.Identifier b/modules/user/user.tokens.inc:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/modules/user/user.tokens.inc:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/minimal/minimal.info b/profiles/minimal/minimal.info index d3b5d57599..3e6913a791 100644 --- a/profiles/minimal/minimal.info +++ b/profiles/minimal/minimal.info @@ -5,7 +5,7 @@ core = 7.x dependencies[] = block dependencies[] = dblog -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/profiles/minimal/minimal.info:Zone.Identifier b/profiles/minimal/minimal.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/minimal/minimal.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/minimal/minimal.install:Zone.Identifier b/profiles/minimal/minimal.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/minimal/minimal.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/minimal/minimal.profile:Zone.Identifier b/profiles/minimal/minimal.profile:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/minimal/minimal.profile:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/minimal/translations/README.txt:Zone.Identifier b/profiles/minimal/translations/README.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/minimal/translations/README.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/standard/standard.info b/profiles/standard/standard.info index 917c293abc..887ac6ab78 100644 --- a/profiles/standard/standard.info +++ b/profiles/standard/standard.info @@ -24,7 +24,7 @@ dependencies[] = field_ui dependencies[] = file dependencies[] = rdf -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/profiles/standard/standard.info:Zone.Identifier b/profiles/standard/standard.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/standard/standard.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/standard/standard.install b/profiles/standard/standard.install index ae34eafafe..158c4eaaa0 100644 --- a/profiles/standard/standard.install +++ b/profiles/standard/standard.install @@ -356,7 +356,7 @@ function standard_install() { 'required' => FALSE, 'settings' => array( - 'file_directory' => 'field/image', + 'file_directory' => '[date:custom:Y]-[date:custom:m]', 'file_extensions' => 'png gif jpg jpeg', 'max_filesize' => '', 'max_resolution' => '', diff --git a/profiles/standard/standard.install:Zone.Identifier b/profiles/standard/standard.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/standard/standard.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/standard/standard.profile:Zone.Identifier b/profiles/standard/standard.profile:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/standard/standard.profile:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/standard/translations/README.txt:Zone.Identifier b/profiles/standard/translations/README.txt:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/standard/translations/README.txt:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index ce74c6086f..9bebfb5ca1 100644 --- a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -6,7 +6,7 @@ core = 7.x hidden = TRUE files[] = drupal_system_listing_compatible_test.test -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info:Zone.Identifier b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module:Zone.Identifier b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.test:Zone.Identifier b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.test:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.test:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index 1d735e2773..eaf1fdd30e 100644 --- a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -8,7 +8,7 @@ version = VERSION core = 6.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info:Zone.Identifier b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module:Zone.Identifier b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/testing/testing.info b/profiles/testing/testing.info index ccc3d731df..f8730a516c 100644 --- a/profiles/testing/testing.info +++ b/profiles/testing/testing.info @@ -4,7 +4,7 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2021-07-21 -version = "7.82" +; Information added by Drupal.org packaging script on 2022-09-07 +version = "7.92" project = "drupal" -datestamp = "1626883669" +datestamp = "1662554078" diff --git a/profiles/testing/testing.info:Zone.Identifier b/profiles/testing/testing.info:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/testing/testing.info:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/testing/testing.install:Zone.Identifier b/profiles/testing/testing.install:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/testing/testing.install:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/profiles/testing/testing.profile:Zone.Identifier b/profiles/testing/testing.profile:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/profiles/testing/testing.profile:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index b18fd142ab..bc90233915 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -142,6 +142,8 @@ All arguments are long options. --all Run all available tests. --class Run tests identified by specific class names, instead of group names. + A specific test method can be added, for example, + 'UserAccountLinksUnitTests::testDisabledAccountLink'. --file Run tests identified by specific file names, instead of group names. Specify the path and the extension (i.e. 'modules/user/user.test'). @@ -326,7 +328,11 @@ function simpletest_script_init($server_software) { if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') { // Ensure that any and all environment variables are changed to https://. foreach ($_SERVER as $key => $value) { - $_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]); + // The first time this script runs $_SERVER['SERVER_SOFTWARE'] will be + // NULL, so avoid errors from str_replace(). + if (!empty($_SERVER[$key])) { + $_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]); + } } } @@ -408,10 +414,19 @@ function simpletest_script_run_one_test($test_id, $test_class) { simpletest_classloader_register(); - $test = new $test_class($test_id); + if (strpos($test_class, '::') > 0) { + list($class_name, $method) = explode('::', $test_class, 2); + $methods = array($method); + } + else { + $class_name = $test_class; + // Use empty array to run all the test methods. + $methods = array(); + } + $test = new $class_name($test_id); $test->useSetupInstallationCache = !empty($args['cache']); $test->useSetupModulesCache = !empty($args['cache-modules']); - $test->run(); + $test->run($methods); $info = $test->getInfo(); $had_fails = (isset($test->results['#fail']) && $test->results['#fail'] > 0); @@ -477,8 +492,16 @@ function simpletest_script_get_test_list() { // Check for valid class names. $test_list = array(); foreach ($args['test_names'] as $test_class) { - if (class_exists($test_class)) { - $test_list[] = $test_class; + list($class_name, $method) = explode('::', $test_class, 2); + if (class_exists($class_name)) { + if (empty($method) || method_exists($class_name, $method)) { + $test_list[] = $test_class; + } else { + $all_methods = get_class_methods($class_name); + simpletest_script_print_error('Test method not found: ' . $test_class); + simpletest_script_print_alternatives($method, $all_methods, 6); + exit(1); + } } else { $groups = simpletest_test_get_all(); @@ -486,8 +509,8 @@ function simpletest_script_get_test_list() { foreach ($groups as $group) { $all_classes = array_merge($all_classes, array_keys($group)); } - simpletest_script_print_error('Test class not found: ' . $test_class); - simpletest_script_print_alternatives($test_class, $all_classes, 6); + simpletest_script_print_error('Test class not found: ' . $class_name); + simpletest_script_print_alternatives($class_name, $all_classes, 6); exit(SIMPLETEST_SCRIPT_EXIT_FAILURE); } } @@ -597,9 +620,14 @@ function simpletest_script_reporter_init() { } else { echo "Tests to be run:\n"; - foreach ($test_list as $class_name) { - $info = call_user_func(array($class_name, 'getInfo')); - echo " - " . $info['name'] . ' (' . $class_name . ')' . "\n"; + foreach ($test_list as $test_name) { + if (strpos($test_name, '::') > 0) { + list($test_class, $method) = explode('::', $test_name, 2); + $info = call_user_func(array($test_class, 'getInfo')); + } else { + $info = call_user_func(array($test_name, 'getInfo')); + } + echo " - " . $info['name'] . ' (' . $test_name . ')' . "\n"; } echo "\n"; } diff --git a/scripts/run-tests.sh:Zone.Identifier b/scripts/run-tests.sh:Zone.Identifier new file mode 100644 index 0000000000..7b43b5f55a --- /dev/null +++ b/scripts/run-tests.sh:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +ReferrerUrl=C:\Users\Rob Davis (Work)\Downloads\drupal-7.92.zip diff --git a/sites/all/libraries/vendor/autoload.php b/sites/all/libraries/vendor/autoload.php index 6fbdaae191..b752f3deb7 100644 --- a/sites/all/libraries/vendor/autoload.php +++ b/sites/all/libraries/vendor/autoload.php @@ -2,6 +2,24 @@ // autoload.php @generated by Composer +if (PHP_VERSION_ID < 50600) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, $err); + } elseif (!headers_sent()) { + echo $err; + } + } + trigger_error( + $err, + E_USER_ERROR + ); +} + require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInit737e2bc6f7218ac89562dae1a4248a16::getLoader(); diff --git a/sites/all/libraries/vendor/composer/ClassLoader.php b/sites/all/libraries/vendor/composer/ClassLoader.php index fce8549f07..afef3fa2ad 100644 --- a/sites/all/libraries/vendor/composer/ClassLoader.php +++ b/sites/all/libraries/vendor/composer/ClassLoader.php @@ -37,57 +37,130 @@ * * @author Fabien Potencier * @author Jordi Boggiano - * @see http://www.php-fig.org/psr/psr-0/ - * @see http://www.php-fig.org/psr/psr-4/ + * @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', $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 array $classMap Class to filename map + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void */ public function addClassMap(array $classMap) { @@ -102,9 +175,11 @@ public function addClassMap(array $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 array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories + * @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) { @@ -147,11 +222,13 @@ public function add($prefix, $paths, $prepend = false) * 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 array|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @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) { @@ -195,8 +272,10 @@ public function addPsr4($prefix, $paths, $prepend = false) * 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 array|string $paths The PSR-0 base directories + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void */ public function set($prefix, $paths) { @@ -211,10 +290,12 @@ public function set($prefix, $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 array|string $paths The PSR-4 base directories + * @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) { @@ -234,6 +315,8 @@ public function setPsr4($prefix, $paths) * Turns on searching the include path for class files. * * @param bool $useIncludePath + * + * @return void */ public function setUseIncludePath($useIncludePath) { @@ -256,6 +339,8 @@ public function getUseIncludePath() * that have not been registered with the class map. * * @param bool $classMapAuthoritative + * + * @return void */ public function setClassMapAuthoritative($classMapAuthoritative) { @@ -276,6 +361,8 @@ public function isClassMapAuthoritative() * 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) { @@ -296,25 +383,44 @@ public function getApcuPrefix() * 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 bool|null True if loaded, null otherwise + * @return true|null True if loaded, null otherwise */ public function loadClass($class) { @@ -323,6 +429,8 @@ public function loadClass($class) return true; } + + return null; } /** @@ -367,6 +475,21 @@ public function findFile($class) 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 @@ -438,6 +561,10 @@ private function findFileWithExtension($class, $ext) * Scope isolated include. * * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + * @private */ function includeFile($file) { diff --git a/sites/all/libraries/vendor/composer/InstalledVersions.php b/sites/all/libraries/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000000..c6b54af7ba --- /dev/null +++ b/sites/all/libraries/vendor/composer/InstalledVersions.php @@ -0,0 +1,352 @@ + + * 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` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-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}|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, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + 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, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, 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, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = require __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/sites/all/libraries/vendor/composer/autoload_classmap.php b/sites/all/libraries/vendor/composer/autoload_classmap.php index b9461a6371..7ad24ff267 100644 --- a/sites/all/libraries/vendor/composer/autoload_classmap.php +++ b/sites/all/libraries/vendor/composer/autoload_classmap.php @@ -2,8 +2,15 @@ // autoload_classmap.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname(dirname(dirname(dirname($vendorDir)))); return array( + 'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', + 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', ); diff --git a/sites/all/libraries/vendor/composer/autoload_files.php b/sites/all/libraries/vendor/composer/autoload_files.php index ab9922c39a..e2392f3a12 100644 --- a/sites/all/libraries/vendor/composer/autoload_files.php +++ b/sites/all/libraries/vendor/composer/autoload_files.php @@ -2,11 +2,14 @@ // autoload_files.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname(dirname(dirname(dirname($vendorDir)))); return array( + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', ); diff --git a/sites/all/libraries/vendor/composer/autoload_namespaces.php b/sites/all/libraries/vendor/composer/autoload_namespaces.php index c503234eed..95191c943c 100644 --- a/sites/all/libraries/vendor/composer/autoload_namespaces.php +++ b/sites/all/libraries/vendor/composer/autoload_namespaces.php @@ -2,7 +2,7 @@ // autoload_namespaces.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname(dirname(dirname(dirname($vendorDir)))); return array( diff --git a/sites/all/libraries/vendor/composer/autoload_psr4.php b/sites/all/libraries/vendor/composer/autoload_psr4.php index fd508720d4..474b9da6ae 100644 --- a/sites/all/libraries/vendor/composer/autoload_psr4.php +++ b/sites/all/libraries/vendor/composer/autoload_psr4.php @@ -2,13 +2,21 @@ // autoload_psr4.php @generated by Composer -$vendorDir = dirname(dirname(__FILE__)); +$vendorDir = dirname(__DIR__); $baseDir = dirname(dirname(dirname(dirname($vendorDir)))); return array( + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), + 'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'), + 'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), + 'Symfony\\Contracts\\HttpClient\\' => array($vendorDir . '/symfony/http-client-contracts'), + 'Symfony\\Component\\HttpClient\\' => array($vendorDir . '/symfony/http-client'), 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), + 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), 'Michelf\\' => array($vendorDir . '/michelf/php-markdown/Michelf'), + 'IucnApi\\' => array($vendorDir . '/jbroutier/iucn-api-client/src'), 'Http\\Promise\\' => array($vendorDir . '/php-http/promise/src'), 'Http\\Client\\' => array($vendorDir . '/php-http/httplug/src'), 'Http\\Adapter\\Guzzle6\\' => array($vendorDir . '/php-http/guzzle6-adapter/src'), @@ -16,4 +24,6 @@ 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), 'Github\\' => array($vendorDir . '/knplabs/github-api/lib/Github'), + 'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'), + 'Doctrine\\Common\\Collections\\' => array($vendorDir . '/doctrine/collections/lib/Doctrine/Common/Collections'), ); diff --git a/sites/all/libraries/vendor/composer/autoload_real.php b/sites/all/libraries/vendor/composer/autoload_real.php index c3458d7606..b029a9c71d 100644 --- a/sites/all/libraries/vendor/composer/autoload_real.php +++ b/sites/all/libraries/vendor/composer/autoload_real.php @@ -13,45 +13,27 @@ public static function loadClassLoader($class) } } + /** + * @return \Composer\Autoload\ClassLoader + */ public static function getLoader() { if (null !== self::$loader) { return self::$loader; } + require __DIR__ . '/platform_check.php'; + spl_autoload_register(array('ComposerAutoloaderInit737e2bc6f7218ac89562dae1a4248a16', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); spl_autoload_unregister(array('ComposerAutoloaderInit737e2bc6f7218ac89562dae1a4248a16', 'loadClassLoader')); - $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); - if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; - - call_user_func(\Composer\Autoload\ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16::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); - } - } + require __DIR__ . '/autoload_static.php'; + call_user_func(\Composer\Autoload\ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16::getInitializer($loader)); $loader->register(true); - if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16::$files; - } else { - $includeFiles = require __DIR__ . '/autoload_files.php'; - } + $includeFiles = \Composer\Autoload\ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16::$files; foreach ($includeFiles as $fileIdentifier => $file) { composerRequire737e2bc6f7218ac89562dae1a4248a16($fileIdentifier, $file); } @@ -60,11 +42,16 @@ public static function getLoader() } } +/** + * @param string $fileIdentifier + * @param string $file + * @return void + */ function composerRequire737e2bc6f7218ac89562dae1a4248a16($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - require $file; - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; } } diff --git a/sites/all/libraries/vendor/composer/autoload_static.php b/sites/all/libraries/vendor/composer/autoload_static.php index 31676ac140..f6a3685334 100644 --- a/sites/all/libraries/vendor/composer/autoload_static.php +++ b/sites/all/libraries/vendor/composer/autoload_static.php @@ -7,24 +7,38 @@ class ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16 { public static $files = array ( + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', ); public static $prefixLengthsPsr4 = array ( 'S' => array ( + 'Symfony\\Polyfill\\Php80\\' => 23, + 'Symfony\\Polyfill\\Php73\\' => 23, + 'Symfony\\Contracts\\Service\\' => 26, + 'Symfony\\Contracts\\HttpClient\\' => 29, + 'Symfony\\Component\\HttpClient\\' => 29, 'Symfony\\Component\\EventDispatcher\\' => 34, ), 'P' => array ( + 'Psr\\Log\\' => 8, 'Psr\\Http\\Message\\' => 17, + 'Psr\\Container\\' => 14, ), 'M' => array ( 'Michelf\\' => 8, ), + 'I' => + array ( + 'IucnApi\\' => 8, + ), 'H' => array ( 'Http\\Promise\\' => 13, @@ -38,21 +52,58 @@ class ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16 'GuzzleHttp\\' => 11, 'Github\\' => 7, ), + 'D' => + array ( + 'Doctrine\\Deprecations\\' => 22, + 'Doctrine\\Common\\Collections\\' => 28, + ), ); public static $prefixDirsPsr4 = array ( + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), + 'Symfony\\Polyfill\\Php73\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php73', + ), + 'Symfony\\Contracts\\Service\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/service-contracts', + ), + 'Symfony\\Contracts\\HttpClient\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/http-client-contracts', + ), + 'Symfony\\Component\\HttpClient\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/http-client', + ), 'Symfony\\Component\\EventDispatcher\\' => array ( 0 => __DIR__ . '/..' . '/symfony/event-dispatcher', ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', + ), 'Psr\\Http\\Message\\' => array ( 0 => __DIR__ . '/..' . '/psr/http-message/src', ), + 'Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), 'Michelf\\' => array ( 0 => __DIR__ . '/..' . '/michelf/php-markdown/Michelf', ), + 'IucnApi\\' => + array ( + 0 => __DIR__ . '/..' . '/jbroutier/iucn-api-client/src', + ), 'Http\\Promise\\' => array ( 0 => __DIR__ . '/..' . '/php-http/promise/src', @@ -81,6 +132,14 @@ class ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16 array ( 0 => __DIR__ . '/..' . '/knplabs/github-api/lib/Github', ), + 'Doctrine\\Deprecations\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations', + ), + 'Doctrine\\Common\\Collections\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/collections/lib/Doctrine/Common/Collections', + ), ); public static $prefixesPsr0 = array ( @@ -97,12 +156,23 @@ class ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16 ), ); + public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', + 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', + ); + public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { $loader->prefixLengthsPsr4 = ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16::$prefixDirsPsr4; $loader->prefixesPsr0 = ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16::$prefixesPsr0; + $loader->classMap = ComposerStaticInit737e2bc6f7218ac89562dae1a4248a16::$classMap; }, null, ClassLoader::class); } diff --git a/sites/all/libraries/vendor/composer/installed.json b/sites/all/libraries/vendor/composer/installed.json index 4087e7253d..039eb51db0 100644 --- a/sites/all/libraries/vendor/composer/installed.json +++ b/sites/all/libraries/vendor/composer/installed.json @@ -1,685 +1,1475 @@ -[ - { - "name": "guzzle/guzzle", - "version": "v3.9.3", - "version_normalized": "3.9.3.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle3.git", - "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", - "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "php": ">=5.3.3", - "symfony/event-dispatcher": "~2.1" - }, - "replace": { - "guzzle/batch": "self.version", - "guzzle/cache": "self.version", - "guzzle/common": "self.version", - "guzzle/http": "self.version", - "guzzle/inflection": "self.version", - "guzzle/iterator": "self.version", - "guzzle/log": "self.version", - "guzzle/parser": "self.version", - "guzzle/plugin": "self.version", - "guzzle/plugin-async": "self.version", - "guzzle/plugin-backoff": "self.version", - "guzzle/plugin-cache": "self.version", - "guzzle/plugin-cookie": "self.version", - "guzzle/plugin-curlauth": "self.version", - "guzzle/plugin-error-response": "self.version", - "guzzle/plugin-history": "self.version", - "guzzle/plugin-log": "self.version", - "guzzle/plugin-md5": "self.version", - "guzzle/plugin-mock": "self.version", - "guzzle/plugin-oauth": "self.version", - "guzzle/service": "self.version", - "guzzle/stream": "self.version" - }, - "require-dev": { - "doctrine/cache": "~1.3", - "monolog/monolog": "~1.0", - "phpunit/phpunit": "3.7.*", - "psr/log": "~1.0", - "symfony/class-loader": "~2.1", - "zendframework/zend-cache": "2.*,<2.3", - "zendframework/zend-log": "2.*,<2.3" - }, - "suggest": { - "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." - }, - "time": "2015-03-18T18:23:50+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.9-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "Guzzle": "src/", - "Guzzle\\Tests": "tests/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Guzzle Community", - "homepage": "https://github.com/guzzle/guzzle/contributors" - } - ], - "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "abandoned": "guzzlehttp/guzzle" - }, - { - "name": "guzzlehttp/guzzle", - "version": "6.3.3", - "version_normalized": "6.3.3.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", - "shasum": "" - }, - "require": { - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4", - "php": ">=5.5" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" - }, - "suggest": { - "psr/log": "Required for using the Log middleware" - }, - "time": "2018-04-22T15:46:56+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.3-dev" - } - }, - "installation-source": "dist", - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "GuzzleHttp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ] - }, - { - "name": "guzzlehttp/promises", - "version": "v1.3.1", - "version_normalized": "1.3.1.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0" - }, - "time": "2016-12-20T10:07:11+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle promises library", - "keywords": [ - "promise" - ] - }, - { - "name": "guzzlehttp/psr7", - "version": "1.4.2", - "version_normalized": "1.4.2.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "shasum": "" - }, - "require": { - "php": ">=5.4.0", - "psr/http-message": "~1.0" - }, - "provide": { - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "time": "2017-03-20T17:10:46+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "Tobias Schultze", - "homepage": "https://github.com/Tobion" - } - ], - "description": "PSR-7 message implementation that also provides common utility methods", - "keywords": [ - "http", - "message", - "request", - "response", - "stream", - "uri", - "url" - ] - }, - { - "name": "knplabs/github-api", - "version": "1.7.1", - "version_normalized": "1.7.1.0", - "source": { - "type": "git", - "url": "https://github.com/KnpLabs/php-github-api.git", - "reference": "98d0bcd2c4c96a40ded9081f8f6289907f73823c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/KnpLabs/php-github-api/zipball/98d0bcd2c4c96a40ded9081f8f6289907f73823c", - "reference": "98d0bcd2c4c96a40ded9081f8f6289907f73823c", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "guzzle/guzzle": "~3.7", - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0", - "sllh/php-cs-fixer-styleci-bridge": "~1.3" - }, - "suggest": { - "knplabs/gaufrette": "Needed for optional Gaufrette cache" - }, - "time": "2016-07-26T08:49:38+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.8.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Github\\": "lib/Github/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Thibault Duplessis", - "email": "thibault.duplessis@gmail.com", - "homepage": "http://ornicar.github.com" - }, - { - "name": "KnpLabs Team", - "homepage": "http://knplabs.com" - } - ], - "description": "GitHub API v3 client", - "homepage": "https://github.com/KnpLabs/php-github-api", - "keywords": [ - "api", - "gh", - "gist", - "github" - ] - }, - { - "name": "michelf/php-markdown", - "version": "1.8.0", - "version_normalized": "1.8.0.0", - "source": { - "type": "git", - "url": "https://github.com/michelf/php-markdown.git", - "reference": "01ab082b355bf188d907b9929cd99b2923053495" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/michelf/php-markdown/zipball/01ab082b355bf188d907b9929cd99b2923053495", - "reference": "01ab082b355bf188d907b9929cd99b2923053495", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "time": "2018-01-15T00:49:33+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Michelf\\": "Michelf/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Michel Fortin", - "email": "michel.fortin@michelf.ca", - "homepage": "https://michelf.ca/", - "role": "Developer" - }, - { - "name": "John Gruber", - "homepage": "https://daringfireball.net/" - } - ], - "description": "PHP Markdown", - "homepage": "https://michelf.ca/projects/php-markdown/", - "keywords": [ - "markdown" - ] - }, - { - "name": "php-http/guzzle6-adapter", - "version": "v1.1.1", - "version_normalized": "1.1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/guzzle6-adapter.git", - "reference": "a56941f9dc6110409cfcddc91546ee97039277ab" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/guzzle6-adapter/zipball/a56941f9dc6110409cfcddc91546ee97039277ab", - "reference": "a56941f9dc6110409cfcddc91546ee97039277ab", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": "^6.0", - "php": ">=5.5.0", - "php-http/httplug": "^1.0" - }, - "provide": { - "php-http/async-client-implementation": "1.0", - "php-http/client-implementation": "1.0" - }, - "require-dev": { - "ext-curl": "*", - "php-http/adapter-integration-tests": "^0.4" - }, - "time": "2016-05-10T06:13:32+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Http\\Adapter\\Guzzle6\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - }, - { - "name": "David de Boer", - "email": "david@ddeboer.nl" - } - ], - "description": "Guzzle 6 HTTP Adapter", - "homepage": "http://httplug.io", - "keywords": [ - "Guzzle", - "http" - ] - }, - { - "name": "php-http/httplug", - "version": "v1.1.0", - "version_normalized": "1.1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/httplug.git", - "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/httplug/zipball/1c6381726c18579c4ca2ef1ec1498fdae8bdf018", - "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018", - "shasum": "" - }, - "require": { - "php": ">=5.4", - "php-http/promise": "^1.0", - "psr/http-message": "^1.0" - }, - "require-dev": { - "henrikbjorn/phpspec-code-coverage": "^1.0", - "phpspec/phpspec": "^2.4" - }, - "time": "2016-08-31T08:30:17+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Eric GELOEN", - "email": "geloen.eric@gmail.com" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "HTTPlug, the HTTP client abstraction for PHP", - "homepage": "http://httplug.io", - "keywords": [ - "client", - "http" - ] - }, - { - "name": "php-http/promise", - "version": "v1.0.0", - "version_normalized": "1.0.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/promise.git", - "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/promise/zipball/dc494cdc9d7160b9a09bd5573272195242ce7980", - "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980", - "shasum": "" - }, - "require-dev": { - "henrikbjorn/phpspec-code-coverage": "^1.0", - "phpspec/phpspec": "^2.4" - }, - "time": "2016-01-26T13:27:02+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Http\\Promise\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - }, - { - "name": "Joel Wurtz", - "email": "joel.wurtz@gmail.com" - } - ], - "description": "Promise used for asynchronous HTTP requests", - "homepage": "http://httplug.io", - "keywords": [ - "promise" - ] - }, - { - "name": "psr/http-message", - "version": "1.0.1", - "version_normalized": "1.0.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "time": "2016-08-06T14:39:51+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ] - }, - { - "name": "symfony/event-dispatcher", - "version": "v2.8.48", - "version_normalized": "2.8.48.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0", - "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^2.0.5|~3.0.0", - "symfony/dependency-injection": "~2.6|~3.0.0", - "symfony/expression-language": "~2.6|~3.0.0", - "symfony/stopwatch": "~2.3|~3.0.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "time": "2018-11-21T14:20:20+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "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 EventDispatcher Component", - "homepage": "https://symfony.com" - } -] +{ + "packages": [ + { + "name": "doctrine/collections", + "version": "1.8.0", + "version_normalized": "1.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "2b44dd4cbca8b5744327de78bafef5945c7e7b5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/2b44dd4cbca8b5744327de78bafef5945c7e7b5e", + "reference": "2b44dd4cbca8b5744327de78bafef5945c7e7b5e", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^0.5.3 || ^1", + "php": "^7.1.3 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0 || ^10.0", + "phpstan/phpstan": "^1.4.8", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.1.5", + "vimeo/psalm": "^4.22" + }, + "time": "2022-09-01T20:12:10+00:00", + "type": "library", + "installation-source": "source", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "keywords": [ + "array", + "collections", + "iterators", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/collections/issues", + "source": "https://github.com/doctrine/collections/tree/1.8.0" + }, + "install-path": "../doctrine/collections" + }, + { + "name": "doctrine/deprecations", + "version": "v1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "time": "2022-05-02T15:47:09+00:00", + "type": "library", + "installation-source": "source", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + }, + "install-path": "../doctrine/deprecations" + }, + { + "name": "guzzle/guzzle", + "version": "v3.9.3", + "version_normalized": "3.9.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": "~2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", + "phpunit/phpunit": "3.7.*", + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." + }, + "time": "2015-03-18T18:23:50+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "abandoned": "guzzlehttp/guzzle", + "install-path": "../guzzle/guzzle" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.3", + "version_normalized": "6.3.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "time": "2018-04-22T15:46:56+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.3-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "install-path": "../guzzlehttp/guzzle" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "version_normalized": "1.3.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "time": "2016-12-20T10:07:11+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "install-path": "../guzzlehttp/promises" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.4.2", + "version_normalized": "1.4.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "time": "2017-03-20T17:10:46+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "install-path": "../guzzlehttp/psr7" + }, + { + "name": "jbroutier/iucn-api-client", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/jbroutier/iucn-api-client.git", + "reference": "d2b95768b40d3c4606030a626e7c99393deef1de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jbroutier/iucn-api-client/zipball/d2b95768b40d3c4606030a626e7c99393deef1de", + "reference": "d2b95768b40d3c4606030a626e7c99393deef1de", + "shasum": "" + }, + "require": { + "doctrine/collections": "^1.7.2", + "php": "^7.4|^8.0", + "symfony/http-client": "^5.4|^6.0" + }, + "require-dev": { + "ekino/phpstan-banned-code": "^1.0.0", + "ext-json": "*", + "phpstan/extension-installer": "^1.1.0", + "phpstan/phpstan": "^1.8.4", + "phpstan/phpstan-deprecation-rules": "^1.0.0", + "phpstan/phpstan-phpunit": "^1.1.1", + "phpstan/phpstan-strict-rules": "^1.4.3", + "phpunit/phpunit": "^9.5.24" + }, + "time": "2022-09-09T16:48:06+00:00", + "type": "library", + "installation-source": "source", + "autoload": { + "psr-4": { + "IucnApi\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérémie BROUTIER", + "email": "jeremie.broutier@posteo.net", + "homepage": "https://github.com/jbroutier", + "role": "developer" + } + ], + "description": "A PHP client to retrieve data from The IUCN Red List of Threatened Species™.", + "support": { + "issues": "https://github.com/jbroutier/iucn-api-client/issues", + "source": "https://github.com/jbroutier/iucn-api-client/tree/1.0.0" + }, + "install-path": "../jbroutier/iucn-api-client" + }, + { + "name": "knplabs/github-api", + "version": "1.7.1", + "version_normalized": "1.7.1.0", + "source": { + "type": "git", + "url": "https://github.com/KnpLabs/php-github-api.git", + "reference": "98d0bcd2c4c96a40ded9081f8f6289907f73823c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/KnpLabs/php-github-api/zipball/98d0bcd2c4c96a40ded9081f8f6289907f73823c", + "reference": "98d0bcd2c4c96a40ded9081f8f6289907f73823c", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "guzzle/guzzle": "~3.7", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "sllh/php-cs-fixer-styleci-bridge": "~1.3" + }, + "suggest": { + "knplabs/gaufrette": "Needed for optional Gaufrette cache" + }, + "time": "2016-07-26T08:49:38+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Github\\": "lib/Github/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Thibault Duplessis", + "email": "thibault.duplessis@gmail.com", + "homepage": "http://ornicar.github.com" + }, + { + "name": "KnpLabs Team", + "homepage": "http://knplabs.com" + } + ], + "description": "GitHub API v3 client", + "homepage": "https://github.com/KnpLabs/php-github-api", + "keywords": [ + "api", + "gh", + "gist", + "github" + ], + "install-path": "../knplabs/github-api" + }, + { + "name": "michelf/php-markdown", + "version": "1.8.0", + "version_normalized": "1.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/michelf/php-markdown.git", + "reference": "01ab082b355bf188d907b9929cd99b2923053495" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/michelf/php-markdown/zipball/01ab082b355bf188d907b9929cd99b2923053495", + "reference": "01ab082b355bf188d907b9929cd99b2923053495", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2018-01-15T00:49:33+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Michelf\\": "Michelf/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Michel Fortin", + "email": "michel.fortin@michelf.ca", + "homepage": "https://michelf.ca/", + "role": "Developer" + }, + { + "name": "John Gruber", + "homepage": "https://daringfireball.net/" + } + ], + "description": "PHP Markdown", + "homepage": "https://michelf.ca/projects/php-markdown/", + "keywords": [ + "markdown" + ], + "install-path": "../michelf/php-markdown" + }, + { + "name": "php-http/guzzle6-adapter", + "version": "v1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/guzzle6-adapter.git", + "reference": "a56941f9dc6110409cfcddc91546ee97039277ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/guzzle6-adapter/zipball/a56941f9dc6110409cfcddc91546ee97039277ab", + "reference": "a56941f9dc6110409cfcddc91546ee97039277ab", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "php": ">=5.5.0", + "php-http/httplug": "^1.0" + }, + "provide": { + "php-http/async-client-implementation": "1.0", + "php-http/client-implementation": "1.0" + }, + "require-dev": { + "ext-curl": "*", + "php-http/adapter-integration-tests": "^0.4" + }, + "time": "2016-05-10T06:13:32+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Http\\Adapter\\Guzzle6\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + }, + { + "name": "David de Boer", + "email": "david@ddeboer.nl" + } + ], + "description": "Guzzle 6 HTTP Adapter", + "homepage": "http://httplug.io", + "keywords": [ + "Guzzle", + "http" + ], + "install-path": "../php-http/guzzle6-adapter" + }, + { + "name": "php-http/httplug", + "version": "v1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/httplug.git", + "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/httplug/zipball/1c6381726c18579c4ca2ef1ec1498fdae8bdf018", + "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "php-http/promise": "^1.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "^1.0", + "phpspec/phpspec": "^2.4" + }, + "time": "2016-08-31T08:30:17+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eric GELOEN", + "email": "geloen.eric@gmail.com" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "HTTPlug, the HTTP client abstraction for PHP", + "homepage": "http://httplug.io", + "keywords": [ + "client", + "http" + ], + "install-path": "../php-http/httplug" + }, + { + "name": "php-http/promise", + "version": "v1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/promise.git", + "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/promise/zipball/dc494cdc9d7160b9a09bd5573272195242ce7980", + "reference": "dc494cdc9d7160b9a09bd5573272195242ce7980", + "shasum": "" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "^1.0", + "phpspec/phpspec": "^2.4" + }, + "time": "2016-01-26T13:27:02+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Http\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + }, + { + "name": "Joel Wurtz", + "email": "joel.wurtz@gmail.com" + } + ], + "description": "Promise used for asynchronous HTTP requests", + "homepage": "http://httplug.io", + "keywords": [ + "promise" + ], + "install-path": "../php-http/promise" + }, + { + "name": "psr/container", + "version": "1.1.2", + "version_normalized": "1.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "time": "2021-11-05T16:50:12+00:00", + "type": "library", + "installation-source": "source", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "install-path": "../psr/container" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-08-06T14:39:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "install-path": "../psr/http-message" + }, + { + "name": "psr/log", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2021-05-03T11:20:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "source", + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "install-path": "../psr/log" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2022-01-02T09:53:40+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "source", + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + }, + "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/deprecation-contracts" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.8.48", + "version_normalized": "2.8.48.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0", + "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "time": "2018-11-21T14:20:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "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 EventDispatcher Component", + "homepage": "https://symfony.com", + "install-path": "../symfony/event-dispatcher" + }, + { + "name": "symfony/http-client", + "version": "v5.4.15", + "version_normalized": "5.4.15.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "8f29b0f06c9ff48c8431e78eb90c8bd6f82cb12b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/8f29b0f06c9ff48c8431e78eb90c8bd6f82cb12b", + "reference": "8f29b0f06c9ff48c8431e78eb90c8bd6f82cb12b", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/http-client-contracts": "^2.4", + "symfony/polyfill-php73": "^1.11", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.0|^2|^3" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "2.4" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4.13|^5.1.5|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "time": "2022-10-25T16:22:13+00:00", + "type": "library", + "installation-source": "source", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-client/tree/v5.4.15" + }, + "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/http-client" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "time": "2022-04-12T15:48:08+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "source", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "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/http-client-contracts" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.27.0", + "version_normalized": "1.27.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2022-11-03T14:55:06+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "source", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" + }, + "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/polyfill-php73" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "version_normalized": "1.27.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2022-11-03T14:55:06+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "source", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "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/polyfill-php80" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "time": "2022-05-30T19:17:29+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "source", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "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/service-contracts" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/sites/all/libraries/vendor/composer/installed.php b/sites/all/libraries/vendor/composer/installed.php new file mode 100644 index 0000000000..f8257a5546 --- /dev/null +++ b/sites/all/libraries/vendor/composer/installed.php @@ -0,0 +1,385 @@ + array( + 'name' => 'naturalhistorymuseum/scratchpads2', + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => 'e3a9e1bd0acf65734d9fc9845749e77a4de7b166', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../../../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + 'doctrine/collections' => array( + 'pretty_version' => '1.8.0', + 'version' => '1.8.0.0', + 'reference' => '2b44dd4cbca8b5744327de78bafef5945c7e7b5e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/collections', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'doctrine/deprecations' => array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'reference' => '0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de', + 'type' => 'library', + 'install_path' => __DIR__ . '/../doctrine/deprecations', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzle/batch' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/cache' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/common' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/guzzle' => array( + 'pretty_version' => 'v3.9.3', + 'version' => '3.9.3.0', + 'reference' => '0645b70d953bc1c067bbc8d5bc53194706b628d9', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzle/guzzle', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzle/http' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/inflection' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/iterator' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/log' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/parser' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-async' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-backoff' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-cache' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-cookie' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-curlauth' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-error-response' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-history' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-log' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-md5' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-mock' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/plugin-oauth' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/service' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzle/stream' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => 'v3.9.3', + ), + ), + 'guzzlehttp/guzzle' => array( + 'pretty_version' => '6.3.3', + 'version' => '6.3.3.0', + 'reference' => '407b0cb880ace85c9b63c5f9551db498cb2d50ba', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/promises' => array( + 'pretty_version' => 'v1.3.1', + 'version' => '1.3.1.0', + 'reference' => 'a59da6cf61d80060647ff4d3eb2c03a2bc694646', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/promises', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/psr7' => array( + 'pretty_version' => '1.4.2', + 'version' => '1.4.2.0', + 'reference' => 'f5b8a8512e2b58b0071a7280e39f14f72e05d87c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/psr7', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'jbroutier/iucn-api-client' => array( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'reference' => 'd2b95768b40d3c4606030a626e7c99393deef1de', + 'type' => 'library', + 'install_path' => __DIR__ . '/../jbroutier/iucn-api-client', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'knplabs/github-api' => array( + 'pretty_version' => '1.7.1', + 'version' => '1.7.1.0', + 'reference' => '98d0bcd2c4c96a40ded9081f8f6289907f73823c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../knplabs/github-api', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'michelf/php-markdown' => array( + 'pretty_version' => '1.8.0', + 'version' => '1.8.0.0', + 'reference' => '01ab082b355bf188d907b9929cd99b2923053495', + 'type' => 'library', + 'install_path' => __DIR__ . '/../michelf/php-markdown', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'naturalhistorymuseum/scratchpads2' => array( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => 'e3a9e1bd0acf65734d9fc9845749e77a4de7b166', + 'type' => 'project', + 'install_path' => __DIR__ . '/../../../../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'php-http/async-client-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + 1 => '*', + ), + ), + 'php-http/client-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + 1 => '*', + ), + ), + 'php-http/guzzle6-adapter' => array( + 'pretty_version' => 'v1.1.1', + 'version' => '1.1.1.0', + 'reference' => 'a56941f9dc6110409cfcddc91546ee97039277ab', + 'type' => 'library', + 'install_path' => __DIR__ . '/../php-http/guzzle6-adapter', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'php-http/httplug' => array( + 'pretty_version' => 'v1.1.0', + 'version' => '1.1.0.0', + 'reference' => '1c6381726c18579c4ca2ef1ec1498fdae8bdf018', + 'type' => 'library', + 'install_path' => __DIR__ . '/../php-http/httplug', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'php-http/promise' => array( + 'pretty_version' => 'v1.0.0', + 'version' => '1.0.0.0', + 'reference' => 'dc494cdc9d7160b9a09bd5573272195242ce7980', + 'type' => 'library', + 'install_path' => __DIR__ . '/../php-http/promise', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/container' => array( + 'pretty_version' => '1.1.2', + 'version' => '1.1.2.0', + 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/container', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-client-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/http-message' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-message', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-message-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/log' => array( + 'pretty_version' => '1.1.4', + 'version' => '1.1.4.0', + 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/deprecation-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher' => array( + 'pretty_version' => 'v2.8.48', + 'version' => '2.8.48.0', + 'reference' => 'a77e974a5fecb4398833b0709210e3d5e334ffb0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/event-dispatcher', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/http-client' => array( + 'pretty_version' => 'v5.4.15', + 'version' => '5.4.15.0', + 'reference' => '8f29b0f06c9ff48c8431e78eb90c8bd6f82cb12b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/http-client', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/http-client-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => 'ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/http-client-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/http-client-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '2.4', + ), + ), + 'symfony/polyfill-php73' => array( + 'pretty_version' => 'v1.27.0', + 'version' => '1.27.0.0', + 'reference' => '9e8ecb5f92152187c4799efd3c96b78ccab18ff9', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php73', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php80' => array( + 'pretty_version' => 'v1.27.0', + 'version' => '1.27.0.0', + 'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php80', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/service-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => '4b426aac47d6427cc1a1d0f7e2ac724627f5966c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/service-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/sites/all/libraries/vendor/composer/platform_check.php b/sites/all/libraries/vendor/composer/platform_check.php new file mode 100644 index 0000000000..0204806b37 --- /dev/null +++ b/sites/all/libraries/vendor/composer/platform_check.php @@ -0,0 +1,29 @@ += 70400)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.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/sites/all/libraries/vendor/doctrine/collections/.doctrine-project.json b/sites/all/libraries/vendor/doctrine/collections/.doctrine-project.json new file mode 100644 index 0000000000..9c89e50c0e --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/.doctrine-project.json @@ -0,0 +1,32 @@ +{ + "active": true, + "name": "Collections", + "slug": "collections", + "docsSlug": "doctrine-collections", + "versions": [ + { + "name": "2.0", + "branchName": "2.0.x", + "slug": "latest", + "upcoming": true + }, + { + "name": "1.8", + "branchName": "1.8.x", + "slug": "1.8", + "upcoming": true + }, + { + "name": "1.7", + "branchName": "1.7.x", + "slug": "1.7", + "current": true + }, + { + "name": "1.6", + "branchName": "1.6.x", + "slug": "1.6", + "maintained": false + } + ] +} diff --git a/sites/all/libraries/vendor/doctrine/collections/CONTRIBUTING.md b/sites/all/libraries/vendor/doctrine/collections/CONTRIBUTING.md new file mode 100644 index 0000000000..7a0a8c9a1a --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/CONTRIBUTING.md @@ -0,0 +1,44 @@ +# Contribute to Doctrine + +Thank you for contributing to Doctrine! + +Before we can merge your Pull-Request here are some guidelines that you need to follow. +These guidelines exist not to annoy you, but to keep the code base clean, +unified and future proof. + +## Coding Standard + +We use the [Doctrine Coding Standard](https://github.com/doctrine/coding-standard). + +## Unit-Tests + +Please try to add a test for your pull-request. + +* If you want to contribute new functionality add unit- or functional tests + depending on the scope of the feature. + +You can run the unit-tests by calling ``vendor/bin/phpunit`` from the root of the project. +It will run all the project tests. + +In order to do that, you will need a fresh copy of doctrine/collections, and you +will have to run a composer installation in the project: + +```sh +git clone git@github.com:doctrine/collections.git +cd collections +curl -sS https://getcomposer.org/installer | php -- +./composer.phar install +``` + +## Github Actions + +We automatically run your pull request through Github Actions against supported +PHP versions. If you break the tests, we cannot merge your code, so please make +sure that your code is working before opening up a Pull-Request. + +## Getting merged + +Please allow us time to review your pull requests. We will give our best to review +everything as fast as possible, but cannot always live up to our own expectations. + +Thank you very much again for your contribution! diff --git a/sites/all/libraries/vendor/doctrine/collections/LICENSE b/sites/all/libraries/vendor/doctrine/collections/LICENSE new file mode 100644 index 0000000000..5e781fce4b --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2013 Doctrine Project + +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/sites/all/libraries/vendor/doctrine/collections/README.md b/sites/all/libraries/vendor/doctrine/collections/README.md new file mode 100644 index 0000000000..048fb614df --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/README.md @@ -0,0 +1,6 @@ +# Doctrine Collections + +[![Build Status](https://github.com/doctrine/collections/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/collections/actions) +[![Code Coverage](https://codecov.io/gh/doctrine/collections/branch/2.0.x/graph/badge.svg)](https://codecov.io/gh/doctrine/collections/branch/2.0.x) + +Collections Abstraction library diff --git a/sites/all/libraries/vendor/doctrine/collections/composer.json b/sites/all/libraries/vendor/doctrine/collections/composer.json new file mode 100644 index 0000000000..d9422dd119 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/composer.json @@ -0,0 +1,61 @@ +{ + "name": "doctrine/collections", + "description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.", + "license": "MIT", + "type": "library", + "keywords": [ + "php", + "collections", + "array", + "iterators" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "homepage": "https://www.doctrine-project.org/projects/collections.html", + "require": { + "php": "^7.1.3 || ^8.0", + "doctrine/deprecations": "^0.5.3 || ^1" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0 || ^10.0", + "phpstan/phpstan": "^1.4.8", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.1.5", + "vimeo/psalm": "^4.22" + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" + } + }, + "autoload-dev": { + "psr-4": { + "Doctrine\\Tests\\": "tests/Doctrine/Tests" + } + }, + "config": { + "allow-plugins": { + "composer/package-versions-deprecated": true, + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/docs/en/derived-collections.rst b/sites/all/libraries/vendor/doctrine/collections/docs/en/derived-collections.rst new file mode 100644 index 0000000000..03d9da5d61 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/docs/en/derived-collections.rst @@ -0,0 +1,26 @@ +Derived Collections +=================== + +You can create custom collection classes by extending the +``Doctrine\Common\Collections\ArrayCollection`` class. If the +``__construct`` semantics are different from the default ``ArrayCollection`` +you can override the ``createFrom`` method: + +.. code-block:: php + final class DerivedArrayCollection extends ArrayCollection + { + /** @var \stdClass */ + private $foo; + + public function __construct(\stdClass $foo, array $elements = []) + { + $this->foo = $foo; + + parent::__construct($elements); + } + + protected function createFrom(array $elements) : self + { + return new static($this->foo, $elements); + } + } diff --git a/sites/all/libraries/vendor/doctrine/collections/docs/en/expression-builder.rst b/sites/all/libraries/vendor/doctrine/collections/docs/en/expression-builder.rst new file mode 100644 index 0000000000..ad4055b543 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/docs/en/expression-builder.rst @@ -0,0 +1,173 @@ +Expression Builder +================== + +The Expression Builder is a convenient fluent interface for +building expressions to be used with the ``Doctrine\Common\Collections\Criteria`` +class: + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $criteria = new Criteria(); + $criteria->where($expressionBuilder->eq('name', 'jwage')); + $criteria->orWhere($expressionBuilder->eq('name', 'romanb')); + + $collection->matching($criteria); + +The ``ExpressionBuilder`` has the following API: + +andX +---- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->andX( + $expressionBuilder->eq('foo', 1), + $expressionBuilder->eq('bar', 1) + ); + + $collection->matching(new Criteria($expression)); + +orX +--- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->orX( + $expressionBuilder->eq('foo', 1), + $expressionBuilder->eq('bar', 1) + ); + + $collection->matching(new Criteria($expression)); + +eq +--- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->eq('foo', 1); + + $collection->matching(new Criteria($expression)); + +gt +--- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->gt('foo', 1); + + $collection->matching(new Criteria($expression)); + +lt +--- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->lt('foo', 1); + + $collection->matching(new Criteria($expression)); + +gte +--- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->gte('foo', 1); + + $collection->matching(new Criteria($expression)); + +lte +--- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->lte('foo', 1); + + $collection->matching(new Criteria($expression)); + +neq +--- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->neq('foo', 1); + + $collection->matching(new Criteria($expression)); + +isNull +------ + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->isNull('foo'); + + $collection->matching(new Criteria($expression)); + +in +--- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->in('foo', ['value1', 'value2']); + + $collection->matching(new Criteria($expression)); + +notIn +----- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->notIn('foo', ['value1', 'value2']); + + $collection->matching(new Criteria($expression)); + +contains +-------- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->contains('foo', 'value1'); + + $collection->matching(new Criteria($expression)); + +memberOf +-------- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->memberOf('foo', ['value1', 'value2']); + + $collection->matching(new Criteria($expression)); + +startsWith +---------- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->startsWith('foo', 'hello'); + + $collection->matching(new Criteria($expression)); + +endsWith +-------- + +.. code-block:: php + $expressionBuilder = Criteria::expr(); + + $expression = $expressionBuilder->endsWith('foo', 'world'); + + $collection->matching(new Criteria($expression)); diff --git a/sites/all/libraries/vendor/doctrine/collections/docs/en/expressions.rst b/sites/all/libraries/vendor/doctrine/collections/docs/en/expressions.rst new file mode 100644 index 0000000000..db943b246b --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/docs/en/expressions.rst @@ -0,0 +1,102 @@ +Expressions +=========== + +The ``Doctrine\Common\Collections\Expr\Comparison`` class +can be used to create expressions to be used with the +``Doctrine\Common\Collections\Criteria`` class. It has the +following operator constants: + +- ``Comparison::EQ`` +- ``Comparison::NEQ`` +- ``Comparison::LT`` +- ``Comparison::LTE`` +- ``Comparison::GT`` +- ``Comparison::GTE`` +- ``Comparison::IS`` +- ``Comparison::IN`` +- ``Comparison::NIN`` +- ``Comparison::CONTAINS`` +- ``Comparison::MEMBER_OF`` +- ``Comparison::STARTS_WITH`` +- ``Comparison::ENDS_WITH`` + +The ``Doctrine\Common\Collections\Criteria`` class has the following +API to be used with expressions: + +where +----- + +Sets the where expression to evaluate when this Criteria is searched for. + +.. code-block:: php + $expr = new Comparison('key', Comparison::EQ, 'value'); + + $criteria->where($expr); + +andWhere +-------- + +Appends the where expression to evaluate when this Criteria is searched for +using an AND with previous expression. + +.. code-block:: php + $expr = new Comparison('key', Comparison::EQ, 'value'); + + $criteria->andWhere($expr); + +orWhere +------- + +Appends the where expression to evaluate when this Criteria is searched for +using an OR with previous expression. + +.. code-block:: php + $expr1 = new Comparison('key', Comparison::EQ, 'value1'); + $expr2 = new Comparison('key', Comparison::EQ, 'value2'); + + $criteria->where($expr1); + $criteria->orWhere($expr2); + +orderBy +------- + +Sets the ordering of the result of this Criteria. + +.. code-block:: php + $criteria->orderBy(['name' => Criteria::ASC]); + +setFirstResult +-------------- + +Set the number of first result that this Criteria should return. + +.. code-block:: php + $criteria->setFirstResult(0); + +getFirstResult +-------------- + +Gets the current first result option of this Criteria. + +.. code-block:: php + $criteria->setFirstResult(10); + + echo $criteria->getFirstResult(); // 10 + +setMaxResults +------------- + +Sets the max results that this Criteria should return. + +.. code-block:: php + $criteria->setMaxResults(20); + +getMaxResults +------------- + +Gets the current max results option of this Criteria. + +.. code-block:: php + $criteria->setMaxResults(20); + + echo $criteria->getMaxResults(); // 20 diff --git a/sites/all/libraries/vendor/doctrine/collections/docs/en/index.rst b/sites/all/libraries/vendor/doctrine/collections/docs/en/index.rst new file mode 100644 index 0000000000..8ca97229b4 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/docs/en/index.rst @@ -0,0 +1,333 @@ +Introduction +============ + +Doctrine Collections is a library that contains classes for working with +arrays of data. Here is an example using the simple +``Doctrine\Common\Collections\ArrayCollection`` class: + +.. code-block:: php + filter(function($element) { + return $element > 1; + }); // [2, 3] + +Collection Methods +================== + +Doctrine Collections provides an interface named ``Doctrine\Common\Collections\Collection`` +that resembles the nature of a regular PHP array. That is, +it is essentially an **ordered map** that can also be used +like a list. + +A Collection has an internal iterator just like a PHP array. In addition, +a Collection can be iterated with external iterators, which is preferable. +To use an external iterator simply use the foreach language construct to +iterate over the collection, which calls ``getIterator()`` internally, or +explicitly retrieve an iterator though ``getIterator()`` which can then be +used to iterate over the collection. You can not rely on the internal iterator +of the collection being at a certain position unless you explicitly positioned it before. + +Methods that do not alter the collection or have template types +appearing in invariant or contravariant positions are not directly +defined in ``Doctrine\Common\Collections\Collection``, but are inherited +from the ``Doctrine\Common\Collections\ReadableCollection`` interface. + +The methods available on the interface are: + +add +--- + +Adds an element at the end of the collection. + +.. code-block:: php + $collection->add('test'); + +clear +----- + +Clears the collection, removing all elements. + +.. code-block:: php + $collection->clear(); + +contains +-------- + +Checks whether an element is contained in the collection. This is an O(n) operation, where n is the size of the collection. + +.. code-block:: php + $collection = new Collection(['test']); + + $contains = $collection->contains('test'); // true + +containsKey +----------- + +Checks whether the collection contains an element with the specified key/index. + +.. code-block:: php + $collection = new Collection(['test' => true]); + + $contains = $collection->containsKey('test'); // true + +current +------- + +Gets the element of the collection at the current iterator position. + +.. code-block:: php + $collection = new Collection(['first', 'second', 'third']); + + $current = $collection->current(); // first + +get +--- + +Gets the element at the specified key/index. + +.. code-block:: php + $collection = new Collection([ + 'key' => 'value', + ]); + + $value = $collection->get('key'); // value + +getKeys +------- + +Gets all keys/indices of the collection. + +.. code-block:: php + $collection = new Collection(['a', 'b', 'c']); + + $keys = $collection->getKeys(); // [0, 1, 2] + +getValues +--------- + +Gets all values of the collection. + +.. code-block:: php + $collection = new Collection([ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => 'value3', + ]); + + $values = $collection->getValues(); // ['value1', 'value2', 'value3'] + +isEmpty +------- + +Checks whether the collection is empty (contains no elements). + +.. code-block:: php + $collection = new Collection(['a', 'b', 'c']); + + $isEmpty = $collection->isEmpty(); // false + +first +----- + +Sets the internal iterator to the first element in the collection and returns this element. + +.. code-block:: php + $collection = new Collection(['first', 'second', 'third']); + + $first = $collection->first(); // first + +exists +------ + +Tests for the existence of an element that satisfies the given predicate. + +.. code-block:: php + $collection = new Collection(['first', 'second', 'third']); + + $exists = $collection->exists(function($key, $value) { + return $value === 'first'; + }); // true + +filter +------ + +Returns all the elements of this collection for which your callback function returns `true`. +The order and keys of the elements are preserved. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $filteredCollection = $collection->filter(function($element) { + return $element > 1; + }); // [2, 3] + +forAll +------ + +Tests whether the given predicate holds for all elements of this collection. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $forAll = $collection->forAll(function($key, $value) { + return $value > 1; + }); // false + +indexOf +------- + +Gets the index/key of a given element. The comparison of two elements is strict, that means not only the value but also the type must match. For objects this means reference equality. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $indexOf = $collection->indexOf(3); // 2 + +key +--- + +Gets the key/index of the element at the current iterator position. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $collection->next(); + + $key = $collection->key(); // 1 + +last +---- + +Sets the internal iterator to the last element in the collection and returns this element. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $last = $collection->last(); // 3 + +map +--- + +Applies the given function to each element in the collection and returns a new collection with the elements returned by the function. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $mappedCollection = $collection->map(function($value) { + return $value + 1; + }); // [2, 3, 4] + +next +---- + +Moves the internal iterator position to the next element and returns this element. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $next = $collection->next(); // 2 + +partition +--------- + +Partitions this collection in two collections according to a predicate. Keys are preserved in the resulting collections. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $mappedCollection = $collection->partition(function($key, $value) { + return $value > 1 + }); // [[2, 3], [1]] + +remove +------ + +Removes the element at the specified index from the collection. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $collection->remove(0); // [2, 3] + +removeElement +------------- + +Removes the specified element from the collection, if it is found. + +.. code-block:: php + $collection = new ArrayCollection([1, 2, 3]); + + $collection->removeElement(3); // [1, 2] + +set +--- + +Sets an element in the collection at the specified key/index. + +.. code-block:: php + $collection = new ArrayCollection(); + + $collection->set('name', 'jwage'); + +slice +----- + +Extracts a slice of $length elements starting at position $offset from the Collection. If $length is null it returns all elements from $offset to the end of the Collection. Keys have to be preserved by this method. Calling this method will only return the selected slice and NOT change the elements contained in the collection slice is called on. + +.. code-block:: php + $collection = new ArrayCollection([0, 1, 2, 3, 4, 5]); + + $slice = $collection->slice(1, 2); // [1, 2] + +toArray +------- + +Gets a native PHP array representation of the collection. + +.. code-block:: php + $collection = new ArrayCollection([0, 1, 2, 3, 4, 5]); + + $array = $collection->toArray(); // [0, 1, 2, 3, 4, 5] + +Selectable Methods +================== + +Some Doctrine Collections, like ``Doctrine\Common\Collections\ArrayCollection``, +implement an interface named ``Doctrine\Common\Collections\Selectable`` +that offers the usage of a powerful expressions API, where conditions +can be applied to a collection to get a result with matching elements +only. + +matching +-------- + +Selects all elements from a selectable that match the expression and +returns a new collection containing these elements. + +.. code-block:: php + use Doctrine\Common\Collections\Criteria; + use Doctrine\Common\Collections\Expr\Comparison; + + $collection = new ArrayCollection([ + [ + 'name' => 'jwage', + ], + [ + 'name' => 'romanb', + ], + ]); + + $expr = new Comparison('name', '=', 'jwage'); + + $criteria = new Criteria(); + + $criteria->where($expr); + + $matched = $collection->matching($criteria); // ['jwage'] + +You can read more about expressions :ref:`here `. diff --git a/sites/all/libraries/vendor/doctrine/collections/docs/en/lazy-collections.rst b/sites/all/libraries/vendor/doctrine/collections/docs/en/lazy-collections.rst new file mode 100644 index 0000000000..b9cafb60bf --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/docs/en/lazy-collections.rst @@ -0,0 +1,26 @@ +Lazy Collections +================ + +To create a lazy collection you can extend the +``Doctrine\Common\Collections\AbstractLazyCollection`` class +and define the ``doInitialize`` method. Here is an example where +we lazily query the database for a collection of user records: + +.. code-block:: php + use Doctrine\DBAL\Connection; + + class UsersLazyCollection extends AbstractLazyCollection + { + /** @var Connection */ + private $connection; + + public function __construct(Connection $connection) + { + $this->connection = $connection; + } + + protected function doInitialize() : void + { + $this->collection = $this->connection->fetchAll('SELECT * FROM users'); + } + } diff --git a/sites/all/libraries/vendor/doctrine/collections/docs/en/sidebar.rst b/sites/all/libraries/vendor/doctrine/collections/docs/en/sidebar.rst new file mode 100644 index 0000000000..69279a0bb9 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/docs/en/sidebar.rst @@ -0,0 +1,8 @@ +.. toctree:: + :depth: 3 + + index + expressions + expression-builder + derived-collections + lazy-collections diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php new file mode 100644 index 0000000000..baab4d599c --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/AbstractLazyCollection.php @@ -0,0 +1,389 @@ + + */ +abstract class AbstractLazyCollection implements Collection +{ + /** + * The backed collection to use + * + * @psalm-var Collection|null + * @var Collection|null + */ + protected $collection; + + /** @var bool */ + protected $initialized = false; + + /** + * {@inheritDoc} + * + * @return int + */ + #[ReturnTypeWillChange] + public function count() + { + $this->initialize(); + + return $this->collection->count(); + } + + /** + * {@inheritDoc} + */ + public function add($element) + { + $this->initialize(); + + return $this->collection->add($element); + } + + /** + * {@inheritDoc} + */ + public function clear() + { + $this->initialize(); + $this->collection->clear(); + } + + /** + * {@inheritDoc} + * + * @template TMaybeContained + */ + public function contains($element) + { + $this->initialize(); + + return $this->collection->contains($element); + } + + /** + * {@inheritDoc} + */ + public function isEmpty() + { + $this->initialize(); + + return $this->collection->isEmpty(); + } + + /** + * {@inheritDoc} + */ + public function remove($key) + { + $this->initialize(); + + return $this->collection->remove($key); + } + + /** + * {@inheritDoc} + */ + public function removeElement($element) + { + $this->initialize(); + + return $this->collection->removeElement($element); + } + + /** + * {@inheritDoc} + */ + public function containsKey($key) + { + $this->initialize(); + + return $this->collection->containsKey($key); + } + + /** + * {@inheritDoc} + */ + public function get($key) + { + $this->initialize(); + + return $this->collection->get($key); + } + + /** + * {@inheritDoc} + */ + public function getKeys() + { + $this->initialize(); + + return $this->collection->getKeys(); + } + + /** + * {@inheritDoc} + */ + public function getValues() + { + $this->initialize(); + + return $this->collection->getValues(); + } + + /** + * {@inheritDoc} + */ + public function set($key, $value) + { + $this->initialize(); + $this->collection->set($key, $value); + } + + /** + * {@inheritDoc} + */ + public function toArray() + { + $this->initialize(); + + return $this->collection->toArray(); + } + + /** + * {@inheritDoc} + */ + public function first() + { + $this->initialize(); + + return $this->collection->first(); + } + + /** + * {@inheritDoc} + */ + public function last() + { + $this->initialize(); + + return $this->collection->last(); + } + + /** + * {@inheritDoc} + */ + public function key() + { + $this->initialize(); + + return $this->collection->key(); + } + + /** + * {@inheritDoc} + */ + public function current() + { + $this->initialize(); + + return $this->collection->current(); + } + + /** + * {@inheritDoc} + */ + public function next() + { + $this->initialize(); + + return $this->collection->next(); + } + + /** + * {@inheritDoc} + */ + public function exists(Closure $p) + { + $this->initialize(); + + return $this->collection->exists($p); + } + + /** + * {@inheritDoc} + */ + public function filter(Closure $p) + { + $this->initialize(); + + return $this->collection->filter($p); + } + + /** + * {@inheritDoc} + */ + public function forAll(Closure $p) + { + $this->initialize(); + + return $this->collection->forAll($p); + } + + /** + * {@inheritDoc} + */ + public function map(Closure $func) + { + $this->initialize(); + + return $this->collection->map($func); + } + + /** + * {@inheritDoc} + */ + public function partition(Closure $p) + { + $this->initialize(); + + return $this->collection->partition($p); + } + + /** + * {@inheritDoc} + * + * @template TMaybeContained + */ + public function indexOf($element) + { + $this->initialize(); + + return $this->collection->indexOf($element); + } + + /** + * {@inheritDoc} + */ + public function slice($offset, $length = null) + { + $this->initialize(); + + return $this->collection->slice($offset, $length); + } + + /** + * {@inheritDoc} + * + * @return Traversable + * @psalm-return Traversable + */ + #[ReturnTypeWillChange] + public function getIterator() + { + $this->initialize(); + + return $this->collection->getIterator(); + } + + /** + * @param TKey $offset + * + * @return bool + */ + #[ReturnTypeWillChange] + public function offsetExists($offset) + { + $this->initialize(); + + return $this->collection->offsetExists($offset); + } + + /** + * @param TKey $offset + * + * @return mixed + */ + #[ReturnTypeWillChange] + public function offsetGet($offset) + { + $this->initialize(); + + return $this->collection->offsetGet($offset); + } + + /** + * @param TKey|null $offset + * @param T $value + * + * @return void + */ + #[ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + $this->initialize(); + $this->collection->offsetSet($offset, $value); + } + + /** + * @param TKey $offset + * + * @return void + */ + #[ReturnTypeWillChange] + public function offsetUnset($offset) + { + $this->initialize(); + $this->collection->offsetUnset($offset); + } + + /** + * Is the lazy collection already initialized? + * + * @return bool + * + * @psalm-assert-if-true Collection $this->collection + */ + public function isInitialized() + { + return $this->initialized; + } + + /** + * Initialize the collection + * + * @return void + * + * @psalm-assert Collection $this->collection + */ + protected function initialize() + { + if ($this->initialized) { + return; + } + + $this->doInitialize(); + $this->initialized = true; + + if ($this->collection === null) { + throw new LogicException('You must initialize the collection property in the doInitialize() method.'); + } + } + + /** + * Do the initialization logic + * + * @return void + */ + abstract protected function doInitialize(); +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php new file mode 100644 index 0000000000..186f6ec4cc --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php @@ -0,0 +1,466 @@ + + * @template-implements Selectable + * @psalm-consistent-constructor + */ +class ArrayCollection implements Collection, Selectable +{ + /** + * An array containing the entries of this collection. + * + * @psalm-var array + * @var mixed[] + */ + private $elements; + + /** + * Initializes a new ArrayCollection. + * + * @param array $elements + * @psalm-param array $elements + */ + public function __construct(array $elements = []) + { + $this->elements = $elements; + } + + /** + * {@inheritDoc} + */ + public function toArray() + { + return $this->elements; + } + + /** + * {@inheritDoc} + */ + public function first() + { + return reset($this->elements); + } + + /** + * Creates a new instance from the specified elements. + * + * This method is provided for derived classes to specify how a new + * instance should be created when constructor semantics have changed. + * + * @param array $elements Elements. + * @psalm-param array $elements + * + * @return static + * @psalm-return static + * + * @psalm-template K of array-key + * @psalm-template V + */ + protected function createFrom(array $elements) + { + return new static($elements); + } + + /** + * {@inheritDoc} + */ + public function last() + { + return end($this->elements); + } + + /** + * {@inheritDoc} + */ + public function key() + { + return key($this->elements); + } + + /** + * {@inheritDoc} + */ + public function next() + { + return next($this->elements); + } + + /** + * {@inheritDoc} + */ + public function current() + { + return current($this->elements); + } + + /** + * {@inheritDoc} + */ + public function remove($key) + { + if (! isset($this->elements[$key]) && ! array_key_exists($key, $this->elements)) { + return null; + } + + $removed = $this->elements[$key]; + unset($this->elements[$key]); + + return $removed; + } + + /** + * {@inheritDoc} + */ + public function removeElement($element) + { + $key = array_search($element, $this->elements, true); + + if ($key === false) { + return false; + } + + unset($this->elements[$key]); + + return true; + } + + /** + * Required by interface ArrayAccess. + * + * @param TKey $offset + * + * @return bool + */ + #[ReturnTypeWillChange] + public function offsetExists($offset) + { + return $this->containsKey($offset); + } + + /** + * Required by interface ArrayAccess. + * + * @param TKey $offset + * + * @return mixed + */ + #[ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->get($offset); + } + + /** + * Required by interface ArrayAccess. + * + * @param TKey|null $offset + * @param T $value + * + * @return void + */ + #[ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + if (! isset($offset)) { + $this->add($value); + + return; + } + + $this->set($offset, $value); + } + + /** + * Required by interface ArrayAccess. + * + * @param TKey $offset + * + * @return void + */ + #[ReturnTypeWillChange] + public function offsetUnset($offset) + { + $this->remove($offset); + } + + /** + * {@inheritDoc} + */ + public function containsKey($key) + { + return isset($this->elements[$key]) || array_key_exists($key, $this->elements); + } + + /** + * {@inheritDoc} + * + * @template TMaybeContained + */ + public function contains($element) + { + return in_array($element, $this->elements, true); + } + + /** + * {@inheritDoc} + */ + public function exists(Closure $p) + { + foreach ($this->elements as $key => $element) { + if ($p($key, $element)) { + return true; + } + } + + return false; + } + + /** + * {@inheritDoc} + * + * @psalm-param TMaybeContained $element + * + * @psalm-return (TMaybeContained is T ? TKey|false : false) + * + * @template TMaybeContained + */ + public function indexOf($element) + { + return array_search($element, $this->elements, true); + } + + /** + * {@inheritDoc} + */ + public function get($key) + { + return $this->elements[$key] ?? null; + } + + /** + * {@inheritDoc} + */ + public function getKeys() + { + return array_keys($this->elements); + } + + /** + * {@inheritDoc} + */ + public function getValues() + { + return array_values($this->elements); + } + + /** + * {@inheritDoc} + * + * @return int + */ + #[ReturnTypeWillChange] + public function count() + { + return count($this->elements); + } + + /** + * {@inheritDoc} + */ + public function set($key, $value) + { + $this->elements[$key] = $value; + } + + /** + * {@inheritDoc} + * + * @psalm-suppress InvalidPropertyAssignmentValue + * + * This breaks assumptions about the template type, but it would + * be a backwards-incompatible change to remove this method + */ + public function add($element) + { + $this->elements[] = $element; + + return true; + } + + /** + * {@inheritDoc} + */ + public function isEmpty() + { + return empty($this->elements); + } + + /** + * {@inheritDoc} + * + * @return Traversable + * @psalm-return Traversable + */ + #[ReturnTypeWillChange] + public function getIterator() + { + return new ArrayIterator($this->elements); + } + + /** + * {@inheritDoc} + * + * @psalm-param Closure(T):U $func + * + * @return static + * @psalm-return static + * + * @psalm-template U + */ + public function map(Closure $func) + { + return $this->createFrom(array_map($func, $this->elements)); + } + + /** + * {@inheritDoc} + * + * @return static + * @psalm-return static + */ + public function filter(Closure $p) + { + return $this->createFrom(array_filter($this->elements, $p, ARRAY_FILTER_USE_BOTH)); + } + + /** + * {@inheritDoc} + */ + public function forAll(Closure $p) + { + foreach ($this->elements as $key => $element) { + if (! $p($key, $element)) { + return false; + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + public function partition(Closure $p) + { + $matches = $noMatches = []; + + foreach ($this->elements as $key => $element) { + if ($p($key, $element)) { + $matches[$key] = $element; + } else { + $noMatches[$key] = $element; + } + } + + return [$this->createFrom($matches), $this->createFrom($noMatches)]; + } + + /** + * Returns a string representation of this object. + * + * @return string + */ + public function __toString() + { + return self::class . '@' . spl_object_hash($this); + } + + /** + * {@inheritDoc} + */ + public function clear() + { + $this->elements = []; + } + + /** + * {@inheritDoc} + */ + public function slice($offset, $length = null) + { + return array_slice($this->elements, $offset, $length, true); + } + + /** + * {@inheritDoc} + */ + public function matching(Criteria $criteria) + { + $expr = $criteria->getWhereExpression(); + $filtered = $this->elements; + + if ($expr) { + $visitor = new ClosureExpressionVisitor(); + $filter = $visitor->dispatch($expr); + $filtered = array_filter($filtered, $filter); + } + + $orderings = $criteria->getOrderings(); + + if ($orderings) { + $next = null; + foreach (array_reverse($orderings) as $field => $ordering) { + $next = ClosureExpressionVisitor::sortByField($field, $ordering === Criteria::DESC ? -1 : 1, $next); + } + + uasort($filtered, $next); + } + + $offset = $criteria->getFirstResult(); + $length = $criteria->getMaxResults(); + + if ($offset || $length) { + $filtered = array_slice($filtered, (int) $offset, $length); + } + + return $this->createFrom($filtered); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php new file mode 100644 index 0000000000..fb091923c7 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Collection.php @@ -0,0 +1,99 @@ +ordered map that can also be used + * like a list. + * + * A Collection has an internal iterator just like a PHP array. In addition, + * a Collection can be iterated with external iterators, which is preferable. + * To use an external iterator simply use the foreach language construct to + * iterate over the collection (which calls {@link getIterator()} internally) or + * explicitly retrieve an iterator though {@link getIterator()} which can then be + * used to iterate over the collection. + * You can not rely on the internal iterator of the collection being at a certain + * position unless you explicitly positioned it before. Prefer iteration with + * external iterators. + * + * @psalm-template TKey of array-key + * @psalm-template T + * @template-extends ReadableCollection + * @template-extends ArrayAccess + */ +interface Collection extends ReadableCollection, ArrayAccess +{ + /** + * Adds an element at the end of the collection. + * + * @param mixed $element The element to add. + * @psalm-param T $element + * + * @return true Always TRUE. + */ + public function add($element); + + /** + * Clears the collection, removing all elements. + * + * @return void + */ + public function clear(); + + /** + * Removes the element at the specified index from the collection. + * + * @param string|int $key The key/index of the element to remove. + * @psalm-param TKey $key + * + * @return mixed The removed element or NULL, if the collection did not contain the element. + * @psalm-return T|null + */ + public function remove($key); + + /** + * Removes the specified element from the collection, if it is found. + * + * @param mixed $element The element to remove. + * @psalm-param T $element + * + * @return bool TRUE if this collection contained the specified element, FALSE otherwise. + */ + public function removeElement($element); + + /** + * Sets an element in the collection at the specified key/index. + * + * @param string|int $key The key/index of the element to set. + * @param mixed $value The element to set. + * @psalm-param TKey $key + * @psalm-param T $value + * + * @return void + */ + public function set($key, $value); + + /** + * {@inheritdoc} + * + * @return Collection A collection with the results of the filter operation. + * @psalm-return Collection + */ + public function filter(Closure $p); + + /** + * {@inheritdoc} + * + * @return Collection[] An array with two elements. The first element contains the collection + * of elements where the predicate returned TRUE, the second element + * contains the collection of elements where the predicate returned FALSE. + * @psalm-return array{0: Collection, 1: Collection} + */ + public function partition(Closure $p); +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php new file mode 100644 index 0000000000..c1639d3f3e --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Criteria.php @@ -0,0 +1,245 @@ +expression = $expression; + + if ($firstResult === null && func_num_args() > 2) { + Deprecation::trigger( + 'doctrine/collections', + 'https://github.com/doctrine/collections/pull/311', + 'Passing null as $firstResult to the constructor of %s is deprecated. Pass 0 instead or omit the argument.', + self::class + ); + } + + $this->setFirstResult($firstResult); + $this->setMaxResults($maxResults); + + if ($orderings === null) { + return; + } + + $this->orderBy($orderings); + } + + /** + * Sets the where expression to evaluate when this Criteria is searched for. + * + * @return $this + */ + public function where(Expression $expression) + { + $this->expression = $expression; + + return $this; + } + + /** + * Appends the where expression to evaluate when this Criteria is searched for + * using an AND with previous expression. + * + * @return $this + */ + public function andWhere(Expression $expression) + { + if ($this->expression === null) { + return $this->where($expression); + } + + $this->expression = new CompositeExpression( + CompositeExpression::TYPE_AND, + [$this->expression, $expression] + ); + + return $this; + } + + /** + * Appends the where expression to evaluate when this Criteria is searched for + * using an OR with previous expression. + * + * @return $this + */ + public function orWhere(Expression $expression) + { + if ($this->expression === null) { + return $this->where($expression); + } + + $this->expression = new CompositeExpression( + CompositeExpression::TYPE_OR, + [$this->expression, $expression] + ); + + return $this; + } + + /** + * Gets the expression attached to this Criteria. + * + * @return Expression|null + */ + public function getWhereExpression() + { + return $this->expression; + } + + /** + * Gets the current orderings of this Criteria. + * + * @return string[] + */ + public function getOrderings() + { + return $this->orderings; + } + + /** + * Sets the ordering of the result of this Criteria. + * + * Keys are field and values are the order, being either ASC or DESC. + * + * @see Criteria::ASC + * @see Criteria::DESC + * + * @param string[] $orderings + * + * @return $this + */ + public function orderBy(array $orderings) + { + $this->orderings = array_map( + static function (string $ordering): string { + return strtoupper($ordering) === Criteria::ASC ? Criteria::ASC : Criteria::DESC; + }, + $orderings + ); + + return $this; + } + + /** + * Gets the current first result option of this Criteria. + * + * @return int|null + */ + public function getFirstResult() + { + return $this->firstResult; + } + + /** + * Set the number of first result that this Criteria should return. + * + * @param int|null $firstResult The value to set. + * + * @return $this + */ + public function setFirstResult($firstResult) + { + if ($firstResult === null) { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/collections', + 'https://github.com/doctrine/collections/pull/311', + 'Passing null to %s() is deprecated, pass 0 instead.', + __METHOD__ + ); + } + + $this->firstResult = $firstResult; + + return $this; + } + + /** + * Gets maxResults. + * + * @return int|null + */ + public function getMaxResults() + { + return $this->maxResults; + } + + /** + * Sets maxResults. + * + * @param int|null $maxResults The value to set. + * + * @return $this + */ + public function setMaxResults($maxResults) + { + $this->maxResults = $maxResults; + + return $this; + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php new file mode 100644 index 0000000000..c10b8d516f --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php @@ -0,0 +1,269 @@ +$accessor(); + } + } + + if (preg_match('/^is[A-Z]+/', $field) === 1 && method_exists($object, $field)) { + return $object->$field(); + } + + // __call should be triggered for get. + $accessor = $accessors[0] . $field; + + if (method_exists($object, '__call')) { + return $object->$accessor(); + } + + if ($object instanceof ArrayAccess) { + return $object[$field]; + } + + if (isset($object->$field)) { + return $object->$field; + } + + // camelcase field name to support different variable naming conventions + $ccField = preg_replace_callback('/_(.?)/', static function ($matches) { + return strtoupper($matches[1]); + }, $field); + + foreach ($accessors as $accessor) { + $accessor .= $ccField; + + if (method_exists($object, $accessor)) { + return $object->$accessor(); + } + } + + return $object->$field; + } + + /** + * Helper for sorting arrays of objects based on multiple fields + orientations. + * + * @param string $name + * @param int $orientation + * + * @return Closure + */ + public static function sortByField($name, $orientation = 1, ?Closure $next = null) + { + if (! $next) { + $next = static function (): int { + return 0; + }; + } + + return static function ($a, $b) use ($name, $next, $orientation): int { + $aValue = ClosureExpressionVisitor::getObjectFieldValue($a, $name); + + $bValue = ClosureExpressionVisitor::getObjectFieldValue($b, $name); + + if ($aValue === $bValue) { + return $next($a, $b); + } + + return ($aValue > $bValue ? 1 : -1) * $orientation; + }; + } + + /** + * {@inheritDoc} + */ + public function walkComparison(Comparison $comparison) + { + $field = $comparison->getField(); + $value = $comparison->getValue()->getValue(); // shortcut for walkValue() + + switch ($comparison->getOperator()) { + case Comparison::EQ: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value; + }; + + case Comparison::NEQ: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value; + }; + + case Comparison::LT: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value; + }; + + case Comparison::LTE: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value; + }; + + case Comparison::GT: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value; + }; + + case Comparison::GTE: + return static function ($object) use ($field, $value): bool { + return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value; + }; + + case Comparison::IN: + return static function ($object) use ($field, $value): bool { + $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field); + + return in_array($fieldValue, $value, is_scalar($fieldValue)); + }; + + case Comparison::NIN: + return static function ($object) use ($field, $value): bool { + $fieldValue = ClosureExpressionVisitor::getObjectFieldValue($object, $field); + + return ! in_array($fieldValue, $value, is_scalar($fieldValue)); + }; + + case Comparison::CONTAINS: + return static function ($object) use ($field, $value) { + return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) !== false; + }; + + case Comparison::MEMBER_OF: + return static function ($object) use ($field, $value): bool { + $fieldValues = ClosureExpressionVisitor::getObjectFieldValue($object, $field); + + if (! is_array($fieldValues)) { + $fieldValues = iterator_to_array($fieldValues); + } + + return in_array($value, $fieldValues, true); + }; + + case Comparison::STARTS_WITH: + return static function ($object) use ($field, $value): bool { + return strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value) === 0; + }; + + case Comparison::ENDS_WITH: + return static function ($object) use ($field, $value): bool { + return $value === substr(ClosureExpressionVisitor::getObjectFieldValue($object, $field), -strlen($value)); + }; + + default: + throw new RuntimeException('Unknown comparison operator: ' . $comparison->getOperator()); + } + } + + /** + * {@inheritDoc} + */ + public function walkValue(Value $value) + { + return $value->getValue(); + } + + /** + * {@inheritDoc} + */ + public function walkCompositeExpression(CompositeExpression $expr) + { + $expressionList = []; + + foreach ($expr->getExpressionList() as $child) { + $expressionList[] = $this->dispatch($child); + } + + switch ($expr->getType()) { + case CompositeExpression::TYPE_AND: + return $this->andExpressions($expressionList); + + case CompositeExpression::TYPE_OR: + return $this->orExpressions($expressionList); + + default: + throw new RuntimeException('Unknown composite ' . $expr->getType()); + } + } + + /** @param callable[] $expressions */ + private function andExpressions(array $expressions): callable + { + return static function ($object) use ($expressions): bool { + foreach ($expressions as $expression) { + if (! $expression($object)) { + return false; + } + } + + return true; + }; + } + + /** @param callable[] $expressions */ + private function orExpressions(array $expressions): callable + { + return static function ($object) use ($expressions): bool { + foreach ($expressions as $expression) { + if ($expression($object)) { + return true; + } + } + + return false; + }; + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php new file mode 100644 index 0000000000..6762b8be06 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Comparison.php @@ -0,0 +1,74 @@ +'; + public const LT = '<'; + public const LTE = '<='; + public const GT = '>'; + public const GTE = '>='; + public const IS = '='; // no difference with EQ + public const IN = 'IN'; + public const NIN = 'NIN'; + public const CONTAINS = 'CONTAINS'; + public const MEMBER_OF = 'MEMBER_OF'; + public const STARTS_WITH = 'STARTS_WITH'; + public const ENDS_WITH = 'ENDS_WITH'; + + /** @var string */ + private $field; + + /** @var string */ + private $op; + + /** @var Value */ + private $value; + + /** + * @param string $field + * @param string $operator + * @param mixed $value + */ + public function __construct($field, $operator, $value) + { + if (! ($value instanceof Value)) { + $value = new Value($value); + } + + $this->field = $field; + $this->op = $operator; + $this->value = $value; + } + + /** @return string */ + public function getField() + { + return $this->field; + } + + /** @return Value */ + public function getValue() + { + return $this->value; + } + + /** @return string */ + public function getOperator() + { + return $this->op; + } + + /** + * {@inheritDoc} + */ + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkComparison($this); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php new file mode 100644 index 0000000000..174b21b8a6 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/CompositeExpression.php @@ -0,0 +1,67 @@ +type = $type; + + foreach ($expressions as $expr) { + if ($expr instanceof Value) { + throw new RuntimeException('Values are not supported expressions as children of and/or expressions.'); + } + + if (! ($expr instanceof Expression)) { + throw new RuntimeException('No expression given to CompositeExpression.'); + } + + $this->expressions[] = $expr; + } + } + + /** + * Returns the list of expressions nested in this composite. + * + * @return Expression[] + */ + public function getExpressionList() + { + return $this->expressions; + } + + /** @return string */ + public function getType() + { + return $this->type; + } + + /** + * {@inheritDoc} + */ + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkCompositeExpression($this); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php new file mode 100644 index 0000000000..566d6d50de --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Expression.php @@ -0,0 +1,12 @@ +walkComparison($expr); + + case $expr instanceof Value: + return $this->walkValue($expr); + + case $expr instanceof CompositeExpression: + return $this->walkCompositeExpression($expr); + + default: + throw new RuntimeException('Unknown Expression ' . get_class($expr)); + } + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php new file mode 100644 index 0000000000..693d345b03 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Expr/Value.php @@ -0,0 +1,29 @@ +value = $value; + } + + /** @return mixed */ + public function getValue() + { + return $this->value; + } + + /** + * {@inheritDoc} + */ + public function visit(ExpressionVisitor $visitor) + { + return $visitor->walkValue($this); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php new file mode 100644 index 0000000000..ebb21caafe --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/ExpressionBuilder.php @@ -0,0 +1,181 @@ + + */ +interface ReadableCollection extends Countable, IteratorAggregate +{ + /** + * Checks whether an element is contained in the collection. + * This is an O(n) operation, where n is the size of the collection. + * + * @param mixed $element The element to search for. + * @psalm-param TMaybeContained $element + * + * @return bool TRUE if the collection contains the element, FALSE otherwise. + * @psalm-return (TMaybeContained is T ? bool : false) + * + * @template TMaybeContained + */ + public function contains($element); + + /** + * Checks whether the collection is empty (contains no elements). + * + * @return bool TRUE if the collection is empty, FALSE otherwise. + */ + public function isEmpty(); + + /** + * Checks whether the collection contains an element with the specified key/index. + * + * @param string|int $key The key/index to check for. + * @psalm-param TKey $key + * + * @return bool TRUE if the collection contains an element with the specified key/index, + * FALSE otherwise. + */ + public function containsKey($key); + + /** + * Gets the element at the specified key/index. + * + * @param string|int $key The key/index of the element to retrieve. + * @psalm-param TKey $key + * + * @return mixed + * @psalm-return T|null + */ + public function get($key); + + /** + * Gets all keys/indices of the collection. + * + * @return int[]|string[] The keys/indices of the collection, in the order of the corresponding + * elements in the collection. + * @psalm-return list + */ + public function getKeys(); + + /** + * Gets all values of the collection. + * + * @return mixed[] The values of all elements in the collection, in the + * order they appear in the collection. + * @psalm-return list + */ + public function getValues(); + + /** + * Gets a native PHP array representation of the collection. + * + * @return mixed[] + * @psalm-return array + */ + public function toArray(); + + /** + * Sets the internal iterator to the first element in the collection and returns this element. + * + * @return mixed + * @psalm-return T|false + */ + public function first(); + + /** + * Sets the internal iterator to the last element in the collection and returns this element. + * + * @return mixed + * @psalm-return T|false + */ + public function last(); + + /** + * Gets the key/index of the element at the current iterator position. + * + * @return int|string|null + * @psalm-return TKey|null + */ + public function key(); + + /** + * Gets the element of the collection at the current iterator position. + * + * @return mixed + * @psalm-return T|false + */ + public function current(); + + /** + * Moves the internal iterator position to the next element and returns this element. + * + * @return mixed + * @psalm-return T|false + */ + public function next(); + + /** + * Extracts a slice of $length elements starting at position $offset from the Collection. + * + * If $length is null it returns all elements from $offset to the end of the Collection. + * Keys have to be preserved by this method. Calling this method will only return the + * selected slice and NOT change the elements contained in the collection slice is called on. + * + * @param int $offset The offset to start from. + * @param int|null $length The maximum number of elements to return, or null for no limit. + * + * @return mixed[] + * @psalm-return array + */ + public function slice($offset, $length = null); + + /** + * Tests for the existence of an element that satisfies the given predicate. + * + * @param Closure $p The predicate. + * @psalm-param Closure(TKey, T):bool $p + * + * @return bool TRUE if the predicate is TRUE for at least one element, FALSE otherwise. + */ + public function exists(Closure $p); + + /** + * Returns all the elements of this collection that satisfy the predicate p. + * The order of the elements is preserved. + * + * @param Closure $p The predicate used for filtering. + * @psalm-param Closure(T):bool $p + * + * @return ReadableCollection A collection with the results of the filter operation. + * @psalm-return ReadableCollection + */ + public function filter(Closure $p); + + /** + * Applies the given function to each element in the collection and returns + * a new collection with the elements returned by the function. + * + * @psalm-param Closure(T):U $func + * + * @return Collection + * @psalm-return Collection + * + * @psalm-template U + */ + public function map(Closure $func); + + /** + * Partitions this collection in two collections according to a predicate. + * Keys are preserved in the resulting collections. + * + * @param Closure $p The predicate on which to partition. + * @psalm-param Closure(TKey, T):bool $p + * + * @return ReadableCollection[] An array with two elements. The first element contains the collection + * of elements where the predicate returned TRUE, the second element + * contains the collection of elements where the predicate returned FALSE. + * @psalm-return array{0: ReadableCollection, 1: ReadableCollection} + */ + public function partition(Closure $p); + + /** + * Tests whether the given predicate p holds for all elements of this collection. + * + * @param Closure $p The predicate. + * @psalm-param Closure(TKey, T):bool $p + * + * @return bool TRUE, if the predicate yields TRUE for all elements, FALSE otherwise. + */ + public function forAll(Closure $p); + + /** + * Gets the index/key of a given element. The comparison of two elements is strict, + * that means not only the value but also the type must match. + * For objects this means reference equality. + * + * @param mixed $element The element to search for. + * @psalm-param TMaybeContained $element + * + * @return int|string|bool The key/index of the element or FALSE if the element was not found. + * @psalm-return (TMaybeContained is T ? TKey|false : false) + * + * @template TMaybeContained + */ + public function indexOf($element); +} diff --git a/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php new file mode 100644 index 0000000000..9f7586de3a --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/lib/Doctrine/Common/Collections/Selectable.php @@ -0,0 +1,30 @@ +&Selectable + * @psalm-return Collection&Selectable + */ + public function matching(Criteria $criteria); +} diff --git a/sites/all/libraries/vendor/doctrine/collections/phpcs.xml.dist b/sites/all/libraries/vendor/doctrine/collections/phpcs.xml.dist new file mode 100644 index 0000000000..2ea04bb31d --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/phpcs.xml.dist @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + lib + tests + + + + + + + + + + + + + + tests/* + + + + tests/* + + + + lib/Doctrine/Common/Collections/AbstractLazyCollection.php + + + + tests/Doctrine/Tests/Common/Collections/ClosureExpressionVisitorTest.php + + + tests/Doctrine/Tests/Common/Collections/ClosureExpressionVisitorTest.php + + diff --git a/sites/all/libraries/vendor/doctrine/collections/phpstan.neon.dist b/sites/all/libraries/vendor/doctrine/collections/phpstan.neon.dist new file mode 100644 index 0000000000..0b85a3dc94 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/phpstan.neon.dist @@ -0,0 +1,11 @@ +parameters: + level: 8 + paths: + - lib + ignoreErrors: + - + message: '~Parameter #1 \$key of method Doctrine\\Common\\Collections\\ArrayCollection::set\(\) expects TKey of \(int\|string\), int\|string given\.~' + path: 'lib/Doctrine/Common/Collections/ArrayCollection.php' + - + message: '~Cannot call method .* on Doctrine\\Common\\Collections\\Collection\|null\.~' + path: 'lib/Doctrine/Common/Collections/AbstractLazyCollection.php' diff --git a/sites/all/libraries/vendor/doctrine/collections/phpunit.xml.dist b/sites/all/libraries/vendor/doctrine/collections/phpunit.xml.dist new file mode 100644 index 0000000000..f9eb964804 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/phpunit.xml.dist @@ -0,0 +1,21 @@ + + + + + + ./tests/Doctrine/ + + + + + + ./lib/Doctrine/ + + + diff --git a/sites/all/libraries/vendor/doctrine/collections/psalm.xml.dist b/sites/all/libraries/vendor/doctrine/collections/psalm.xml.dist new file mode 100644 index 0000000000..53ad4f2f45 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/psalm.xml.dist @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/AbstractLazyArrayCollectionTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/AbstractLazyArrayCollectionTest.php new file mode 100644 index 0000000000..522537a2f1 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/AbstractLazyArrayCollectionTest.php @@ -0,0 +1,36 @@ + + */ + protected function buildCollection(array $elements = []): Collection + { + return new LazyArrayCollection(new ArrayCollection($elements)); + } + + public function testLazyCollection(): void + { + $collection = $this->buildCollection(['a', 'b', 'c']); + assert($collection instanceof LazyArrayCollection); + + self::assertFalse($collection->isInitialized()); + self::assertCount(3, $collection); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/AbstractLazyCollectionTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/AbstractLazyCollectionTest.php new file mode 100644 index 0000000000..77a6f6b14d --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/AbstractLazyCollectionTest.php @@ -0,0 +1,19 @@ +collection = new LazyArrayCollection(new ArrayCollection()); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ArrayCollectionTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ArrayCollectionTest.php new file mode 100644 index 0000000000..d36b0cec4b --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ArrayCollectionTest.php @@ -0,0 +1,24 @@ + + */ + protected function buildCollection(array $elements = []): Collection + { + return new ArrayCollection($elements); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/BaseArrayCollectionTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/BaseArrayCollectionTest.php new file mode 100644 index 0000000000..e16b236fba --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/BaseArrayCollectionTest.php @@ -0,0 +1,348 @@ + + */ + abstract protected function buildCollection(array $elements = []): Collection; + + /** @param object $obj */ + protected function isSelectable($obj): bool + { + return $obj instanceof Selectable; + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testToArray($elements): void + { + $collection = $this->buildCollection($elements); + + self::assertSame($elements, $collection->toArray()); + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testFirst($elements): void + { + $collection = $this->buildCollection($elements); + self::assertSame(reset($elements), $collection->first()); + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testLast($elements): void + { + $collection = $this->buildCollection($elements); + self::assertSame(end($elements), $collection->last()); + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testKey($elements): void + { + $collection = $this->buildCollection($elements); + + self::assertSame(key($elements), $collection->key()); + + next($elements); + $collection->next(); + + self::assertSame(key($elements), $collection->key()); + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testNext($elements): void + { + $collection = $this->buildCollection($elements); + + while (true) { + $collectionNext = $collection->next(); + $arrayNext = next($elements); + + if (! $collectionNext || ! $arrayNext) { + break; + } + + self::assertSame($arrayNext, $collectionNext, 'Returned value of ArrayCollection::next() and next() not match'); + self::assertSame(key($elements), $collection->key(), 'Keys not match'); + self::assertSame(current($elements), $collection->current(), 'Current values not match'); + } + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testCurrent($elements): void + { + $collection = $this->buildCollection($elements); + + self::assertSame(current($elements), $collection->current()); + + next($elements); + $collection->next(); + + self::assertSame(current($elements), $collection->current()); + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testGetKeys($elements): void + { + $collection = $this->buildCollection($elements); + + self::assertSame(array_keys($elements), $collection->getKeys()); + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testGetValues($elements): void + { + $collection = $this->buildCollection($elements); + + self::assertSame(array_values($elements), $collection->getValues()); + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testCount($elements): void + { + $collection = $this->buildCollection($elements); + + self::assertSame(count($elements), $collection->count()); + } + + /** + * @param mixed[] $elements + * + * @dataProvider provideDifferentElements + */ + public function testIterator($elements): void + { + $collection = $this->buildCollection($elements); + + $iterations = 0; + foreach ($collection->getIterator() as $key => $item) { + self::assertSame($elements[$key], $item, 'Item ' . $key . ' not match'); + ++$iterations; + } + + self::assertEquals(count($elements), $iterations, 'Number of iterations not match'); + } + + /** @psalm-return array */ + public function provideDifferentElements(): array + { + return [ + 'indexed' => [[1, 2, 3, 4, 5]], + 'associative' => [['A' => 'a', 'B' => 'b', 'C' => 'c']], + 'mixed' => [['A' => 'a', 1, 'B' => 'b', 2, 3]], + ]; + } + + public function testRemove(): void + { + $elements = [1, 'A' => 'a', 2, 'B' => 'b', 3]; + $collection = $this->buildCollection($elements); + + self::assertEquals(1, $collection->remove(0)); + unset($elements[0]); + + self::assertEquals(null, $collection->remove('non-existent')); + unset($elements['non-existent']); + + self::assertEquals(2, $collection->remove(1)); + unset($elements[1]); + + self::assertEquals('a', $collection->remove('A')); + unset($elements['A']); + + self::assertEquals($elements, $collection->toArray()); + } + + public function testRemoveElement(): void + { + $elements = [1, 'A' => 'a', 2, 'B' => 'b', 3, 'A2' => 'a', 'B2' => 'b']; + $collection = $this->buildCollection($elements); + + self::assertTrue($collection->removeElement(1)); + unset($elements[0]); + + self::assertFalse($collection->removeElement('non-existent')); + + self::assertTrue($collection->removeElement('a')); + unset($elements['A']); + + self::assertTrue($collection->removeElement('a')); + unset($elements['A2']); + + self::assertEquals($elements, $collection->toArray()); + } + + public function testContainsKey(): void + { + $elements = [1, 'A' => 'a', 2, 'null' => null, 3, 'A2' => 'a', 'B2' => 'b']; + $collection = $this->buildCollection($elements); + + self::assertTrue($collection->containsKey(0), 'Contains index 0'); + self::assertTrue($collection->containsKey('A'), 'Contains key "A"'); + self::assertTrue($collection->containsKey('null'), 'Contains key "null", with value null'); + self::assertFalse($collection->containsKey('non-existent'), "Doesn't contain key"); + } + + public function testEmpty(): void + { + $collection = $this->buildCollection(); + self::assertTrue($collection->isEmpty(), 'Empty collection'); + + $collection->add(1); + self::assertFalse($collection->isEmpty(), 'Not empty collection'); + } + + public function testContains(): void + { + $elements = [1, 'A' => 'a', 2, 'null' => null, 3, 'A2' => 'a', 'zero' => 0]; + $collection = $this->buildCollection($elements); + + self::assertTrue($collection->contains(0), 'Contains Zero'); + self::assertTrue($collection->contains('a'), 'Contains "a"'); + self::assertTrue($collection->contains(null), 'Contains Null'); + self::assertFalse($collection->contains('non-existent'), "Doesn't contain an element"); + } + + public function testExists(): void + { + $elements = [1, 'A' => 'a', 2, 'null' => null, 3, 'A2' => 'a', 'zero' => 0]; + $collection = $this->buildCollection($elements); + + self::assertTrue($collection->exists(static function ($key, $element) { + return $key === 'A' && $element === 'a'; + }), 'Element exists'); + + self::assertFalse($collection->exists(static function ($key, $element) { + return $key === 'non-existent' && $element === 'non-existent'; + }), 'Element not exists'); + } + + public function testIndexOf(): void + { + $elements = [1, 'A' => 'a', 2, 'null' => null, 3, 'A2' => 'a', 'zero' => 0]; + $collection = $this->buildCollection($elements); + + self::assertSame(array_search(2, $elements, true), $collection->indexOf(2), 'Index of 2'); + self::assertSame(array_search(null, $elements, true), $collection->indexOf(null), 'Index of null'); + self::assertSame(array_search('non-existent', $elements, true), $collection->indexOf('non-existent'), 'Index of non existent'); + } + + public function testGet(): void + { + $elements = [1, 'A' => 'a', 2, 'null' => null, 3, 'A2' => 'a', 'zero' => 0]; + $collection = $this->buildCollection($elements); + + self::assertSame(2, $collection->get(1), 'Get element by index'); + self::assertSame('a', $collection->get('A'), 'Get element by name'); + self::assertSame(null, $collection->get('non-existent'), 'Get non existent element'); + } + + public function testMatchingWithSortingPreserveKeys(): void + { + $object1 = new stdClass(); + $object2 = new stdClass(); + + $object1->sortField = 2; + $object2->sortField = 1; + + $collection = $this->buildCollection([ + 'object1' => $object1, + 'object2' => $object2, + ]); + + if (! $this->isSelectable($collection)) { + $this->markTestSkipped('Collection does not support Selectable interface'); + } + + self::assertSame( + [ + 'object2' => $object2, + 'object1' => $object1, + ], + $collection + ->matching(new Criteria(null, ['sortField' => Criteria::ASC])) + ->toArray() + ); + } + + public function testMultiColumnSortAppliesAllSorts(): void + { + $collection = $this->buildCollection([ + ['foo' => 1, 'bar' => 2], + ['foo' => 2, 'bar' => 4], + ['foo' => 2, 'bar' => 3], + ]); + + $expected = [ + 1 => ['foo' => 2, 'bar' => 4], + 2 => ['foo' => 2, 'bar' => 3], + 0 => ['foo' => 1, 'bar' => 2], + ]; + + if (! $this->isSelectable($collection)) { + $this->markTestSkipped('Collection does not support Selectable interface'); + } + + self::assertSame( + $expected, + $collection + ->matching(new Criteria(null, ['foo' => Criteria::DESC, 'bar' => Criteria::DESC])) + ->toArray() + ); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/BaseCollectionTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/BaseCollectionTest.php new file mode 100644 index 0000000000..61d0c200fd --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/BaseCollectionTest.php @@ -0,0 +1,255 @@ + */ + protected $collection; + + public function testIssetAndUnset(): void + { + self::assertFalse(isset($this->collection[0])); + $this->collection->add('testing'); + self::assertTrue(isset($this->collection[0])); + unset($this->collection[0]); + self::assertFalse(isset($this->collection[0])); + } + + public function testRemovingNonExistentEntryReturnsNull(): void + { + self::assertEquals(null, $this->collection->remove('testing_does_not_exist')); + } + + public function testExists(): void + { + $this->collection->add('one'); + $this->collection->add('two'); + $exists = $this->collection->exists(static function ($k, $e) { + return $e === 'one'; + }); + self::assertTrue($exists); + $exists = $this->collection->exists(static function ($k, $e) { + return $e === 'other'; + }); + self::assertFalse($exists); + } + + public function testMap(): void + { + $this->collection->add(1); + $this->collection->add(2); + $res = $this->collection->map(static function ($e) { + return $e * 2; + }); + self::assertEquals([2, 4], $res->toArray()); + } + + public function testFilter(): void + { + $this->collection->add(1); + $this->collection->add('foo'); + $this->collection->add(3); + $res = $this->collection->filter(static function ($e) { + return is_numeric($e); + }); + self::assertEquals([0 => 1, 2 => 3], $res->toArray()); + } + + public function testFilterByValueAndKey(): void + { + $this->collection->add(1); + $this->collection->add('foo'); + $this->collection->add(3); + $this->collection->add(4); + $this->collection->add(5); + $res = $this->collection->filter(static function ($v, $k) { + return is_numeric($v) && $k % 2 === 0; + }); + self::assertSame([0 => 1, 2 => 3, 4 => 5], $res->toArray()); + } + + public function testFirstAndLast(): void + { + $this->collection->add('one'); + $this->collection->add('two'); + + self::assertEquals($this->collection->first(), 'one'); + self::assertEquals($this->collection->last(), 'two'); + } + + public function testArrayAccess(): void + { + $this->collection[] = 'one'; + $this->collection[] = 'two'; + + self::assertEquals($this->collection[0], 'one'); + self::assertEquals($this->collection[1], 'two'); + + unset($this->collection[0]); + self::assertEquals($this->collection->count(), 1); + } + + public function testContainsKey(): void + { + $this->collection[5] = 'five'; + self::assertTrue($this->collection->containsKey(5)); + } + + public function testContains(): void + { + $this->collection[0] = 'test'; + self::assertTrue($this->collection->contains('test')); + } + + public function testSearch(): void + { + $this->collection[0] = 'test'; + self::assertEquals(0, $this->collection->indexOf('test')); + } + + public function testGet(): void + { + $this->collection[0] = 'test'; + self::assertEquals('test', $this->collection->get(0)); + } + + public function testGetKeys(): void + { + $this->collection[] = 'one'; + $this->collection[] = 'two'; + self::assertEquals([0, 1], $this->collection->getKeys()); + } + + public function testGetValues(): void + { + $this->collection[] = 'one'; + $this->collection[] = 'two'; + self::assertEquals(['one', 'two'], $this->collection->getValues()); + } + + public function testCount(): void + { + $this->collection[] = 'one'; + $this->collection[] = 'two'; + self::assertEquals($this->collection->count(), 2); + self::assertEquals(count($this->collection), 2); + } + + public function testForAll(): void + { + $this->collection[] = 'one'; + $this->collection[] = 'two'; + self::assertEquals($this->collection->forAll(static function ($k, $e) { + return is_string($e); + }), true); + self::assertEquals($this->collection->forAll(static function ($k, $e) { + return is_array($e); + }), false); + } + + public function testPartition(): void + { + $this->collection[] = true; + $this->collection[] = false; + $partition = $this->collection->partition(static function ($k, $e) { + return $e === true; + }); + self::assertEquals($partition[0][0], true); + self::assertEquals($partition[1][0], false); + } + + public function testClear(): void + { + $this->collection[] = 'one'; + $this->collection[] = 'two'; + $this->collection->clear(); + self::assertEquals($this->collection->isEmpty(), true); + } + + public function testRemove(): void + { + $this->collection[] = 'one'; + $this->collection[] = 'two'; + $el = $this->collection->remove(0); + + self::assertEquals('one', $el); + self::assertEquals($this->collection->contains('one'), false); + self::assertNull($this->collection->remove(0)); + } + + public function testRemoveElement(): void + { + $this->collection[] = 'one'; + $this->collection[] = 'two'; + + self::assertTrue($this->collection->removeElement('two')); + self::assertFalse($this->collection->contains('two')); + self::assertFalse($this->collection->removeElement('two')); + } + + public function testSlice(): void + { + $this->collection[] = 'one'; + $this->collection[] = 'two'; + $this->collection[] = 'three'; + + $slice = $this->collection->slice(0, 1); + self::assertIsArray($slice); + self::assertEquals(['one'], $slice); + + $slice = $this->collection->slice(1); + self::assertEquals([1 => 'two', 2 => 'three'], $slice); + + $slice = $this->collection->slice(1, 1); + self::assertEquals([1 => 'two'], $slice); + } + + protected function fillMatchingFixture(): void + { + $std1 = new stdClass(); + $std1->foo = 'bar'; + $this->collection[] = $std1; + + $std2 = new stdClass(); + $std2->foo = 'baz'; + $this->collection[] = $std2; + } + + public function testCanRemoveNullValuesByKey(): void + { + $this->collection->add(null); + $this->collection->remove(0); + self::assertTrue($this->collection->isEmpty()); + } + + public function testCanVerifyExistingKeysWithNullValues(): void + { + $this->collection->set('key', null); + self::assertTrue($this->collection->containsKey('key')); + } + + public function testMatchingAlwaysReturnsCollection(): void + { + if (! $this->collection instanceof Selectable) { + self::markTestSkipped(sprintf('Collection does not implement %s', Selectable::class)); + } + + $criteria = Criteria::create(); + + self::assertInstanceOf(Collection::class, $this->collection->matching($criteria)); + self::assertInstanceOf(Selectable::class, $this->collection->matching($criteria)); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ClosureExpressionVisitorTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ClosureExpressionVisitorTest.php new file mode 100644 index 0000000000..4b45ef65c2 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ClosureExpressionVisitorTest.php @@ -0,0 +1,564 @@ +visitor = new ClosureExpressionVisitor(); + $this->builder = new ExpressionBuilder(); + } + + public function testEmbeddedObjectComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->eq('foo.foo', 1)); + $this->assertTrue($closure(new TestObject(new TestObject(1)))); + $this->assertFalse($closure(new TestObject(new TestObject(2)))); + } + + public function testGetObjectFieldValueIsAccessor(): void + { + $object = new TestObject(1, 2, true); + + self::assertTrue($this->visitor->getObjectFieldValue($object, 'baz')); + } + + public function testGetObjectFieldValueIsAccessorWithIsPrefix(): void + { + $object = new TestObject(1, 2, true); + + self::assertTrue($this->visitor->getObjectFieldValue($object, 'isBaz')); + } + + public function testGetObjectFieldValueIsAccessorCamelCase(): void + { + $object = new TestObjectNotCamelCase(1); + + self::assertEquals(1, $this->visitor->getObjectFieldValue($object, 'foo_bar')); + self::assertEquals(1, $this->visitor->getObjectFieldValue($object, 'foobar')); + self::assertEquals(1, $this->visitor->getObjectFieldValue($object, 'fooBar')); + } + + public function testGetObjectFieldValueIsAccessorBoth(): void + { + $object = new TestObjectBothCamelCaseAndUnderscore(1, 2); + + self::assertEquals(2, $this->visitor->getObjectFieldValue($object, 'foo_bar')); + self::assertEquals(2, $this->visitor->getObjectFieldValue($object, 'foobar')); + self::assertEquals(2, $this->visitor->getObjectFieldValue($object, 'fooBar')); + } + + public function testGetObjectFieldValueIsAccessorOnePublic(): void + { + $object = new TestObjectPublicCamelCaseAndPrivateUnderscore(1, 2); + + self::assertEquals(2, $this->visitor->getObjectFieldValue($object, 'foo_bar')); + self::assertEquals(2, $this->visitor->getObjectFieldValue($object, 'foobar')); + self::assertEquals(2, $this->visitor->getObjectFieldValue($object, 'fooBar')); + } + + public function testGetObjectFieldValueIsAccessorBothPublic(): void + { + $object = new TestObjectPublicCamelCaseAndPrivateUnderscore(1, 2); + + self::assertEquals(2, $this->visitor->getObjectFieldValue($object, 'foo_bar')); + self::assertEquals(2, $this->visitor->getObjectFieldValue($object, 'foobar')); + self::assertEquals(2, $this->visitor->getObjectFieldValue($object, 'fooBar')); + } + + public function testGetObjectFieldValueBlankAccessor(): void + { + $object = new TestObjectBlankGetter(1); + + self::assertEquals(1, $this->visitor->getObjectFieldValue($object, 'foobar')); + self::assertEquals(1, $this->visitor->getObjectFieldValue($object, 'fooBar')); + } + + public function testGetObjectFieldValueMagicCallMethod(): void + { + $object = new TestObject(1, 2, true, 3); + + self::assertEquals(3, $this->visitor->getObjectFieldValue($object, 'qux')); + } + + public function testGetObjectFieldValueArrayAccess(): void + { + $object = self::createMock(ArrayAccess::class); + $object->expects(self::once()) + ->method('offsetGet') + ->with('foo') + ->willReturn(33); + + self::assertSame(33, $this->visitor->getObjectFieldValue($object, 'foo')); + } + + public function testGetObjectFieldValuePublicPropertyIsNull(): void + { + $object = new stdClass(); + $object->foo = null; + + self::assertSame(null, $this->visitor->getObjectFieldValue($object, 'foo')); + } + + public function testWalkEqualsComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->eq('foo', 1)); + + self::assertTrue($closure(new TestObject(1))); + self::assertFalse($closure(new TestObject(2))); + } + + public function testWalkNotEqualsComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->neq('foo', 1)); + + self::assertFalse($closure(new TestObject(1))); + self::assertTrue($closure(new TestObject(2))); + } + + public function testWalkLessThanComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->lt('foo', 1)); + + self::assertFalse($closure(new TestObject(1))); + self::assertTrue($closure(new TestObject(0))); + } + + public function testWalkLessThanEqualsComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->lte('foo', 1)); + + self::assertFalse($closure(new TestObject(2))); + self::assertTrue($closure(new TestObject(1))); + self::assertTrue($closure(new TestObject(0))); + } + + public function testWalkGreaterThanEqualsComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->gte('foo', 1)); + + self::assertTrue($closure(new TestObject(2))); + self::assertTrue($closure(new TestObject(1))); + self::assertFalse($closure(new TestObject(0))); + } + + public function testWalkGreaterThanComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->gt('foo', 1)); + + self::assertTrue($closure(new TestObject(2))); + self::assertFalse($closure(new TestObject(1))); + self::assertFalse($closure(new TestObject(0))); + } + + public function testWalkInComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->in('foo', [1, 2, 3, '04'])); + + self::assertTrue($closure(new TestObject(2))); + self::assertTrue($closure(new TestObject(1))); + self::assertFalse($closure(new TestObject(0))); + self::assertFalse($closure(new TestObject(4))); + self::assertTrue($closure(new TestObject('04'))); + } + + public function testWalkInComparisonObjects(): void + { + $closure = $this->visitor->walkComparison($this->builder->in('foo', [new TestObject(1), new TestObject(2), new TestObject(4)])); + + self::assertTrue($closure(new TestObject(new TestObject(2)))); + self::assertTrue($closure(new TestObject(new TestObject(1)))); + self::assertFalse($closure(new TestObject(new TestObject(0)))); + self::assertTrue($closure(new TestObject(new TestObject(4)))); + self::assertFalse($closure(new TestObject(new TestObject('baz')))); + } + + public function testWalkNotInComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->notIn('foo', [1, 2, 3, '04'])); + + self::assertFalse($closure(new TestObject(1))); + self::assertFalse($closure(new TestObject(2))); + self::assertTrue($closure(new TestObject(0))); + self::assertTrue($closure(new TestObject(4))); + self::assertFalse($closure(new TestObject('04'))); + } + + public function testWalkNotInComparisonObjects(): void + { + $closure = $this->visitor->walkComparison($this->builder->notIn('foo', [new TestObject(1), new TestObject(2), new TestObject(4)])); + + self::assertFalse($closure(new TestObject(new TestObject(1)))); + self::assertFalse($closure(new TestObject(new TestObject(2)))); + self::assertTrue($closure(new TestObject(new TestObject(0)))); + self::assertFalse($closure(new TestObject(new TestObject(4)))); + self::assertTrue($closure(new TestObject(new TestObject('baz')))); + } + + public function testWalkContainsComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->contains('foo', 'hello')); + + self::assertTrue($closure(new TestObject('hello world'))); + self::assertFalse($closure(new TestObject('world'))); + } + + public function testWalkMemberOfComparisonWithObject(): void + { + $closure = $this->visitor->walkComparison($this->builder->memberof('foo', 2)); + + self::assertTrue($closure(new TestObject([1, 2, 3]))); + self::assertTrue($closure(new TestObject([2]))); + self::assertTrue($closure(new TestObject(new ArrayIterator([2])))); + self::assertFalse($closure(new TestObject([1, 3, 5]))); + self::assertFalse($closure(new TestObject([1, '02']))); + self::assertFalse($closure(new TestObject(new ArrayIterator([4])))); + } + + public function testWalkStartsWithComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->startsWith('foo', 'hello')); + + self::assertTrue($closure(new TestObject('hello world'))); + self::assertFalse($closure(new TestObject('world'))); + } + + public function testWalkEndsWithComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->endsWith('foo', 'world')); + + self::assertTrue($closure(new TestObject('hello world'))); + self::assertFalse($closure(new TestObject('hello'))); + } + + public function testWalkUnknownOperatorComparisonThrowException(): void + { + self::expectException(RuntimeException::class); + self::expectExceptionMessage('Unknown comparison operator: unknown'); + + $closure = $this->visitor->walkComparison(new Comparison('foo', 'unknown', 2)); + + $closure(new TestObject(2)); + } + + public function testWalkAndCompositeExpression(): void + { + $closure = $this->visitor->walkCompositeExpression( + $this->builder->andX( + $this->builder->eq('foo', 1), + $this->builder->eq('bar', 1) + ) + ); + + self::assertTrue($closure(new TestObject(1, 1))); + self::assertFalse($closure(new TestObject(1, 0))); + self::assertFalse($closure(new TestObject(0, 1))); + self::assertFalse($closure(new TestObject(0, 0))); + } + + public function testWalkOrCompositeExpression(): void + { + $closure = $this->visitor->walkCompositeExpression( + $this->builder->orX( + $this->builder->eq('foo', 1), + $this->builder->eq('bar', 1) + ) + ); + + self::assertTrue($closure(new TestObject(1, 1))); + self::assertTrue($closure(new TestObject(1, 0))); + self::assertTrue($closure(new TestObject(0, 1))); + self::assertFalse($closure(new TestObject(0, 0))); + } + + public function testWalkOrAndCompositeExpression(): void + { + $closure = $this->visitor->walkCompositeExpression( + $this->builder->orX( + $this->builder->andX( + $this->builder->eq('foo', 1), + $this->builder->eq('bar', 1) + ), + $this->builder->andX( + $this->builder->eq('foo', 2), + $this->builder->eq('bar', 2) + ) + ) + ); + + self::assertTrue($closure(new TestObject(1, 1))); + self::assertTrue($closure(new TestObject(2, 2))); + self::assertFalse($closure(new TestObject(1, 2))); + self::assertFalse($closure(new TestObject(2, 1))); + self::assertFalse($closure(new TestObject(0, 0))); + } + + public function testWalkAndOrCompositeExpression(): void + { + $closure = $this->visitor->walkCompositeExpression( + $this->builder->andX( + $this->builder->orX( + $this->builder->eq('foo', 1), + $this->builder->eq('foo', 2) + ), + $this->builder->orX( + $this->builder->eq('bar', 3), + $this->builder->eq('bar', 4) + ) + ) + ); + + self::assertTrue($closure(new TestObject(1, 3))); + self::assertTrue($closure(new TestObject(1, 4))); + self::assertTrue($closure(new TestObject(2, 3))); + self::assertTrue($closure(new TestObject(2, 4))); + self::assertFalse($closure(new TestObject(1, 0))); + self::assertFalse($closure(new TestObject(2, 0))); + self::assertFalse($closure(new TestObject(0, 3))); + self::assertFalse($closure(new TestObject(0, 4))); + } + + public function testWalkUnknownCompositeExpressionThrowException(): void + { + self::expectException(RuntimeException::class); + self::expectExceptionMessage('Unknown composite Unknown'); + + $closure = $this->visitor->walkCompositeExpression( + new CompositeExpression('Unknown', []) + ); + + $closure(new TestObject()); + } + + public function testSortByFieldAscending(): void + { + $objects = [new TestObject('b'), new TestObject('a'), new TestObject('c')]; + $sort = ClosureExpressionVisitor::sortByField('foo'); + + usort($objects, $sort); + + self::assertEquals('a', $objects[0]->getFoo()); + self::assertEquals('b', $objects[1]->getFoo()); + self::assertEquals('c', $objects[2]->getFoo()); + } + + public function testSortByFieldDescending(): void + { + $objects = [new TestObject('b'), new TestObject('a'), new TestObject('c')]; + $sort = ClosureExpressionVisitor::sortByField('foo', -1); + + usort($objects, $sort); + + self::assertEquals('c', $objects[0]->getFoo()); + self::assertEquals('b', $objects[1]->getFoo()); + self::assertEquals('a', $objects[2]->getFoo()); + } + + public function testSortByFieldKeepOrderWhenSameValue(): void + { + $firstElement = new TestObject('a'); + $secondElement = new TestObject('a'); + + $objects = [$firstElement, $secondElement]; + $sort = ClosureExpressionVisitor::sortByField('foo'); + + usort($objects, $sort); + + self::assertSame([$firstElement, $secondElement], $objects); + } + + public function testSortDelegate(): void + { + $objects = [new TestObject('a', 'c'), new TestObject('a', 'b'), new TestObject('a', 'a')]; + $sort = ClosureExpressionVisitor::sortByField('bar', 1); + $sort = ClosureExpressionVisitor::sortByField('foo', 1, $sort); + + usort($objects, $sort); + + self::assertEquals('a', $objects[0]->getBar()); + self::assertEquals('b', $objects[1]->getBar()); + self::assertEquals('c', $objects[2]->getBar()); + } + + public function testArrayComparison(): void + { + $closure = $this->visitor->walkComparison($this->builder->eq('foo', 42)); + + self::assertTrue($closure(['foo' => 42])); + } +} + +class TestObject +{ + /** @var mixed */ + private $foo; + + /** @var mixed */ + private $bar; + + /** @var mixed */ + private $baz; + + /** @var mixed */ + private $qux; + + /** + * @param mixed $foo + * @param mixed $bar + * @param mixed $baz + * @param mixed $qux + */ + public function __construct($foo = null, $bar = null, $baz = null, $qux = null) + { + $this->foo = $foo; + $this->bar = $bar; + $this->baz = $baz; + $this->qux = $qux; + } + + /** + * @param mixed[] $arguments + * + * @return mixed + */ + public function __call(string $name, array $arguments) + { + if ($name === 'getqux') { + return $this->qux; + } + } + + /** @return mixed */ + public function getFoo() + { + return $this->foo; + } + + /** @return mixed */ + public function getBar() + { + return $this->bar; + } + + /** @return mixed */ + public function isBaz() + { + return $this->baz; + } +} + +class TestObjectNotCamelCase +{ + /** @var int|null */ + private $foo_bar; + + public function __construct(?int $foo_bar) + { + $this->foo_bar = $foo_bar; + } + + public function getFooBar(): ?int + { + return $this->foo_bar; + } +} + +class TestObjectBothCamelCaseAndUnderscore +{ + /** @var int|null */ + private $foo_bar; + + /** @var int|null */ + private $fooBar; + + public function __construct(?int $foo_bar = null, ?int $fooBar = null) + { + $this->foo_bar = $foo_bar; + $this->fooBar = $fooBar; + } + + public function getFooBar(): ?int + { + return $this->fooBar; + } +} + +class TestObjectPublicCamelCaseAndPrivateUnderscore +{ + /** @var int|null */ + private $foo_bar; + + /** @var int|null */ + public $fooBar; + + public function __construct(?int $foo_bar = null, ?int $fooBar = null) + { + $this->foo_bar = $foo_bar; + $this->fooBar = $fooBar; + } + + public function getFooBar(): ?int + { + return $this->fooBar; + } +} + +class TestObjectBothPublic +{ + /** @var mixed */ + public $foo_bar; + /** @var mixed */ + public $fooBar; + + /** + * @param mixed $foo_bar + * @param mixed $fooBar + */ + public function __construct($foo_bar = null, $fooBar = null) + { + $this->foo_bar = $foo_bar; + $this->fooBar = $fooBar; + } + + /** @return mixed */ + public function getFooBar() + { + return $this->foo_bar; + } +} + +class TestObjectBlankGetter +{ + /** @var int|null */ + public $fooBar; + + public function __construct(?int $fooBar = null) + { + $this->fooBar = $fooBar; + } + + public function fooBar(): ?int + { + return $this->fooBar; + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/CollectionTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/CollectionTest.php new file mode 100644 index 0000000000..d3593463f8 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/CollectionTest.php @@ -0,0 +1,96 @@ +collection = new ArrayCollection(); + } + + public function testToString(): void + { + $this->collection->add('testing'); + self::assertTrue(is_string((string) $this->collection)); + } + + /** @group DDC-1637 */ + public function testMatching(): void + { + $this->fillMatchingFixture(); + + $col = $this->collection->matching(new Criteria(Criteria::expr()->eq('foo', 'bar'))); + self::assertInstanceOf(Collection::class, $col); + self::assertNotSame($col, $this->collection); + self::assertEquals(1, count($col)); + } + + public function testMatchingCallable(): void + { + $this->fillMatchingFixture(); + $this->collection[0]->foo = 1; + + $col = $this->collection->matching( + new Criteria( + new Value(static function (stdClass $test): bool { + return $test->foo === 1; + }) + ) + ); + + self::assertInstanceOf(Collection::class, $col); + self::assertNotSame($col, $this->collection); + self::assertEquals(1, count($col)); + } + + public function testMatchingUnknownThrowException(): void + { + self::expectException(RuntimeException::class); + self::expectExceptionMessage('Unknown Expression GenericExpression'); + + $genericExpression = $this->getMockBuilder(Expression::class) + ->setMockClassName('GenericExpression') + ->getMock(); + + $this->collection->matching(new Criteria($genericExpression)); + } + + /** @group DDC-1637 */ + public function testMatchingOrdering(): void + { + $this->fillMatchingFixture(); + + $col = $this->collection->matching(new Criteria(null, ['foo' => 'DESC'])); + + self::assertInstanceOf(Collection::class, $col); + self::assertNotSame($col, $this->collection); + self::assertEquals(2, count($col)); + self::assertEquals('baz', $col->first()->foo); + self::assertEquals('bar', $col->last()->foo); + } + + /** @group DDC-1637 */ + public function testMatchingSlice(): void + { + $this->fillMatchingFixture(); + + $col = $this->collection->matching(new Criteria(null, null, 1, 1)); + + self::assertInstanceOf(Collection::class, $col); + self::assertNotSame($col, $this->collection); + self::assertEquals(1, count($col)); + self::assertEquals('baz', $col[0]->foo); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/CriteriaTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/CriteriaTest.php new file mode 100644 index 0000000000..b537189906 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/CriteriaTest.php @@ -0,0 +1,132 @@ + 'ASC'], 10, 20); + + self::assertSame($expr, $criteria->getWhereExpression()); + self::assertSame(['foo' => 'ASC'], $criteria->getOrderings()); + self::assertSame(10, $criteria->getFirstResult()); + self::assertSame(20, $criteria->getMaxResults()); + } + + public function testDeprecatedNullOffset(): void + { + $expr = new Comparison('field', '=', 'value'); + + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/collections/pull/311'); + $criteria = new Criteria($expr, ['foo' => 'ASC'], null, 20); + + self::assertSame($expr, $criteria->getWhereExpression()); + self::assertSame(['foo' => 'ASC'], $criteria->getOrderings()); + self::assertNull($criteria->getFirstResult()); + self::assertSame(20, $criteria->getMaxResults()); + } + + public function testDefaultConstructor(): void + { + $this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/collections/pull/311'); + $criteria = new Criteria(); + + self::assertNull($criteria->getWhereExpression()); + self::assertSame([], $criteria->getOrderings()); + self::assertNull($criteria->getFirstResult()); + self::assertNull($criteria->getMaxResults()); + } + + public function testWhere(): void + { + $expr = new Comparison('field', '=', 'value'); + $criteria = new Criteria(); + + $criteria->where($expr); + + self::assertSame($expr, $criteria->getWhereExpression()); + } + + public function testAndWhere(): void + { + $expr = new Comparison('field', '=', 'value'); + $criteria = new Criteria(); + + $criteria->where($expr); + $expr = $criteria->getWhereExpression(); + $criteria->andWhere($expr); + + $where = $criteria->getWhereExpression(); + self::assertInstanceOf(CompositeExpression::class, $where); + + self::assertEquals(CompositeExpression::TYPE_AND, $where->getType()); + self::assertSame([$expr, $expr], $where->getExpressionList()); + } + + public function testAndWhereWithoutWhere(): void + { + $expr = new Comparison('field', '=', 'value'); + $criteria = new Criteria(); + + $criteria->andWhere($expr); + + self::assertSame($expr, $criteria->getWhereExpression()); + } + + public function testOrWhere(): void + { + $expr = new Comparison('field', '=', 'value'); + $criteria = new Criteria(); + + $criteria->where($expr); + $expr = $criteria->getWhereExpression(); + $criteria->orWhere($expr); + + $where = $criteria->getWhereExpression(); + self::assertInstanceOf(CompositeExpression::class, $where); + + self::assertEquals(CompositeExpression::TYPE_OR, $where->getType()); + self::assertSame([$expr, $expr], $where->getExpressionList()); + } + + public function testOrWhereWithoutWhere(): void + { + $expr = new Comparison('field', '=', 'value'); + $criteria = new Criteria(); + + $criteria->orWhere($expr); + + self::assertSame($expr, $criteria->getWhereExpression()); + } + + public function testOrderings(): void + { + $criteria = Criteria::create() + ->orderBy(['foo' => 'ASC']); + + self::assertEquals(['foo' => 'ASC'], $criteria->getOrderings()); + } + + public function testExpr(): void + { + self::assertInstanceOf(ExpressionBuilder::class, Criteria::expr()); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/DerivedCollectionTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/DerivedCollectionTest.php new file mode 100644 index 0000000000..1b7e8b3bda --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/DerivedCollectionTest.php @@ -0,0 +1,28 @@ +map($closure)); + self::assertInstanceOf(DerivedArrayCollection::class, $collection->filter($closure)); + self::assertContainsOnlyInstancesOf(DerivedArrayCollection::class, $collection->partition($closure)); + self::assertInstanceOf(DerivedArrayCollection::class, $collection->matching(new Criteria())); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/Expr/ComparisonTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/Expr/ComparisonTest.php new file mode 100644 index 0000000000..3ead131312 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/Expr/ComparisonTest.php @@ -0,0 +1,30 @@ +expects(self::once()) + ->method('walkComparison') + ->with($comparison) + ->willReturn($callableExpected); + + self::assertSame($callableExpected, $comparison->visit($visitor)); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/Expr/CompositeExpressionTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/Expr/CompositeExpressionTest.php new file mode 100644 index 0000000000..605efaf6b1 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/Expr/CompositeExpressionTest.php @@ -0,0 +1,76 @@ + */ + public function invalidDataProvider(): array + { + return [ + ['expression' => new Value('value')], + ['expression' => 'wrong-type'], + ]; + } + + /** + * @param mixed $expression + * + * @dataProvider invalidDataProvider + */ + public function testExceptions($expression): void + { + $type = CompositeExpression::TYPE_AND; + $expressions = [$expression]; + + $this->expectException(RuntimeException::class); + new CompositeExpression($type, $expressions); + } + + public function testGetType(): void + { + $compositeExpression = $this->createCompositeExpression(); + + $expectedType = CompositeExpression::TYPE_AND; + $actualType = $compositeExpression->getType(); + + self::assertSame($expectedType, $actualType); + } + + protected function createCompositeExpression(): CompositeExpression + { + $type = CompositeExpression::TYPE_AND; + $expressions = [$this->createMock(Expression::class)]; + + return new CompositeExpression($type, $expressions); + } + + public function testGetExpressionList(): void + { + $compositeExpression = $this->createCompositeExpression(); + $expectedExpressionList = [$this->createMock(Expression::class)]; + $actualExpressionList = $compositeExpression->getExpressionList(); + + self::assertEquals($expectedExpressionList, $actualExpressionList); + } + + public function testVisitor(): void + { + $compositeExpression = $this->createCompositeExpression(); + + $visitor = $this->getMockForAbstractClass(ExpressionVisitor::class); + $visitor + ->expects($this->once()) + ->method('walkCompositeExpression'); + + $compositeExpression->visit($visitor); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/Expr/ValueTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/Expr/ValueTest.php new file mode 100644 index 0000000000..083884d28b --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/Expr/ValueTest.php @@ -0,0 +1,33 @@ +getValue(); + + self::assertEquals($value, $actualValue); + } + + public function testVisitor(): void + { + $visitor = $this->getMockForAbstractClass(ExpressionVisitor::class); + $visitor + ->expects($this->once()) + ->method('walkValue'); + + $value = 'foo'; + $valueExpression = new Value($value); + $valueExpression->visit($visitor); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ExpressionBuilderTest.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ExpressionBuilderTest.php new file mode 100644 index 0000000000..a634050e74 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ExpressionBuilderTest.php @@ -0,0 +1,147 @@ +builder = new ExpressionBuilder(); + } + + public function testAndX(): void + { + $expr = $this->builder->andX($this->builder->eq('a', 'b')); + + self::assertInstanceOf(CompositeExpression::class, $expr); + self::assertEquals(CompositeExpression::TYPE_AND, $expr->getType()); + } + + public function testOrX(): void + { + $expr = $this->builder->orX($this->builder->eq('a', 'b')); + + self::assertInstanceOf(CompositeExpression::class, $expr); + self::assertEquals(CompositeExpression::TYPE_OR, $expr->getType()); + } + + public function testInvalidAndXArgument(): void + { + $this->expectException(RuntimeException::class); + $this->builder->andX('foo'); + } + + public function testEq(): void + { + $expr = $this->builder->eq('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::EQ, $expr->getOperator()); + } + + public function testNeq(): void + { + $expr = $this->builder->neq('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::NEQ, $expr->getOperator()); + } + + public function testLt(): void + { + $expr = $this->builder->lt('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::LT, $expr->getOperator()); + } + + public function testGt(): void + { + $expr = $this->builder->gt('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::GT, $expr->getOperator()); + } + + public function testGte(): void + { + $expr = $this->builder->gte('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::GTE, $expr->getOperator()); + } + + public function testLte(): void + { + $expr = $this->builder->lte('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::LTE, $expr->getOperator()); + } + + public function testIn(): void + { + $expr = $this->builder->in('a', ['b']); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::IN, $expr->getOperator()); + } + + public function testNotIn(): void + { + $expr = $this->builder->notIn('a', ['b']); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::NIN, $expr->getOperator()); + } + + public function testIsNull(): void + { + $expr = $this->builder->isNull('a'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::EQ, $expr->getOperator()); + } + + public function testContains(): void + { + $expr = $this->builder->contains('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::CONTAINS, $expr->getOperator()); + } + + public function testMemberOf(): void + { + $expr = $this->builder->memberOf('b', ['a']); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::MEMBER_OF, $expr->getOperator()); + } + + public function testStartsWith(): void + { + $expr = $this->builder->startsWith('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::STARTS_WITH, $expr->getOperator()); + } + + public function testEndsWith(): void + { + $expr = $this->builder->endsWith('a', 'b'); + + self::assertInstanceOf(Comparison::class, $expr); + self::assertEquals(Comparison::ENDS_WITH, $expr->getOperator()); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/DerivedArrayCollection.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/DerivedArrayCollection.php new file mode 100644 index 0000000000..d1f71069b1 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/DerivedArrayCollection.php @@ -0,0 +1,33 @@ +foo = $foo; + + parent::__construct($elements); + } + + /** + * @param mixed[] $elements + * + * @return self + */ + protected function createFrom(array $elements): self + { + return new static($this->foo, $elements); + } +} diff --git a/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/LazyArrayCollection.php b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/LazyArrayCollection.php new file mode 100644 index 0000000000..a26b4f7fa2 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/collections/tests/Doctrine/Tests/LazyArrayCollection.php @@ -0,0 +1,33 @@ + + */ + private $collectionOnInitialization; + + /** @param Collection $collection */ + public function __construct(Collection $collection) + { + $this->collectionOnInitialization = $collection; + } + + /** + * Do the initialization logic. + */ + protected function doInitialize(): void + { + $this->collection = $this->collectionOnInitialization; + } +} diff --git a/sites/all/libraries/vendor/doctrine/deprecations/LICENSE b/sites/all/libraries/vendor/doctrine/deprecations/LICENSE new file mode 100644 index 0000000000..156905cdd0 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020-2021 Doctrine Project + +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/sites/all/libraries/vendor/doctrine/deprecations/README.md b/sites/all/libraries/vendor/doctrine/deprecations/README.md new file mode 100644 index 0000000000..22f0cced3e --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/README.md @@ -0,0 +1,154 @@ +# Doctrine Deprecations + +A small (side-effect free by default) layer on top of +`trigger_error(E_USER_DEPRECATED)` or PSR-3 logging. + +- no side-effects by default, making it a perfect fit for libraries that don't know how the error handler works they operate under +- options to avoid having to rely on error handlers global state by using PSR-3 logging +- deduplicate deprecation messages to avoid excessive triggering and reduce overhead + +We recommend to collect Deprecations using a PSR logger instead of relying on +the global error handler. + +## Usage from consumer perspective: + +Enable Doctrine deprecations to be sent to a PSR3 logger: + +```php +\Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger); +``` + +Enable Doctrine deprecations to be sent as `@trigger_error($message, E_USER_DEPRECATED)` +messages. + +```php +\Doctrine\Deprecations\Deprecation::enableWithTriggerError(); +``` + +If you only want to enable deprecation tracking, without logging or calling `trigger_error` then call: + +```php +\Doctrine\Deprecations\Deprecation::enableTrackingDeprecations(); +``` + +Tracking is enabled with all three modes and provides access to all triggered +deprecations and their individual count: + +```php +$deprecations = \Doctrine\Deprecations\Deprecation::getTriggeredDeprecations(); + +foreach ($deprecations as $identifier => $count) { + echo $identifier . " was triggered " . $count . " times\n"; +} +``` + +### Suppressing Specific Deprecations + +Disable triggering about specific deprecations: + +```php +\Doctrine\Deprecations\Deprecation::ignoreDeprecations("https://link/to/deprecations-description-identifier"); +``` + +Disable all deprecations from a package + +```php +\Doctrine\Deprecations\Deprecation::ignorePackage("doctrine/orm"); +``` + +### Other Operations + +When used within PHPUnit or other tools that could collect multiple instances of the same deprecations +the deduplication can be disabled: + +```php +\Doctrine\Deprecations\Deprecation::withoutDeduplication(); +``` + +Disable deprecation tracking again: + +```php +\Doctrine\Deprecations\Deprecation::disable(); +``` + +## Usage from a library/producer perspective: + +When you want to unconditionally trigger a deprecation even when called +from the library itself then the `trigger` method is the way to go: + +```php +\Doctrine\Deprecations\Deprecation::trigger( + "doctrine/orm", + "https://link/to/deprecations-description", + "message" +); +``` + +If variable arguments are provided at the end, they are used with `sprintf` on +the message. + +```php +\Doctrine\Deprecations\Deprecation::trigger( + "doctrine/orm", + "https://github.com/doctrine/orm/issue/1234", + "message %s %d", + "foo", + 1234 +); +``` + +When you want to trigger a deprecation only when it is called by a function +outside of the current package, but not trigger when the package itself is the cause, +then use: + +```php +\Doctrine\Deprecations\Deprecation::triggerIfCalledFromOutside( + "doctrine/orm", + "https://link/to/deprecations-description", + "message" +); +``` + +Based on the issue link each deprecation message is only triggered once per +request. + +A limited stacktrace is included in the deprecation message to find the +offending location. + +Note: A producer/library should never call `Deprecation::enableWith` methods +and leave the decision how to handle deprecations to application and +frameworks. + +## Usage in PHPUnit tests + +There is a `VerifyDeprecations` trait that you can use to make assertions on +the occurrence of deprecations within a test. + +```php +use Doctrine\Deprecations\PHPUnit\VerifyDeprecations; + +class MyTest extends TestCase +{ + use VerifyDeprecations; + + public function testSomethingDeprecation() + { + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234'); + + triggerTheCodeWithDeprecation(); + } + + public function testSomethingDeprecationFixed() + { + $this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234'); + + triggerTheCodeWithoutDeprecation(); + } +} +``` + +## What is a deprecation identifier? + +An identifier for deprecations is just a link to any resource, most often a +Github Issue or Pull Request explaining the deprecation and potentially its +alternative. diff --git a/sites/all/libraries/vendor/doctrine/deprecations/composer.json b/sites/all/libraries/vendor/doctrine/deprecations/composer.json new file mode 100644 index 0000000000..c79e38cdcd --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/composer.json @@ -0,0 +1,32 @@ +{ + "name": "doctrine/deprecations", + "type": "library", + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "license": "MIT", + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3", + "doctrine/coding-standard": "^9" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "autoload": { + "psr-4": {"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"} + }, + "autoload-dev": { + "psr-4": { + "DeprecationTests\\": "test_fixtures/src", + "Doctrine\\Foo\\": "test_fixtures/vendor/doctrine/foo" + } + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/sites/all/libraries/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php b/sites/all/libraries/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php new file mode 100644 index 0000000000..1029372faa --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php @@ -0,0 +1,266 @@ + */ + private static $ignoredPackages = []; + + /** @var array */ + private static $ignoredLinks = []; + + /** @var bool */ + private static $deduplication = true; + + /** + * Trigger a deprecation for the given package and identfier. + * + * The link should point to a Github issue or Wiki entry detailing the + * deprecation. It is additionally used to de-duplicate the trigger of the + * same deprecation during a request. + * + * @param mixed $args + */ + public static function trigger(string $package, string $link, string $message, ...$args): void + { + if (self::$type === self::TYPE_NONE) { + return; + } + + if (array_key_exists($link, self::$ignoredLinks)) { + self::$ignoredLinks[$link]++; + } else { + self::$ignoredLinks[$link] = 1; + } + + if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) { + return; + } + + if (isset(self::$ignoredPackages[$package])) { + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + + $message = sprintf($message, ...$args); + + self::delegateTriggerToBackend($message, $backtrace, $link, $package); + } + + /** + * Trigger a deprecation for the given package and identifier when called from outside. + * + * "Outside" means we assume that $package is currently installed as a + * dependency and the caller is not a file in that package. When $package + * is installed as a root package then deprecations triggered from the + * tests folder are also considered "outside". + * + * This deprecation method assumes that you are using Composer to install + * the dependency and are using the default /vendor/ folder and not a + * Composer plugin to change the install location. The assumption is also + * that $package is the exact composer packge name. + * + * Compared to {@link trigger()} this method causes some overhead when + * deprecation tracking is enabled even during deduplication, because it + * needs to call {@link debug_backtrace()} + * + * @param mixed $args + */ + public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void + { + if (self::$type === self::TYPE_NONE) { + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); + + // first check that the caller is not from a tests folder, in which case we always let deprecations pass + if (strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) { + $path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package . DIRECTORY_SEPARATOR; + + if (strpos($backtrace[0]['file'], $path) === false) { + return; + } + + if (strpos($backtrace[1]['file'], $path) !== false) { + return; + } + } + + if (array_key_exists($link, self::$ignoredLinks)) { + self::$ignoredLinks[$link]++; + } else { + self::$ignoredLinks[$link] = 1; + } + + if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) { + return; + } + + if (isset(self::$ignoredPackages[$package])) { + return; + } + + $message = sprintf($message, ...$args); + + self::delegateTriggerToBackend($message, $backtrace, $link, $package); + } + + /** + * @param array $backtrace + */ + private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void + { + if ((self::$type & self::TYPE_PSR_LOGGER) > 0) { + $context = [ + 'file' => $backtrace[0]['file'], + 'line' => $backtrace[0]['line'], + 'package' => $package, + 'link' => $link, + ]; + + self::$logger->notice($message, $context); + } + + if (! ((self::$type & self::TYPE_TRIGGER_ERROR) > 0)) { + return; + } + + $message .= sprintf( + ' (%s:%d called by %s:%d, %s, package %s)', + self::basename($backtrace[0]['file']), + $backtrace[0]['line'], + self::basename($backtrace[1]['file']), + $backtrace[1]['line'], + $link, + $package + ); + + @trigger_error($message, E_USER_DEPRECATED); + } + + /** + * A non-local-aware version of PHPs basename function. + */ + private static function basename(string $filename): string + { + $pos = strrpos($filename, DIRECTORY_SEPARATOR); + + if ($pos === false) { + return $filename; + } + + return substr($filename, $pos + 1); + } + + public static function enableTrackingDeprecations(): void + { + self::$type |= self::TYPE_TRACK_DEPRECATIONS; + } + + public static function enableWithTriggerError(): void + { + self::$type |= self::TYPE_TRIGGER_ERROR; + } + + public static function enableWithPsrLogger(LoggerInterface $logger): void + { + self::$type |= self::TYPE_PSR_LOGGER; + self::$logger = $logger; + } + + public static function withoutDeduplication(): void + { + self::$deduplication = false; + } + + public static function disable(): void + { + self::$type = self::TYPE_NONE; + self::$logger = null; + self::$deduplication = true; + + foreach (self::$ignoredLinks as $link => $count) { + self::$ignoredLinks[$link] = 0; + } + } + + public static function ignorePackage(string $packageName): void + { + self::$ignoredPackages[$packageName] = true; + } + + public static function ignoreDeprecations(string ...$links): void + { + foreach ($links as $link) { + self::$ignoredLinks[$link] = 0; + } + } + + public static function getUniqueTriggeredDeprecationsCount(): int + { + return array_reduce(self::$ignoredLinks, static function (int $carry, int $count) { + return $carry + $count; + }, 0); + } + + /** + * Returns each triggered deprecation link identifier and the amount of occurrences. + * + * @return array + */ + public static function getTriggeredDeprecations(): array + { + return self::$ignoredLinks; + } +} diff --git a/sites/all/libraries/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php b/sites/all/libraries/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php new file mode 100644 index 0000000000..4c3366a971 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php @@ -0,0 +1,66 @@ + */ + private $doctrineDeprecationsExpectations = []; + + /** @var array */ + private $doctrineNoDeprecationsExpectations = []; + + public function expectDeprecationWithIdentifier(string $identifier): void + { + $this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + } + + public function expectNoDeprecationWithIdentifier(string $identifier): void + { + $this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + } + + /** + * @before + */ + public function enableDeprecationTracking(): void + { + Deprecation::enableTrackingDeprecations(); + } + + /** + * @after + */ + public function verifyDeprecationsAreTriggered(): void + { + foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) { + $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + + $this->assertTrue( + $actualCount > $expectation, + sprintf( + "Expected deprecation with identifier '%s' was not triggered by code executed in test.", + $identifier + ) + ); + } + + foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) { + $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; + + $this->assertTrue( + $actualCount === $expectation, + sprintf( + "Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.", + $identifier + ) + ); + } + } +} diff --git a/sites/all/libraries/vendor/doctrine/deprecations/phpcs.xml b/sites/all/libraries/vendor/doctrine/deprecations/phpcs.xml new file mode 100644 index 0000000000..f115e43dd0 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/phpcs.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + lib + tests + + + + + + diff --git a/sites/all/libraries/vendor/doctrine/deprecations/phpunit.xml.dist b/sites/all/libraries/vendor/doctrine/deprecations/phpunit.xml.dist new file mode 100644 index 0000000000..4740c06042 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/phpunit.xml.dist @@ -0,0 +1,8 @@ + + + + + tests + + + diff --git a/sites/all/libraries/vendor/doctrine/deprecations/test_fixtures/src/Foo.php b/sites/all/libraries/vendor/doctrine/deprecations/test_fixtures/src/Foo.php new file mode 100644 index 0000000000..c4b8ebecee --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/test_fixtures/src/Foo.php @@ -0,0 +1,22 @@ +oldFunc(); + } + + public static function triggerDependencyWithDeprecationFromInside(): void + { + $bar = new Bar(); + $bar->newFunc(); + } +} diff --git a/sites/all/libraries/vendor/doctrine/deprecations/test_fixtures/src/RootDeprecation.php b/sites/all/libraries/vendor/doctrine/deprecations/test_fixtures/src/RootDeprecation.php new file mode 100644 index 0000000000..feccd48650 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/test_fixtures/src/RootDeprecation.php @@ -0,0 +1,20 @@ +oldFunc(); + } +} diff --git a/sites/all/libraries/vendor/doctrine/deprecations/test_fixtures/vendor/doctrine/foo/Baz.php b/sites/all/libraries/vendor/doctrine/deprecations/test_fixtures/vendor/doctrine/foo/Baz.php new file mode 100644 index 0000000000..62b2bb1034 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/test_fixtures/vendor/doctrine/foo/Baz.php @@ -0,0 +1,14 @@ +oldFunc(); + } +} diff --git a/sites/all/libraries/vendor/doctrine/deprecations/tests/Doctrine/Deprecations/DeprecationTest.php b/sites/all/libraries/vendor/doctrine/deprecations/tests/Doctrine/Deprecations/DeprecationTest.php new file mode 100644 index 0000000000..e59c1466c0 --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/tests/Doctrine/Deprecations/DeprecationTest.php @@ -0,0 +1,251 @@ +setAccessible(true); + $reflectionProperty->setValue([]); + + $reflectionProperty = new ReflectionProperty(Deprecation::class, 'ignoredLinks'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue([]); + + Deprecation::enableTrackingDeprecations(); + } + + public function expectDeprecation(): void + { + if (method_exists(TestCase::class, 'expectDeprecation')) { + parent::expectDeprecation(); + } else { + parent::expectException(Deprecated::class); + } + } + + public function expectDeprecationMessage(string $message): void + { + if (method_exists(TestCase::class, 'expectDeprecationMessage')) { + parent::expectDeprecationMessage($message); + } else { + parent::expectExceptionMessage($message); + } + } + + public function expectErrorHandler(string $expectedMessage, string $identifier, int $times = 1): void + { + set_error_handler(function ($type, $message) use ($expectedMessage, $identifier, $times): void { + $this->assertStringMatchesFormat( + $expectedMessage, + $message + ); + $this->assertEquals([$identifier => $times], Deprecation::getTriggeredDeprecations()); + }); + } + + public function testDeprecation(): void + { + Deprecation::enableWithTriggerError(); + + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/deprecations/1234'); + + $this->expectErrorHandler( + 'this is deprecated foo 1234 (DeprecationTest.php:%d called by TestCase.php:%d, https://github.com/doctrine/deprecations/1234, package doctrine/orm)', + 'https://github.com/doctrine/deprecations/1234' + ); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/1234', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + + $this->assertEquals(1, Deprecation::getUniqueTriggeredDeprecationsCount()); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/1234', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + + $this->assertEquals(2, Deprecation::getUniqueTriggeredDeprecationsCount()); + } + + public function testDeprecationWithoutDeduplication(): void + { + Deprecation::enableWithTriggerError(); + Deprecation::withoutDeduplication(); + + $this->expectErrorHandler( + 'this is deprecated foo 2222 (DeprecationTest.php:%d called by TestCase.php:%d, https://github.com/doctrine/deprecations/2222, package doctrine/orm)', + 'https://github.com/doctrine/deprecations/2222' + ); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/2222', + 'this is deprecated %s %d', + 'foo', + 2222 + ); + + $this->assertEquals(1, Deprecation::getUniqueTriggeredDeprecationsCount()); + + $this->expectErrorHandler( + 'this is deprecated foo 2222 (DeprecationTest.php:%d called by TestCase.php:%d, https://github.com/doctrine/deprecations/2222, package doctrine/orm)', + 'https://github.com/doctrine/deprecations/2222', + 2 + ); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/2222', + 'this is deprecated %s %d', + 'foo', + 2222 + ); + + $this->assertEquals(2, Deprecation::getUniqueTriggeredDeprecationsCount()); + } + + public function testDeprecationResetsCounts(): void + { + try { + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/1234', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + } catch (Throwable $e) { + Deprecation::disable(); + + $this->assertEquals(0, Deprecation::getUniqueTriggeredDeprecationsCount()); + $this->assertEquals(['https://github.com/doctrine/deprecations/1234' => 0], Deprecation::getTriggeredDeprecations()); + } + } + + public function expectDeprecationMock(string $message, string $identifier, string $package): MockObject + { + $mock = $this->createMock(LoggerInterface::class); + $mock->method('notice')->with($message, $this->callback(function ($context) use ($identifier, $package) { + $this->assertEquals($package, $context['package']); + $this->assertEquals($identifier, $context['link']); + + return true; + })); + + return $mock; + } + + public function testDeprecationWithPsrLogger(): void + { + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/deprecations/2222'); + + $mock = $this->expectDeprecationMock( + 'this is deprecated foo 1234', + 'https://github.com/doctrine/deprecations/2222', + 'doctrine/orm' + ); + Deprecation::enableWithPsrLogger($mock); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/deprecations/2222', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + } + + public function testDeprecationWithIgnoredPackage(): void + { + Deprecation::enableWithTriggerError(); + Deprecation::ignorePackage('doctrine/orm'); + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/orm/issue/1234', + 'this is deprecated %s %d', + 'foo', + 1234 + ); + + $this->assertEquals(1, Deprecation::getUniqueTriggeredDeprecationsCount()); + $this->assertEquals(['https://github.com/doctrine/orm/issue/1234' => 1], Deprecation::getTriggeredDeprecations()); + } + + public function testDeprecationIfCalledFromOutside(): void + { + Deprecation::enableWithTriggerError(); + + $this->expectErrorHandler( + 'Bar::oldFunc() is deprecated, use Bar::newFunc() instead. (Bar.php:16 called by Foo.php:14, https://github.com/doctrine/foo, package doctrine/foo)', + 'https://github.com/doctrine/foo' + ); + + Foo::triggerDependencyWithDeprecation(); + } + + public function testDeprecationIfCalledFromOutsideNotTriggeringFromInside(): void + { + Deprecation::enableWithTriggerError(); + + Foo::triggerDependencyWithDeprecationFromInside(); + + $this->assertEquals(0, Deprecation::getUniqueTriggeredDeprecationsCount()); + } + + public function testDeprecationIfCalledFromOutsideNotTriggeringFromInsideClass(): void + { + Deprecation::enableWithTriggerError(); + + $baz = new Baz(); + $baz->usingOldFunc(); + + $this->assertEquals(0, Deprecation::getUniqueTriggeredDeprecationsCount()); + } + + public function testDeprecationCalledFromOutsideInRoot(): void + { + Deprecation::enableWithTriggerError(); + + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/deprecations/4444'); + + $this->expectErrorHandler( + 'this is deprecated foo 1234 (RootDeprecation.php:%d called by DeprecationTest.php:%d, https://github.com/doctrine/deprecations/4444, package doctrine/orm)', + 'https://github.com/doctrine/deprecations/4444' + ); + + RootDeprecation::run(); + + $this->assertEquals(1, Deprecation::getUniqueTriggeredDeprecationsCount()); + } +} diff --git a/sites/all/libraries/vendor/doctrine/deprecations/tests/Doctrine/Deprecations/VerifyDeprecationsTest.php b/sites/all/libraries/vendor/doctrine/deprecations/tests/Doctrine/Deprecations/VerifyDeprecationsTest.php new file mode 100644 index 0000000000..8681f7d69c --- /dev/null +++ b/sites/all/libraries/vendor/doctrine/deprecations/tests/Doctrine/Deprecations/VerifyDeprecationsTest.php @@ -0,0 +1,35 @@ +expectDeprecationWithIdentifier('http://example.com'); + + Deprecation::trigger('doctrine/dbal', 'http://example.com', 'message'); + } + + public function testExpectNoDeprecationWithIdentifier(): void + { + $this->expectNoDeprecationWithIdentifier('http://example.com'); + + Deprecation::trigger('doctrine/dbal', 'http://otherexample.com', 'message'); + } +} diff --git a/sites/all/libraries/vendor/guzzle/guzzle/.gitignore b/sites/all/libraries/vendor/guzzle/guzzle/.gitignore deleted file mode 100644 index 893035d5ba..0000000000 --- a/sites/all/libraries/vendor/guzzle/guzzle/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# Ingore common cruft -.DS_STORE -coverage -.idea - -# Ignore binary files -guzzle.phar -guzzle-min.phar - -# Ignore potentially sensitive phpunit file -phpunit.xml - -# Ignore composer generated files -composer.phar -composer.lock -composer-test.lock -vendor/ - -# Ignore build files -build/ -phing/build.properties - -# Ignore subsplit working directory -.subsplit - -docs/_build -docs/*.pyc diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/.editorconfig b/sites/all/libraries/vendor/jbroutier/iucn-api-client/.editorconfig new file mode 100644 index 0000000000..677e36e295 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/CHANGELOG-1.x.md b/sites/all/libraries/vendor/jbroutier/iucn-api-client/CHANGELOG-1.x.md new file mode 100644 index 0000000000..972cb5eba9 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/CHANGELOG-1.x.md @@ -0,0 +1,3 @@ +**Version 1.0.0 (2022-09-09)** + +- Initial stable release. diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/LICENSE b/sites/all/libraries/vendor/jbroutier/iucn-api-client/LICENSE new file mode 100644 index 0000000000..39452a57fe --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Jérémie BROUTIER + +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/sites/all/libraries/vendor/jbroutier/iucn-api-client/README.md b/sites/all/libraries/vendor/jbroutier/iucn-api-client/README.md new file mode 100644 index 0000000000..a4d2abc6da --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/README.md @@ -0,0 +1,68 @@ +[![PHP](https://github.com/jbroutier/iucn-api-client/actions/workflows/php.yml/badge.svg)](https://github.com/jbroutier/iucn-api-client/actions/workflows/php.yml) +[![codecov](https://codecov.io/gh/jbroutier/iucn-api-client/branch/develop/graph/badge.svg?token=20HBOP8NB3)](https://codecov.io/gh/jbroutier/iucn-api-client) +[![PHP version](https://img.shields.io/badge/php-7.4+-787cb5?logo=php)](https://github.com/jbroutier/iucn-api-client) +[![License](https://img.shields.io/github/license/jbroutier/iucn-api-client)](https://github.com/jbroutier/iucn-api-client/blob/main/LICENSE) +[![Packagist](https://img.shields.io/packagist/v/jbroutier/iucn-api-client)](https://packagist.org/packages/jbroutier/iucn-api-client) + +# IUCN API Client + +A PHP client to retrieve data from [The IUCN Red List of Threatened Species™](https://www.iucnredlist.org/). +It currently supports the version 3 of the API as described in +the [API reference](https://apiv3.iucnredlist.org/api/v3/docs), with the IUCN database version 2022-1. + +## Disclaimer + +:warning: This project is not supported or endorsed in any manner by the IUCN. :warning: + +## Installation + +```bash +composer require jbroutier/iucn-api-client +``` + +## Requirements + +An API key (token) is required to authenticate yourself and be able to use the IUCN API. To obtain an API key, please +use the [application form](https://apiv3.iucnredlist.org/api/v3/token) and submit your request to the IUCN. + +## Getting started + +Start by creating an instance of the client. + +```php +$client = new IucnApi\Client(''); +``` + +You can pass an array of options to the underlying HTTP client, if you want to configure the timeout for example. See +the [Symfony HTTP client](https://symfony.com/doc/current/http_client.html) documentation for a list of available +options. + +```php +$client = new IucnApi\Client('', ['timeout' => 5000]); +``` + +You can then request the details of a species for example. + +```php +try { + $species = $client->getSpeciesByName('Ailurus fulgens'); +} catch (\IucnApi\Exception\IucnApiException $exception) { + // Something doesn't look good… +} + +echo $species->getKigdom(); // ANIMALIA +echo $species->getPhylum(); // CHORDATA +echo $species->getClass(); // MAMMALIA +echo $species->getOrder(); // CARNIVORA +echo $species->getFamily(); // AILURIDAE +echo $species->getGenus(); // Ailurus +echo $species->getMainCommonName(); // Red Panda +``` + +The full list of available methods is described in +the [ClientInterface](https://github.com/jbroutier/iucn-api-client/blob/main/src/ClientInterface.php) interface. + +## Documentation + +The official API documentation is available [here](https://apiv3.iucnredlist.org/api/v3/docs). The IUCN Red List +database changelog can be found [here](https://apiv3.iucnredlist.org/changelog). diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/composer.json b/sites/all/libraries/vendor/jbroutier/iucn-api-client/composer.json new file mode 100644 index 0000000000..4a799580d4 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/composer.json @@ -0,0 +1,55 @@ +{ + "name": "jbroutier/iucn-api-client", + "description": "A PHP client to retrieve data from The IUCN Red List of Threatened Species™.", + "version": "1.0.0", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Jérémie BROUTIER", + "email": "jeremie.broutier@posteo.net", + "homepage": "https://github.com/jbroutier", + "role": "developer" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/jbroutier/iucn-api-client.git" + }, + "require": { + "php": "^7.4|^8.0", + "doctrine/collections": "^1.7.2", + "symfony/http-client": "^5.4|^6.0" + }, + "require-dev": { + "ext-json": "*", + "ekino/phpstan-banned-code": "^1.0.0", + "phpstan/extension-installer": "^1.1.0", + "phpstan/phpstan": "^1.8.4", + "phpstan/phpstan-deprecation-rules": "^1.0.0", + "phpstan/phpstan-phpunit": "^1.1.1", + "phpstan/phpstan-strict-rules": "^1.4.3", + "phpunit/phpunit": "^9.5.24" + }, + "autoload": { + "psr-4": { + "IucnApi\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "IucnApi\\Tests\\": "tests/" + } + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true + } + }, + "scripts": { + "phpstan": "vendor/bin/phpstan analyse --memory-limit 1G", + "tests:all": "vendor/bin/phpunit --testdox --coverage-html coverage", + "tests:functional": "vendor/bin/phpunit --testsuite=functional --testdox --coverage-clover coverage-functional.xml", + "tests:unit": "vendor/bin/phpunit --testsuite=unit --testdox --coverage-clover coverage-unit.xml" + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/phpstan.neon b/sites/all/libraries/vendor/jbroutier/iucn-api-client/phpstan.neon new file mode 100644 index 0000000000..08566d07a4 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/phpstan.neon @@ -0,0 +1,5 @@ +parameters: + level: 9 + paths: + - src + - tests diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/phpunit.xml.dist b/sites/all/libraries/vendor/jbroutier/iucn-api-client/phpunit.xml.dist new file mode 100644 index 0000000000..7684269da4 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/phpunit.xml.dist @@ -0,0 +1,20 @@ + + + + + src + + + + + tests/Functional + + + tests/Unit + + + diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Client.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Client.php new file mode 100644 index 0000000000..a4c0b829b7 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Client.php @@ -0,0 +1,684 @@ += php 7.4: protected HttpClientInterface $httpClient; + protected $httpClient; + + /** + * Create a new instance of the client. + * + * @param string $token The API authentication token. + * @param array|null $options An optional array of options. These options will be passed directly to the underlying HTTP client. + */ + public function __construct(string $token, ?array $options = null) + { + $options = array_merge_recursive($options ?? [], [ + 'headers' => [ + 'accept' => 'application/json', + ], + 'query' => [ + 'token' => $token, + ], + ]); + + $this->httpClient = HttpClient::createForBaseUri('https://apiv3.iucnredlist.org/api/v3/', $options); + } + + public function getCountries(): Collection + { + try { + $response = $this->httpClient->request('GET', 'country/list'); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['results'] as $result) { + $country = Country::createFromArray($result); + $collection->add($country); + } + + return $collection; + } + + public function getComprehensiveGroups(): Collection + { + try { + $response = $this->httpClient->request('GET', 'comp-group/list'); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $group = Group::createFromArray($result); + $collection->add($group); + } + + return $collection; + } + + public function getPlantGrowthFormsById(int $id, string $region = null): Collection + { + $url = 'growth_forms/species/id/' . $id; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $plantGrowthForm = GrowthForm::createFromArray($result); + $collection->add($plantGrowthForm); + } + + return $collection; + } + + public function getPlantGrowthFormsByName(string $name, string $region = null): Collection + { + $url = 'growth_forms/species/name/' . $name; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $plantGrowthForm = GrowthForm::createFromArray($result); + $collection->add($plantGrowthForm); + } + + return $collection; + } + + public function getRegions(): Collection + { + try { + $response = $this->httpClient->request('GET', 'region/list'); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['results'] as $result) { + $region = Region::createFromArray($result); + $collection->add($region); + } + + return $collection; + } + + public function getSpeciesAssessmentsById(int $id, string $region = null): Collection + { + $url = 'species/history/id/' . $id; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $assessment = Assessment::createFromArray($result); + $collection->add($assessment); + } + + return $collection; + } + + public function getSpeciesAssessmentsByName(string $name, string $region = null): Collection + { + $url = 'species/history/name/' . $name; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $assessment = Assessment::createFromArray($result); + $collection->add($assessment); + } + + return $collection; + } + + public function getSpeciesByCategory(string $category): Collection + { + try { + $response = $this->httpClient->request('GET', 'species/category/' . $category); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $result['category'] = $data['category']; + $species = Species::createFromArray($result); + $collection->add($species); + } + + return $collection; + } + + public function getSpeciesByComprehensiveGroup(string $group): Collection + { + try { + $response = $this->httpClient->request('GET', 'comp-group/getspecies/' . $group); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $species = Species::createFromArray($result); + $collection->add($species); + } + + return $collection; + } + + public function getSpeciesByCountry(string $country): Collection + { + try { + $response = $this->httpClient->request('GET', 'country/getspecies/' . $country); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $species = Species::createFromArray($result); + $collection->add($species); + } + + return $collection; + } + + public function getSpeciesById(int $id, string $region = null): ?SpeciesDetails + { + $url = 'species/id/' . $id; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + if (count($data['result']) === 0) { + return null; + } + + return SpeciesDetails::createFromArray($data['result'][0]); + } + + // public function getSpeciesByName(string $name, string $region = null): ?SpeciesDetails + public function getSpeciesByName(string $name, string $region = null) { + $url = 'species/' . $name; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url, ['base_uri' => variable_get('iucn_api_v3_url', FALSE), 'query' => ['token' => variable_get('iucn_api_v3_api_key_token', FALSE)]]); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + if (count($data['result']) === 0) { + return null; + } + + return SpeciesDetails::createFromArray($data['result'][0]); + } + + public function getSpeciesCitationById(int $id, string $region = null): ?Citation + { + $url = 'species/citation/id/' . $id; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + if (count($data['result']) === 0) { + return null; + } + + return Citation::createFromArray($data['result'][0]); + } + + public function getSpeciesCitationByName(string $name, string $region = null): ?Citation + { + $url = 'species/citation/' . $name; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + if (count($data['result']) === 0) { + return null; + } + + return Citation::createFromArray($data['result'][0]); + } + + public function getSpeciesCommonNames(string $name): Collection + { + try { + $response = $this->httpClient->request('GET', 'species/common_names/' . $name); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $commonName = CommonName::createFromArray($result); + $collection->add($commonName); + } + + return $collection; + } + + public function getSpeciesConservationMeasuresById(int $id, string $region = null): Collection + { + $url = 'measures/species/id/' . $id; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $conservationMeasure = ConservationMeasure::createFromArray($result); + $collection->add($conservationMeasure); + } + + return $collection; + } + + public function getSpeciesConservationMeasuresByName(string $name, string $region = null): Collection + { + $url = 'measures/species/name/' . $name; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $conservationMeasure = ConservationMeasure::createFromArray($result); + $collection->add($conservationMeasure); + } + + return $collection; + } + + public function getSpeciesCount(string $region = null, bool $includeSubspecies = true): int + { + $url = 'speciescount'; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + return intval($includeSubspecies ? $data['count'] : $data['speciescount']); + } + + public function getSpeciesHabitatsById(int $id, string $region = null): Collection + { + $url = 'habitats/species/id/' . $id; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $habitat = Habitat::createFromArray($result); + $collection->add($habitat); + } + + return $collection; + } + + public function getSpeciesHabitatsByName(string $name, string $region = null): Collection + { + $url = 'habitats/species/name/' . $name; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $habitat = Habitat::createFromArray($result); + $collection->add($habitat); + } + + return $collection; + } + + public function getSpeciesNarrativeTextById(int $id, string $region = null): ?NarrativeText + { + $url = 'species/narrative/id/' . $id; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + if (count($data['result']) === 0) { + return null; + } + + return NarrativeText::createFromArray($data['result'][0]); + } + + public function getSpeciesNarrativeTextByName(string $name, string $region = null): ?NarrativeText + { + $url = 'species/narrative/' . $name; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + if (count($data['result']) === 0) { + return null; + } + + return NarrativeText::createFromArray($data['result'][0]); + } + + public function getSpeciesOccurrencesById(int $id, string $region = null): Collection + { + $url = 'species/countries/id/' . $id; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $occurrence = Occurrence::createFromArray($result); + $collection->add($occurrence); + } + + return $collection; + } + + public function getSpeciesOccurrencesByName(string $name, string $region = null): Collection + { + $url = 'species/countries/name/' . $name; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $occurrence = Occurrence::createFromArray($result); + $collection->add($occurrence); + } + + return $collection; + } + + public function getSpeciesSynonyms(string $name): Collection + { + try { + $response = $this->httpClient->request('GET', 'species/synonym/' . $name); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $synonym = Synonym::createFromArray($result); + $collection->add($synonym); + } + + return $collection; + } + + public function getSpeciesThreatsById(int $id, string $region = null): Collection + { + $url = 'threats/species/id/' . $id; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $threat = Threat::createFromArray($result); + $collection->add($threat); + } + + return $collection; + } + + public function getSpeciesThreatsByName(string $name, string $region = null): Collection + { + $url = 'threats/species/name/' . $name; + + if (!is_null($region)) { + $url .= '/region/' . $region; + } + + try { + $response = $this->httpClient->request('GET', $url); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + $collection = new ArrayCollection(); + + foreach ($data['result'] as $result) { + $threat = Threat::createFromArray($result); + $collection->add($threat); + } + + return $collection; + } + + public function getVersion(): string + { + try { + $response = $this->httpClient->request('GET', 'version'); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + return $data['version']; + } + + public function getWebsiteLink(string $name): ?string + { + try { + $response = $this->httpClient->request('GET', 'weblink/' . $name); + $data = $response->toArray(); + } catch (ExceptionInterface $exception) { + throw new IucnApiException($exception->getMessage(), $exception->getCode(), $exception); + } + + if (!array_key_exists('rlurl', $data)) { + return null; + } + + return $data['rlurl']; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/ClientInterface.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/ClientInterface.php new file mode 100644 index 0000000000..275a2453a6 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/ClientInterface.php @@ -0,0 +1,412 @@ + + * + * @throws IucnApiException If any error occurs. + */ + public function getCountries(): Collection; + + /** + * Get a list of comprehensive groups. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#comp-groups + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getComprehensiveGroups(): Collection; + + /** + * Get a list of growth forms for a plant species, by species ID. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#growth-forms-id + * + * @param int $id The species ID. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getPlantGrowthFormsById(int $id, string $region = null): Collection; + + /** + * Get a list of growth forms for a plant species, by species name. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#growth-forms-name + * + * @param string $name The species name. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getPlantGrowthFormsByName(string $name, string $region = null): Collection; + + /** + * Get a list of regions. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#regions + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getRegions(): Collection; + + /** + * Get a list of historical assessments for a species, by species ID. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-history-id + * + * @param int $id The species ID. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesAssessmentsById(int $id, string $region = null): Collection; + + /** + * Get a list of historical assessments for a species, by species name. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-history-name + * + * @param string $name The species name. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesAssessmentsByName(string $name, string $region = null): Collection; + + /** + * Get a list of species by category. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-category + * + * @param string $category The category code. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesByCategory(string $category): Collection; + + /** + * Get a list of species by comprehensive group. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#comp-groups-species + * + * @param string $group The group code. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesByComprehensiveGroup(string $group): Collection; + + /** + * Get a list of species by country. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#countries-species + * + * @param string $country The country, as an ISO 3166-1 alpha 2 country code. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesByCountry(string $country): Collection; + + /** + * Get a species, by species ID. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-individual-id + * + * @param int $id The species ID. + * @param string|null $region An optional region identifier. + * + * @return SpeciesDetails|null + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesById(int $id, string $region = null): ?SpeciesDetails; + + /** + * Get a species, by species name. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-individual-name + * + * @param string $name The species name. + * @param string|null $region An optional region identifier. + * + * @return SpeciesDetails|null + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesByName(string $name, string $region = null); + + /** + * Get the citation for a species, by species ID. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-citation-id + * + * @param int $id The species ID. + * @param string|null $region An optional region identifier. + * + * @return Citation|null + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesCitationById(int $id, string $region = null): ?Citation; + + /** + * Get the citation for a species, by species name. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-citation-name + * + * @param string $name The species name. + * @param string|null $region An optional region identifier. + * + * @return Citation|null + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesCitationByName(string $name, string $region = null): ?Citation; + + /** + * Get a list of common names for a species. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-common + * + * @param string $name The species name. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesCommonNames(string $name): Collection; + + /** + * Get a list of conservation measures for a species, by species ID. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#measures-id + * + * @param int $id The species ID. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesConservationMeasuresById(int $id, string $region = null): Collection; + + /** + * Get a list of conservation measures for a species, by species name. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#measures-name + * + * @param string $name The species name. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesConservationMeasuresByName(string $name, string $region = null): Collection; + + /** + * Get the total species count. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-count + * + * @param string|null $region An optional region identifier. + * @param bool $includeSubspecies Whether subspecies should be included or not. + * + * @return int + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesCount(string $region = null, bool $includeSubspecies = true): int; + + /** + * Get a list of habitats for a species, by species ID. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#habitat-id + * + * @param int $id The species ID. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesHabitatsById(int $id, string $region = null): Collection; + + /** + * Get a list of habitats for a species, by species name. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#habitat-name + * + * @param string $name The species name. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesHabitatsByName(string $name, string $region = null): Collection; + + /** + * Get narrative information for a species, by species ID. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-narrative-id + * + * @param int $id The species ID. + * @param string|null $region An optional region identifier. + * + * @return NarrativeText|null + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesNarrativeTextById(int $id, string $region = null): ?NarrativeText; + + /** + * Get narrative information for a species, by species name. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-narrative-name + * + * @param string $name The species name. + * @param string|null $region An optional region identifier. + * + * @return NarrativeText|null + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesNarrativeTextByName(string $name, string $region = null): ?NarrativeText; + + /** + * Get a list of countries of occurrence for a species, by species ID. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-occurrence-id + * + * @param int $id The species ID. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesOccurrencesById(int $id, string $region = null): Collection; + + /** + * Get a list of countries of occurrence for a species, by species name. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-occurrence-name + * + * @param string $name The species name. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesOccurrencesByName(string $name, string $region = null): Collection; + + /** + * Get a list of synonyms for a species. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#species-synonym + * + * @param string $name The species name. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesSynonyms(string $name): Collection; + + /** + * Get a list of threats to a species, by species ID. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#threat-id + * + * @param int $id The species ID. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesThreatsById(int $id, string $region = null): Collection; + + /** + * Get a list of threats to a species, by species name. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#threat-name + * + * @param string $name The species name. + * @param string|null $region An optional region identifier. + * + * @return Collection + * + * @throws IucnApiException If any error occurs. + */ + public function getSpeciesThreatsByName(string $name, string $region = null): Collection; + + /** + * Get the version of the IUCN Red List database. + * + * @see http://apiv3.iucnredlist.org/api/v3/docs#version + * + * @return string + * + * @throws IucnApiException If any error occurs. + */ + public function getVersion(): string; + + /** + * Get the IUCN website link for a species. + * + * @see https://apiv3.iucnredlist.org/api/v3/docs#weblink + * + * @param string $name The species name. + * + * @return string|null + * + * @throws IucnApiException If any error occurs. + */ + public function getWebsiteLink(string $name): ?string; +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Exception/IucnApiException.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Exception/IucnApiException.php new file mode 100644 index 0000000000..96f1f9c319 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Exception/IucnApiException.php @@ -0,0 +1,7 @@ +assessmentYear; + } + + public function getCategoryCode(): ?string + { + return $this->categoryCode; + } + + public function getCategoryName(): ?string + { + return $this->categoryName; + } + + public function getPublicationYear(): ?int + { + return $this->publicationYear; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Assessment + { + $assessment = new Assessment(); + $assessment->assessmentYear = !is_null($data['assess_year']) ? intval($data['assess_year']) : null; + $assessment->categoryCode = !is_null($data['code']) ? strval($data['code']) : null; + $assessment->categoryName = !is_null($data['category']) ? strval($data['category']) : null; + $assessment->publicationYear = !is_null($data['year']) ? intval($data['year']) : null; + + return $assessment; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Citation.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Citation.php new file mode 100644 index 0000000000..8f55a17ea0 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Citation.php @@ -0,0 +1,24 @@ +citation; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Citation + { + $citation = new Citation(); + $citation->citation = !is_null($data['citation']) ? strval($data['citation']) : null; + + return $citation; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/CommonName.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/CommonName.php new file mode 100644 index 0000000000..d19741840c --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/CommonName.php @@ -0,0 +1,38 @@ +language; + } + + public function getName(): ?string + { + return $this->name; + } + + public function isPrimary(): ?bool + { + return $this->primary; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): CommonName + { + $commonName = new CommonName(); + $commonName->language = !is_null($data['language']) ? strval($data['language']) : null; + $commonName->name = !is_null($data['taxonname']) ? strval($data['taxonname']) : null; + $commonName->primary = !is_null($data['primary']) ? boolval($data['primary']) : null; + + return $commonName; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/ConservationMeasure.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/ConservationMeasure.php new file mode 100644 index 0000000000..3b0d461c29 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/ConservationMeasure.php @@ -0,0 +1,31 @@ +code; + } + + public function getTitle(): ?string + { + return $this->title; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): ConservationMeasure + { + $conservationMeasure = new ConservationMeasure(); + $conservationMeasure->code = !is_null($data['code']) ? strval($data['code']) : null; + $conservationMeasure->title = !is_null($data['title']) ? strval($data['title']) : null; + + return $conservationMeasure; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Country.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Country.php new file mode 100644 index 0000000000..cbff78cb6c --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Country.php @@ -0,0 +1,31 @@ +code; + } + + public function getName(): ?string + { + return $this->name; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Country + { + $country = new Country(); + $country->code = !is_null($data['isocode']) ? strval($data['isocode']) : null; + $country->name = !is_null($data['country']) ? strval($data['country']) : null; + + return $country; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Group.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Group.php new file mode 100644 index 0000000000..d3482795af --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Group.php @@ -0,0 +1,24 @@ +code; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Group + { + $group = new Group(); + $group->code = !is_null($data['group_name']) ? strval($data['group_name']) : null; + + return $group; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/GrowthForm.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/GrowthForm.php new file mode 100644 index 0000000000..e81cfba03b --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/GrowthForm.php @@ -0,0 +1,24 @@ +name; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): GrowthForm + { + $plantGrowthForm = new GrowthForm(); + $plantGrowthForm->name = !is_null($data['name']) ? strval($data['name']) : null; + + return $plantGrowthForm; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Habitat.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Habitat.php new file mode 100644 index 0000000000..cb54fb5143 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Habitat.php @@ -0,0 +1,52 @@ +code; + } + + public function getMajorImportance(): ?string + { + return $this->majorImportance; + } + + public function getName(): ?string + { + return $this->name; + } + + public function getSeason(): ?string + { + return $this->season; + } + + public function getSuitability(): ?string + { + return $this->suitability; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Habitat + { + $habitat = new Habitat(); + $habitat->code = !is_null($data['code']) ? strval($data['code']) : null; + $habitat->majorImportance = !is_null($data['majorimportance']) ? strval($data['majorimportance']) : null; + $habitat->name = !is_null($data['habitat']) ? strval($data['habitat']) : null; + $habitat->season = !is_null($data['season']) ? strval($data['season']) : null; + $habitat->suitability = !is_null($data['suitability']) ? strval($data['suitability']) : null; + + return $habitat; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/NarrativeText.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/NarrativeText.php new file mode 100644 index 0000000000..f2df4665dc --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/NarrativeText.php @@ -0,0 +1,81 @@ +conservationMeasures; + } + + public function getGeographicRange(): ?string + { + return $this->geographicRange; + } + + public function getHabitat(): ?string + { + return $this->habitat; + } + + public function getPopulation(): ?string + { + return $this->population; + } + + public function getPopulationTrend(): ?string + { + return $this->populationTrend; + } + + public function getRationale(): ?string + { + return $this->rationale; + } + + public function getTaxonomicNotes(): ?string + { + return $this->taxonomicNotes; + } + + public function getThreats(): ?string + { + return $this->threats; + } + + public function getUseTrade(): ?string + { + return $this->useTrade; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): NarrativeText + { + $narrativeText = new NarrativeText(); + $narrativeText->conservationMeasures = !is_null($data['conservationmeasures']) + ? strval($data['conservationmeasures']) : null; + $narrativeText->geographicRange = !is_null($data['geographicrange']) ? strval($data['geographicrange']) : null; + $narrativeText->habitat = !is_null($data['habitat']) ? strval($data['habitat']) : null; + $narrativeText->population = !is_null($data['population']) ? strval($data['population']) : null; + $narrativeText->populationTrend = !is_null($data['populationtrend']) ? strval($data['populationtrend']) : null; + $narrativeText->rationale = !is_null($data['rationale']) ? strval($data['rationale']) : null; + $narrativeText->taxonomicNotes = !is_null($data['taxonomicnotes']) ? strval($data['taxonomicnotes']) : null; + $narrativeText->threats = !is_null($data['threats']) ? strval($data['threats']) : null; + $narrativeText->useTrade = !is_null($data['usetrade']) ? strval($data['usetrade']) : null; + + return $narrativeText; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Occurrence.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Occurrence.php new file mode 100644 index 0000000000..16308d5498 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Occurrence.php @@ -0,0 +1,53 @@ +countryCode; + } + + public function getCountryName(): ?string + { + return $this->countryName; + } + + public function getDistributionCode(): ?string + { + return $this->distributionCode; + } + + public function getOrigin(): ?string + { + return $this->origin; + } + + public function getPresence(): ?string + { + return $this->presence; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Occurrence + { + $occurrence = new Occurrence(); + $occurrence->countryCode = !is_null($data['code']) ? strval($data['code']) : null; + $occurrence->countryName = !is_null($data['country']) ? strval($data['country']) : null; + $occurrence->distributionCode = !is_null($data['distribution_code']) + ? strval($data['distribution_code']) : null; + $occurrence->origin = !is_null($data['origin']) ? strval($data['origin']) : null; + $occurrence->presence = !is_null($data['presence']) ? strval($data['presence']) : null; + + return $occurrence; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Region.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Region.php new file mode 100644 index 0000000000..f3acc7c558 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Region.php @@ -0,0 +1,31 @@ +identifier; + } + + public function getName(): ?string + { + return $this->name; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Region + { + $region = new Region(); + $region->identifier = !is_null($data['identifier']) ? strval($data['identifier']) : null; + $region->name = !is_null($data['name']) ? strval($data['name']) : null; + + return $region; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Species.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Species.php new file mode 100644 index 0000000000..7c8be4e53f --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Species.php @@ -0,0 +1,59 @@ +category; + } + + public function getScientificName(): ?string + { + return $this->scientificName; + } + + public function getSubpopulation(): ?string + { + return $this->subpopulation; + } + + public function getSubspeciesName(): ?string + { + return $this->subspeciesName; + } + + public function getSubspeciesRank(): ?string + { + return $this->subspeciesRank; + } + + public function getTaxonId(): ?int + { + return $this->taxonId; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Species + { + $species = new Species(); + $species->category = !is_null($data['category']) ? strval($data['category']) : null; + $species->scientificName = !is_null($data['scientific_name']) ? strval($data['scientific_name']) : null; + $species->subpopulation = !is_null($data['subpopulation']) ? strval($data['subpopulation']) : null; + $species->subspeciesName = !is_null($data['subspecies']) ? strval($data['subspecies']) : null; + $species->subspeciesRank = !is_null($data['rank']) ? strval($data['rank']) : null; + $species->taxonId = !is_null($data['taxonid']) ? intval($data['taxonid']) : null; + + return $species; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/SpeciesDetails.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/SpeciesDetails.php new file mode 100644 index 0000000000..31776075b0 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/SpeciesDetails.php @@ -0,0 +1,231 @@ +amended; + } + + public function getAmendedReason(): ?string + { + return $this->amendedReason; + } + + public function getAOO(): ?int + { + return $this->aoo; + } + + public function getAssessmentDate(): ?string + { + return $this->assessmentDate; + } + + public function getAssessor(): ?string + { + return $this->assessor; + } + + public function getAuthority(): ?string + { + return $this->authority; + } + + public function getCategory(): ?string + { + return $this->category; + } + + public function getClass(): ?string + { + return $this->class; + } + + public function getCriteria(): ?string + { + return $this->criteria; + } + + public function getDepthLower(): ?int + { + return $this->depthLower; + } + + public function getDepthUpper(): ?int + { + return $this->depthUpper; + } + + public function getElevationLower(): ?int + { + return $this->elevationLower; + } + + public function getElevationUpper(): ?int + { + return $this->elevationUpper; + } + + public function getEOO(): ?int + { + return $this->eoo; + } + + public function isErrata(): ?bool + { + return $this->errata; + } + + public function getErrataReason(): ?string + { + return $this->errataReason; + } + + public function getFamily(): ?string + { + return $this->family; + } + + public function isFreshwaterSystem(): ?bool + { + return $this->freshwaterSystem; + } + + public function getGenus(): ?string + { + return $this->genus; + } + + public function getKingdom(): ?string + { + return $this->kingdom; + } + + public function getMainCommonName(): ?string + { + return $this->mainCommonName; + } + + public function isMarineSystem(): ?bool + { + return $this->marineSystem; + } + + public function getOrder(): ?string + { + return $this->order; + } + + public function getPhylum(): ?string + { + return $this->phylum; + } + + public function getPopulationTrend(): ?string + { + return $this->populationTrend; + } + + public function getPublicationYear(): ?int + { + return $this->publicationYear; + } + + public function getReviewer(): ?string + { + return $this->reviewer; + } + + public function getScientificName(): ?string + { + return $this->scientificName; + } + + public function getTaxonId(): ?int + { + return $this->taxonId; + } + + public function isTerrestrialSystem(): ?bool + { + return $this->terrestrialSystem; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): SpeciesDetails + { + $speciesDetails = new SpeciesDetails(); + $speciesDetails->amended = !is_null($data['amended_flag']) ? boolval($data['amended_flag']) : null; + $speciesDetails->amendedReason = !is_null($data['amended_reason']) ? strval($data['amended_reason']) : null; + $speciesDetails->aoo = !is_null($data['aoo_km2']) ? intval($data['aoo_km2']) : null; + $speciesDetails->assessmentDate = !is_null($data['assessment_date']) ? strval($data['assessment_date']) : null; + $speciesDetails->assessor = !is_null($data['assessor']) ? strval($data['assessor']) : null; + $speciesDetails->authority = !is_null($data['authority']) ? strval($data['authority']) : null; + $speciesDetails->category = !is_null($data['category']) ? strval($data['category']) : null; + $speciesDetails->class = !is_null($data['class']) ? strval($data['class']) : null; + $speciesDetails->criteria = !is_null($data['criteria']) ? strval($data['criteria']) : null; + $speciesDetails->depthLower = !is_null($data['depth_lower']) ? intval($data['depth_lower']) : null; + $speciesDetails->depthUpper = !is_null($data['depth_upper']) ? intval($data['depth_upper']) : null; + $speciesDetails->elevationLower = !is_null($data['elevation_lower']) ? intval($data['elevation_lower']) : null; + $speciesDetails->elevationUpper = !is_null($data['elevation_upper']) ? intval($data['elevation_upper']) : null; + $speciesDetails->eoo = !is_null($data['eoo_km2']) ? intval($data['eoo_km2']) : null; + $speciesDetails->errata = !is_null($data['errata_flag']) ? boolval($data['errata_flag']) : null; + $speciesDetails->errataReason = !is_null($data['errata_reason']) ? strval($data['errata_reason']) : null; + $speciesDetails->family = !is_null($data['family']) ? strval($data['family']) : null; + $speciesDetails->freshwaterSystem = !is_null($data['freshwater_system']) + ? boolval($data['freshwater_system']) : null; + $speciesDetails->genus = !is_null($data['genus']) ? strval($data['genus']) : null; + $speciesDetails->kingdom = !is_null($data['kingdom']) ? strval($data['kingdom']) : null; + $speciesDetails->mainCommonName = !is_null($data['main_common_name']) + ? strval($data['main_common_name']) : null; + $speciesDetails->marineSystem = !is_null($data['marine_system']) ? boolval($data['marine_system']) : null; + $speciesDetails->order = !is_null($data['order']) ? strval($data['order']) : null; + $speciesDetails->phylum = !is_null($data['phylum']) ? strval($data['phylum']) : null; + $speciesDetails->populationTrend = !is_null($data['population_trend']) + ? strval($data['population_trend']) : null; + $speciesDetails->publicationYear = !is_null($data['published_year']) ? intval($data['published_year']) : null; + $speciesDetails->reviewer = !is_null($data['reviewer']) ? strval($data['reviewer']) : null; + $speciesDetails->scientificName = !is_null($data['scientific_name']) ? strval($data['scientific_name']) : null; + $speciesDetails->taxonId = !is_null($data['taxonid']) ? intval($data['taxonid']) : null; + $speciesDetails->terrestrialSystem = !is_null($data['terrestrial_system']) + ? boolval($data['terrestrial_system']) : null; + + return $speciesDetails; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Synonym.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Synonym.php new file mode 100644 index 0000000000..c41ee55c84 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Synonym.php @@ -0,0 +1,52 @@ +acceptedId; + } + + public function getAcceptedName(): ?string + { + return $this->acceptedName; + } + + public function getAcceptedNameAuthority(): ?string + { + return $this->acceptedNameAuthority; + } + + public function getSynonym(): ?string + { + return $this->synonym; + } + + public function getSynonymAuthority(): ?string + { + return $this->synonymAuthority; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Synonym + { + $synonym = new Synonym(); + $synonym->acceptedId = !is_null($data['accepted_id']) ? intval($data['accepted_id']) : null; + $synonym->acceptedName = !is_null($data['accepted_name']) ? strval($data['accepted_name']) : null; + $synonym->acceptedNameAuthority = !is_null($data['authority']) ? strval($data['authority']) : null; + $synonym->synonym = !is_null($data['synonym']) ? strval($data['synonym']) : null; + $synonym->synonymAuthority = !is_null($data['syn_authority']) ? strval($data['syn_authority']) : null; + + return $synonym; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Threat.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Threat.php new file mode 100644 index 0000000000..098da2bb64 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/src/Model/Threat.php @@ -0,0 +1,66 @@ +code; + } + + public function getInvasive(): ?string + { + return $this->invasive; + } + + public function getScope(): ?string + { + return $this->scope; + } + + public function getScore(): ?string + { + return $this->score; + } + + public function getSeverity(): ?string + { + return $this->severity; + } + + public function getTiming(): ?string + { + return $this->timing; + } + + public function getTitle(): ?string + { + return $this->title; + } + + /** + * @param array $data + */ + public static function createFromArray(array $data): Threat + { + $threat = new Threat(); + $threat->code = !is_null($data['code']) ? strval($data['code']) : null; + $threat->invasive = !is_null($data['invasive']) ? strval($data['invasive']) : null; + $threat->scope = !is_null($data['scope']) ? strval($data['scope']) : null; + $threat->score = !is_null($data['score']) ? strval($data['score']) : null; + $threat->severity = !is_null($data['severity']) ? strval($data['severity']) : null; + $threat->timing = !is_null($data['timing']) ? strval($data['timing']) : null; + $threat->title = !is_null($data['title']) ? strval($data['title']) : null; + + return $threat; + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Functional/ClientTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Functional/ClientTest.php new file mode 100644 index 0000000000..fa74266b98 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Functional/ClientTest.php @@ -0,0 +1,675 @@ +httpClient = new MockHttpClient($responses, 'https://apiv3.iucnredlist.org/api/v3/'); + } +} + +final class ClientTest extends TestCase +{ + protected ClientInterface $client; + + public function setUp(): void + { + if (($json = file_get_contents(dirname(__FILE__) . '/responses.json')) === false) { + throw new \Exception('Could not read "responses.json" file.'); + } + + if (($responses = json_decode($json, true)) === false) { + throw new \Exception('Could not parse "responses.json" file.'); + } + + $responses = (array)$responses; + + $this->client = new MockClient(function ($method, $url) use ($responses) { + if (array_key_exists($url, $responses)) { + return new MockResponse((string)json_encode($responses[$url])); + } + + return new MockResponse(); + }); + } + + public function testGetCountries(): void + { + $countries = $this->client->getCountries(); + + self::assertCount(251, $countries); + + $country = $countries->first(); + + self::assertInstanceOf(Country::class, $country); + self::assertEquals('UZ', $country->getCode()); + self::assertEquals('Uzbekistan', $country->getName()); + } + + public function testGetComprehensiveGroups(): void + { + $groups = $this->client->getComprehensiveGroups(); + + self::assertCount(31, $groups); + + $group = $groups->first(); + + self::assertInstanceOf(Group::class, $group); + self::assertEquals('reef_building_corals', $group->getCode()); + } + + public function testGetPlantGrowthFormsById(): void + { + $growthForms = $this->client->getPlantGrowthFormsById(19891625); + + self::assertCount(4, $growthForms); + + $growthForm = $growthForms->first(); + + self::assertInstanceOf(GrowthForm::class, $growthForm); + self::assertEquals('Annual', $growthForm->getName()); + + $growthForms = $this->client->getPlantGrowthFormsById(63532, 'europe'); + + self::assertCount(1, $growthForms); + + $growthForm = $growthForms->first(); + + self::assertInstanceOf(GrowthForm::class, $growthForm); + self::assertEquals('Tree - large', $growthForm->getName()); + } + + public function testGetPlantGrowthFormsByName(): void + { + $growthForms = $this->client->getPlantGrowthFormsByName('Mucuna bracteata'); + + self::assertCount(4, $growthForms); + + $growthForm = $growthForms->first(); + + self::assertInstanceOf(GrowthForm::class, $growthForm); + self::assertEquals('Annual', $growthForm->getName()); + + $growthForms = $this->client->getPlantGrowthFormsByName('Quercus robur', 'europe'); + + self::assertCount(1, $growthForms); + + $growthForm = $growthForms->first(); + + self::assertInstanceOf(GrowthForm::class, $growthForm); + self::assertEquals('Tree - large', $growthForm->getName()); + } + + public function testGetRegions(): void + { + $regions = $this->client->getRegions(); + + self::assertCount(10, $regions); + + $region = $regions->first(); + + self::assertInstanceOf(Region::class, $region); + self::assertEquals('northeastern_africa', $region->getIdentifier()); + self::assertEquals('Northeastern Africa', $region->getName()); + } + + public function testGetSpeciesAssessmentsById(): void + { + $assessments = $this->client->getSpeciesAssessmentsById(181008073); + + self::assertCount(1, $assessments); + + $assessment = $assessments->first(); + + self::assertInstanceOf(Assessment::class, $assessment); + self::assertEquals('2020', $assessment->getAssessmentYear()); + self::assertEquals('EN', $assessment->getCategoryCode()); + self::assertEquals('Endangered', $assessment->getCategoryName()); + self::assertEquals('2021', $assessment->getPublicationYear()); + + $assessments = $this->client->getSpeciesAssessmentsById(22823, 'europe'); + + self::assertCount(1, $assessments); + + $assessment = $assessments->first(); + + self::assertInstanceOf(Assessment::class, $assessment); + self::assertEquals('2006', $assessment->getAssessmentYear()); + self::assertEquals('VU', $assessment->getCategoryCode()); + self::assertEquals('Vulnerable', $assessment->getCategoryName()); + self::assertEquals('2007', $assessment->getPublicationYear()); + } + + public function testGetSpeciesAssessmentsByName(): void + { + $assessments = $this->client->getSpeciesAssessmentsByName('Loxodonta africana'); + + self::assertCount(1, $assessments); + + $assessment = $assessments->first(); + + self::assertInstanceOf(Assessment::class, $assessment); + self::assertEquals('2020', $assessment->getAssessmentYear()); + self::assertEquals('EN', $assessment->getCategoryCode()); + self::assertEquals('Endangered', $assessment->getCategoryName()); + self::assertEquals('2021', $assessment->getPublicationYear()); + + $assessments = $this->client->getSpeciesAssessmentsByName('Ursus maritimus', 'europe'); + + self::assertCount(1, $assessments); + + $assessment = $assessments->first(); + + self::assertInstanceOf(Assessment::class, $assessment); + self::assertEquals('2006', $assessment->getAssessmentYear()); + self::assertEquals('VU', $assessment->getCategoryCode()); + self::assertEquals('Vulnerable', $assessment->getCategoryName()); + self::assertEquals('2007', $assessment->getPublicationYear()); + } + + public function testGetSpeciesByCategory(): void + { + $species = $this->client->getSpeciesByCategory('LRlc'); + + self::assertCount(512, $species); + + $species = $species->first(); + + self::assertInstanceOf(Species::class, $species); + self::assertEquals('LR/lc', $species->getCategory()); + self::assertEquals('Abarema commutata', $species->getScientificName()); + self::assertNull($species->getSubpopulation()); + self::assertNull($species->getSubspeciesName()); + self::assertNull($species->getSubspeciesRank()); + self::assertEquals(36549, $species->getTaxonId()); + } + + public function testGetSpeciesByComprehensiveGroup(): void + { + $species = $this->client->getSpeciesByComprehensiveGroup('mammals'); + + self::assertCount(6423, $species); + + $species = $species->first(); + + self::assertInstanceOf(Species::class, $species); + self::assertEquals('DD', $species->getCategory()); + self::assertEquals('Abditomys latidens', $species->getScientificName()); + self::assertNull($species->getSubpopulation()); + self::assertNull($species->getSubspeciesName()); + self::assertNull($species->getSubspeciesRank()); + self::assertEquals(42641, $species->getTaxonId()); + } + + public function testGetSpeciesByCountry(): void + { + $species = $this->client->getSpeciesByCountry('AZ'); + + self::assertCount(1162, $species); + + $species = $species->first(); + + self::assertInstanceOf(Species::class, $species); + self::assertEquals('LC', $species->getCategory()); + self::assertEquals('Abies nordmanniana', $species->getScientificName()); + self::assertNull($species->getSubpopulation()); + self::assertNull($species->getSubspeciesName()); + self::assertNull($species->getSubspeciesRank()); + self::assertEquals(42293, $species->getTaxonId()); + } + + public function testGetSpeciesById(): void + { + $species = $this->client->getSpeciesById(181008073); + + self::assertInstanceOf(SpeciesDetails::class, $species); + self::assertEquals('EN', $species->getCategory()); + self::assertEquals('MAMMALIA', $species->getClass()); + self::assertEquals('ELEPHANTIDAE', $species->getFamily()); + self::assertEquals('Loxodonta', $species->getGenus()); + self::assertEquals('ANIMALIA', $species->getKingdom()); + self::assertEquals('African Savanna Elephant', $species->getMainCommonName()); + self::assertEquals('PROBOSCIDEA', $species->getOrder()); + self::assertEquals('CHORDATA', $species->getPhylum()); + self::assertEquals('Loxodonta africana', $species->getScientificName()); + self::assertEquals(181008073, $species->getTaxonId()); + + $species = $this->client->getSpeciesById(22694927, 'europe'); + + self::assertInstanceOf(SpeciesDetails::class, $species); + self::assertEquals('EN', $species->getCategory()); + self::assertEquals('AVES', $species->getClass()); + self::assertEquals('ALCIDAE', $species->getFamily()); + self::assertEquals('Fratercula', $species->getGenus()); + self::assertEquals('ANIMALIA', $species->getKingdom()); + self::assertEquals('Atlantic Puffin', $species->getMainCommonName()); + self::assertEquals('CHARADRIIFORMES', $species->getOrder()); + self::assertEquals('CHORDATA', $species->getPhylum()); + self::assertEquals('Fratercula arctica', $species->getScientificName()); + self::assertEquals(22694927, $species->getTaxonId()); + } + + public function testGetSpeciesByName(): void + { + $species = $this->client->getSpeciesByName('Loxodonta africana'); + + self::assertInstanceOf(SpeciesDetails::class, $species); + self::assertEquals('EN', $species->getCategory()); + self::assertEquals('MAMMALIA', $species->getClass()); + self::assertEquals('ELEPHANTIDAE', $species->getFamily()); + self::assertEquals('Loxodonta', $species->getGenus()); + self::assertEquals('ANIMALIA', $species->getKingdom()); + self::assertEquals('African Savanna Elephant', $species->getMainCommonName()); + self::assertEquals('PROBOSCIDEA', $species->getOrder()); + self::assertEquals('CHORDATA', $species->getPhylum()); + self::assertEquals('Loxodonta africana', $species->getScientificName()); + self::assertEquals(181008073, $species->getTaxonId()); + + $species = $this->client->getSpeciesByName('Fratercula arctica', 'europe'); + + self::assertInstanceOf(SpeciesDetails::class, $species); + self::assertEquals('EN', $species->getCategory()); + self::assertEquals('AVES', $species->getClass()); + self::assertEquals('ALCIDAE', $species->getFamily()); + self::assertEquals('Fratercula', $species->getGenus()); + self::assertEquals('ANIMALIA', $species->getKingdom()); + self::assertEquals('Atlantic Puffin', $species->getMainCommonName()); + self::assertEquals('CHARADRIIFORMES', $species->getOrder()); + self::assertEquals('CHORDATA', $species->getPhylum()); + self::assertEquals('Fratercula arctica', $species->getScientificName()); + self::assertEquals(22694927, $species->getTaxonId()); + } + + public function testGetSpeciesCitationById(): void + { + $citation = $this->client->getSpeciesCitationById(181008073); + + self::assertInstanceOf(Citation::class, $citation); + self::assertStringStartsWith('Gobush, K.S., Edwards, C.T.T', (string)$citation->getCitation()); + + $citation = $this->client->getSpeciesCitationById(2467, 'europe'); + + self::assertInstanceOf(Citation::class, $citation); + self::assertStringStartsWith('Species account by IUCN', (string)$citation->getCitation()); + } + + public function testGetSpeciesCitationByName(): void + { + $citation = $this->client->getSpeciesCitationByName('Loxodonta africana'); + + self::assertInstanceOf(Citation::class, $citation); + self::assertStringStartsWith('Gobush, K.S., Edwards, C.T.T', (string)$citation->getCitation()); + + $citation = $this->client->getSpeciesCitationByName('Balaena mysticetus', 'europe'); + + self::assertInstanceOf(Citation::class, $citation); + self::assertStringStartsWith('Species account by IUCN', (string)$citation->getCitation()); + } + + public function testGetSpeciesCommonNames(): void + { + $commonNames = $this->client->getSpeciesCommonNames('Loxodonta africana'); + + self::assertCount(7, $commonNames); + + $commonName = $commonNames->first(); + + self::assertInstanceOf(CommonName::class, $commonName); + self::assertEquals('eng', $commonName->getLanguage()); + self::assertEquals('African Savanna Elephant', $commonName->getName()); + self::assertTrue($commonName->isPrimary()); + } + + public function testGetSpeciesConservationMeasuresById(): void + { + $conservationMeasures = $this->client->getSpeciesConservationMeasuresById(181008073); + + self::assertCount(20, $conservationMeasures); + + $conservationMeasure = $conservationMeasures->first(); + + self::assertInstanceOf(ConservationMeasure::class, $conservationMeasure); + self::assertEquals('1.1', $conservationMeasure->getCode()); + self::assertEquals('Site/area protection', $conservationMeasure->getTitle()); + + $conservationMeasures = $this->client->getSpeciesConservationMeasuresById(22823, 'europe'); + + self::assertCount(3, $conservationMeasures); + + $conservationMeasure = $conservationMeasures->first(); + + self::assertInstanceOf(ConservationMeasure::class, $conservationMeasure); + self::assertEquals('1.1', $conservationMeasure->getCode()); + self::assertEquals('Site/area protection', $conservationMeasure->getTitle()); + } + + public function testGetSpeciesConservationMeasuresByName(): void + { + $conservationMeasures = $this->client->getSpeciesConservationMeasuresByName('Loxodonta africana'); + + self::assertCount(20, $conservationMeasures); + + $conservationMeasure = $conservationMeasures->first(); + + self::assertInstanceOf(ConservationMeasure::class, $conservationMeasure); + self::assertEquals('1.1', $conservationMeasure->getCode()); + self::assertEquals('Site/area protection', $conservationMeasure->getTitle()); + + $conservationMeasures = $this->client->getSpeciesConservationMeasuresByName('Ursus maritimus', 'europe'); + + self::assertCount(3, $conservationMeasures); + + $conservationMeasure = $conservationMeasures->first(); + + self::assertInstanceOf(ConservationMeasure::class, $conservationMeasure); + self::assertEquals('1.1', $conservationMeasure->getCode()); + self::assertEquals('Site/area protection', $conservationMeasure->getTitle()); + } + + public function testGetSpeciesCount(): void + { + self::assertEquals(150754, $this->client->getSpeciesCount()); + self::assertEquals(147517, $this->client->getSpeciesCount(null, false)); + self::assertEquals(16232, $this->client->getSpeciesCount('europe')); + self::assertEquals(16132, $this->client->getSpeciesCount('europe', false)); + } + + public function testGetSpeciesHabitatsById(): void + { + $habitats = $this->client->getSpeciesHabitatsById(181008073); + + self::assertCount(17, $habitats); + + $habitat = $habitats->first(); + + self::assertInstanceOf(Habitat::class, $habitat); + self::assertEquals('1.5', $habitat->getCode()); + self::assertEquals('Yes', $habitat->getMajorImportance()); + self::assertEquals('Forest - Subtropical/Tropical Dry', $habitat->getName()); + self::assertNull($habitat->getSeason()); + self::assertEquals('Suitable', $habitat->getSuitability()); + + $habitats = $this->client->getSpeciesHabitatsById(22823, 'europe'); + + self::assertCount(6, $habitats); + + $habitat = $habitats->first(); + + self::assertInstanceOf(Habitat::class, $habitat); + self::assertEquals('12.1', $habitat->getCode()); + self::assertNull($habitat->getMajorImportance()); + self::assertEquals('Marine Intertidal - Rocky Shoreline', $habitat->getName()); + self::assertNull($habitat->getSeason()); + self::assertEquals('Suitable', $habitat->getSuitability()); + } + + public function testGetSpeciesHabitatsByName(): void + { + $habitats = $this->client->getSpeciesHabitatsByName('Loxodonta africana'); + + self::assertCount(17, $habitats); + + $habitat = $habitats->first(); + + self::assertInstanceOf(Habitat::class, $habitat); + self::assertEquals('1.5', $habitat->getCode()); + self::assertEquals('Yes', $habitat->getMajorImportance()); + self::assertEquals('Forest - Subtropical/Tropical Dry', $habitat->getName()); + self::assertNull($habitat->getSeason()); + self::assertEquals('Suitable', $habitat->getSuitability()); + + $habitats = $this->client->getSpeciesHabitatsByName('Ursus maritimus', 'europe'); + + self::assertCount(6, $habitats); + + $habitat = $habitats->first(); + + self::assertInstanceOf(Habitat::class, $habitat); + self::assertEquals('12.1', $habitat->getCode()); + self::assertNull($habitat->getMajorImportance()); + self::assertEquals('Marine Intertidal - Rocky Shoreline', $habitat->getName()); + self::assertNull($habitat->getSeason()); + self::assertEquals('Suitable', $habitat->getSuitability()); + } + + public function testGetSpeciesNarrativeTextById(): void + { + $narrativeText = $this->client->getSpeciesNarrativeTextById(181008073); + + self::assertInstanceOf(NarrativeText::class, $narrativeText); + self::assertStringStartsWith('

The African Savanna', (string)$narrativeText->getConservationMeasures()); + self::assertStringStartsWith('

African Savanna Elephants', (string)$narrativeText->getGeographicRange()); + self::assertStringStartsWith('

African Savanna Elephants', (string)$narrativeText->getHabitat()); + self::assertStringStartsWith('

Over the past century', (string)$narrativeText->getPopulation()); + self::assertEquals('decreasing', $narrativeText->getPopulationTrend()); + self::assertStringStartsWith('

The African Savanna Elephant', (string)$narrativeText->getRationale()); + self::assertStringStartsWith('Three elephant taxa remain', (string)$narrativeText->getTaxonomicNotes()); + self::assertStringStartsWith('Poaching of African Savanna Elephants', (string)$narrativeText->getThreats()); + self::assertStringStartsWith('Ivory:', (string)$narrativeText->getUseTrade()); + + $narrativeText = $this->client->getSpeciesNarrativeTextById(2467, 'europe'); + + self::assertInstanceOf(NarrativeText::class, $narrativeText); + self::assertStringStartsWith('The International', (string)$narrativeText->getConservationMeasures()); + self::assertStringStartsWith('Bowhead whales are found', (string)$narrativeText->getGeographicRange()); + self::assertStringStartsWith('The seasonal distribution', (string)$narrativeText->getHabitat()); + self::assertStringStartsWith('Current population size', (string)$narrativeText->getPopulation()); + self::assertEquals('unknown', $narrativeText->getPopulationTrend()); + self::assertStringStartsWith('This species is assessed', (string)$narrativeText->getRationale()); + self::assertStringStartsWith('The taxonomy is not in doubt', (string)$narrativeText->getTaxonomicNotes()); + self::assertStringStartsWith('Heavy commercial hunting', (string)$narrativeText->getThreats()); + self::assertNull($narrativeText->getUseTrade()); + } + + public function testGetSpeciesNarrativeTextByName(): void + { + $narrativeText = $this->client->getSpeciesNarrativeTextByName('Loxodonta africana'); + + self::assertInstanceOf(NarrativeText::class, $narrativeText); + self::assertStringStartsWith('

The African Savanna', (string)$narrativeText->getConservationMeasures()); + self::assertStringStartsWith('

African Savanna Elephants', (string)$narrativeText->getGeographicRange()); + self::assertStringStartsWith('

African Savanna Elephants', (string)$narrativeText->getHabitat()); + self::assertStringStartsWith('

Over the past century', (string)$narrativeText->getPopulation()); + self::assertEquals('decreasing', $narrativeText->getPopulationTrend()); + self::assertStringStartsWith('

The African Savanna Elephant', (string)$narrativeText->getRationale()); + self::assertStringStartsWith('Three elephant taxa remain', (string)$narrativeText->getTaxonomicNotes()); + self::assertStringStartsWith('Poaching of African Savanna Elephants', (string)$narrativeText->getThreats()); + self::assertStringStartsWith('Ivory:', (string)$narrativeText->getUseTrade()); + + $narrativeText = $this->client->getSpeciesNarrativeTextByName('Fratercula arctica', 'europe'); + + self::assertInstanceOf(NarrativeText::class, $narrativeText); + self::assertStringStartsWith('Conservation Actions', (string)$narrativeText->getConservationMeasures()); + self::assertStringStartsWith('The species can be found', (string)$narrativeText->getGeographicRange()); + self::assertStringStartsWith('The breeding range', (string)$narrativeText->getHabitat()); + self::assertStringStartsWith('The European breeding', (string)$narrativeText->getPopulation()); + self::assertEquals('decreasing', $narrativeText->getPopulationTrend()); + self::assertStringStartsWith('European regional assessment', (string)$narrativeText->getRationale()); + self::assertNull($narrativeText->getTaxonomicNotes()); + self::assertStringStartsWith('This species is highly', (string)$narrativeText->getThreats()); + self::assertNull($narrativeText->getUseTrade()); + } + + public function testGetSpeciesOccurrencesById(): void + { + $occurrences = $this->client->getSpeciesOccurrencesById(181008073); + + self::assertCount(26, $occurrences); + + $occurrence = $occurrences->first(); + + self::assertInstanceOf(Occurrence::class, $occurrence); + self::assertEquals('AO', $occurrence->getCountryCode()); + self::assertEquals('Angola', $occurrence->getCountryName()); + self::assertEquals('Native', $occurrence->getDistributionCode()); + self::assertEquals('Native', $occurrence->getOrigin()); + self::assertEquals('Extant', $occurrence->getPresence()); + + $occurrences = $this->client->getSpeciesOccurrencesById(22823, 'europe'); + + self::assertCount(3, $occurrences); + + $occurrence = $occurrences->first(); + + self::assertInstanceOf(Occurrence::class, $occurrence); + self::assertEquals('NO', $occurrence->getCountryCode()); + self::assertEquals('Norway', $occurrence->getCountryName()); + self::assertEquals('Native', $occurrence->getDistributionCode()); + self::assertEquals('Native', $occurrence->getOrigin()); + self::assertEquals('Extant', $occurrence->getPresence()); + } + + public function testGetSpeciesOccurrencesByName(): void + { + $occurrences = $this->client->getSpeciesOccurrencesByName('Loxodonta africana'); + + self::assertCount(26, $occurrences); + + $occurrence = $occurrences->first(); + + self::assertInstanceOf(Occurrence::class, $occurrence); + self::assertEquals('AO', $occurrence->getCountryCode()); + self::assertEquals('Angola', $occurrence->getCountryName()); + self::assertEquals('Native', $occurrence->getDistributionCode()); + self::assertEquals('Native', $occurrence->getOrigin()); + self::assertEquals('Extant', $occurrence->getPresence()); + + $occurrences = $this->client->getSpeciesOccurrencesByName('Ursus maritimus', 'europe'); + + self::assertCount(3, $occurrences); + + $occurrence = $occurrences->first(); + + self::assertInstanceOf(Occurrence::class, $occurrence); + self::assertEquals('NO', $occurrence->getCountryCode()); + self::assertEquals('Norway', $occurrence->getCountryName()); + self::assertEquals('Native', $occurrence->getDistributionCode()); + self::assertEquals('Native', $occurrence->getOrigin()); + self::assertEquals('Extant', $occurrence->getPresence()); + } + + public function testGetSpeciesSynonyms(): void + { + $synonyms = $this->client->getSpeciesSynonyms('Loxodonta africana'); + + self::assertCount(3, $synonyms); + + $synonym = $synonyms->first(); + + self::assertInstanceOf(Synonym::class, $synonym); + self::assertEquals(181007989, $synonym->getAcceptedId()); + self::assertEquals('Loxodonta cyclotis', $synonym->getAcceptedName()); + self::assertEquals('Matschie, 1900', $synonym->getAcceptedNameAuthority()); + self::assertEquals('Loxodonta africana', $synonym->getSynonym()); + self::assertNull($synonym->getSynonymAuthority()); + } + + public function testGetSpeciesThreatsById(): void + { + $threats = $this->client->getSpeciesThreatsById(181008073); + + self::assertCount(40, $threats); + + $threat = $threats->first(); + + self::assertInstanceOf(Threat::class, $threat); + self::assertEquals('1.1', $threat->getCode()); + self::assertNull($threat->getInvasive()); + self::assertEquals('Minority (<50%)', $threat->getScope()); + self::assertEquals('Unknown', $threat->getScore()); + self::assertEquals('Unknown', $threat->getSeverity()); + self::assertEquals('Ongoing', $threat->getTiming()); + self::assertEquals('Housing & urban areas', $threat->getTitle()); + + $threats = $this->client->getSpeciesThreatsById(2467, 'europe'); + + self::assertCount(2, $threats); + + $threat = $threats->first(); + + self::assertInstanceOf(Threat::class, $threat); + self::assertEquals('9.2', $threat->getCode()); + self::assertNull($threat->getInvasive()); + self::assertNull($threat->getScope()); + self::assertNull($threat->getScore()); + self::assertNull($threat->getSeverity()); + self::assertEquals('Ongoing', $threat->getTiming()); + self::assertEquals('Industrial & military effluents', $threat->getTitle()); + } + + public function testGetSpeciesThreatsByName(): void + { + $threats = $this->client->getSpeciesThreatsByName('Loxodonta africana'); + + self::assertCount(40, $threats); + + $threat = $threats->first(); + + self::assertInstanceOf(Threat::class, $threat); + self::assertEquals('1.1', $threat->getCode()); + self::assertNull($threat->getInvasive()); + self::assertEquals('Minority (<50%)', $threat->getScope()); + self::assertEquals('Unknown', $threat->getScore()); + self::assertEquals('Unknown', $threat->getSeverity()); + self::assertEquals('Ongoing', $threat->getTiming()); + self::assertEquals('Housing & urban areas', $threat->getTitle()); + + $threats = $this->client->getSpeciesThreatsByName('Fratercula arctica', 'europe'); + + self::assertCount(17, $threats); + + $threat = $threats->first(); + + self::assertInstanceOf(Threat::class, $threat); + self::assertEquals('11.1', $threat->getCode()); + self::assertNull($threat->getInvasive()); + self::assertEquals('Unknown', $threat->getScope()); + self::assertEquals('Unknown', $threat->getScore()); + self::assertEquals('Unknown', $threat->getSeverity()); + self::assertEquals('Ongoing', $threat->getTiming()); + self::assertEquals('Habitat shifting & alteration', $threat->getTitle()); + } + + public function testGetVersion(): void + { + self::assertEquals('2022-1', $this->client->getVersion()); + } + + public function testGetWebsiteLink(): void + { + self::assertEquals( + 'https://www.iucnredlist.org/species/181008073/204401095', + $this->client->getWebsiteLink('Loxodonta africana') + ); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Functional/responses.json b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Functional/responses.json new file mode 100644 index 0000000000..23c04c6645 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Functional/responses.json @@ -0,0 +1,67769 @@ +{ + "https://apiv3.iucnredlist.org/api/v3/comp-group/getspecies/mammals": { + "count": 6423, + "result": [ + { + "taxonid": 42641, + "scientific_name": "Abditomys latidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17879, + "scientific_name": "Abeomelomys sevia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47761700, + "scientific_name": "Abrawayaomys chebezi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 47760825, + "scientific_name": "Abrawayaomys ruschii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42656, + "scientific_name": "Abrocoma bennettii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18, + "scientific_name": "Abrocoma boliviensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136334, + "scientific_name": "Abrocoma budini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42657, + "scientific_name": "Abrocoma cinerea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136367, + "scientific_name": "Abrocoma famatina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136525, + "scientific_name": "Abrocoma shistacea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136302, + "scientific_name": "Abrocoma uspallata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136546, + "scientific_name": "Abrocoma vaccarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4803, + "scientific_name": "Abrothrix andinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 735, + "scientific_name": "Abrothrix illutea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4804, + "scientific_name": "Abrothrix jelskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 740, + "scientific_name": "Abrothrix lanosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 743, + "scientific_name": "Abrothrix longipilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 114955961, + "scientific_name": "Abrothrix manni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 751, + "scientific_name": "Abrothrix olivaceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 754, + "scientific_name": "Abrothrix sanborni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 137, + "scientific_name": "Acerodon celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 138, + "scientific_name": "Acerodon humilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 139, + "scientific_name": "Acerodon jubatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 140, + "scientific_name": "Acerodon leucotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 142, + "scientific_name": "Acerodon mackloti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 219, + "scientific_name": "Acinonyx jubatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 44936, + "scientific_name": "Acomys airensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 263, + "scientific_name": "Acomys cahirinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 264, + "scientific_name": "Acomys cilicicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 265, + "scientific_name": "Acomys cineraceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136471, + "scientific_name": "Acomys dimidiatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 266, + "scientific_name": "Acomys ignitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44938, + "scientific_name": "Acomys johannis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 267, + "scientific_name": "Acomys kempi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 268, + "scientific_name": "Acomys louisae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 269, + "scientific_name": "Acomys minous", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 270, + "scientific_name": "Acomys mullah", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47806447, + "scientific_name": "Acomys muzei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 271, + "scientific_name": "Acomys nesiotes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 47806534, + "scientific_name": "Acomys ngurui", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 272, + "scientific_name": "Acomys percivali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 273, + "scientific_name": "Acomys russatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47806307, + "scientific_name": "Acomys selousi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44939, + "scientific_name": "Acomys seurati", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47805694, + "scientific_name": "Acomys spinosissimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 275, + "scientific_name": "Acomys subspinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 276, + "scientific_name": "Acomys wilsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 278, + "scientific_name": "Aconaemys fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136331, + "scientific_name": "Aconaemys porteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 279, + "scientific_name": "Aconaemys sagei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40584, + "scientific_name": "Acrobates pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 512, + "scientific_name": "Addax nasomaculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 15595, + "scientific_name": "Aegialomys galapagoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15616, + "scientific_name": "Aegialomys xanthaeolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 548, + "scientific_name": "Aepeomys lugens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136484, + "scientific_name": "Aepeomys reigi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 550, + "scientific_name": "Aepyceros melampus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136944, + "scientific_name": "Aepyceros melampus ssp. melampus", + "subspecies": "melampus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 549, + "scientific_name": "Aepyceros melampus ssp. petersi", + "subspecies": "petersi", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40558, + "scientific_name": "Aepyprymnus rufescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 555, + "scientific_name": "Aeretes melanopterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 556, + "scientific_name": "Aeromys tephromelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 557, + "scientific_name": "Aeromys thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136541, + "scientific_name": "Aethalops aequalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 565, + "scientific_name": "Aethalops alecto", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 568, + "scientific_name": "Aethomys bocagei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 569, + "scientific_name": "Aethomys chrysophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 571, + "scientific_name": "Aethomys hindei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44990, + "scientific_name": "Aethomys ineptus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 572, + "scientific_name": "Aethomys kaiseri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 574, + "scientific_name": "Aethomys nyikae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 567, + "scientific_name": "Aethomys silindensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 575, + "scientific_name": "Aethomys stannarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 576, + "scientific_name": "Aethomys thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 712, + "scientific_name": "Ailuropoda melanoleuca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136218, + "scientific_name": "Ailurops melanotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 40637, + "scientific_name": "Ailurops ursinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 714, + "scientific_name": "Ailurus fulgens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 723, + "scientific_name": "Akodon aerosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 724, + "scientific_name": "Akodon affinis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 725, + "scientific_name": "Akodon albiventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 726, + "scientific_name": "Akodon azarae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 728, + "scientific_name": "Akodon boliviensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 729, + "scientific_name": "Akodon budini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 114956458, + "scientific_name": "Akodon caenosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 730, + "scientific_name": "Akodon cursor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 731, + "scientific_name": "Akodon dayi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 114957548, + "scientific_name": "Akodon dolores", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 733, + "scientific_name": "Akodon fumeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 736, + "scientific_name": "Akodon iniscatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 737, + "scientific_name": "Akodon juninensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 739, + "scientific_name": "Akodon kofordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 742, + "scientific_name": "Akodon lindberghi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 753, + "scientific_name": "Akodon lutescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 746, + "scientific_name": "Akodon mimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 747, + "scientific_name": "Akodon molinae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 748, + "scientific_name": "Akodon mollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136197, + "scientific_name": "Akodon montensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136260, + "scientific_name": "Akodon mystax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 752, + "scientific_name": "Akodon orophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136483, + "scientific_name": "Akodon paranaensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136676, + "scientific_name": "Akodon pervalens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136753, + "scientific_name": "Akodon philipmyersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48300296, + "scientific_name": "Akodon polopi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136693, + "scientific_name": "Akodon reigi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 755, + "scientific_name": "Akodon sanctipaulensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 756, + "scientific_name": "Akodon serrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 757, + "scientific_name": "Akodon siberiae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 758, + "scientific_name": "Akodon simulator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48302281, + "scientific_name": "Akodon spegazzinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 760, + "scientific_name": "Akodon subfuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 761, + "scientific_name": "Akodon surdus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 762, + "scientific_name": "Akodon sylvanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 763, + "scientific_name": "Akodon toba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 764, + "scientific_name": "Akodon torques", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 766, + "scientific_name": "Akodon varius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 811, + "scientific_name": "Alcelaphus buselaphus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 813, + "scientific_name": "Alcelaphus buselaphus ssp. buselaphus", + "subspecies": "buselaphus", + "rank": "ssp.", + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 814, + "scientific_name": "Alcelaphus buselaphus ssp. caama", + "subspecies": "caama", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 815, + "scientific_name": "Alcelaphus buselaphus ssp. cokii", + "subspecies": "cokii", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 816, + "scientific_name": "Alcelaphus buselaphus ssp. lelwel", + "subspecies": "lelwel", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 812, + "scientific_name": "Alcelaphus buselaphus ssp. lichtensteinii", + "subspecies": "lichtensteinii", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 817, + "scientific_name": "Alcelaphus buselaphus ssp. major", + "subspecies": "major", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 809, + "scientific_name": "Alcelaphus buselaphus ssp. swaynei", + "subspecies": "swaynei", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 810, + "scientific_name": "Alcelaphus buselaphus ssp. tora", + "subspecies": "tora", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 56003281, + "scientific_name": "Alces alces", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 843, + "scientific_name": "Alionycteris paucidentata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 851, + "scientific_name": "Allactaga balikunica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 852, + "scientific_name": "Allactaga bullata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 855, + "scientific_name": "Allactaga firouzi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 856, + "scientific_name": "Allactaga hotsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 857, + "scientific_name": "Allactaga major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 858, + "scientific_name": "Allactaga severtzovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 859, + "scientific_name": "Allactaga sibirica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 850, + "scientific_name": "Allactaga tetradactyla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 861, + "scientific_name": "Allactodipus bobrinskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 865, + "scientific_name": "Allenopithecus nigroviridis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 868, + "scientific_name": "Allocebus trichotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4220, + "scientific_name": "Allochrocebus lhoesti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4227, + "scientific_name": "Allochrocebus preussi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4237, + "scientific_name": "Allochrocebus preussi ssp. insularis", + "subspecies": "insularis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4244, + "scientific_name": "Allochrocebus preussi ssp. preussi", + "subspecies": "preussi", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4230, + "scientific_name": "Allochrocebus solatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42640, + "scientific_name": "Allocricetulus curtatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 875, + "scientific_name": "Allocricetulus eversmanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136486, + "scientific_name": "Alouatta arctoidea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39957, + "scientific_name": "Alouatta belzebul", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41545, + "scientific_name": "Alouatta caraya", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 43912, + "scientific_name": "Alouatta discolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39916, + "scientific_name": "Alouatta guariba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39918, + "scientific_name": "Alouatta guariba ssp. clamitans", + "subspecies": "clamitans", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39917, + "scientific_name": "Alouatta guariba ssp. guariba", + "subspecies": "guariba", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 922, + "scientific_name": "Alouatta juara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 198622924, + "scientific_name": "Alouatta macconnelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136332, + "scientific_name": "Alouatta nigerrima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39960, + "scientific_name": "Alouatta palliata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 919, + "scientific_name": "Alouatta palliata ssp. aequatorialis", + "subspecies": "aequatorialis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 43899, + "scientific_name": "Alouatta palliata ssp. coibensis", + "subspecies": "coibensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 925, + "scientific_name": "Alouatta palliata ssp. mexicana", + "subspecies": "mexicana", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 43928, + "scientific_name": "Alouatta palliata ssp. palliata", + "subspecies": "palliata", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 43900, + "scientific_name": "Alouatta palliata ssp. trabeata", + "subspecies": "trabeata", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 914, + "scientific_name": "Alouatta pigra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136787, + "scientific_name": "Alouatta puruensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41546, + "scientific_name": "Alouatta sara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 198676562, + "scientific_name": "Alouatta seniculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 918, + "scientific_name": "Alouatta ululata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 948, + "scientific_name": "Alticola albicaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 949, + "scientific_name": "Alticola argentatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 950, + "scientific_name": "Alticola barakshin", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 951, + "scientific_name": "Alticola lemminus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 952, + "scientific_name": "Alticola macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 953, + "scientific_name": "Alticola montosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136648, + "scientific_name": "Alticola olchonensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 954, + "scientific_name": "Alticola roylei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 955, + "scientific_name": "Alticola semicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 956, + "scientific_name": "Alticola stoliczkanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 958, + "scientific_name": "Alticola strelzowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 959, + "scientific_name": "Alticola tuvinicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62006, + "scientific_name": "Amblysomus corriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41316, + "scientific_name": "Amblysomus hottentotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62007, + "scientific_name": "Amblysomus marleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 62008, + "scientific_name": "Amblysomus robustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 62009, + "scientific_name": "Amblysomus septentrionalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 1137, + "scientific_name": "Ametrida centurio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1140, + "scientific_name": "Ammodillus imbellis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 1141, + "scientific_name": "Ammodorcas clarkei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42399, + "scientific_name": "Ammospermophilus harrisii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42451, + "scientific_name": "Ammospermophilus interpres", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42452, + "scientific_name": "Ammospermophilus leucurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1149, + "scientific_name": "Ammospermophilus nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 1151, + "scientific_name": "Ammotragus lervia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 1154, + "scientific_name": "Amorphochilus schnablii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136723, + "scientific_name": "Amphinectomys savamis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 39593, + "scientific_name": "Anathana ellioti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1264, + "scientific_name": "Andalgalomys olrogi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1265, + "scientific_name": "Andalgalomys pearsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1271, + "scientific_name": "Andinomys edax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1307, + "scientific_name": "Anisomys imitator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44857, + "scientific_name": "Anomalurus beecrofti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1550, + "scientific_name": "Anomalurus derbianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1551, + "scientific_name": "Anomalurus pelii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1553, + "scientific_name": "Anomalurus pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1559, + "scientific_name": "Anonymomys mindorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 1564, + "scientific_name": "Anotomys leander", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 88109381, + "scientific_name": "Anoura aequatoris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88109476, + "scientific_name": "Anoura cadenai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88108473, + "scientific_name": "Anoura caudifer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1566, + "scientific_name": "Anoura cultrata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136239, + "scientific_name": "Anoura fistulata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88109511, + "scientific_name": "Anoura geoffroyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1568, + "scientific_name": "Anoura latidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1569, + "scientific_name": "Anoura luismanueli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88109497, + "scientific_name": "Anoura peruana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136802, + "scientific_name": "Anourosorex assamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136589, + "scientific_name": "Anourosorex schmidi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41450, + "scientific_name": "Anourosorex squamipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136257, + "scientific_name": "Anourosorex yamashinai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1581, + "scientific_name": "Antechinomys laniger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136555, + "scientific_name": "Antechinus adustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1590, + "scientific_name": "Antechinus agilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40523, + "scientific_name": "Antechinus bellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40524, + "scientific_name": "Antechinus flavipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1583, + "scientific_name": "Antechinus godmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1584, + "scientific_name": "Antechinus leo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40525, + "scientific_name": "Antechinus minimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40526, + "scientific_name": "Antechinus stuartii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136755, + "scientific_name": "Antechinus subtropicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41508, + "scientific_name": "Antechinus swainsonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1620, + "scientific_name": "Anthops ornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 1676, + "scientific_name": "Antidorcas marsupialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1677, + "scientific_name": "Antilocapra americana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1679, + "scientific_name": "Antilocapra americana ssp. peninsularis", + "subspecies": "peninsularis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 1680, + "scientific_name": "Antilocapra americana ssp. sonoriensis", + "subspecies": "sonoriensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 1681, + "scientific_name": "Antilope cervicapra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1790, + "scientific_name": "Antrozous pallidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1793, + "scientific_name": "Aonyx capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 44166, + "scientific_name": "Aonyx cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 1794, + "scientific_name": "Aonyx congicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41539, + "scientific_name": "Aotus azarae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43930, + "scientific_name": "Aotus azarae ssp. azarae", + "subspecies": "azarae", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 43931, + "scientific_name": "Aotus azarae ssp. boliviensis", + "subspecies": "boliviensis", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 43932, + "scientific_name": "Aotus azarae ssp. infulatus", + "subspecies": "infulatus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39915, + "scientific_name": "Aotus brumbacki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 1807, + "scientific_name": "Aotus griseimembra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136211, + "scientific_name": "Aotus jorgehernandezi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 1808, + "scientific_name": "Aotus lemurinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 1802, + "scientific_name": "Aotus miconax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41540, + "scientific_name": "Aotus nancymaae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41542, + "scientific_name": "Aotus nigriceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41543, + "scientific_name": "Aotus trivirgatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41544, + "scientific_name": "Aotus vociferans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39953, + "scientific_name": "Aotus zonalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 1869, + "scientific_name": "Aplodontia rufa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1888, + "scientific_name": "Apodemus agrarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1907, + "scientific_name": "Apodemus alpicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42642, + "scientific_name": "Apodemus argenteus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45953906, + "scientific_name": "Apodemus avicennicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 1890, + "scientific_name": "Apodemus chevrieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1891, + "scientific_name": "Apodemus draco", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136816, + "scientific_name": "Apodemus epimelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1892, + "scientific_name": "Apodemus flavicollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1894, + "scientific_name": "Apodemus gurkha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1896, + "scientific_name": "Apodemus hyrcanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 1897, + "scientific_name": "Apodemus latronum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1898, + "scientific_name": "Apodemus mystacinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1906, + "scientific_name": "Apodemus pallipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1899, + "scientific_name": "Apodemus peninsulae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1900, + "scientific_name": "Apodemus ponticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1901, + "scientific_name": "Apodemus rusiges", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1902, + "scientific_name": "Apodemus semotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1903, + "scientific_name": "Apodemus speciosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1904, + "scientific_name": "Apodemus sylvaticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1905, + "scientific_name": "Apodemus uralensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135724, + "scientific_name": "Apodemus witherbyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42643, + "scientific_name": "Apomys abrae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45953968, + "scientific_name": "Apomys aurorae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45953973, + "scientific_name": "Apomys banahao", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45953976, + "scientific_name": "Apomys brownorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136362, + "scientific_name": "Apomys camiguinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 1910, + "scientific_name": "Apomys datae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1917, + "scientific_name": "Apomys gracilirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1911, + "scientific_name": "Apomys hylocetes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1912, + "scientific_name": "Apomys insignis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112139458, + "scientific_name": "Apomys iridensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1913, + "scientific_name": "Apomys littoralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 112139517, + "scientific_name": "Apomys lubangensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45953979, + "scientific_name": "Apomys magnus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1914, + "scientific_name": "Apomys microdon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45953991, + "scientific_name": "Apomys minganensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1915, + "scientific_name": "Apomys musculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1916, + "scientific_name": "Apomys sacobianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45954010, + "scientific_name": "Apomys sierrae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45954013, + "scientific_name": "Apomys zambalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1933, + "scientific_name": "Aproteles bulmerae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9918, + "scientific_name": "Arabitragus jayakari", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2017, + "scientific_name": "Arborimus albipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42615, + "scientific_name": "Arborimus longicaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2018, + "scientific_name": "Arborimus pomo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2045, + "scientific_name": "Archboldomys luzonensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 45954066, + "scientific_name": "Archboldomys maximus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41690, + "scientific_name": "Arctictis binturong", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2053, + "scientific_name": "Arctocebus aureus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2054, + "scientific_name": "Arctocebus calabarensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2055, + "scientific_name": "Arctocephalus australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 72050476, + "scientific_name": "Arctocephalus australis Peruvian/Northern Chilean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Peruvian/Northern Chilean subpopulation", + "category": "VU" + }, + { + "taxonid": 2064, + "scientific_name": "Arctocephalus australis ssp. australis", + "subspecies": "australis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41664, + "scientific_name": "Arctocephalus forsteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2057, + "scientific_name": "Arctocephalus galapagoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2058, + "scientific_name": "Arctocephalus gazella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2059, + "scientific_name": "Arctocephalus philippii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2060, + "scientific_name": "Arctocephalus pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2067, + "scientific_name": "Arctocephalus pusillus ssp. doriferus", + "subspecies": "doriferus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2066, + "scientific_name": "Arctocephalus pusillus ssp. pusillus", + "subspecies": "pusillus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2061, + "scientific_name": "Arctocephalus townsendi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2062, + "scientific_name": "Arctocephalus tropicalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41691, + "scientific_name": "Arctogalidia trivirgata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70206273, + "scientific_name": "Arctonyx albogularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70205537, + "scientific_name": "Arctonyx collaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 70205771, + "scientific_name": "Arctonyx hoevenii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2089, + "scientific_name": "Ardops nichollsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41534, + "scientific_name": "Arielulus circumdatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40775, + "scientific_name": "Arielulus cuprosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40776, + "scientific_name": "Arielulus societatis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40032, + "scientific_name": "Arielulus torquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2110, + "scientific_name": "Ariteus flavescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88109970, + "scientific_name": "Artibeus aequatorialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2121, + "scientific_name": "Artibeus amplus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2125, + "scientific_name": "Artibeus concolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2126, + "scientific_name": "Artibeus fimbriatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2127, + "scientific_name": "Artibeus fraterculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2131, + "scientific_name": "Artibeus hirsutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2132, + "scientific_name": "Artibeus inopinatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88109731, + "scientific_name": "Artibeus jamaicensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2136, + "scientific_name": "Artibeus lituratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2137, + "scientific_name": "Artibeus obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2139, + "scientific_name": "Artibeus planirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88109897, + "scientific_name": "Artibeus schwartzi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 2144, + "scientific_name": "Arvicanthis abyssinicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44991, + "scientific_name": "Arvicanthis ansorgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2145, + "scientific_name": "Arvicanthis blicki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2146, + "scientific_name": "Arvicanthis nairobae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2148, + "scientific_name": "Arvicanthis neumanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2147, + "scientific_name": "Arvicanthis niloticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44992, + "scientific_name": "Arvicanthis rufinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2149, + "scientific_name": "Arvicola amphibius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2150, + "scientific_name": "Arvicola sapidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136766, + "scientific_name": "Arvicola scherman", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80222726, + "scientific_name": "Asellia arabica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 80221456, + "scientific_name": "Asellia italosomalica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 2153, + "scientific_name": "Asellia patrizii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80221529, + "scientific_name": "Asellia tridens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2155, + "scientific_name": "Aselliscus stoliczkanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2156, + "scientific_name": "Aselliscus tricuspidatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40602, + "scientific_name": "Atelerix albiventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 27926, + "scientific_name": "Atelerix algirus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2274, + "scientific_name": "Atelerix frontalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2275, + "scientific_name": "Atelerix sclateri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2276, + "scientific_name": "Ateles belzebuth", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41547, + "scientific_name": "Ateles chamek", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 135446, + "scientific_name": "Ateles fusciceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39922, + "scientific_name": "Ateles fusciceps ssp. fusciceps", + "subspecies": "fusciceps", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39921, + "scientific_name": "Ateles fusciceps ssp. rufiventris", + "subspecies": "rufiventris", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2279, + "scientific_name": "Ateles geoffroyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2286, + "scientific_name": "Ateles geoffroyi ssp. azuerensis", + "subspecies": "azuerensis", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2280, + "scientific_name": "Ateles geoffroyi ssp. frontatus", + "subspecies": "frontatus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 43901, + "scientific_name": "Ateles geoffroyi ssp. geoffroyi", + "subspecies": "geoffroyi", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2287, + "scientific_name": "Ateles geoffroyi ssp. grisescens", + "subspecies": "grisescens", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 2289, + "scientific_name": "Ateles geoffroyi ssp. ornatus", + "subspecies": "ornatus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 160872795, + "scientific_name": "Ateles geoffroyi ssp. vellerosus", + "subspecies": "vellerosus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39961, + "scientific_name": "Ateles hybridus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2282, + "scientific_name": "Ateles marginatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2283, + "scientific_name": "Ateles paniscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6924, + "scientific_name": "Atelocynus microtis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2353, + "scientific_name": "Atherurus africanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2354, + "scientific_name": "Atherurus macrourus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41590, + "scientific_name": "Atilax paludinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2358, + "scientific_name": "Atlantoxerus getulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20320, + "scientific_name": "Atopogale cubana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2395, + "scientific_name": "Auliscomys boliviensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2397, + "scientific_name": "Auliscomys pictus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2398, + "scientific_name": "Auliscomys sublimis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21313, + "scientific_name": "Austronomus australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136201, + "scientific_name": "Austronomus kuboriensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136767, + "scientific_name": "Avahi betsileo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136335, + "scientific_name": "Avahi cleesei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2434, + "scientific_name": "Avahi laniger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136369, + "scientific_name": "Avahi meridionalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16971566, + "scientific_name": "Avahi mooreorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2435, + "scientific_name": "Avahi occidentalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136285, + "scientific_name": "Avahi peyrierasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136434, + "scientific_name": "Avahi ramanantsoavanai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41579, + "scientific_name": "Avahi unicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41783, + "scientific_name": "Axis axis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2446, + "scientific_name": "Axis calamianensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2447, + "scientific_name": "Axis kuhlii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41784, + "scientific_name": "Axis porcinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2461, + "scientific_name": "Babyrousa babyrussa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136446, + "scientific_name": "Babyrousa celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136472, + "scientific_name": "Babyrousa togeanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19679, + "scientific_name": "Baeodon alleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19681, + "scientific_name": "Baeodon gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2465, + "scientific_name": "Baiomys musculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2466, + "scientific_name": "Baiomys taylori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10311, + "scientific_name": "Baiyankamys habbema", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10314, + "scientific_name": "Baiyankamys shawmayeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2467, + "scientific_name": "Balaena mysticetus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2468, + "scientific_name": "Balaena mysticetus Bering-Chukchi-Beaufort Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Bering-Chukchi-Beaufort Sea subpopulation", + "category": "LR/cd" + }, + { + "taxonid": 2472, + "scientific_name": "Balaena mysticetus East Greenland-Svalbard-Barents Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "East Greenland-Svalbard-Barents Sea subpopulation", + "category": "EN" + }, + { + "taxonid": 2469, + "scientific_name": "Balaena mysticetus Okhotsk Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Okhotsk Sea subpopulation", + "category": "EN" + }, + { + "taxonid": 2474, + "scientific_name": "Balaenoptera acutorostrata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2480, + "scientific_name": "Balaenoptera bonaerensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2475, + "scientific_name": "Balaenoptera borealis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2476, + "scientific_name": "Balaenoptera edeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2477, + "scientific_name": "Balaenoptera musculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41713, + "scientific_name": "Balaenoptera musculus ssp. intermedia", + "subspecies": "intermedia", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136623, + "scientific_name": "Balaenoptera omurai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 2478, + "scientific_name": "Balaenoptera physalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16208224, + "scientific_name": "Balaenoptera physalus Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mediterranean subpopulation", + "category": "EN" + }, + { + "taxonid": 215823373, + "scientific_name": "Balaenoptera ricei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2531, + "scientific_name": "Balantiopteryx infusca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2532, + "scientific_name": "Balantiopteryx io", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2533, + "scientific_name": "Balantiopteryx plicata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84454322, + "scientific_name": "Balionycteris maculata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84454980, + "scientific_name": "Balionycteris seimundi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2540, + "scientific_name": "Bandicota bengalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2541, + "scientific_name": "Bandicota indica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2542, + "scientific_name": "Bandicota savilei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2553, + "scientific_name": "Barbastella barbastellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 85180824, + "scientific_name": "Barbastella beijingensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85197261, + "scientific_name": "Barbastella darjelingensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85181182, + "scientific_name": "Barbastella leucomelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48637566, + "scientific_name": "Bassaricyon alleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48637946, + "scientific_name": "Bassaricyon gabbii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48637802, + "scientific_name": "Bassaricyon medius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48637280, + "scientific_name": "Bassaricyon neblina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41680, + "scientific_name": "Bassariscus astutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2613, + "scientific_name": "Bassariscus sumichrasti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2619, + "scientific_name": "Bathyergus janetta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2620, + "scientific_name": "Bathyergus suillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2642, + "scientific_name": "Batomys dentatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 111876319, + "scientific_name": "Batomys granti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45954108, + "scientific_name": "Batomys hamiguitan", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136394, + "scientific_name": "Batomys russatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2643, + "scientific_name": "Batomys salomonseni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111876611, + "scientific_name": "Batomys uragon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1789, + "scientific_name": "Bauerus dubiaquercus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41591, + "scientific_name": "Bdeogale crassicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2675, + "scientific_name": "Bdeogale jacksoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41592, + "scientific_name": "Bdeogale nigripes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136686, + "scientific_name": "Bdeogale omnivora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2676, + "scientific_name": "Beamys hindei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6234, + "scientific_name": "Beatragus hunteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2756, + "scientific_name": "Belomys pearsonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 2762, + "scientific_name": "Berardius arnuxii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2763, + "scientific_name": "Berardius bairdii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 178756893, + "scientific_name": "Berardius minimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2767, + "scientific_name": "Berylmys berdmorei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2768, + "scientific_name": "Berylmys bowersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2769, + "scientific_name": "Berylmys mackenziei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 2770, + "scientific_name": "Berylmys manipulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 71510353, + "scientific_name": "Bettongia anhydra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 2783, + "scientific_name": "Bettongia gaimardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2784, + "scientific_name": "Bettongia lesueur", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2785, + "scientific_name": "Bettongia penicillata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136805, + "scientific_name": "Bettongia pusilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 2787, + "scientific_name": "Bettongia tropica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2801, + "scientific_name": "Bibimys chacoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2802, + "scientific_name": "Bibimys labiosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2803, + "scientific_name": "Bibimys torresi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2815, + "scientific_name": "Bison bison", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2814, + "scientific_name": "Bison bonasus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2816, + "scientific_name": "Biswamoyopterus biswasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 88700294, + "scientific_name": "Biswamoyopterus laoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 2823, + "scientific_name": "Blanfordimys afghanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2824, + "scientific_name": "Blanfordimys bucharensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41451, + "scientific_name": "Blarina brevicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41452, + "scientific_name": "Blarina carolinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41453, + "scientific_name": "Blarina hylophaga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136365, + "scientific_name": "Blarinella griselda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40613, + "scientific_name": "Blarinella quadraticauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 2825, + "scientific_name": "Blarinella wardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2827, + "scientific_name": "Blarinomys breviceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2828, + "scientific_name": "Blastocerus dichotomus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19749, + "scientific_name": "Boneia bidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2885, + "scientific_name": "Boromys offella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 2886, + "scientific_name": "Boromys torrei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 2893, + "scientific_name": "Boselaphus tragocamelus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2891, + "scientific_name": "Bos gaurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2888, + "scientific_name": "Bos javanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 2892, + "scientific_name": "Bos mutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136721, + "scientific_name": "Bos primigenius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 2890, + "scientific_name": "Bos sauveli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2957, + "scientific_name": "Brachiones przewalskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2963, + "scientific_name": "Brachylagus idahoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2982, + "scientific_name": "Brachyphylla cavernarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2983, + "scientific_name": "Brachyphylla nana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2991, + "scientific_name": "Brachytarsomys albicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136399, + "scientific_name": "Brachytarsomys villosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2993, + "scientific_name": "Brachyteles arachnoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2994, + "scientific_name": "Brachyteles hypoxanthus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2997, + "scientific_name": "Brachyuromys betsileoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2998, + "scientific_name": "Brachyuromys ramirohitra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61925, + "scientific_name": "Bradypus pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 3036, + "scientific_name": "Bradypus torquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3037, + "scientific_name": "Bradypus tridactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3038, + "scientific_name": "Bradypus variegatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5042, + "scientific_name": "Brassomys albidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3121, + "scientific_name": "Brotomys voratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 114980541, + "scientific_name": "Brucepattersonius griserufescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136402, + "scientific_name": "Brucepattersonius guarani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136672, + "scientific_name": "Brucepattersonius igniventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15787, + "scientific_name": "Brucepattersonius iheringi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136457, + "scientific_name": "Brucepattersonius misionensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136198, + "scientific_name": "Brucepattersonius paradisus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136442, + "scientific_name": "Brucepattersonius soricinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3129, + "scientific_name": "Bubalus arnee", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 3126, + "scientific_name": "Bubalus depressicornis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 3127, + "scientific_name": "Bubalus mindorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 3128, + "scientific_name": "Bubalus quarlesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 3160, + "scientific_name": "Budorcas taxicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3322, + "scientific_name": "Bullimus bagobus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136264, + "scientific_name": "Bullimus gamay", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3323, + "scientific_name": "Bullimus luzonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3326, + "scientific_name": "Bunolagus monticularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 3327, + "scientific_name": "Bunomys andrewsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3328, + "scientific_name": "Bunomys chrysocomus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3329, + "scientific_name": "Bunomys coelestis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 3330, + "scientific_name": "Bunomys fratrorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 92440861, + "scientific_name": "Bunomys karokophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3332, + "scientific_name": "Bunomys penitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3333, + "scientific_name": "Bunomys prolatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 92440844, + "scientific_name": "Bunomys torajae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3339, + "scientific_name": "Burramys parvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 3412, + "scientific_name": "Cabassous centralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3413, + "scientific_name": "Cabassous chacoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 3414, + "scientific_name": "Cabassous tatouay", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3415, + "scientific_name": "Cabassous unicinctus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136419, + "scientific_name": "Cacajao ayresi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3416, + "scientific_name": "Cacajao calvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3419, + "scientific_name": "Cacajao calvus ssp. calvus", + "subspecies": "calvus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3421, + "scientific_name": "Cacajao calvus ssp. novaesi", + "subspecies": "novaesi", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3422, + "scientific_name": "Cacajao calvus ssp. rubicundus", + "subspecies": "rubicundus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3420, + "scientific_name": "Cacajao calvus ssp. ucayalii", + "subspecies": "ucayalii", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136640, + "scientific_name": "Cacajao hosomi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 160875418, + "scientific_name": "Cacajao melanocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40521, + "scientific_name": "Caenolestes caniventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136743, + "scientific_name": "Caenolestes condorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40522, + "scientific_name": "Caenolestes convelatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41506, + "scientific_name": "Caenolestes fuliginosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 51222063, + "scientific_name": "Caenolestes sangay", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3519, + "scientific_name": "Calcochloris obtusirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4767, + "scientific_name": "Calcochloris tytonis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41584, + "scientific_name": "Callibella humilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39929, + "scientific_name": "Callicebus barbarabrownae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39954, + "scientific_name": "Callicebus coimbrai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39930, + "scientific_name": "Callicebus melanochir", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39943, + "scientific_name": "Callicebus nigrifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 3555, + "scientific_name": "Callicebus personatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3564, + "scientific_name": "Callimico goeldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6985, + "scientific_name": "Callistomys pictus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 3570, + "scientific_name": "Callithrix aurita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 3571, + "scientific_name": "Callithrix flaviceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 3572, + "scientific_name": "Callithrix geoffroyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41518, + "scientific_name": "Callithrix jacchus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3575, + "scientific_name": "Callithrix kuhlii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41519, + "scientific_name": "Callithrix penicillata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3590, + "scientific_name": "Callorhinus ursinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3591, + "scientific_name": "Callosciurus adamsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 3592, + "scientific_name": "Callosciurus albescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3593, + "scientific_name": "Callosciurus baluensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3594, + "scientific_name": "Callosciurus caniceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3595, + "scientific_name": "Callosciurus erythraeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3596, + "scientific_name": "Callosciurus finlaysonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3597, + "scientific_name": "Callosciurus inornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3598, + "scientific_name": "Callosciurus melanogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3599, + "scientific_name": "Callosciurus nigrovittatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3600, + "scientific_name": "Callosciurus notatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3601, + "scientific_name": "Callosciurus orestes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3602, + "scientific_name": "Callosciurus phayrei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3603, + "scientific_name": "Callosciurus prevostii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3604, + "scientific_name": "Callosciurus pygerythrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3605, + "scientific_name": "Callosciurus quinquestriatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42468, + "scientific_name": "Callospermophilus lateralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20485, + "scientific_name": "Callospermophilus madrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42562, + "scientific_name": "Callospermophilus saturatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3609, + "scientific_name": "Calomys boliviae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3610, + "scientific_name": "Calomys callidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3611, + "scientific_name": "Calomys callosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3618, + "scientific_name": "Calomyscus bailwardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3619, + "scientific_name": "Calomyscus baluchi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136377, + "scientific_name": "Calomyscus elburzensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136252, + "scientific_name": "Calomyscus grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3620, + "scientific_name": "Calomyscus hotsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3621, + "scientific_name": "Calomyscus mystax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3622, + "scientific_name": "Calomyscus tsolovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3623, + "scientific_name": "Calomyscus urartensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136689, + "scientific_name": "Calomys expulsus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136737, + "scientific_name": "Calomys fecundus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3612, + "scientific_name": "Calomys hummelincki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3613, + "scientific_name": "Calomys laucha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3614, + "scientific_name": "Calomys lepidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3615, + "scientific_name": "Calomys musculinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3616, + "scientific_name": "Calomys sorellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3617, + "scientific_name": "Calomys tener", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136679, + "scientific_name": "Calomys tocantinsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136304, + "scientific_name": "Calomys venustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3626, + "scientific_name": "Caloprymnus campestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 3650, + "scientific_name": "Caluromys derbianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3651, + "scientific_name": "Caluromysiops irrupta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3648, + "scientific_name": "Caluromys lanatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3649, + "scientific_name": "Caluromys philander", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4703, + "scientific_name": "Calyptophractus retusus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 63543, + "scientific_name": "Camelus ferus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 3753, + "scientific_name": "Canis adustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 118264161, + "scientific_name": "Canis aureus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3745, + "scientific_name": "Canis latrans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 118264888, + "scientific_name": "Canis lupaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3746, + "scientific_name": "Canis lupus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3755, + "scientific_name": "Canis mesomelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3747, + "scientific_name": "Canis rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 3748, + "scientific_name": "Canis simensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 3759, + "scientific_name": "Cannomys badius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3760, + "scientific_name": "Cansumys canus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3778, + "scientific_name": "Caperea marginata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3786, + "scientific_name": "Capra aegagrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 3794, + "scientific_name": "Capra caucasica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 3795, + "scientific_name": "Capra cylindricornis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 3787, + "scientific_name": "Capra falconeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42397, + "scientific_name": "Capra ibex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3796, + "scientific_name": "Capra nubiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3798, + "scientific_name": "Capra pyrenaica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42398, + "scientific_name": "Capra sibirica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 3797, + "scientific_name": "Capra walie", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42395, + "scientific_name": "Capreolus capreolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42396, + "scientific_name": "Capreolus pygargus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3811, + "scientific_name": "Capricornis crispus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3815, + "scientific_name": "Capricornis rubidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 162916735, + "scientific_name": "Capricornis sumatraensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3810, + "scientific_name": "Capricornis swinhoei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3833, + "scientific_name": "Caprolagus hispidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 3842, + "scientific_name": "Capromys pilorides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18306, + "scientific_name": "Caracal aurata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3847, + "scientific_name": "Caracal caracal", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3858, + "scientific_name": "Cardiocranius paradoxus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3859, + "scientific_name": "Cardioderma cor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21492, + "scientific_name": "Carlito syrichta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 162369855, + "scientific_name": "Carlito syrichta ssp. carbonarius", + "subspecies": "carbonarius", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 162369880, + "scientific_name": "Carlito syrichta ssp. fraterculus", + "subspecies": "fraterculus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 162369759, + "scientific_name": "Carlito syrichta ssp. syrichta", + "subspecies": "syrichta", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 88110352, + "scientific_name": "Carollia benkeithi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3903, + "scientific_name": "Carollia brevicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88110411, + "scientific_name": "Carollia castanea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136782, + "scientific_name": "Carollia manu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88110257, + "scientific_name": "Carollia monohernandezi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3905, + "scientific_name": "Carollia perspicillata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136268, + "scientific_name": "Carollia sowelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3906, + "scientific_name": "Carollia subrufa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40596, + "scientific_name": "Carpitalpa arendsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 3917, + "scientific_name": "Carpomys melanurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 3916, + "scientific_name": "Carpomys phaeurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3921, + "scientific_name": "Carterodon sulcidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 7799, + "scientific_name": "Caryomys eva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7800, + "scientific_name": "Caryomys inez", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3999, + "scientific_name": "Casinycteris argynnis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84455300, + "scientific_name": "Casinycteris campomaanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4003, + "scientific_name": "Castor canadensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4007, + "scientific_name": "Castor fiber", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4015, + "scientific_name": "Catagonus wagneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4037, + "scientific_name": "Catopuma badia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4038, + "scientific_name": "Catopuma temminckii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 86257782, + "scientific_name": "Cavia aperea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4065, + "scientific_name": "Cavia fulgida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136520, + "scientific_name": "Cavia intermedia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 4066, + "scientific_name": "Cavia magna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 86263590, + "scientific_name": "Cavia patzelti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4068, + "scientific_name": "Cavia tschudii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136865, + "scientific_name": "Cebuella niveiventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136926, + "scientific_name": "Cebuella pygmaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4081, + "scientific_name": "Cebus aequatorialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39951, + "scientific_name": "Cebus albifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81237954, + "scientific_name": "Cebus brunneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 81257277, + "scientific_name": "Cebus capucinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 43934, + "scientific_name": "Cebus capucinus ssp. capucinus", + "subspecies": "capucinus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4087, + "scientific_name": "Cebus capucinus ssp. curtus", + "subspecies": "curtus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 43941, + "scientific_name": "Cebus castaneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4082, + "scientific_name": "Cebus cesarae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4075, + "scientific_name": "Cebus cuscinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 81265980, + "scientific_name": "Cebus imitator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40019, + "scientific_name": "Cebus kaapori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 70333164, + "scientific_name": "Cebus leucocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4084, + "scientific_name": "Cebus malitiosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 81384371, + "scientific_name": "Cebus olivaceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4085, + "scientific_name": "Cebus trinitatis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 70333194, + "scientific_name": "Cebus unicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39952, + "scientific_name": "Cebus versicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4076, + "scientific_name": "Cebus yuracus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136350, + "scientific_name": "Centronycteris centralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4112, + "scientific_name": "Centronycteris maximiliani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4133, + "scientific_name": "Centurio senex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21488, + "scientific_name": "Cephalopachus bancanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39762, + "scientific_name": "Cephalopachus bancanus ssp. bancanus", + "subspecies": "bancanus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39763, + "scientific_name": "Cephalopachus bancanus ssp. borneanus", + "subspecies": "borneanus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39764, + "scientific_name": "Cephalopachus bancanus ssp. natunensis", + "subspecies": "natunensis", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39765, + "scientific_name": "Cephalopachus bancanus ssp. saltator", + "subspecies": "saltator", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4137, + "scientific_name": "Cephalophus adersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4138, + "scientific_name": "Cephalophus callipygus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4139, + "scientific_name": "Cephalophus dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4154, + "scientific_name": "Cephalophus harveyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4140, + "scientific_name": "Cephalophus jentinki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4141, + "scientific_name": "Cephalophus leucogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4144, + "scientific_name": "Cephalophus natalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4145, + "scientific_name": "Cephalophus niger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4146, + "scientific_name": "Cephalophus nigrifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4147, + "scientific_name": "Cephalophus nigrifrons ssp. rubidus", + "subspecies": "rubidus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4148, + "scientific_name": "Cephalophus ogilbyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136902, + "scientific_name": "Cephalophus ogilbyi ssp. brookei", + "subspecies": "brookei", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4155, + "scientific_name": "Cephalophus ogilbyi ssp. crusalbum", + "subspecies": "crusalbum", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136878, + "scientific_name": "Cephalophus ogilbyi ssp. ogilbyi", + "subspecies": "ogilbyi", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4149, + "scientific_name": "Cephalophus rufilatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4150, + "scientific_name": "Cephalophus silvicultor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4151, + "scientific_name": "Cephalophus spadix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4152, + "scientific_name": "Cephalophus weynsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4153, + "scientific_name": "Cephalophus zebra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4159, + "scientific_name": "Cephalorhynchus commersonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4160, + "scientific_name": "Cephalorhynchus eutropia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4161, + "scientific_name": "Cephalorhynchus heavisidii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4162, + "scientific_name": "Cephalorhynchus hectori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39427, + "scientific_name": "Cephalorhynchus hectori ssp. maui", + "subspecies": "maui", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 4185, + "scientific_name": "Ceratotherium simum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4183, + "scientific_name": "Ceratotherium simum ssp. cottoni", + "subspecies": "cottoni", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39317, + "scientific_name": "Ceratotherium simum ssp. simum", + "subspecies": "simum", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4192, + "scientific_name": "Cercartetus caudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40576, + "scientific_name": "Cercartetus concinnus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40577, + "scientific_name": "Cercartetus lepidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40578, + "scientific_name": "Cercartetus nanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136615, + "scientific_name": "Cercocebus agilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136933, + "scientific_name": "Cercocebus atys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4207, + "scientific_name": "Cercocebus chrysogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4200, + "scientific_name": "Cercocebus galeritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 4206, + "scientific_name": "Cercocebus lunulatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4203, + "scientific_name": "Cercocebus sanjei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4201, + "scientific_name": "Cercocebus torquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4212, + "scientific_name": "Cercopithecus ascanius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136886, + "scientific_name": "Cercopithecus ascanius ssp. ascanius", + "subspecies": "ascanius", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136869, + "scientific_name": "Cercopithecus ascanius ssp. atrinasus", + "subspecies": "atrinasus", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136868, + "scientific_name": "Cercopithecus ascanius ssp. katangae", + "subspecies": "katangae", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136917, + "scientific_name": "Cercopithecus ascanius ssp. schmidti", + "subspecies": "schmidti", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136947, + "scientific_name": "Cercopithecus ascanius ssp. whitesidei", + "subspecies": "whitesidei", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136930, + "scientific_name": "Cercopithecus campbelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4214, + "scientific_name": "Cercopithecus cephus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136915, + "scientific_name": "Cercopithecus cephus ssp. cephodes", + "subspecies": "cephodes", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136882, + "scientific_name": "Cercopithecus cephus ssp. cephus", + "subspecies": "cephus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40011, + "scientific_name": "Cercopithecus cephus ssp. ngottoensis", + "subspecies": "ngottoensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136885, + "scientific_name": "Cercopithecus denti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4245, + "scientific_name": "Cercopithecus diana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4217, + "scientific_name": "Cercopithecus erythrogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40003, + "scientific_name": "Cercopithecus erythrogaster ssp. erythrogaster", + "subspecies": "erythrogaster", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 40004, + "scientific_name": "Cercopithecus erythrogaster ssp. pococki", + "subspecies": "pococki", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4218, + "scientific_name": "Cercopithecus erythrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136851, + "scientific_name": "Cercopithecus erythrotis ssp. camerunensis", + "subspecies": "camerunensis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4235, + "scientific_name": "Cercopithecus erythrotis ssp. erythrotis", + "subspecies": "erythrotis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4219, + "scientific_name": "Cercopithecus hamlyni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 92401376, + "scientific_name": "Cercopithecus lomamiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136931, + "scientific_name": "Cercopithecus lowei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4221, + "scientific_name": "Cercopithecus mitis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40645, + "scientific_name": "Cercopithecus mitis ssp. albogularis", + "subspecies": "albogularis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39990, + "scientific_name": "Cercopithecus mitis ssp. albotorquatus", + "subspecies": "albotorquatus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136901, + "scientific_name": "Cercopithecus mitis ssp. boutourlinii", + "subspecies": "boutourlinii", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136861, + "scientific_name": "Cercopithecus mitis ssp. doggetti", + "subspecies": "doggetti", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136887, + "scientific_name": "Cercopithecus mitis ssp. erythrarchus", + "subspecies": "erythrarchus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136877, + "scientific_name": "Cercopithecus mitis ssp. heymansi", + "subspecies": "heymansi", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4236, + "scientific_name": "Cercopithecus mitis ssp. kandti", + "subspecies": "kandti", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136927, + "scientific_name": "Cercopithecus mitis ssp. kolbi", + "subspecies": "kolbi", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41245, + "scientific_name": "Cercopithecus mitis ssp. labiatus", + "subspecies": "labiatus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 95596261, + "scientific_name": "Cercopithecus mitis ssp. manyaraensis", + "subspecies": "manyaraensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136943, + "scientific_name": "Cercopithecus mitis ssp. mitis", + "subspecies": "mitis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 96189741, + "scientific_name": "Cercopithecus mitis ssp. moloneyi", + "subspecies": "moloneyi", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136942, + "scientific_name": "Cercopithecus mitis ssp. monoides", + "subspecies": "monoides", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136850, + "scientific_name": "Cercopithecus mitis ssp. opisthostictus", + "subspecies": "opisthostictus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96183584, + "scientific_name": "Cercopithecus mitis ssp. stuhlmanni", + "subspecies": "stuhlmanni", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136925, + "scientific_name": "Cercopithecus mitis ssp. zammaranoi", + "subspecies": "zammaranoi", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 4222, + "scientific_name": "Cercopithecus mona", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4223, + "scientific_name": "Cercopithecus neglectus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4224, + "scientific_name": "Cercopithecus nictitans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 92488656, + "scientific_name": "Cercopithecus nictitans ssp. insolitus", + "subspecies": "insolitus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 92488692, + "scientific_name": "Cercopithecus nictitans ssp. ludio", + "subspecies": "ludio", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 92489579, + "scientific_name": "Cercopithecus nictitans ssp. martini", + "subspecies": "martini", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136922, + "scientific_name": "Cercopithecus nictitans ssp. nictitans", + "subspecies": "nictitans", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41208, + "scientific_name": "Cercopithecus nictitans ssp. stampflii", + "subspecies": "stampflii", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4225, + "scientific_name": "Cercopithecus petaurista", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136910, + "scientific_name": "Cercopithecus petaurista ssp. buettikoferi", + "subspecies": "buettikoferi", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136905, + "scientific_name": "Cercopithecus petaurista ssp. petaurista", + "subspecies": "petaurista", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 92411527, + "scientific_name": "Cercopithecus pogonias", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136907, + "scientific_name": "Cercopithecus pogonias ssp. grayi", + "subspecies": "grayi", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136940, + "scientific_name": "Cercopithecus pogonias ssp. nigripes", + "subspecies": "nigripes", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4239, + "scientific_name": "Cercopithecus pogonias ssp. pogonias", + "subspecies": "pogonias", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4232, + "scientific_name": "Cercopithecus roloway", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 4229, + "scientific_name": "Cercopithecus sclateri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 92466239, + "scientific_name": "Cercopithecus wolfi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136938, + "scientific_name": "Cercopithecus wolfi ssp. elegans", + "subspecies": "elegans", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136921, + "scientific_name": "Cercopithecus wolfi ssp. pyrogaster", + "subspecies": "pyrogaster", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40646, + "scientific_name": "Cercopithecus wolfi ssp. wolfi", + "subspecies": "wolfi", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4248, + "scientific_name": "Cerdocyon thous", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136276, + "scientific_name": "Cerradomys maracajuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136511, + "scientific_name": "Cerradomys marinhus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 114955348, + "scientific_name": "Cerradomys scotti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15614, + "scientific_name": "Cerradomys subflavus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4256, + "scientific_name": "Cervus albirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 55997823, + "scientific_name": "Cervus canadensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 55997072, + "scientific_name": "Cervus elaphus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4261, + "scientific_name": "Cervus hanglu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 113259123, + "scientific_name": "Cervus hanglu ssp. hanglu", + "subspecies": "hanglu", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41788, + "scientific_name": "Cervus nippon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136547, + "scientific_name": "Chacodelphys formosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4305, + "scientific_name": "Chaerephon aloysiisabaudiae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4306, + "scientific_name": "Chaerephon ansorgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 67360705, + "scientific_name": "Chaerephon atsinanana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4307, + "scientific_name": "Chaerephon bemmeleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4308, + "scientific_name": "Chaerephon bivittatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4309, + "scientific_name": "Chaerephon bregullae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4310, + "scientific_name": "Chaerephon chapini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4311, + "scientific_name": "Chaerephon gallagheri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4312, + "scientific_name": "Chaerephon jobensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136393, + "scientific_name": "Chaerephon jobimena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4313, + "scientific_name": "Chaerephon johorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4314, + "scientific_name": "Chaerephon major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4315, + "scientific_name": "Chaerephon nigeriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4316, + "scientific_name": "Chaerephon plicatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 67362271, + "scientific_name": "Chaerephon pumilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4319, + "scientific_name": "Chaerephon russatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4320, + "scientific_name": "Chaerephon solomonis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4321, + "scientific_name": "Chaerephon tomensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4322, + "scientific_name": "Chaeropus ecaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 6860, + "scientific_name": "Chaetocauda sichuanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 96812094, + "scientific_name": "Chaetodipus ammophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136421, + "scientific_name": "Chaetodipus ammophilus ssp. dalquesti", + "subspecies": "dalquesti", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 92459293, + "scientific_name": "Chaetodipus arenarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4327, + "scientific_name": "Chaetodipus artus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4328, + "scientific_name": "Chaetodipus baileyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4329, + "scientific_name": "Chaetodipus californicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136606, + "scientific_name": "Chaetodipus eremicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4330, + "scientific_name": "Chaetodipus fallax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4331, + "scientific_name": "Chaetodipus formosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4332, + "scientific_name": "Chaetodipus goldmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4333, + "scientific_name": "Chaetodipus hispidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4334, + "scientific_name": "Chaetodipus intermedius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136361, + "scientific_name": "Chaetodipus lineatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4335, + "scientific_name": "Chaetodipus nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4336, + "scientific_name": "Chaetodipus penicillatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4337, + "scientific_name": "Chaetodipus pernix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136837, + "scientific_name": "Chaetodipus rudinoris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92461708, + "scientific_name": "Chaetodipus siccus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4338, + "scientific_name": "Chaetodipus spinatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4366, + "scientific_name": "Chaetomys subspinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 89604632, + "scientific_name": "Chaetophractus vellerosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4369, + "scientific_name": "Chaetophractus villosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4414, + "scientific_name": "Chalinolobus dwyeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4417, + "scientific_name": "Chalinolobus gouldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4419, + "scientific_name": "Chalinolobus morio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4420, + "scientific_name": "Chalinolobus neocaledonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4421, + "scientific_name": "Chalinolobus nigrogriseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4422, + "scientific_name": "Chalinolobus picatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4425, + "scientific_name": "Chalinolobus tuberculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 163021607, + "scientific_name": "Cheirogaleus andysabini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 163021377, + "scientific_name": "Cheirogaleus crossleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 163021927, + "scientific_name": "Cheirogaleus grovesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 163022131, + "scientific_name": "Cheirogaleus lavasoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 54778911, + "scientific_name": "Cheirogaleus major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 163023599, + "scientific_name": "Cheirogaleus medius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 163020756, + "scientific_name": "Cheirogaleus shethi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41576, + "scientific_name": "Cheirogaleus sibreei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 163022885, + "scientific_name": "Cheirogaleus thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4600, + "scientific_name": "Cheiromeles parvidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4601, + "scientific_name": "Cheiromeles torquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4603, + "scientific_name": "Chelemys macronyx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4604, + "scientific_name": "Chelemys megalonyx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41564, + "scientific_name": "Cheracebus lucifer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41563, + "scientific_name": "Cheracebus lugens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39944, + "scientific_name": "Cheracebus medemi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41566, + "scientific_name": "Cheracebus regulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 210891841, + "scientific_name": "Cheracebus torquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136775, + "scientific_name": "Chibchanomys orcesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4627, + "scientific_name": "Chibchanomys trichotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4634, + "scientific_name": "Chilomys instans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88088745, + "scientific_name": "Chilonatalus macer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88088852, + "scientific_name": "Chilonatalus micropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14361, + "scientific_name": "Chilonatalus tumidifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4647, + "scientific_name": "Chimarrogale hantu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40614, + "scientific_name": "Chimarrogale himalayica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4648, + "scientific_name": "Chimarrogale phaeura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40615, + "scientific_name": "Chimarrogale platycephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40616, + "scientific_name": "Chimarrogale styani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4649, + "scientific_name": "Chimarrogale sumatrana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4651, + "scientific_name": "Chinchilla chinchilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4652, + "scientific_name": "Chinchilla lanigera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4655, + "scientific_name": "Chinchillula sahamae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4658, + "scientific_name": "Chionomys gud", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4659, + "scientific_name": "Chionomys nivalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4660, + "scientific_name": "Chionomys roberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4664, + "scientific_name": "Chiroderma doriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4665, + "scientific_name": "Chiroderma improvisum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4666, + "scientific_name": "Chiroderma salvini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4667, + "scientific_name": "Chiroderma trinitatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4668, + "scientific_name": "Chiroderma villosum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88108434, + "scientific_name": "Chiroderma vizottoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4669, + "scientific_name": "Chiromyscus chiropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4670, + "scientific_name": "Chironax melanocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4671, + "scientific_name": "Chironectes minimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4679, + "scientific_name": "Chiropodomys calamianensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4680, + "scientific_name": "Chiropodomys gliroides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4681, + "scientific_name": "Chiropodomys karlkoopmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4682, + "scientific_name": "Chiropodomys major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4683, + "scientific_name": "Chiropodomys muroides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4684, + "scientific_name": "Chiropodomys pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4685, + "scientific_name": "Chiropotes albinasus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 43891, + "scientific_name": "Chiropotes chiropotes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70330167, + "scientific_name": "Chiropotes sagulatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39956, + "scientific_name": "Chiropotes satanas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 43892, + "scientific_name": "Chiropotes utahickae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4691, + "scientific_name": "Chiruromys forbesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4692, + "scientific_name": "Chiruromys lamia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4693, + "scientific_name": "Chiruromys vates", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4704, + "scientific_name": "Chlamyphorus truncatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4233, + "scientific_name": "Chlorocebus aethiops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 215123466, + "scientific_name": "Chlorocebus aethiops ssp. aethiops", + "subspecies": "aethiops", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 215119320, + "scientific_name": "Chlorocebus aethiops ssp. matschiei", + "subspecies": "matschiei", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136291, + "scientific_name": "Chlorocebus cynosuros", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4240, + "scientific_name": "Chlorocebus djamdjamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 205910256, + "scientific_name": "Chlorocebus djamdjamensis ssp. djamdjamensis", + "subspecies": "djamdjamensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 205910110, + "scientific_name": "Chlorocebus djamdjamensis ssp. harennaensis", + "subspecies": "harennaensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4216, + "scientific_name": "Chlorocebus dryas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136271, + "scientific_name": "Chlorocebus pygerythrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92252725, + "scientific_name": "Chlorocebus pygerythrus ssp. hilgerti", + "subspecies": "hilgerti", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92252747, + "scientific_name": "Chlorocebus pygerythrus ssp. nesiotes", + "subspecies": "nesiotes", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 92252770, + "scientific_name": "Chlorocebus pygerythrus ssp. pygerythrus", + "subspecies": "pygerythrus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92252798, + "scientific_name": "Chlorocebus pygerythrus ssp. rufoviridis", + "subspecies": "rufoviridis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 205895889, + "scientific_name": "Chlorocebus pygerythrus ssp. zavattarii", + "subspecies": "zavattarii", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136265, + "scientific_name": "Chlorocebus sabaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136208, + "scientific_name": "Chlorocebus tantalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92252537, + "scientific_name": "Chlorocebus tantalus ssp. budgetti", + "subspecies": "budgetti", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92252560, + "scientific_name": "Chlorocebus tantalus ssp. marrensis", + "subspecies": "marrensis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 92252582, + "scientific_name": "Chlorocebus tantalus ssp. tantalus", + "subspecies": "tantalus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4768, + "scientific_name": "Chlorotalpa duthieae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4766, + "scientific_name": "Chlorotalpa sclateri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136259, + "scientific_name": "Chodsigoa caovansunga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41430, + "scientific_name": "Chodsigoa hypsibia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41431, + "scientific_name": "Chodsigoa lamula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41435, + "scientific_name": "Chodsigoa parca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136298, + "scientific_name": "Chodsigoa parva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20416, + "scientific_name": "Chodsigoa salenskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41436, + "scientific_name": "Chodsigoa smithii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136760, + "scientific_name": "Chodsigoa sodalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4772, + "scientific_name": "Choeroniscus godmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4774, + "scientific_name": "Choeroniscus minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4775, + "scientific_name": "Choeroniscus periosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4776, + "scientific_name": "Choeronycteris mexicana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10032, + "scientific_name": "Choeropsis liberiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4777, + "scientific_name": "Choloepus didactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4778, + "scientific_name": "Choloepus hoffmanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4806, + "scientific_name": "Chrotogale owstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4807, + "scientific_name": "Chrotomys gonzalesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4808, + "scientific_name": "Chrotomys mindorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136388, + "scientific_name": "Chrotomys sibuyanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4092, + "scientific_name": "Chrotomys silaceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4810, + "scientific_name": "Chrotomys whiteheadi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4811, + "scientific_name": "Chrotopterus auritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40600, + "scientific_name": "Chrysochloris asiatica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40601, + "scientific_name": "Chrysochloris stuhlmanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4812, + "scientific_name": "Chrysochloris visagiei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 4819, + "scientific_name": "Chrysocyon brachyurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4828, + "scientific_name": "Chrysospalax trevelyani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4829, + "scientific_name": "Chrysospalax villosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 44787, + "scientific_name": "Cistugo lesueuri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44788, + "scientific_name": "Cistugo seabrae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41695, + "scientific_name": "Civettictis civetta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4983, + "scientific_name": "Cloeotis percivali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4989, + "scientific_name": "Clyomys laticeps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112391705, + "scientific_name": "Coccymys kirrhos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 112464492, + "scientific_name": "Coccymys ruemmleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112393452, + "scientific_name": "Coccymys shawmayeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5074, + "scientific_name": "Coelops frithii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 5076, + "scientific_name": "Coelops robinsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5075, + "scientific_name": "Coelops robinsoni ssp. hirsutus", + "subspecies": "hirsutus", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 87411473, + "scientific_name": "Coendou baturitensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5083, + "scientific_name": "Coendou bicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136597, + "scientific_name": "Coendou ichillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20631, + "scientific_name": "Coendou insidiosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136738, + "scientific_name": "Coendou melanurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20629, + "scientific_name": "Coendou mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5084, + "scientific_name": "Coendou nycthemera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 101228458, + "scientific_name": "Coendou prehensilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136485, + "scientific_name": "Coendou pruinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136702, + "scientific_name": "Coendou quichua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136518, + "scientific_name": "Coendou roosmalenorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 7010, + "scientific_name": "Coendou rufescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 46205559, + "scientific_name": "Coendou speratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 20630, + "scientific_name": "Coendou spinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20633, + "scientific_name": "Coendou vestitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5113, + "scientific_name": "Coleura afra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80221085, + "scientific_name": "Coleura kibomalandy", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5112, + "scientific_name": "Coleura seychellensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 5142, + "scientific_name": "Colobus angolensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136929, + "scientific_name": "Colobus angolensis ssp. angolensis", + "subspecies": "angolensis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136935, + "scientific_name": "Colobus angolensis ssp. cordieri", + "subspecies": "cordieri", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136923, + "scientific_name": "Colobus angolensis ssp. cottoni", + "subspecies": "cottoni", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40041, + "scientific_name": "Colobus angolensis ssp. nov.", + "subspecies": "nov.", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5148, + "scientific_name": "Colobus angolensis ssp. palliatus", + "subspecies": "palliatus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5149, + "scientific_name": "Colobus angolensis ssp. prigoginei", + "subspecies": "prigoginei", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5147, + "scientific_name": "Colobus angolensis ssp. ruwenzorii", + "subspecies": "ruwenzorii", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 92576098, + "scientific_name": "Colobus angolensis ssp. sharpei", + "subspecies": "sharpei", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136858, + "scientific_name": "Colobus caudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5143, + "scientific_name": "Colobus guereza", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136880, + "scientific_name": "Colobus guereza ssp. dodingae", + "subspecies": "dodingae", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5150, + "scientific_name": "Colobus guereza ssp. gallarum", + "subspecies": "gallarum", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136896, + "scientific_name": "Colobus guereza ssp. guereza", + "subspecies": "guereza", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136883, + "scientific_name": "Colobus guereza ssp. kikuyuensis", + "subspecies": "kikuyuensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136846, + "scientific_name": "Colobus guereza ssp. matschiei", + "subspecies": "matschiei", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136891, + "scientific_name": "Colobus guereza ssp. occidentalis", + "subspecies": "occidentalis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40007, + "scientific_name": "Colobus guereza ssp. percivali", + "subspecies": "percivali", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5144, + "scientific_name": "Colobus polykomos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5145, + "scientific_name": "Colobus satanas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40012, + "scientific_name": "Colobus satanas ssp. anthracinus", + "subspecies": "anthracinus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40008, + "scientific_name": "Colobus satanas ssp. satanas", + "subspecies": "satanas", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 5146, + "scientific_name": "Colobus vellerosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 5151, + "scientific_name": "Colomys goslingi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41458, + "scientific_name": "Condylura cristata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41630, + "scientific_name": "Conepatus chinga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41631, + "scientific_name": "Conepatus humboldtii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41632, + "scientific_name": "Conepatus leuconotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41633, + "scientific_name": "Conepatus semistriatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136343, + "scientific_name": "Congosorex phillipsorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 5221, + "scientific_name": "Congosorex polli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44935, + "scientific_name": "Congosorex verheyeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5223, + "scientific_name": "Conilurus albipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 75927841, + "scientific_name": "Conilurus capricornensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 5224, + "scientific_name": "Conilurus penicillatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5228, + "scientific_name": "Connochaetes gnou", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5229, + "scientific_name": "Connochaetes taurinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41527, + "scientific_name": "Cormura brevirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17599, + "scientific_name": "Corynorhinus mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 17600, + "scientific_name": "Corynorhinus rafinesquii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17598, + "scientific_name": "Corynorhinus townsendii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5414, + "scientific_name": "Coryphomys buehleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 5481, + "scientific_name": "Craseonycteris thonglongyai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 5499, + "scientific_name": "Crateromys australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5502, + "scientific_name": "Crateromys heaneyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5501, + "scientific_name": "Crateromys paulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5500, + "scientific_name": "Crateromys schadenbergi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16025, + "scientific_name": "Cratogeomys castanops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136215, + "scientific_name": "Cratogeomys fulvescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16026, + "scientific_name": "Cratogeomys fumosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136647, + "scientific_name": "Cratogeomys goldmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16028, + "scientific_name": "Cratogeomys merriami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136396, + "scientific_name": "Cratogeomys perotensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136249, + "scientific_name": "Cratogeomys planiceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5513, + "scientific_name": "Cremnomys cutchicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5514, + "scientific_name": "Cremnomys elvira", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 112256552, + "scientific_name": "Cricetomys ansorgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5521, + "scientific_name": "Cricetomys emini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112169507, + "scientific_name": "Cricetomys gambianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5523, + "scientific_name": "Cricetulus alticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5524, + "scientific_name": "Cricetulus barabensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5525, + "scientific_name": "Cricetulus kamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136746, + "scientific_name": "Cricetulus lama", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5526, + "scientific_name": "Cricetulus longicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5528, + "scientific_name": "Cricetulus migratorius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5527, + "scientific_name": "Cricetulus sokolovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136527, + "scientific_name": "Cricetulus tibetanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5529, + "scientific_name": "Cricetus cricetus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 111747853, + "scientific_name": "Crocidura absconditus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 112517405, + "scientific_name": "Crocidura afeworkbekelei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40617, + "scientific_name": "Crocidura aleksandrisi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5620, + "scientific_name": "Crocidura allex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5595, + "scientific_name": "Crocidura andamanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 48296764, + "scientific_name": "Crocidura annamitensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5558, + "scientific_name": "Crocidura ansellorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40618, + "scientific_name": "Crocidura arabica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136270, + "scientific_name": "Crocidura arispa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5596, + "scientific_name": "Crocidura armenica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48296412, + "scientific_name": "Crocidura attenuata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5621, + "scientific_name": "Crocidura attila", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5559, + "scientific_name": "Crocidura baileyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136726, + "scientific_name": "Crocidura baluensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48297939, + "scientific_name": "Crocidura batakorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40620, + "scientific_name": "Crocidura batesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5597, + "scientific_name": "Crocidura beatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5598, + "scientific_name": "Crocidura beccarii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40621, + "scientific_name": "Crocidura bottegi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5622, + "scientific_name": "Crocidura bottegoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136742, + "scientific_name": "Crocidura brunnea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40622, + "scientific_name": "Crocidura buettikoferi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5623, + "scientific_name": "Crocidura caliginea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5560, + "scientific_name": "Crocidura canariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136444, + "scientific_name": "Crocidura caspica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41317, + "scientific_name": "Crocidura cinderella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5561, + "scientific_name": "Crocidura congobelgica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48296479, + "scientific_name": "Crocidura cranbrooki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5562, + "scientific_name": "Crocidura crenata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40624, + "scientific_name": "Crocidura crossei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40625, + "scientific_name": "Crocidura cyanea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40626, + "scientific_name": "Crocidura denti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5624, + "scientific_name": "Crocidura desperata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5599, + "scientific_name": "Crocidura dhofarensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40628, + "scientific_name": "Crocidura dolichura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40629, + "scientific_name": "Crocidura douceti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40627, + "scientific_name": "Crocidura dsinezumi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111764928, + "scientific_name": "Crocidura eburnea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5565, + "scientific_name": "Crocidura eisentrauti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5625, + "scientific_name": "Crocidura elgonius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40630, + "scientific_name": "Crocidura elongata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5626, + "scientific_name": "Crocidura erica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 111739377, + "scientific_name": "Crocidura fingui", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5627, + "scientific_name": "Crocidura fischeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5628, + "scientific_name": "Crocidura flavescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5600, + "scientific_name": "Crocidura floweri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136578, + "scientific_name": "Crocidura foetida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5629, + "scientific_name": "Crocidura foxi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40631, + "scientific_name": "Crocidura fuliginosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40632, + "scientific_name": "Crocidura fulvastra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5630, + "scientific_name": "Crocidura fumosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40633, + "scientific_name": "Crocidura fuscomurina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111765432, + "scientific_name": "Crocidura gathornei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5566, + "scientific_name": "Crocidura glassi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41319, + "scientific_name": "Crocidura gmelini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112518189, + "scientific_name": "Crocidura goliath", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5631, + "scientific_name": "Crocidura gracilipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41321, + "scientific_name": "Crocidura grandiceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 5601, + "scientific_name": "Crocidura grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5567, + "scientific_name": "Crocidura grassei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5602, + "scientific_name": "Crocidura grayi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5632, + "scientific_name": "Crocidura greenwoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48296877, + "scientific_name": "Crocidura guy", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5633, + "scientific_name": "Crocidura harenna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136596, + "scientific_name": "Crocidura hikmiya", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41322, + "scientific_name": "Crocidura hildegardeae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136226, + "scientific_name": "Crocidura hilliana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41323, + "scientific_name": "Crocidura hirta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5603, + "scientific_name": "Crocidura hispida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41324, + "scientific_name": "Crocidura horsfieldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136781, + "scientific_name": "Crocidura hutanis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136733, + "scientific_name": "Crocidura indochinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41325, + "scientific_name": "Crocidura jacksoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5604, + "scientific_name": "Crocidura jenkinsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136327, + "scientific_name": "Crocidura jouvenetae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136634, + "scientific_name": "Crocidura katinka", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5568, + "scientific_name": "Crocidura kivuana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41326, + "scientific_name": "Crocidura lamottei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5569, + "scientific_name": "Crocidura lanosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41327, + "scientific_name": "Crocidura lasiura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5570, + "scientific_name": "Crocidura latona", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41328, + "scientific_name": "Crocidura lea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136792, + "scientific_name": "Crocidura lepidura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29651, + "scientific_name": "Crocidura leucodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41329, + "scientific_name": "Crocidura levicula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41330, + "scientific_name": "Crocidura littoralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5571, + "scientific_name": "Crocidura longipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5572, + "scientific_name": "Crocidura lucina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5589, + "scientific_name": "Crocidura ludia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41331, + "scientific_name": "Crocidura luna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41332, + "scientific_name": "Crocidura lusitania", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112139630, + "scientific_name": "Crocidura lwiroensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41333, + "scientific_name": "Crocidura macarthuri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5634, + "scientific_name": "Crocidura macmillani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 5635, + "scientific_name": "Crocidura macowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5605, + "scientific_name": "Crocidura malayana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5575, + "scientific_name": "Crocidura manengubae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5576, + "scientific_name": "Crocidura maquassiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41334, + "scientific_name": "Crocidura mariquensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41335, + "scientific_name": "Crocidura maurisca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41336, + "scientific_name": "Crocidura maxi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112503346, + "scientific_name": "Crocidura mdumai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 48269124, + "scientific_name": "Crocidura mindorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5608, + "scientific_name": "Crocidura miya", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 111767309, + "scientific_name": "Crocidura monax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41337, + "scientific_name": "Crocidura monticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41338, + "scientific_name": "Crocidura montis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112503202, + "scientific_name": "Crocidura munissii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41339, + "scientific_name": "Crocidura muricauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136711, + "scientific_name": "Crocidura musseri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41340, + "scientific_name": "Crocidura mutesae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41341, + "scientific_name": "Crocidura nana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41342, + "scientific_name": "Crocidura nanilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136786, + "scientific_name": "Crocidura negligens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5609, + "scientific_name": "Crocidura negrina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 112503255, + "scientific_name": "Crocidura newmarki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 5610, + "scientific_name": "Crocidura nicobarica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41344, + "scientific_name": "Crocidura nigeriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41345, + "scientific_name": "Crocidura nigricans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41447, + "scientific_name": "Crocidura nigripes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41346, + "scientific_name": "Crocidura nigrofusca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5578, + "scientific_name": "Crocidura nimbae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 112519468, + "scientific_name": "Crocidura nimbasilvanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48269338, + "scientific_name": "Crocidura ninoyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41347, + "scientific_name": "Crocidura niobe", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111754705, + "scientific_name": "Crocidura obscurior", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41348, + "scientific_name": "Crocidura olivieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5611, + "scientific_name": "Crocidura orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5590, + "scientific_name": "Crocidura orii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40623, + "scientific_name": "Crocidura pachyura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5613, + "scientific_name": "Crocidura palawanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48297786, + "scientific_name": "Crocidura panayensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5614, + "scientific_name": "Crocidura paradoxura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41349, + "scientific_name": "Crocidura parvipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41350, + "scientific_name": "Crocidura pasha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5615, + "scientific_name": "Crocidura pergrisea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5580, + "scientific_name": "Crocidura phaeura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 45954204, + "scientific_name": "Crocidura phanluongi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45954289, + "scientific_name": "Crocidura phuquocensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5636, + "scientific_name": "Crocidura picea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5637, + "scientific_name": "Crocidura pitmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41351, + "scientific_name": "Crocidura planiceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41352, + "scientific_name": "Crocidura poensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5591, + "scientific_name": "Crocidura polia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41353, + "scientific_name": "Crocidura pullata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5592, + "scientific_name": "Crocidura raineyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136722, + "scientific_name": "Crocidura ramona", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136783, + "scientific_name": "Crocidura rapax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5616, + "scientific_name": "Crocidura religiosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41354, + "scientific_name": "Crocidura rhoditis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41355, + "scientific_name": "Crocidura roosevelti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29652, + "scientific_name": "Crocidura russula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112465460, + "scientific_name": "Crocidura sapaensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5593, + "scientific_name": "Crocidura selina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29654, + "scientific_name": "Crocidura serezkyensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5617, + "scientific_name": "Crocidura shantungensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41356, + "scientific_name": "Crocidura sibirica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29655, + "scientific_name": "Crocidura sicula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41357, + "scientific_name": "Crocidura silacea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41358, + "scientific_name": "Crocidura smithii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45954331, + "scientific_name": "Crocidura sokolovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41359, + "scientific_name": "Crocidura somalica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5582, + "scientific_name": "Crocidura stenocephala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 29656, + "scientific_name": "Crocidura suaveolens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5618, + "scientific_name": "Crocidura susiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136238, + "scientific_name": "Crocidura tanakae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112513345, + "scientific_name": "Crocidura tansaniana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41360, + "scientific_name": "Crocidura tarella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41361, + "scientific_name": "Crocidura tarfayensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5584, + "scientific_name": "Crocidura telfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5619, + "scientific_name": "Crocidura tenuis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5585, + "scientific_name": "Crocidura thalia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41362, + "scientific_name": "Crocidura theresae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5594, + "scientific_name": "Crocidura thomensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136379, + "scientific_name": "Crocidura trichura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41363, + "scientific_name": "Crocidura turba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5638, + "scientific_name": "Crocidura ultima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 112465479, + "scientific_name": "Crocidura umbra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 112515709, + "scientific_name": "Crocidura usambarae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41364, + "scientific_name": "Crocidura viaria", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136602, + "scientific_name": "Crocidura virgata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41365, + "scientific_name": "Crocidura voi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136454, + "scientific_name": "Crocidura vorax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136447, + "scientific_name": "Crocidura vosmaeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136341, + "scientific_name": "Crocidura watasei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41366, + "scientific_name": "Crocidura whitakeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5587, + "scientific_name": "Crocidura wimmeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136382, + "scientific_name": "Crocidura wuchihensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5639, + "scientific_name": "Crocidura xantippe", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112517512, + "scientific_name": "Crocidura yaldeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41367, + "scientific_name": "Crocidura yankariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45954341, + "scientific_name": "Crocidura zaitsevi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41368, + "scientific_name": "Crocidura zaphiri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41369, + "scientific_name": "Crocidura zarudnyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5640, + "scientific_name": "Crocidura zimmeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5588, + "scientific_name": "Crocidura zimmermanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5674, + "scientific_name": "Crocuta crocuta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41593, + "scientific_name": "Crossarchus alexandri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41594, + "scientific_name": "Crossarchus ansorgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41595, + "scientific_name": "Crossarchus obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41596, + "scientific_name": "Crossarchus platycephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5679, + "scientific_name": "Crossomys moncktoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5704, + "scientific_name": "Crunomys celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5705, + "scientific_name": "Crunomys fallax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5706, + "scientific_name": "Crunomys melanius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29458, + "scientific_name": "Crunomys suncoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5748, + "scientific_name": "Cryptochloris wintoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 5749, + "scientific_name": "Cryptochloris zyli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 111932681, + "scientific_name": "Cryptomys hottentotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111933779, + "scientific_name": "Cryptomys mahali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 111935513, + "scientific_name": "Cryptomys natalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111935780, + "scientific_name": "Cryptomys pretoriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136545, + "scientific_name": "Cryptonanus agricolai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136845, + "scientific_name": "Cryptonanus chacoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136705, + "scientific_name": "Cryptonanus guahybae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41320, + "scientific_name": "Cryptonanus ignitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 136749, + "scientific_name": "Cryptonanus unduaviensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5760, + "scientific_name": "Cryptoprocta ferox", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136456, + "scientific_name": "Cryptoprocta spelea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 136789, + "scientific_name": "Cryptotis alticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45954361, + "scientific_name": "Cryptotis aroensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136736, + "scientific_name": "Cryptotis brachyonyx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 96829126, + "scientific_name": "Cryptotis cavatorculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 96828906, + "scientific_name": "Cryptotis celaque", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136795, + "scientific_name": "Cryptotis colombiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 114956336, + "scientific_name": "Cryptotis dinirensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5763, + "scientific_name": "Cryptotis endersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136438, + "scientific_name": "Cryptotis equatoris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41371, + "scientific_name": "Cryptotis goldmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48269679, + "scientific_name": "Cryptotis goodwini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5764, + "scientific_name": "Cryptotis gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48269619, + "scientific_name": "Cryptotis griseoventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5765, + "scientific_name": "Cryptotis hondurensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48269646, + "scientific_name": "Cryptotis lacertosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5766, + "scientific_name": "Cryptotis magna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 48269568, + "scientific_name": "Cryptotis mam", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136488, + "scientific_name": "Cryptotis mayensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96829093, + "scientific_name": "Cryptotis mccarthyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136267, + "scientific_name": "Cryptotis medellinia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48268560, + "scientific_name": "Cryptotis meridensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136398, + "scientific_name": "Cryptotis merriami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136299, + "scientific_name": "Cryptotis merus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41374, + "scientific_name": "Cryptotis mexicana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41375, + "scientific_name": "Cryptotis montivaga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136389, + "scientific_name": "Cryptotis nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 96829156, + "scientific_name": "Cryptotis niausa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41376, + "scientific_name": "Cryptotis nigrescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136462, + "scientific_name": "Cryptotis obscura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45954370, + "scientific_name": "Cryptotis oreoryctes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136838, + "scientific_name": "Cryptotis orophila", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41377, + "scientific_name": "Cryptotis parva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136550, + "scientific_name": "Cryptotis peregrina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 91356351, + "scientific_name": "Cryptotis perijensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136734, + "scientific_name": "Cryptotis peruviensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136639, + "scientific_name": "Cryptotis phillipsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41378, + "scientific_name": "Cryptotis squamipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136780, + "scientific_name": "Cryptotis tamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41379, + "scientific_name": "Cryptotis thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136757, + "scientific_name": "Cryptotis tropicalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48267978, + "scientific_name": "Cryptotis venezuelensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5792, + "scientific_name": "Ctenodactylus gundi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5793, + "scientific_name": "Ctenodactylus vali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5795, + "scientific_name": "Ctenomys argentinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 5796, + "scientific_name": "Ctenomys australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5797, + "scientific_name": "Ctenomys azarae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136687, + "scientific_name": "Ctenomys bergi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5798, + "scientific_name": "Ctenomys boliviensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5799, + "scientific_name": "Ctenomys bonettoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5800, + "scientific_name": "Ctenomys brasiliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5801, + "scientific_name": "Ctenomys colburni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136308, + "scientific_name": "Ctenomys coludo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5802, + "scientific_name": "Ctenomys conoveri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136295, + "scientific_name": "Ctenomys coyhaiquensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136234, + "scientific_name": "Ctenomys dorbignyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 5803, + "scientific_name": "Ctenomys dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5804, + "scientific_name": "Ctenomys emilianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136588, + "scientific_name": "Ctenomys famosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136464, + "scientific_name": "Ctenomys flamarioni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136499, + "scientific_name": "Ctenomys fochi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136601, + "scientific_name": "Ctenomys fodax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 115553730, + "scientific_name": "Ctenomys frater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5806, + "scientific_name": "Ctenomys fulvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136607, + "scientific_name": "Ctenomys goodfellowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5807, + "scientific_name": "Ctenomys haigi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45958852, + "scientific_name": "Ctenomys ibicuiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136281, + "scientific_name": "Ctenomys johannis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136556, + "scientific_name": "Ctenomys juris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5808, + "scientific_name": "Ctenomys knighti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136567, + "scientific_name": "Ctenomys lami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 5809, + "scientific_name": "Ctenomys latro", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5810, + "scientific_name": "Ctenomys leucodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5811, + "scientific_name": "Ctenomys lewisi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5812, + "scientific_name": "Ctenomys magellanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5813, + "scientific_name": "Ctenomys maulinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5814, + "scientific_name": "Ctenomys mendocinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5815, + "scientific_name": "Ctenomys minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5817, + "scientific_name": "Ctenomys occultus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5818, + "scientific_name": "Ctenomys opimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136390, + "scientific_name": "Ctenomys osvaldoreigi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 5819, + "scientific_name": "Ctenomys pearsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 5820, + "scientific_name": "Ctenomys perrensi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5821, + "scientific_name": "Ctenomys peruanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136289, + "scientific_name": "Ctenomys pilarensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 5822, + "scientific_name": "Ctenomys pontifex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5823, + "scientific_name": "Ctenomys porteousi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136370, + "scientific_name": "Ctenomys pundti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136635, + "scientific_name": "Ctenomys rionegrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136633, + "scientific_name": "Ctenomys roigi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 5824, + "scientific_name": "Ctenomys saltarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136568, + "scientific_name": "Ctenomys scagliai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5825, + "scientific_name": "Ctenomys sericeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5826, + "scientific_name": "Ctenomys sociabilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 5827, + "scientific_name": "Ctenomys steinbachi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5828, + "scientific_name": "Ctenomys talarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5829, + "scientific_name": "Ctenomys torquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5830, + "scientific_name": "Ctenomys tuconax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5831, + "scientific_name": "Ctenomys tucumanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136826, + "scientific_name": "Ctenomys tulduco", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5832, + "scientific_name": "Ctenomys validus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136758, + "scientific_name": "Ctenomys viperinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136681, + "scientific_name": "Ctenomys yolandae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 699, + "scientific_name": "Cuniculus paca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 700, + "scientific_name": "Cuniculus taczanowskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 5953, + "scientific_name": "Cuon alpinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136466, + "scientific_name": "Cuscomys ashaninka", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136658, + "scientific_name": "Cuscomys oblativa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6019, + "scientific_name": "Cyclopes didactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 173393, + "scientific_name": "Cyclopes didactylus Northeastern Brazil subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Northeastern Brazil subpopulation", + "category": "DD" + }, + { + "taxonid": 41597, + "scientific_name": "Cynictis penicillata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6081, + "scientific_name": "Cynocephalus volans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6082, + "scientific_name": "Cynogale bennettii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13637, + "scientific_name": "Cynomops abrasus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13639, + "scientific_name": "Cynomops greenhalli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136611, + "scientific_name": "Cynomops mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87993512, + "scientific_name": "Cynomops milleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87993365, + "scientific_name": "Cynomops paranus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13642, + "scientific_name": "Cynomops planirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42453, + "scientific_name": "Cynomys gunnisoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42454, + "scientific_name": "Cynomys leucurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6091, + "scientific_name": "Cynomys ludovicianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6089, + "scientific_name": "Cynomys mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6090, + "scientific_name": "Cynomys parvidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6103, + "scientific_name": "Cynopterus brachyotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6104, + "scientific_name": "Cynopterus horsfieldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136798, + "scientific_name": "Cynopterus luzoniensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136423, + "scientific_name": "Cynopterus minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6105, + "scientific_name": "Cynopterus nusatenggara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6106, + "scientific_name": "Cynopterus sphinx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6107, + "scientific_name": "Cynopterus titthaecheilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6204, + "scientific_name": "Cystophora cristata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6206, + "scientific_name": "Cyttarops alecto", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6219, + "scientific_name": "Dacnomys millardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6220, + "scientific_name": "Dactylomys boliviensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6221, + "scientific_name": "Dactylomys dactylinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6222, + "scientific_name": "Dactylomys peruanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6225, + "scientific_name": "Dactylonax palpator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6223, + "scientific_name": "Dactylopsila megalura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6224, + "scientific_name": "Dactylopsila tatei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6226, + "scientific_name": "Dactylopsila trivirgata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42188, + "scientific_name": "Dama dama", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6235, + "scientific_name": "Damaliscus lunatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6241, + "scientific_name": "Damaliscus lunatus ssp. jimela", + "subspecies": "jimela", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6238, + "scientific_name": "Damaliscus lunatus ssp. korrigum", + "subspecies": "korrigum", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6240, + "scientific_name": "Damaliscus lunatus ssp. lunatus", + "subspecies": "lunatus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136860, + "scientific_name": "Damaliscus lunatus ssp. superstes", + "subspecies": "superstes", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6242, + "scientific_name": "Damaliscus lunatus ssp. tiang", + "subspecies": "tiang", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6243, + "scientific_name": "Damaliscus lunatus ssp. topi", + "subspecies": "topi", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 30208, + "scientific_name": "Damaliscus pygargus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 30209, + "scientific_name": "Damaliscus pygargus ssp. phillipsi", + "subspecies": "phillipsi", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6236, + "scientific_name": "Damaliscus pygargus ssp. pygargus", + "subspecies": "pygargus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6232, + "scientific_name": "Dama mesopotamica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6267, + "scientific_name": "Dasycercus blythi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6266, + "scientific_name": "Dasycercus cristicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40527, + "scientific_name": "Dasykaluta rosamondae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6268, + "scientific_name": "Dasymys foxi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6269, + "scientific_name": "Dasymys incomtus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6270, + "scientific_name": "Dasymys montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6271, + "scientific_name": "Dasymys nudipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6272, + "scientific_name": "Dasymys rufulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6278, + "scientific_name": "Dasyprocta azarae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6279, + "scientific_name": "Dasyprocta coibae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 89497187, + "scientific_name": "Dasyprocta croconota", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6281, + "scientific_name": "Dasyprocta fuliginosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6282, + "scientific_name": "Dasyprocta guamara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 89531729, + "scientific_name": "Dasyprocta iacki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6283, + "scientific_name": "Dasyprocta kalinowskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 89497102, + "scientific_name": "Dasyprocta leporina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6285, + "scientific_name": "Dasyprocta mexicana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 6286, + "scientific_name": "Dasyprocta prymnolopha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 89497686, + "scientific_name": "Dasyprocta punctata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6287, + "scientific_name": "Dasyprocta ruatanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 89497716, + "scientific_name": "Dasyprocta variegata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6288, + "scientific_name": "Dasypus hybridus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6289, + "scientific_name": "Dasypus kappleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6290, + "scientific_name": "Dasypus novemcinctus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6291, + "scientific_name": "Dasypus pilosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6292, + "scientific_name": "Dasypus sabanicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6293, + "scientific_name": "Dasypus septemcinctus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61924, + "scientific_name": "Dasypus yepesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6265, + "scientific_name": "Dasyuroides byrnei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6299, + "scientific_name": "Dasyurus albopunctatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6294, + "scientific_name": "Dasyurus geoffroii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6295, + "scientific_name": "Dasyurus hallucatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6300, + "scientific_name": "Dasyurus maculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6301, + "scientific_name": "Dasyurus spartacus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6296, + "scientific_name": "Dasyurus viverrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6302, + "scientific_name": "Daubentonia madagascariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6313, + "scientific_name": "Delanymys brooksi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136338, + "scientific_name": "Delomys collinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6329, + "scientific_name": "Delomys dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6330, + "scientific_name": "Delomys sublineatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6335, + "scientific_name": "Delphinapterus leucas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61442, + "scientific_name": "Delphinapterus leucas Cook Inlet subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Cook Inlet subpopulation", + "category": "CR" + }, + { + "taxonid": 134817215, + "scientific_name": "Delphinus delphis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156206333, + "scientific_name": "Delphinus delphis Gulf of Corinth subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Gulf of Corinth subpopulation", + "category": "CR" + }, + { + "taxonid": 189865869, + "scientific_name": "Delphinus delphis Inner Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Inner Mediterranean subpopulation", + "category": "EN" + }, + { + "taxonid": 41762, + "scientific_name": "Delphinus delphis Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mediterranean subpopulation", + "category": "EN" + }, + { + "taxonid": 133729, + "scientific_name": "Delphinus delphis ssp. ponticus", + "subspecies": "ponticus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 738, + "scientific_name": "Deltamys kempi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6405, + "scientific_name": "Dendrogale melanura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41490, + "scientific_name": "Dendrogale murina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6409, + "scientific_name": "Dendrohyrax arboreus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6410, + "scientific_name": "Dendrohyrax dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136599, + "scientific_name": "Dendrohyrax validus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6426, + "scientific_name": "Dendrolagus bennettianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6427, + "scientific_name": "Dendrolagus dorianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6429, + "scientific_name": "Dendrolagus goodfellowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6431, + "scientific_name": "Dendrolagus inustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6432, + "scientific_name": "Dendrolagus lumholtzi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6433, + "scientific_name": "Dendrolagus matschiei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136668, + "scientific_name": "Dendrolagus mayri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 6437, + "scientific_name": "Dendrolagus mbaiso", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136732, + "scientific_name": "Dendrolagus notatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136696, + "scientific_name": "Dendrolagus pulcherrimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 6435, + "scientific_name": "Dendrolagus scottae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 6436, + "scientific_name": "Dendrolagus spadix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136812, + "scientific_name": "Dendrolagus stellarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6434, + "scientific_name": "Dendrolagus ursinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6440, + "scientific_name": "Dendromus insignis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6439, + "scientific_name": "Dendromus kahuziensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 6441, + "scientific_name": "Dendromus kivu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45958985, + "scientific_name": "Dendromus lachaisei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6442, + "scientific_name": "Dendromus lovati", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6443, + "scientific_name": "Dendromus melanotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6444, + "scientific_name": "Dendromus mesomelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6445, + "scientific_name": "Dendromus messorius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6446, + "scientific_name": "Dendromus mystacalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6447, + "scientific_name": "Dendromus nyikae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6448, + "scientific_name": "Dendromus oreas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45959000, + "scientific_name": "Dendromus ruppi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6449, + "scientific_name": "Dendromus vernayi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6483, + "scientific_name": "Dendroprionomys rousseloti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6490, + "scientific_name": "Deomys ferrugineus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6491, + "scientific_name": "Dephomys defua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2122, + "scientific_name": "Dermanura anderseni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2123, + "scientific_name": "Dermanura azteca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 83683094, + "scientific_name": "Dermanura bogotensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2124, + "scientific_name": "Dermanura cinerea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 83683065, + "scientific_name": "Dermanura glauca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2129, + "scientific_name": "Dermanura gnoma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 83683287, + "scientific_name": "Dermanura phaeotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 83683265, + "scientific_name": "Dermanura rava", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136505, + "scientific_name": "Dermanura rosenbergi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 2140, + "scientific_name": "Dermanura tolteca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 99586593, + "scientific_name": "Dermanura watsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18731, + "scientific_name": "Desmalopex leucopterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 84457227, + "scientific_name": "Desmalopex microleucopterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6506, + "scientific_name": "Desmana moschata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6508, + "scientific_name": "Desmodilliscus braueri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6509, + "scientific_name": "Desmodillus auricularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6510, + "scientific_name": "Desmodus rotundus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6511, + "scientific_name": "Desmomys harringtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45052, + "scientific_name": "Desmomys yaldeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6520, + "scientific_name": "Diaemus youngi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6553, + "scientific_name": "Dicerorhinus sumatrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 6557, + "scientific_name": "Diceros bicornis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39318, + "scientific_name": "Diceros bicornis ssp. bicornis", + "subspecies": "bicornis", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39319, + "scientific_name": "Diceros bicornis ssp. longipes", + "subspecies": "longipes", + "rank": "ssp.", + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 39320, + "scientific_name": "Diceros bicornis ssp. michaeli", + "subspecies": "michaeli", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39321, + "scientific_name": "Diceros bicornis ssp. minor", + "subspecies": "minor", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 6561, + "scientific_name": "Diclidurus albus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6562, + "scientific_name": "Diclidurus ingens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6563, + "scientific_name": "Diclidurus isabella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6564, + "scientific_name": "Diclidurus scutatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42618, + "scientific_name": "Dicrostonyx groenlandicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42619, + "scientific_name": "Dicrostonyx hudsonius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42620, + "scientific_name": "Dicrostonyx nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6567, + "scientific_name": "Dicrostonyx nunatakensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42622, + "scientific_name": "Dicrostonyx richardsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6568, + "scientific_name": "Dicrostonyx torquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39974, + "scientific_name": "Dicrostonyx unalascensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6569, + "scientific_name": "Dicrostonyx vinogradovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40489, + "scientific_name": "Didelphis albiventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40500, + "scientific_name": "Didelphis aurita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136592, + "scientific_name": "Didelphis imperfecta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40501, + "scientific_name": "Didelphis marsupialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136395, + "scientific_name": "Didelphis pernigra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40502, + "scientific_name": "Didelphis virginiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6607, + "scientific_name": "Dinaromys bogdanovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6608, + "scientific_name": "Dinomys branickii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6622, + "scientific_name": "Diomys crumpi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6628, + "scientific_name": "Diphylla ecaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6635, + "scientific_name": "Diplogale hosei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41448, + "scientific_name": "Diplomesodon pulchellum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6662, + "scientific_name": "Diplomys caniceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6663, + "scientific_name": "Diplomys labilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6671, + "scientific_name": "Diplothrix legata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6684, + "scientific_name": "Dipodomys agilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42599, + "scientific_name": "Dipodomys californicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6685, + "scientific_name": "Dipodomys compactus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6686, + "scientific_name": "Dipodomys deserti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6675, + "scientific_name": "Dipodomys elator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6676, + "scientific_name": "Dipodomys gravipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 42600, + "scientific_name": "Dipodomys heermanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6678, + "scientific_name": "Dipodomys ingens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 92465716, + "scientific_name": "Dipodomys merriami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42603, + "scientific_name": "Dipodomys microps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6690, + "scientific_name": "Dipodomys nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6683, + "scientific_name": "Dipodomys nitratoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6691, + "scientific_name": "Dipodomys ordii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92464382, + "scientific_name": "Dipodomys ornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42604, + "scientific_name": "Dipodomys panamintinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92463503, + "scientific_name": "Dipodomys phillipsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136630, + "scientific_name": "Dipodomys simulans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6693, + "scientific_name": "Dipodomys spectabilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6682, + "scientific_name": "Dipodomys stephensi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42605, + "scientific_name": "Dipodomys venustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6705, + "scientific_name": "Dipus sagitta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6765, + "scientific_name": "Distoechurus pennatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136374, + "scientific_name": "Dobsonia anderseni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6772, + "scientific_name": "Dobsonia beauforti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6773, + "scientific_name": "Dobsonia chapmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136571, + "scientific_name": "Dobsonia crenulata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6774, + "scientific_name": "Dobsonia emersa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6775, + "scientific_name": "Dobsonia exoleta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6778, + "scientific_name": "Dobsonia inermis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84882338, + "scientific_name": "Dobsonia magna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6770, + "scientific_name": "Dobsonia minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84882605, + "scientific_name": "Dobsonia moluccensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6776, + "scientific_name": "Dobsonia pannietensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6771, + "scientific_name": "Dobsonia peronii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6777, + "scientific_name": "Dobsonia praedatrix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6780, + "scientific_name": "Dobsonia viridis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6785, + "scientific_name": "Dolichotis patagonum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6786, + "scientific_name": "Dolichotis salinicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41598, + "scientific_name": "Dologale dybowskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6793, + "scientific_name": "Dorcatragus megalotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6794, + "scientific_name": "Dorcopsis atrata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 6795, + "scientific_name": "Dorcopsis hageni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6799, + "scientific_name": "Dorcopsis luctuosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6800, + "scientific_name": "Dorcopsis muelleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6801, + "scientific_name": "Dorcopsulus macleayi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6802, + "scientific_name": "Dorcopsulus vanheurni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6820, + "scientific_name": "Dremomys everetti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136313, + "scientific_name": "Dremomys gularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6821, + "scientific_name": "Dremomys lokriah", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6822, + "scientific_name": "Dremomys pernyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6823, + "scientific_name": "Dremomys pyrrhomerus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6824, + "scientific_name": "Dremomys rufigenis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6834, + "scientific_name": "Dromiciops gliroides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 88120233, + "scientific_name": "Dryadonycteris capixaba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 46205572, + "scientific_name": "Drymoreomys albimaculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6859, + "scientific_name": "Dryomys laniger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40767, + "scientific_name": "Dryomys niethammeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6858, + "scientific_name": "Dryomys nitedula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6909, + "scientific_name": "Dugong dugon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 157011948, + "scientific_name": "Dugong dugon Nansei subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Nansei subpopulation", + "category": "CR" + }, + { + "taxonid": 6923, + "scientific_name": "Dusicyon australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 82337482, + "scientific_name": "Dusicyon avus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 136356, + "scientific_name": "Dyacopterus brooksi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 84457541, + "scientific_name": "Dyacopterus rickarti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6931, + "scientific_name": "Dyacopterus spadiceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41488, + "scientific_name": "Dymecodon pilirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6979, + "scientific_name": "Echimys chrysurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6987, + "scientific_name": "Echimys saturnus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136652, + "scientific_name": "Echimys vieirai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40592, + "scientific_name": "Echinops telfairi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40603, + "scientific_name": "Echinosorex gymnura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136230, + "scientific_name": "Echiothrix centrosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7014, + "scientific_name": "Echiothrix leucura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7015, + "scientific_name": "Echymipera clara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7017, + "scientific_name": "Echymipera davidi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7016, + "scientific_name": "Echymipera echinista", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 7018, + "scientific_name": "Echymipera kalubu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7019, + "scientific_name": "Echymipera rufescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7030, + "scientific_name": "Ectophylla alba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7083, + "scientific_name": "Eidolon dupreanum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 7084, + "scientific_name": "Eidolon helvum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41644, + "scientific_name": "Eira barbara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7112, + "scientific_name": "Elaphodus cephalophus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7121, + "scientific_name": "Elaphurus davidianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EW" + }, + { + "taxonid": 42658, + "scientific_name": "Elephantulus brachyrhynchus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7136, + "scientific_name": "Elephantulus edwardii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42659, + "scientific_name": "Elephantulus fuscipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42660, + "scientific_name": "Elephantulus fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42661, + "scientific_name": "Elephantulus intufi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42662, + "scientific_name": "Elephantulus myurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165924, + "scientific_name": "Elephantulus pilicaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 7137, + "scientific_name": "Elephantulus revoilii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42663, + "scientific_name": "Elephantulus rozeti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42664, + "scientific_name": "Elephantulus rufescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7138, + "scientific_name": "Elephantulus rupestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7140, + "scientific_name": "Elephas maximus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 199856, + "scientific_name": "Elephas maximus ssp. sumatranus", + "subspecies": "sumatranus", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 7577, + "scientific_name": "Eligmodontia moreni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7578, + "scientific_name": "Eligmodontia morgani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7579, + "scientific_name": "Eligmodontia puerulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48303074, + "scientific_name": "Eligmodontia typus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7619, + "scientific_name": "Eliomys melanurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136469, + "scientific_name": "Eliomys munbyanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7618, + "scientific_name": "Eliomys quercinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 48267436, + "scientific_name": "Eliurus antsingy", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48266951, + "scientific_name": "Eliurus carletoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136251, + "scientific_name": "Eliurus danieli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136325, + "scientific_name": "Eliurus ellermani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29460, + "scientific_name": "Eliurus grandidieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7622, + "scientific_name": "Eliurus majori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7621, + "scientific_name": "Eliurus minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7623, + "scientific_name": "Eliurus myoxinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7624, + "scientific_name": "Eliurus penicillatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136316, + "scientific_name": "Eliurus petteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7625, + "scientific_name": "Eliurus tanala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7626, + "scientific_name": "Eliurus webbi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7653, + "scientific_name": "Ellobius alaicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 7654, + "scientific_name": "Ellobius fuscocapillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7655, + "scientific_name": "Ellobius lutescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7656, + "scientific_name": "Ellobius talpinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7657, + "scientific_name": "Ellobius tancrei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7670, + "scientific_name": "Emballonura alecto", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7672, + "scientific_name": "Emballonura beccarii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7673, + "scientific_name": "Emballonura dianae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7667, + "scientific_name": "Emballonura furax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7674, + "scientific_name": "Emballonura monticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7668, + "scientific_name": "Emballonura raffrayana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7669, + "scientific_name": "Emballonura semicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41528, + "scientific_name": "Emballonura serii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 2130, + "scientific_name": "Enchisthenes hartii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7750, + "scientific_name": "Enhydra lutris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7781, + "scientific_name": "Eoglaucomys fimbriatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7782, + "scientific_name": "Eolagurus luteus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7783, + "scientific_name": "Eolagurus przewalskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7786, + "scientific_name": "Eonycteris major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136768, + "scientific_name": "Eonycteris robusta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 7787, + "scientific_name": "Eonycteris spelaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14118, + "scientific_name": "Eospalax fontanierii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14121, + "scientific_name": "Eospalax rothschildi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14122, + "scientific_name": "Eospalax smithii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136507, + "scientific_name": "Eothenomys cachinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7797, + "scientific_name": "Eothenomys chinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7798, + "scientific_name": "Eothenomys custos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7801, + "scientific_name": "Eothenomys melanogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136275, + "scientific_name": "Eothenomys miletus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7802, + "scientific_name": "Eothenomys olitor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7803, + "scientific_name": "Eothenomys proditor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136196, + "scientific_name": "Eothenomys wardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7806, + "scientific_name": "Eozapus setchuanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41428, + "scientific_name": "Episoriculus caudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41429, + "scientific_name": "Episoriculus fumidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41432, + "scientific_name": "Episoriculus leucops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41433, + "scientific_name": "Episoriculus macrurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7899, + "scientific_name": "Epixerus ebii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7901, + "scientific_name": "Epomophorus angolensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136351, + "scientific_name": "Epomophorus anselli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44697, + "scientific_name": "Epomophorus crypturus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7903, + "scientific_name": "Epomophorus gambianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7902, + "scientific_name": "Epomophorus grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 84457881, + "scientific_name": "Epomophorus labiatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7905, + "scientific_name": "Epomophorus minimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84458822, + "scientific_name": "Epomophorus minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7906, + "scientific_name": "Epomophorus wahlbergi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7907, + "scientific_name": "Epomops buettikoferi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7908, + "scientific_name": "Epomops dobsonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7909, + "scientific_name": "Epomops franqueti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85198368, + "scientific_name": "Eptesicus anatolicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7912, + "scientific_name": "Eptesicus andinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7914, + "scientific_name": "Eptesicus bobrinskoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85197425, + "scientific_name": "Eptesicus bottae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7916, + "scientific_name": "Eptesicus brasiliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136524, + "scientific_name": "Eptesicus chiriquinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7922, + "scientific_name": "Eptesicus diminutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7921, + "scientific_name": "Eptesicus dimissus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 7926, + "scientific_name": "Eptesicus floweri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7927, + "scientific_name": "Eptesicus furinalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7928, + "scientific_name": "Eptesicus fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41531, + "scientific_name": "Eptesicus gobiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7929, + "scientific_name": "Eptesicus guadeloupensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7931, + "scientific_name": "Eptesicus hottentotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7932, + "scientific_name": "Eptesicus innoxius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 85200107, + "scientific_name": "Eptesicus isabellinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136823, + "scientific_name": "Eptesicus japonensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 7933, + "scientific_name": "Eptesicus kobayashii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 7910, + "scientific_name": "Eptesicus nilssonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85198662, + "scientific_name": "Eptesicus ognevi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85200202, + "scientific_name": "Eptesicus pachyomus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7936, + "scientific_name": "Eptesicus pachyotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7937, + "scientific_name": "Eptesicus platyops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85199559, + "scientific_name": "Eptesicus serotinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88151044, + "scientific_name": "Eptesicus taddeii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 7942, + "scientific_name": "Eptesicus tatei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 7949, + "scientific_name": "Equus africanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41763, + "scientific_name": "Equus ferus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7961, + "scientific_name": "Equus ferus ssp. przewalskii", + "subspecies": "przewalskii", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7950, + "scientific_name": "Equus grevyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7951, + "scientific_name": "Equus hemionus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7952, + "scientific_name": "Equus hemionus ssp. hemionus", + "subspecies": "hemionus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7962, + "scientific_name": "Equus hemionus ssp. hemippus", + "subspecies": "hemippus", + "rank": "ssp.", + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 7963, + "scientific_name": "Equus hemionus ssp. khur", + "subspecies": "khur", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7964, + "scientific_name": "Equus hemionus ssp. kulan", + "subspecies": "kulan", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7966, + "scientific_name": "Equus hemionus ssp. onager", + "subspecies": "onager", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 7953, + "scientific_name": "Equus kiang", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41013, + "scientific_name": "Equus quagga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7957, + "scientific_name": "Equus quagga ssp. quagga", + "subspecies": "quagga", + "rank": "ssp.", + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 7960, + "scientific_name": "Equus zebra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 7958, + "scientific_name": "Equus zebra ssp. hartmannae", + "subspecies": "hartmannae", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 7959, + "scientific_name": "Equus zebra ssp. zebra", + "subspecies": "zebra", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7994, + "scientific_name": "Eremitalpa granti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7995, + "scientific_name": "Eremodipus lichtensteini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15609, + "scientific_name": "Eremoryzomys polius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8004, + "scientific_name": "Erethizon dorsatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8010, + "scientific_name": "Erignathus barbatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8012, + "scientific_name": "Erignathus barbatus ssp. barbatus", + "subspecies": "barbatus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8013, + "scientific_name": "Erignathus barbatus ssp. nauticus", + "subspecies": "nauticus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40604, + "scientific_name": "Erinaceus amurensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40605, + "scientific_name": "Erinaceus concolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29650, + "scientific_name": "Erinaceus europaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136344, + "scientific_name": "Erinaceus roumanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8032, + "scientific_name": "Eropeplus canus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136247, + "scientific_name": "Erophylla bombifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8033, + "scientific_name": "Erophylla sezekorni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92252436, + "scientific_name": "Erythrocebus baumstarki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 174391079, + "scientific_name": "Erythrocebus patas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 92252458, + "scientific_name": "Erythrocebus patas ssp. patas", + "subspecies": "patas", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 92252480, + "scientific_name": "Erythrocebus patas ssp. pyrrhonotus", + "subspecies": "pyrrhonotus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 205893280, + "scientific_name": "Erythrocebus patas ssp. villiersi", + "subspecies": "villiersi", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 164377509, + "scientific_name": "Erythrocebus poliophaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8097, + "scientific_name": "Eschrichtius robustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8099, + "scientific_name": "Eschrichtius robustus western subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "western subpopulation", + "category": "EN" + }, + { + "taxonid": 8153, + "scientific_name": "Eubalaena australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 133704, + "scientific_name": "Eubalaena australis Chile-Peru subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Chile-Peru subpopulation", + "category": "CR" + }, + { + "taxonid": 41712, + "scientific_name": "Eubalaena glacialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41711, + "scientific_name": "Eubalaena japonica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 133706, + "scientific_name": "Eubalaena japonica Northeast Pacific subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Northeast Pacific subpopulation", + "category": "CR" + }, + { + "taxonid": 8162, + "scientific_name": "Euchoreutes naso", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8166, + "scientific_name": "Euderma maculatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80263386, + "scientific_name": "Eudiscoderma thongareeae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 8168, + "scientific_name": "Eudiscopus denticulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8992, + "scientific_name": "Eudorcas albonotata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8973, + "scientific_name": "Eudorcas rufifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8982, + "scientific_name": "Eudorcas thomsonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8991, + "scientific_name": "Eudorcas tilonura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8204, + "scientific_name": "Eulemur albifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8205, + "scientific_name": "Eulemur cinereiceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 8206, + "scientific_name": "Eulemur collaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8199, + "scientific_name": "Eulemur coronatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8211, + "scientific_name": "Eulemur flavifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 8207, + "scientific_name": "Eulemur fulvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8212, + "scientific_name": "Eulemur macaco", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8202, + "scientific_name": "Eulemur mongoz", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 8203, + "scientific_name": "Eulemur rubriventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136269, + "scientific_name": "Eulemur rufifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8209, + "scientific_name": "Eulemur rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8210, + "scientific_name": "Eulemur sanfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8239, + "scientific_name": "Eumetopias jubatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 17367725, + "scientific_name": "Eumetopias jubatus ssp. jubatus", + "subspecies": "jubatus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 17345844, + "scientific_name": "Eumetopias jubatus ssp. monteriensis", + "subspecies": "monteriensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8241, + "scientific_name": "Eumops auripendulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87993837, + "scientific_name": "Eumops bonariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8243, + "scientific_name": "Eumops dabbenei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87993965, + "scientific_name": "Eumops delticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 87994072, + "scientific_name": "Eumops ferox", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136433, + "scientific_name": "Eumops floridanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 87994083, + "scientific_name": "Eumops glaucinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8245, + "scientific_name": "Eumops hansae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8246, + "scientific_name": "Eumops maurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 87994060, + "scientific_name": "Eumops nanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136825, + "scientific_name": "Eumops patagonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8247, + "scientific_name": "Eumops perotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136809, + "scientific_name": "Eumops trumbulli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8248, + "scientific_name": "Eumops underwoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87993523, + "scientific_name": "Eumops wilsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8256, + "scientific_name": "Euneomys chinchilloides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136261, + "scientific_name": "Euneomys fossor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8257, + "scientific_name": "Euneomys mordax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8258, + "scientific_name": "Euneomys petersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8265, + "scientific_name": "Euoticus elegantulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8266, + "scientific_name": "Euoticus pallidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40002, + "scientific_name": "Euoticus pallidus ssp. pallidus", + "subspecies": "pallidus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136892, + "scientific_name": "Euoticus pallidus ssp. talboti", + "subspecies": "talboti", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 8269, + "scientific_name": "Eupetaurus cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8306, + "scientific_name": "Euphractus sexcinctus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 68336601, + "scientific_name": "Eupleres goudotii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39547, + "scientific_name": "Eupleres major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41459, + "scientific_name": "Euroscaptor grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41460, + "scientific_name": "Euroscaptor klossi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41461, + "scientific_name": "Euroscaptor longirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41462, + "scientific_name": "Euroscaptor micrura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8385, + "scientific_name": "Euroscaptor mizura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8386, + "scientific_name": "Euroscaptor parvidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45955241, + "scientific_name": "Euroscaptor subanura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29402, + "scientific_name": "Euryoryzomys emmonsae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15602, + "scientific_name": "Euryoryzomys lamia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15603, + "scientific_name": "Euryoryzomys legatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15605, + "scientific_name": "Euryoryzomys macconnelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15607, + "scientific_name": "Euryoryzomys nitidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29405, + "scientific_name": "Euryoryzomys russatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8418, + "scientific_name": "Euryzygomatomys spinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21360, + "scientific_name": "Eutamias sibiricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8436, + "scientific_name": "Exilisciurus concinnus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8437, + "scientific_name": "Exilisciurus exilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8438, + "scientific_name": "Exilisciurus whiteheadi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17348, + "scientific_name": "Falsistrellus mackenziei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 17351, + "scientific_name": "Falsistrellus mordax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17359, + "scientific_name": "Falsistrellus petersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17367, + "scientific_name": "Falsistrellus tasmaniensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8539, + "scientific_name": "Felis bieti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8540, + "scientific_name": "Felis chaus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 131299383, + "scientific_name": "Felis lybica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8541, + "scientific_name": "Felis margarita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8542, + "scientific_name": "Felis nigripes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 181049859, + "scientific_name": "Felis silvestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8548, + "scientific_name": "Felovia vae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8551, + "scientific_name": "Feresa attenuata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8553, + "scientific_name": "Feroculus feroculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8668, + "scientific_name": "Fossa fossana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 44858, + "scientific_name": "Fukomys anselli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5752, + "scientific_name": "Fukomys bocagei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5753, + "scientific_name": "Fukomys damarensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44860, + "scientific_name": "Fukomys darlingi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5754, + "scientific_name": "Fukomys foxi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 167462770, + "scientific_name": "Fukomys hanangensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 48295791, + "scientific_name": "Fukomys ilariae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44861, + "scientific_name": "Fukomys kafuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 167463928, + "scientific_name": "Fukomys livingstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5756, + "scientific_name": "Fukomys mechowii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5757, + "scientific_name": "Fukomys ochraceocinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48294834, + "scientific_name": "Fukomys vandewoestijneae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 5751, + "scientific_name": "Fukomys zechi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8700, + "scientific_name": "Funambulus layardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 88814157, + "scientific_name": "Funambulus obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8701, + "scientific_name": "Funambulus palmarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8702, + "scientific_name": "Funambulus pennantii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88813572, + "scientific_name": "Funambulus sublineatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8704, + "scientific_name": "Funambulus tristriatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8756, + "scientific_name": "Funisciurus anerythrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8757, + "scientific_name": "Funisciurus bayonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8755, + "scientific_name": "Funisciurus carruthersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8758, + "scientific_name": "Funisciurus congicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136461, + "scientific_name": "Funisciurus duchaillui", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8759, + "scientific_name": "Funisciurus isabella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8760, + "scientific_name": "Funisciurus lemniscatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8761, + "scientific_name": "Funisciurus leucogenys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8762, + "scientific_name": "Funisciurus pyrropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8763, + "scientific_name": "Funisciurus substriatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8771, + "scientific_name": "Furipterus horrens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8786, + "scientific_name": "Galago gallarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40649, + "scientific_name": "Galagoides demidoff", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 91966225, + "scientific_name": "Galagoides demidoff ssp. demidoff", + "subspecies": "demidoff", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 91967801, + "scientific_name": "Galagoides demidoff ssp. poensis", + "subspecies": "poensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 164378198, + "scientific_name": "Galagoides kumbirensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40653, + "scientific_name": "Galagoides thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8787, + "scientific_name": "Galago matschiei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8788, + "scientific_name": "Galago moholi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8789, + "scientific_name": "Galago senegalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136863, + "scientific_name": "Galago senegalensis ssp. braccatus", + "subspecies": "braccatus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136872, + "scientific_name": "Galago senegalensis ssp. dunni", + "subspecies": "dunni", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136897, + "scientific_name": "Galago senegalensis ssp. senegalensis", + "subspecies": "senegalensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136904, + "scientific_name": "Galago senegalensis ssp. sotikae", + "subspecies": "sotikae", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 86235821, + "scientific_name": "Galea comes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8823, + "scientific_name": "Galea flavidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 86236150, + "scientific_name": "Galea leucoblephara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 86226097, + "scientific_name": "Galea musteloides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 8825, + "scientific_name": "Galea spixii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8826, + "scientific_name": "Galemys pyrenaicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8827, + "scientific_name": "Galenomys garleppi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41502, + "scientific_name": "Galeopterus variegatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41639, + "scientific_name": "Galictis cuja", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41640, + "scientific_name": "Galictis vittata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39426, + "scientific_name": "Galidia elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8833, + "scientific_name": "Galidictis fasciata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8834, + "scientific_name": "Galidictis grandidieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13560, + "scientific_name": "Gardnerycteris crenulatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136266, + "scientific_name": "Gardnerycteris koepckeae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 117582065, + "scientific_name": "Gazella arabica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8978, + "scientific_name": "Gazella bennettii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8987, + "scientific_name": "Gazella bilkis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 8967, + "scientific_name": "Gazella cuvieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8969, + "scientific_name": "Gazella dorcas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8989, + "scientific_name": "Gazella gazella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8972, + "scientific_name": "Gazella leptoceros", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8977, + "scientific_name": "Gazella marica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8980, + "scientific_name": "Gazella saudiya", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 8975, + "scientific_name": "Gazella spekei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8976, + "scientific_name": "Gazella subgutturosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8994, + "scientific_name": "Genetta abyssinica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41696, + "scientific_name": "Genetta angolensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136223, + "scientific_name": "Genetta bourloni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8998, + "scientific_name": "Genetta cristata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41698, + "scientific_name": "Genetta genetta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8997, + "scientific_name": "Genetta johnstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41699, + "scientific_name": "Genetta maculata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136437, + "scientific_name": "Genetta pardina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15628, + "scientific_name": "Genetta piscivora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136435, + "scientific_name": "Genetta poensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41700, + "scientific_name": "Genetta servalina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41701, + "scientific_name": "Genetta thierryi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41702, + "scientific_name": "Genetta tigrina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41703, + "scientific_name": "Genetta victoriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9001, + "scientific_name": "Geocapromys brownii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 9004, + "scientific_name": "Geocapromys columbianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 9002, + "scientific_name": "Geocapromys ingrahami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 9003, + "scientific_name": "Geocapromys thoracatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 9048, + "scientific_name": "Geogale aurita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9054, + "scientific_name": "Geomys arenarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136380, + "scientific_name": "Geomys attwateri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136840, + "scientific_name": "Geomys breviceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42588, + "scientific_name": "Geomys bursarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136258, + "scientific_name": "Geomys knoxjonesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9055, + "scientific_name": "Geomys personatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42589, + "scientific_name": "Geomys pinetis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9062, + "scientific_name": "Geomys texensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9056, + "scientific_name": "Geomys tropicalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 9077, + "scientific_name": "Georychus capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40768, + "scientific_name": "Geoxus annectens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 9089, + "scientific_name": "Geoxus valdivianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21509, + "scientific_name": "Gerbilliscus afra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21510, + "scientific_name": "Gerbilliscus boehmi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21511, + "scientific_name": "Gerbilliscus brantsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45076, + "scientific_name": "Gerbilliscus gambiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21512, + "scientific_name": "Gerbilliscus guineae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21513, + "scientific_name": "Gerbilliscus inclusus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21515, + "scientific_name": "Gerbilliscus kempi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21516, + "scientific_name": "Gerbilliscus leucogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21517, + "scientific_name": "Gerbilliscus nigricaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21518, + "scientific_name": "Gerbilliscus phillipsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21519, + "scientific_name": "Gerbilliscus robustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21520, + "scientific_name": "Gerbilliscus validus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9092, + "scientific_name": "Gerbillurus paeba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9093, + "scientific_name": "Gerbillurus setzeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9094, + "scientific_name": "Gerbillurus tytonis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9095, + "scientific_name": "Gerbillurus vallinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9096, + "scientific_name": "Gerbillus acticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9102, + "scientific_name": "Gerbillus agag", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9104, + "scientific_name": "Gerbillus amoenus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9105, + "scientific_name": "Gerbillus andersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9106, + "scientific_name": "Gerbillus aquilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9109, + "scientific_name": "Gerbillus bottai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9110, + "scientific_name": "Gerbillus brockmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9111, + "scientific_name": "Gerbillus burtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45088, + "scientific_name": "Gerbillus campestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9113, + "scientific_name": "Gerbillus cheesmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9114, + "scientific_name": "Gerbillus cosensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9116, + "scientific_name": "Gerbillus dasyurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9119, + "scientific_name": "Gerbillus dunni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9120, + "scientific_name": "Gerbillus famulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9121, + "scientific_name": "Gerbillus floweri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9123, + "scientific_name": "Gerbillus gerbillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9124, + "scientific_name": "Gerbillus gleadowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9125, + "scientific_name": "Gerbillus grobbeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9126, + "scientific_name": "Gerbillus harwoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9127, + "scientific_name": "Gerbillus henleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9128, + "scientific_name": "Gerbillus hesperinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 9129, + "scientific_name": "Gerbillus hoogstraali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 9130, + "scientific_name": "Gerbillus jamesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9131, + "scientific_name": "Gerbillus juliani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9132, + "scientific_name": "Gerbillus latastei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9133, + "scientific_name": "Gerbillus lowei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9134, + "scientific_name": "Gerbillus mackilligini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9097, + "scientific_name": "Gerbillus maghrebi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9135, + "scientific_name": "Gerbillus mesopotamiae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9099, + "scientific_name": "Gerbillus muriculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9100, + "scientific_name": "Gerbillus nancillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9136, + "scientific_name": "Gerbillus nanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9137, + "scientific_name": "Gerbillus nigeriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9138, + "scientific_name": "Gerbillus occiduus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136703, + "scientific_name": "Gerbillus percivali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9140, + "scientific_name": "Gerbillus perpallidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9141, + "scientific_name": "Gerbillus poecilops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9142, + "scientific_name": "Gerbillus principulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9143, + "scientific_name": "Gerbillus pulvinatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9144, + "scientific_name": "Gerbillus pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9145, + "scientific_name": "Gerbillus pyramidum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9101, + "scientific_name": "Gerbillus rosalinda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45053, + "scientific_name": "Gerbillus rupicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9149, + "scientific_name": "Gerbillus simoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9150, + "scientific_name": "Gerbillus somalicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9151, + "scientific_name": "Gerbillus stigmonyx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9153, + "scientific_name": "Gerbillus tarabuli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9155, + "scientific_name": "Gerbillus watersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9194, + "scientific_name": "Giraffa camelopardalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 88420726, + "scientific_name": "Giraffa camelopardalis ssp. angolensis", + "subspecies": "angolensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88420742, + "scientific_name": "Giraffa camelopardalis ssp. antiquorum", + "subspecies": "antiquorum", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 88420707, + "scientific_name": "Giraffa camelopardalis ssp. camelopardalis", + "subspecies": "camelopardalis", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136913, + "scientific_name": "Giraffa camelopardalis ssp. peralta", + "subspecies": "peralta", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 88420717, + "scientific_name": "Giraffa camelopardalis ssp. reticulata", + "subspecies": "reticulata", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 174469, + "scientific_name": "Giraffa camelopardalis ssp. rothschildi", + "subspecies": "rothschildi", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 88421020, + "scientific_name": "Giraffa camelopardalis ssp. thornicrofti", + "subspecies": "thornicrofti", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 88421036, + "scientific_name": "Giraffa camelopardalis ssp. tippelskirchi", + "subspecies": "tippelskirchi", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39553, + "scientific_name": "Glaucomys sabrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9240, + "scientific_name": "Glaucomys volans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44789, + "scientific_name": "Glauconycteris alboguttata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44790, + "scientific_name": "Glauconycteris argentata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44791, + "scientific_name": "Glauconycteris beatrix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44792, + "scientific_name": "Glauconycteris curryae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44793, + "scientific_name": "Glauconycteris egeria", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44794, + "scientific_name": "Glauconycteris gleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44795, + "scientific_name": "Glauconycteris humeralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44796, + "scientific_name": "Glauconycteris kenyacola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44797, + "scientific_name": "Glauconycteris machadoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44798, + "scientific_name": "Glauconycteris poensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44799, + "scientific_name": "Glauconycteris superba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44800, + "scientific_name": "Glauconycteris variegata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9245, + "scientific_name": "Glironia venusta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9246, + "scientific_name": "Glirulus japonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81189973, + "scientific_name": "Glischropus bucephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9247, + "scientific_name": "Glischropus javanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 81187867, + "scientific_name": "Glischropus tylopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39316, + "scientific_name": "Glis glis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9249, + "scientific_name": "Globicephala macrorhynchus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9250, + "scientific_name": "Globicephala melas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 198785664, + "scientific_name": "Globicephala melas Inner Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Inner Mediterranean subpopulation", + "category": "EN" + }, + { + "taxonid": 198787290, + "scientific_name": "Globicephala melas Strait of Gibraltar subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Strait of Gibraltar subpopulation", + "category": "CR" + }, + { + "taxonid": 9273, + "scientific_name": "Glossophaga commissarisi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9274, + "scientific_name": "Glossophaga leachii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9275, + "scientific_name": "Glossophaga longirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9276, + "scientific_name": "Glossophaga morenoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9277, + "scientific_name": "Glossophaga soricina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13375, + "scientific_name": "Glyphonycteris behnii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13377, + "scientific_name": "Glyphonycteris daviesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13384, + "scientific_name": "Glyphonycteris sylvestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9283, + "scientific_name": "Glyphotes simus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9303, + "scientific_name": "Golunda ellioti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39994, + "scientific_name": "Gorilla beringei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39999, + "scientific_name": "Gorilla beringei ssp. beringei", + "subspecies": "beringei", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39995, + "scientific_name": "Gorilla beringei ssp. graueri", + "subspecies": "graueri", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9404, + "scientific_name": "Gorilla gorilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39998, + "scientific_name": "Gorilla gorilla ssp. diehli", + "subspecies": "diehli", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9406, + "scientific_name": "Gorilla gorilla ssp. gorilla", + "subspecies": "gorilla", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 92363381, + "scientific_name": "Gracilimus radix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9416, + "scientific_name": "Gracilinanus aceramarcae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9417, + "scientific_name": "Gracilinanus agilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9418, + "scientific_name": "Gracilinanus dryas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9419, + "scientific_name": "Gracilinanus emiliae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9420, + "scientific_name": "Gracilinanus marica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9421, + "scientific_name": "Gracilinanus microtarsus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9450, + "scientific_name": "Grammomys aridulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 47967714, + "scientific_name": "Grammomys brevirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9451, + "scientific_name": "Grammomys buntingi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9452, + "scientific_name": "Grammomys caniceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9453, + "scientific_name": "Grammomys cometes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9454, + "scientific_name": "Grammomys dolichurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9455, + "scientific_name": "Grammomys dryas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9456, + "scientific_name": "Grammomys gigas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 9457, + "scientific_name": "Grammomys ibeanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9460, + "scientific_name": "Grammomys kuru", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9458, + "scientific_name": "Grammomys macmillani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9459, + "scientific_name": "Grammomys minnae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 45955965, + "scientific_name": "Grammomys selousi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9461, + "scientific_name": "Grampus griseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16378423, + "scientific_name": "Grampus griseus Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mediterranean subpopulation", + "category": "EN" + }, + { + "taxonid": 114981285, + "scientific_name": "Graomys chacoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9465, + "scientific_name": "Graomys domorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9466, + "scientific_name": "Graomys edithae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9467, + "scientific_name": "Graomys griseoflavus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44915, + "scientific_name": "Graphiurus angolensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9480, + "scientific_name": "Graphiurus christyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9481, + "scientific_name": "Graphiurus crassicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44928, + "scientific_name": "Graphiurus johnstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9483, + "scientific_name": "Graphiurus kelleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9484, + "scientific_name": "Graphiurus lorraineus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9485, + "scientific_name": "Graphiurus microtis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9486, + "scientific_name": "Graphiurus monardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9487, + "scientific_name": "Graphiurus murinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44916, + "scientific_name": "Graphiurus nagtglasii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9488, + "scientific_name": "Graphiurus ocularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9491, + "scientific_name": "Graphiurus platyops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9492, + "scientific_name": "Graphiurus rupicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9493, + "scientific_name": "Graphiurus surdus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 112387339, + "scientific_name": "Graphiurus walterverheyeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9561, + "scientific_name": "Gulo gulo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11062, + "scientific_name": "Gyldenstolpia fronto", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9564, + "scientific_name": "Gymnobelideus leadbeateri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9581, + "scientific_name": "Gymnuromys roberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9608, + "scientific_name": "Habromys chinanteco", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136683, + "scientific_name": "Habromys delicatulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136582, + "scientific_name": "Habromys ixtlani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9609, + "scientific_name": "Habromys lepturus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9610, + "scientific_name": "Habromys lophurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136616, + "scientific_name": "Habromys schmidlyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9611, + "scientific_name": "Habromys simulatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9618, + "scientific_name": "Hadromys humei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136417, + "scientific_name": "Hadromys yunnanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9630, + "scientific_name": "Haeromys margarettae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9631, + "scientific_name": "Haeromys minahassae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 9632, + "scientific_name": "Haeromys pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 9660, + "scientific_name": "Halichoerus grypus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 74491261, + "scientific_name": "Halichoerus grypus Baltic Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Baltic Sea subpopulation", + "category": "LC" + }, + { + "taxonid": 61382004, + "scientific_name": "Halichoerus grypus ssp. grypus", + "subspecies": "grypus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61382025, + "scientific_name": "Halichoerus grypus ssp. macrorhynchus", + "subspecies": "macrorhynchus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112386684, + "scientific_name": "Halmaheramys bokimekot", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15585, + "scientific_name": "Handleyomys alfaroi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15591, + "scientific_name": "Handleyomys chapmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 547, + "scientific_name": "Handleyomys fuscatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15598, + "scientific_name": "Handleyomys intectus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15606, + "scientific_name": "Handleyomys melanotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15611, + "scientific_name": "Handleyomys rhabdops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15612, + "scientific_name": "Handleyomys rostratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15613, + "scientific_name": "Handleyomys saturatior", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9676, + "scientific_name": "Hapalemur alaotrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9672, + "scientific_name": "Hapalemur aureus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9673, + "scientific_name": "Hapalemur griseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136894, + "scientific_name": "Hapalemur griseus ssp. gilberti", + "subspecies": "gilberti", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9677, + "scientific_name": "Hapalemur griseus ssp. griseus", + "subspecies": "griseus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16971595, + "scientific_name": "Hapalemur griseus ssp. ranomafanensis", + "subspecies": "ranomafanensis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136384, + "scientific_name": "Hapalemur meridionalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 9678, + "scientific_name": "Hapalemur occidentalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 9679, + "scientific_name": "Hapalomys delacouri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 9680, + "scientific_name": "Hapalomys longicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 9690, + "scientific_name": "Haplonycteris fischeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 99711843, + "scientific_name": "Harpiocephalus harpia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13941, + "scientific_name": "Harpiola grisea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136445, + "scientific_name": "Harpiola isodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136776, + "scientific_name": "Harpyionycteris celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 9740, + "scientific_name": "Harpyionycteris whiteheadi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9759, + "scientific_name": "Heimyscus fumosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9760, + "scientific_name": "Helarctos malayanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 9828, + "scientific_name": "Heliophobius argenteocinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9830, + "scientific_name": "Heliosciurus gambianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9831, + "scientific_name": "Heliosciurus mutabilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9832, + "scientific_name": "Heliosciurus punctatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9833, + "scientific_name": "Heliosciurus rufobrachium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9834, + "scientific_name": "Heliosciurus ruwenzorii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9835, + "scientific_name": "Heliosciurus undulatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41608, + "scientific_name": "Helogale hirtula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41609, + "scientific_name": "Helogale parvula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9869, + "scientific_name": "Hemibelideus lemuroides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 62011, + "scientific_name": "Hemicentetes nigriceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40593, + "scientific_name": "Hemicentetes semispinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40607, + "scientific_name": "Hemiechinus auritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40608, + "scientific_name": "Hemiechinus collaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41689, + "scientific_name": "Hemigalus derbyanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 9919, + "scientific_name": "Hemitragus jemlahicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 9948, + "scientific_name": "Herpailurus yagouaroundi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70204120, + "scientific_name": "Herpestes auropunctatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41610, + "scientific_name": "Herpestes brachyurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41611, + "scientific_name": "Herpestes edwardsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41599, + "scientific_name": "Herpestes flavescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41612, + "scientific_name": "Herpestes fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41613, + "scientific_name": "Herpestes ichneumon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70203940, + "scientific_name": "Herpestes javanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41615, + "scientific_name": "Herpestes naso", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41605, + "scientific_name": "Herpestes ochraceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41600, + "scientific_name": "Herpestes pulverulentus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41606, + "scientific_name": "Herpestes sanguineus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41616, + "scientific_name": "Herpestes semitorquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41617, + "scientific_name": "Herpestes smithii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41618, + "scientific_name": "Herpestes urva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41619, + "scientific_name": "Herpestes vitticollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9975, + "scientific_name": "Hesperoptenus blanfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9976, + "scientific_name": "Hesperoptenus doriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9977, + "scientific_name": "Hesperoptenus gaskelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 9978, + "scientific_name": "Hesperoptenus tickelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9979, + "scientific_name": "Hesperoptenus tomesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 9987, + "scientific_name": "Heterocephalus glaber", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96802567, + "scientific_name": "Heterogeomys cherriei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42592, + "scientific_name": "Heterogeomys cherriei ssp. matagalpae", + "subspecies": "matagalpae", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96802987, + "scientific_name": "Heterogeomys dariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15550, + "scientific_name": "Heterogeomys dariensis ssp. thaeleri", + "subspecies": "thaeleri", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42591, + "scientific_name": "Heterogeomys lanius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 9997, + "scientific_name": "Heterohyrax brucei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12073, + "scientific_name": "Heteromys adspersus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47802541, + "scientific_name": "Heteromys anomalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10005, + "scientific_name": "Heteromys australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47802999, + "scientific_name": "Heteromys catopterius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47804700, + "scientific_name": "Heteromys desmarestianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10007, + "scientific_name": "Heteromys gaumeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12074, + "scientific_name": "Heteromys irroratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10009, + "scientific_name": "Heteromys nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136638, + "scientific_name": "Heteromys oasicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10010, + "scientific_name": "Heteromys oresterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12075, + "scientific_name": "Heteromys pictus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12076, + "scientific_name": "Heteromys salvini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12077, + "scientific_name": "Heteromys spectabilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136333, + "scientific_name": "Heteromys teleus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10025, + "scientific_name": "Heteropsomys insulans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 10034, + "scientific_name": "Hexolobodon phenax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 10053, + "scientific_name": "Hippocamelus antisensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10054, + "scientific_name": "Hippocamelus bisulcus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10103, + "scientific_name": "Hippopotamus amphibius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40782, + "scientific_name": "Hippopotamus lemerlei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 40783, + "scientific_name": "Hippopotamus madagascariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 10109, + "scientific_name": "Hipposideros abae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80224880, + "scientific_name": "Hipposideros alongensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10110, + "scientific_name": "Hipposideros armiger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80457009, + "scientific_name": "Hipposideros ater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80259774, + "scientific_name": "Hipposideros atrox", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10112, + "scientific_name": "Hipposideros beatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80258800, + "scientific_name": "Hipposideros bicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136566, + "scientific_name": "Hipposideros boeadii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10114, + "scientific_name": "Hipposideros breviceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 80459007, + "scientific_name": "Hipposideros caffer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10116, + "scientific_name": "Hipposideros calcaratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10117, + "scientific_name": "Hipposideros camerunensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10118, + "scientific_name": "Hipposideros cervinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10119, + "scientific_name": "Hipposideros cineraceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10121, + "scientific_name": "Hipposideros coronatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10122, + "scientific_name": "Hipposideros corynophyllus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10123, + "scientific_name": "Hipposideros coxi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10124, + "scientific_name": "Hipposideros crumeniferus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10125, + "scientific_name": "Hipposideros curtus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10126, + "scientific_name": "Hipposideros cyclops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10127, + "scientific_name": "Hipposideros demissus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10128, + "scientific_name": "Hipposideros diadema", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10129, + "scientific_name": "Hipposideros dinops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10130, + "scientific_name": "Hipposideros doriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10131, + "scientific_name": "Hipposideros durgadasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10132, + "scientific_name": "Hipposideros dyacorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10133, + "scientific_name": "Hipposideros edwardshilli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 80222798, + "scientific_name": "Hipposideros einnaythu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10134, + "scientific_name": "Hipposideros fuliginosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10135, + "scientific_name": "Hipposideros fulvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10136, + "scientific_name": "Hipposideros galeritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 180991219, + "scientific_name": "Hipposideros gentilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136478, + "scientific_name": "Hipposideros grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80222915, + "scientific_name": "Hipposideros griffini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10137, + "scientific_name": "Hipposideros halophyllus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10138, + "scientific_name": "Hipposideros hypophyllus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 10139, + "scientific_name": "Hipposideros inexpectatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136739, + "scientific_name": "Hipposideros inornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10140, + "scientific_name": "Hipposideros jonesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136819, + "scientific_name": "Hipposideros khaokhouayensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 85646546, + "scientific_name": "Hipposideros khasiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10141, + "scientific_name": "Hipposideros lamottei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 10142, + "scientific_name": "Hipposideros lankadiva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85646564, + "scientific_name": "Hipposideros larvatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10144, + "scientific_name": "Hipposideros lekaguli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10145, + "scientific_name": "Hipposideros lylei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10146, + "scientific_name": "Hipposideros macrobullatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10147, + "scientific_name": "Hipposideros madurae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10148, + "scientific_name": "Hipposideros maggietaylorae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10149, + "scientific_name": "Hipposideros marisae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10150, + "scientific_name": "Hipposideros megalotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10151, + "scientific_name": "Hipposideros muscinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10152, + "scientific_name": "Hipposideros nequam", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 80458824, + "scientific_name": "Hipposideros nicobarulae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10153, + "scientific_name": "Hipposideros obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136192, + "scientific_name": "Hipposideros orbiculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10107, + "scientific_name": "Hipposideros papua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136600, + "scientific_name": "Hipposideros pelingensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 80224655, + "scientific_name": "Hipposideros pendleburyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 180990825, + "scientific_name": "Hipposideros pomona", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10155, + "scientific_name": "Hipposideros pratti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10156, + "scientific_name": "Hipposideros pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10108, + "scientific_name": "Hipposideros ridleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136477, + "scientific_name": "Hipposideros rotalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10157, + "scientific_name": "Hipposideros ruber", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136586, + "scientific_name": "Hipposideros scutinares", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10160, + "scientific_name": "Hipposideros semoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10161, + "scientific_name": "Hipposideros sorenseni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10162, + "scientific_name": "Hipposideros speoris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10163, + "scientific_name": "Hipposideros stenotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10164, + "scientific_name": "Hipposideros sumbae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85646524, + "scientific_name": "Hipposideros tephrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 80224148, + "scientific_name": "Hipposideros turpis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10166, + "scientific_name": "Hipposideros wollastoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10167, + "scientific_name": "Hippotragus equinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10168, + "scientific_name": "Hippotragus leucophaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 10170, + "scientific_name": "Hippotragus niger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10169, + "scientific_name": "Hippotragus niger ssp. variani", + "subspecies": "variani", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 10200, + "scientific_name": "Histiotus alienus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29606, + "scientific_name": "Histiotus humboldti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136502, + "scientific_name": "Histiotus laephotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10201, + "scientific_name": "Histiotus macrotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136292, + "scientific_name": "Histiotus magellanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10202, + "scientific_name": "Histiotus montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10203, + "scientific_name": "Histiotus velatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41670, + "scientific_name": "Histriophoca fasciata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10211, + "scientific_name": "Hodomys alleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10217, + "scientific_name": "Holochilus brasiliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10218, + "scientific_name": "Holochilus chacarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10220, + "scientific_name": "Holochilus sciureus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39876, + "scientific_name": "Hoolock hoolock", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 167541870, + "scientific_name": "Hoolock hoolock ssp. hoolock", + "subspecies": "hoolock", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 167541945, + "scientific_name": "Hoolock hoolock ssp. mishmiensis", + "subspecies": "mishmiensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 118355453, + "scientific_name": "Hoolock leuconedys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 118355648, + "scientific_name": "Hoolock tianxing", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10259, + "scientific_name": "Hoplomys gymnurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40597, + "scientific_name": "Huetia leucorhina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10274, + "scientific_name": "Hyaena hyaena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 116989865, + "scientific_name": "Hybomys badius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10278, + "scientific_name": "Hybomys basilii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 116990322, + "scientific_name": "Hybomys eisentrauti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10280, + "scientific_name": "Hybomys lunaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10281, + "scientific_name": "Hybomys planifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10282, + "scientific_name": "Hybomys trivirgatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10283, + "scientific_name": "Hybomys univittatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12420, + "scientific_name": "Hydrictis maculicollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10300, + "scientific_name": "Hydrochoerus hydrochaeris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136277, + "scientific_name": "Hydrochoerus isthmius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10303, + "scientific_name": "Hydrodamalis gigas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 10310, + "scientific_name": "Hydromys chrysogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10312, + "scientific_name": "Hydromys hussoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10313, + "scientific_name": "Hydromys neobritannicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136476, + "scientific_name": "Hydromys ziegleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10329, + "scientific_name": "Hydropotes inermis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10340, + "scientific_name": "Hydrurga leptonyx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10341, + "scientific_name": "Hyemoschus aquaticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9422, + "scientific_name": "Hyladelphys kalinowskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136283, + "scientific_name": "Hylaeamys acritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29404, + "scientific_name": "Hylaeamys laticeps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 29403, + "scientific_name": "Hylaeamys megacephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15608, + "scientific_name": "Hylaeamys oniscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136529, + "scientific_name": "Hylaeamys perenensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29401, + "scientific_name": "Hylaeamys tatei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15617, + "scientific_name": "Hylaeamys yunganus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39889, + "scientific_name": "Hylobates abbotti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10543, + "scientific_name": "Hylobates agilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39879, + "scientific_name": "Hylobates albibarbis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39890, + "scientific_name": "Hylobates funereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10547, + "scientific_name": "Hylobates klossii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10548, + "scientific_name": "Hylobates lar", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39882, + "scientific_name": "Hylobates lar ssp. carpenteri", + "subspecies": "carpenteri", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39883, + "scientific_name": "Hylobates lar ssp. entelloides", + "subspecies": "entelloides", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39881, + "scientific_name": "Hylobates lar ssp. lar", + "subspecies": "lar", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39884, + "scientific_name": "Hylobates lar ssp. vestitus", + "subspecies": "vestitus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39885, + "scientific_name": "Hylobates lar ssp. yunnanensis", + "subspecies": "yunnanensis", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10550, + "scientific_name": "Hylobates moloch", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39888, + "scientific_name": "Hylobates muelleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10552, + "scientific_name": "Hylobates pileatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41769, + "scientific_name": "Hylochoerus meinertzhageni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10593, + "scientific_name": "Hylomyscus aeta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10594, + "scientific_name": "Hylomyscus alleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47968796, + "scientific_name": "Hylomyscus anselli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47968299, + "scientific_name": "Hylomyscus arcimontensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10591, + "scientific_name": "Hylomyscus baeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10595, + "scientific_name": "Hylomyscus carillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47968266, + "scientific_name": "Hylomyscus denniae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111679859, + "scientific_name": "Hylomyscus endorobae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45054, + "scientific_name": "Hylomyscus grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 111653543, + "scientific_name": "Hylomyscus heinrichorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 111679568, + "scientific_name": "Hylomyscus kerbispeterhansi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45955968, + "scientific_name": "Hylomyscus pamfi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10592, + "scientific_name": "Hylomyscus parvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47979117, + "scientific_name": "Hylomyscus stella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111679876, + "scientific_name": "Hylomyscus vulcanorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47979811, + "scientific_name": "Hylomyscus walterverheyeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136193, + "scientific_name": "Hylomys megalotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10589, + "scientific_name": "Hylomys parvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40611, + "scientific_name": "Hylomys suillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10598, + "scientific_name": "Hylonycteris underwoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10600, + "scientific_name": "Hylopetes alboniger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10602, + "scientific_name": "Hylopetes bartelsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10604, + "scientific_name": "Hylopetes nigripes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10605, + "scientific_name": "Hylopetes phayrei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136262, + "scientific_name": "Hylopetes platyurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 112296031, + "scientific_name": "Hylopetes sagitta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10606, + "scientific_name": "Hylopetes sipora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10607, + "scientific_name": "Hylopetes spadiceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10608, + "scientific_name": "Hylopetes winstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10632, + "scientific_name": "Hyomys dammermani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10633, + "scientific_name": "Hyomys goliath", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92441853, + "scientific_name": "Hyorhinomys stuempkei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10635, + "scientific_name": "Hyosciurus heinrichi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10636, + "scientific_name": "Hyosciurus ileile", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10642, + "scientific_name": "Hyperacrius fertilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10643, + "scientific_name": "Hyperacrius wynnei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10707, + "scientific_name": "Hyperoodon ampullatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10708, + "scientific_name": "Hyperoodon planifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10714, + "scientific_name": "Hypogeomys antimena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 10734, + "scientific_name": "Hypsignathus monstrosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40559, + "scientific_name": "Hypsiprymnodon moschatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17324, + "scientific_name": "Hypsugo affinis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136560, + "scientific_name": "Hypsugo alaschanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17327, + "scientific_name": "Hypsugo anthonyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17328, + "scientific_name": "Hypsugo arabicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 171619155, + "scientific_name": "Hypsugo ariel", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85200870, + "scientific_name": "Hypsugo bemainty", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17331, + "scientific_name": "Hypsugo cadornae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85201719, + "scientific_name": "Hypsugo dolichodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44854, + "scientific_name": "Hypsugo eisentrauti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17345, + "scientific_name": "Hypsugo joffrei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17346, + "scientific_name": "Hypsugo kitcheneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85202881, + "scientific_name": "Hypsugo lanzai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 17347, + "scientific_name": "Hypsugo lophurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17349, + "scientific_name": "Hypsugo macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44855, + "scientific_name": "Hypsugo musciculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17360, + "scientific_name": "Hypsugo pulveratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44856, + "scientific_name": "Hypsugo savii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44195, + "scientific_name": "Hypsugo vordermanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10748, + "scientific_name": "Hystrix africaeaustralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10749, + "scientific_name": "Hystrix brachyura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10750, + "scientific_name": "Hystrix crassispinis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10746, + "scientific_name": "Hystrix cristata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10751, + "scientific_name": "Hystrix indica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10752, + "scientific_name": "Hystrix javanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10753, + "scientific_name": "Hystrix pumila", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10754, + "scientific_name": "Hystrix sumatrae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10755, + "scientific_name": "Ia io", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41620, + "scientific_name": "Ichneumia albicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10761, + "scientific_name": "Ichthyomys hydrobates", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10762, + "scientific_name": "Ichthyomys pittieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10763, + "scientific_name": "Ichthyomys stolzmanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10764, + "scientific_name": "Ichthyomys tweedii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20487, + "scientific_name": "Ictidomys mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42564, + "scientific_name": "Ictidomys tridecemlineatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41645, + "scientific_name": "Ictonyx libycus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41646, + "scientific_name": "Ictonyx striatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10790, + "scientific_name": "Idionycteris phyllotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10794, + "scientific_name": "Idiurus macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10796, + "scientific_name": "Idiurus zenkeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40635, + "scientific_name": "Indopacetus pacificus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10826, + "scientific_name": "Indri indri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 10831, + "scientific_name": "Inia geoffrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10845, + "scientific_name": "Iomys horsfieldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10846, + "scientific_name": "Iomys sipora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10851, + "scientific_name": "Irenomys tarsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10859, + "scientific_name": "Isolobodon montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 10860, + "scientific_name": "Isolobodon portoricensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 10863, + "scientific_name": "Isoodon auratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40552, + "scientific_name": "Isoodon macrourus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40553, + "scientific_name": "Isoodon obesulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14914835, + "scientific_name": "Isothrix barbarabrownae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 90386297, + "scientific_name": "Isothrix bistriata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136751, + "scientific_name": "Isothrix negrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 90386307, + "scientific_name": "Isothrix orinoci", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10879, + "scientific_name": "Isothrix pagurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41786, + "scientific_name": "Isothrix sinnamariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10886, + "scientific_name": "Isthmomys flavidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10887, + "scientific_name": "Isthmomys pirrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10911, + "scientific_name": "Jaculus blanfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10912, + "scientific_name": "Jaculus jaculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10913, + "scientific_name": "Jaculus orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45958882, + "scientific_name": "Jaculus thaleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 23078, + "scientific_name": "Juliomys pictipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136563, + "scientific_name": "Juliomys rimofrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10946, + "scientific_name": "Juscelinomys candango", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 115555116, + "scientific_name": "Juscelinomys huanchacae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10954, + "scientific_name": "Kadarsanomys sodyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10957, + "scientific_name": "Kannabateomys amblyonyx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10966, + "scientific_name": "Kerivoula africana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10968, + "scientific_name": "Kerivoula agnella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10969, + "scientific_name": "Kerivoula argentata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 154196297, + "scientific_name": "Kerivoula crypta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10971, + "scientific_name": "Kerivoula cuprosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 154195907, + "scientific_name": "Kerivoula depressa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 154195951, + "scientific_name": "Kerivoula dongduongana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10972, + "scientific_name": "Kerivoula eriophora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10973, + "scientific_name": "Kerivoula flora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 154196065, + "scientific_name": "Kerivoula furva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 154195594, + "scientific_name": "Kerivoula hardwickii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10975, + "scientific_name": "Kerivoula intermedia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136240, + "scientific_name": "Kerivoula kachinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136572, + "scientific_name": "Kerivoula krauensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10977, + "scientific_name": "Kerivoula lanosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136428, + "scientific_name": "Kerivoula lenis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10978, + "scientific_name": "Kerivoula minuta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10979, + "scientific_name": "Kerivoula muscina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10980, + "scientific_name": "Kerivoula myrella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 10981, + "scientific_name": "Kerivoula papillosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10983, + "scientific_name": "Kerivoula pellucida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10984, + "scientific_name": "Kerivoula phalaena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10985, + "scientific_name": "Kerivoula picta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10986, + "scientific_name": "Kerivoula smithii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136817, + "scientific_name": "Kerivoula titania", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10987, + "scientific_name": "Kerivoula whiteheadi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136222, + "scientific_name": "Kerodon acrobata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10988, + "scientific_name": "Kerodon rupestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11035, + "scientific_name": "Kobus ellipsiprymnus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11040, + "scientific_name": "Kobus ellipsiprymnus ssp. defassa", + "subspecies": "defassa", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 11039, + "scientific_name": "Kobus ellipsiprymnus ssp. ellipsiprymnus", + "subspecies": "ellipsiprymnus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11036, + "scientific_name": "Kobus kob", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11041, + "scientific_name": "Kobus kob ssp. kob", + "subspecies": "kob", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 11042, + "scientific_name": "Kobus kob ssp. leucotis", + "subspecies": "leucotis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11043, + "scientific_name": "Kobus kob ssp. thomasi", + "subspecies": "thomasi", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11033, + "scientific_name": "Kobus leche", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136937, + "scientific_name": "Kobus leche ssp. anselli", + "subspecies": "anselli", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 11045, + "scientific_name": "Kobus leche ssp. kafuensis", + "subspecies": "kafuensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11044, + "scientific_name": "Kobus leche ssp. leche", + "subspecies": "leche", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 11038, + "scientific_name": "Kobus leche ssp. robertsi", + "subspecies": "robertsi", + "rank": "ssp.", + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 11046, + "scientific_name": "Kobus leche ssp. smithemani", + "subspecies": "smithemani", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 11034, + "scientific_name": "Kobus megaceros", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11037, + "scientific_name": "Kobus vardonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 11047, + "scientific_name": "Kogia breviceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11048, + "scientific_name": "Kogia sima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11050, + "scientific_name": "Komodomys rintjanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 11061, + "scientific_name": "Kunsia tomentosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11135, + "scientific_name": "Laephotis angolensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11136, + "scientific_name": "Laephotis botswanae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11137, + "scientific_name": "Laephotis namibensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11138, + "scientific_name": "Laephotis wintoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11140, + "scientific_name": "Lagenodelphis hosei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11141, + "scientific_name": "Lagenorhynchus acutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11142, + "scientific_name": "Lagenorhynchus albirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11143, + "scientific_name": "Lagenorhynchus australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11144, + "scientific_name": "Lagenorhynchus cruciger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11145, + "scientific_name": "Lagenorhynchus obliquidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11146, + "scientific_name": "Lagenorhynchus obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 134820643, + "scientific_name": "Lagenorhynchus obscurus ssp. posidonia", + "subspecies": "posidonia", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 48295808, + "scientific_name": "Lagidium ahuacaense", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11148, + "scientific_name": "Lagidium viscacia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11149, + "scientific_name": "Lagidium wolffsohni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11160, + "scientific_name": "Lagorchestes asomatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 11161, + "scientific_name": "Lagorchestes conspicillatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11162, + "scientific_name": "Lagorchestes hirsutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 11163, + "scientific_name": "Lagorchestes leporides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 136452, + "scientific_name": "Lagostomus crassus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 11170, + "scientific_name": "Lagostomus maximus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11171, + "scientific_name": "Lagostrophus fasciatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39924, + "scientific_name": "Lagothrix flavicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 160881218, + "scientific_name": "Lagothrix lagothricha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39962, + "scientific_name": "Lagothrix lagothricha ssp. cana", + "subspecies": "cana", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11175, + "scientific_name": "Lagothrix lagothricha ssp. lagothricha", + "subspecies": "lagothricha", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39926, + "scientific_name": "Lagothrix lagothricha ssp. lugens", + "subspecies": "lugens", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39927, + "scientific_name": "Lagothrix lagothricha ssp. poeppigii", + "subspecies": "poeppigii", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39963, + "scientific_name": "Lagothrix lagothricha ssp. tschudii", + "subspecies": "tschudii", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11179, + "scientific_name": "Lagurus lagurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11186, + "scientific_name": "Lama guanicoe", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11202, + "scientific_name": "Lamottemys okuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13376, + "scientific_name": "Lampronycteris brachyotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136474, + "scientific_name": "Laonastes aenigmamus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11304, + "scientific_name": "Lariscus hosei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11305, + "scientific_name": "Lariscus insignis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11306, + "scientific_name": "Lariscus niobe", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11307, + "scientific_name": "Lariscus obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 11339, + "scientific_name": "Lasionycteris noctivagans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11340, + "scientific_name": "Lasiopodomys brandtii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11341, + "scientific_name": "Lasiopodomys fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11342, + "scientific_name": "Lasiopodomys mandarinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11343, + "scientific_name": "Lasiorhinus krefftii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 40555, + "scientific_name": "Lasiorhinus latifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 29607, + "scientific_name": "Lasiurus atratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88151055, + "scientific_name": "Lasiurus blossevillii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11347, + "scientific_name": "Lasiurus borealis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11348, + "scientific_name": "Lasiurus castaneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11345, + "scientific_name": "Lasiurus cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136306, + "scientific_name": "Lasiurus degelidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 11349, + "scientific_name": "Lasiurus ebenus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11350, + "scientific_name": "Lasiurus ega", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11351, + "scientific_name": "Lasiurus egregius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136754, + "scientific_name": "Lasiurus insularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 11352, + "scientific_name": "Lasiurus intermedius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136627, + "scientific_name": "Lasiurus minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136217, + "scientific_name": "Lasiurus pfeifferi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 88151061, + "scientific_name": "Lasiurus salinae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11353, + "scientific_name": "Lasiurus seminolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136690, + "scientific_name": "Lasiurus varius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41532, + "scientific_name": "Lasiurus xanthinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11374, + "scientific_name": "Latidens salimalii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11378, + "scientific_name": "Lavia frons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11385, + "scientific_name": "Leggadina forresti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11384, + "scientific_name": "Leggadina lakedownensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11387, + "scientific_name": "Leimacomys buettneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42624, + "scientific_name": "Lemmiscus curtatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11480, + "scientific_name": "Lemmus amurensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11481, + "scientific_name": "Lemmus lemmus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136303, + "scientific_name": "Lemmus portenkoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11482, + "scientific_name": "Lemmus sibiricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136712, + "scientific_name": "Lemmus trimucronatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11487, + "scientific_name": "Lemniscomys barbarus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11488, + "scientific_name": "Lemniscomys bellieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11489, + "scientific_name": "Lemniscomys griselda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11490, + "scientific_name": "Lemniscomys hoogstraali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11491, + "scientific_name": "Lemniscomys linulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11492, + "scientific_name": "Lemniscomys macculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11486, + "scientific_name": "Lemniscomys mittendorfi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11493, + "scientific_name": "Lemniscomys rosalia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11494, + "scientific_name": "Lemniscomys roseveari", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11495, + "scientific_name": "Lemniscomys striatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41212, + "scientific_name": "Lemniscomys zebra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11496, + "scientific_name": "Lemur catta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11498, + "scientific_name": "Lenomys meyeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11499, + "scientific_name": "Lenothrix canus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11500, + "scientific_name": "Lenoxus apicalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19829, + "scientific_name": "Leontocebus cruzlimai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 160885500, + "scientific_name": "Leontocebus fuscicollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43949, + "scientific_name": "Leontocebus fuscicollis ssp. avilapiresi", + "subspecies": "avilapiresi", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43948, + "scientific_name": "Leontocebus fuscicollis ssp. fuscicollis", + "subspecies": "fuscicollis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172188235, + "scientific_name": "Leontocebus fuscicollis ssp. mura", + "subspecies": "mura", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 43951, + "scientific_name": "Leontocebus fuscicollis ssp. primitivus", + "subspecies": "primitivus", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42693, + "scientific_name": "Leontocebus fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43952, + "scientific_name": "Leontocebus illigeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 43950, + "scientific_name": "Leontocebus lagonotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19826, + "scientific_name": "Leontocebus leucogenys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39945, + "scientific_name": "Leontocebus nigricollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43947, + "scientific_name": "Leontocebus nigricollis ssp. graellsi", + "subspecies": "graellsi", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19828, + "scientific_name": "Leontocebus nigricollis ssp. hernandezi", + "subspecies": "hernandezi", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39946, + "scientific_name": "Leontocebus nigricollis ssp. nigricollis", + "subspecies": "nigricollis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43953, + "scientific_name": "Leontocebus nigrifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19824, + "scientific_name": "Leontocebus tripartitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 160939221, + "scientific_name": "Leontocebus weddelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19830, + "scientific_name": "Leontocebus weddelli ssp. crandalli", + "subspecies": "crandalli", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 43955, + "scientific_name": "Leontocebus weddelli ssp. melanoleucus", + "subspecies": "melanoleucus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43954, + "scientific_name": "Leontocebus weddelli ssp. weddelli", + "subspecies": "weddelli", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11503, + "scientific_name": "Leontopithecus caissara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40643, + "scientific_name": "Leontopithecus chrysomelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11505, + "scientific_name": "Leontopithecus chrysopygus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11506, + "scientific_name": "Leontopithecus rosalia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15309, + "scientific_name": "Leopardus colocolo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15310, + "scientific_name": "Leopardus geoffroyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15311, + "scientific_name": "Leopardus guigna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 54010476, + "scientific_name": "Leopardus guttulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15452, + "scientific_name": "Leopardus jacobita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11509, + "scientific_name": "Leopardus pardalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 54012637, + "scientific_name": "Leopardus tigrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 11511, + "scientific_name": "Leopardus wiedii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136691, + "scientific_name": "Leopoldamys ciliatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45955979, + "scientific_name": "Leopoldamys diwangkarai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11518, + "scientific_name": "Leopoldamys edwardsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136418, + "scientific_name": "Leopoldamys milleti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11519, + "scientific_name": "Leopoldamys neilli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11520, + "scientific_name": "Leopoldamys sabanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11521, + "scientific_name": "Leopoldamys siporanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136376, + "scientific_name": "Lepilemur aeeclis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136843, + "scientific_name": "Lepilemur ahmansoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136731, + "scientific_name": "Lepilemur ankaranensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136662, + "scientific_name": "Lepilemur betsileo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 210368667, + "scientific_name": "Lepilemur dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11617, + "scientific_name": "Lepilemur edwardsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136263, + "scientific_name": "Lepilemur fleuretae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136771, + "scientific_name": "Lepilemur grewcockorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16971489, + "scientific_name": "Lepilemur hollandorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136761, + "scientific_name": "Lepilemur hubbardorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136491, + "scientific_name": "Lepilemur jamesorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 11618, + "scientific_name": "Lepilemur leucopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11619, + "scientific_name": "Lepilemur microdon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136609, + "scientific_name": "Lepilemur milanoii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11620, + "scientific_name": "Lepilemur mustelinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136796, + "scientific_name": "Lepilemur otto", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136677, + "scientific_name": "Lepilemur petteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136254, + "scientific_name": "Lepilemur randrianasoloi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11621, + "scientific_name": "Lepilemur ruficaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136645, + "scientific_name": "Lepilemur sahamalaza", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16971518, + "scientific_name": "Lepilemur scottorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136707, + "scientific_name": "Lepilemur seali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 11622, + "scientific_name": "Lepilemur septentrionalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136709, + "scientific_name": "Lepilemur tymerlachsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136311, + "scientific_name": "Lepilemur wrightae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11633, + "scientific_name": "Leporillus apicalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 11634, + "scientific_name": "Leporillus conditor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 11638, + "scientific_name": "Leptailurus serval", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47983297, + "scientific_name": "Leptomys arfakensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11691, + "scientific_name": "Leptomys elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11692, + "scientific_name": "Leptomys ernstmayri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47989221, + "scientific_name": "Leptomys paulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 11693, + "scientific_name": "Leptomys signatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11696, + "scientific_name": "Leptonychotes weddellii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11699, + "scientific_name": "Leptonycteris curasoae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 11697, + "scientific_name": "Leptonycteris nivalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136659, + "scientific_name": "Leptonycteris yerbabuenae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41272, + "scientific_name": "Lepus alleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41273, + "scientific_name": "Lepus americanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41274, + "scientific_name": "Lepus arcticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41275, + "scientific_name": "Lepus brachyurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41276, + "scientific_name": "Lepus californicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11792, + "scientific_name": "Lepus callotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41277, + "scientific_name": "Lepus capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11797, + "scientific_name": "Lepus castroviejoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41278, + "scientific_name": "Lepus comus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41279, + "scientific_name": "Lepus coreanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41305, + "scientific_name": "Lepus corsicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41280, + "scientific_name": "Lepus europaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11798, + "scientific_name": "Lepus fagani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11790, + "scientific_name": "Lepus flavigularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41306, + "scientific_name": "Lepus granatensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41289, + "scientific_name": "Lepus habessinicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11793, + "scientific_name": "Lepus hainanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 11794, + "scientific_name": "Lepus insularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41281, + "scientific_name": "Lepus mandshuricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41282, + "scientific_name": "Lepus nigricollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41283, + "scientific_name": "Lepus oiostolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11795, + "scientific_name": "Lepus othus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41284, + "scientific_name": "Lepus peguensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41285, + "scientific_name": "Lepus saxatilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41286, + "scientific_name": "Lepus sinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41287, + "scientific_name": "Lepus starcki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41307, + "scientific_name": "Lepus tibetanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11791, + "scientific_name": "Lepus timidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41308, + "scientific_name": "Lepus tolai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41288, + "scientific_name": "Lepus townsendii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41879, + "scientific_name": "Lepus victoriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11796, + "scientific_name": "Lepus yarkandensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 11856, + "scientific_name": "Lestodelphys halli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41507, + "scientific_name": "Lestoros inca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11933, + "scientific_name": "Liberiictis kuhni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 88120307, + "scientific_name": "Lichonycteris degener", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88120245, + "scientific_name": "Lichonycteris obscura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11979, + "scientific_name": "Limnogale mergulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136286, + "scientific_name": "Limnomys bryophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11980, + "scientific_name": "Limnomys sibuanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12078, + "scientific_name": "Lionycteris spurrelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12119, + "scientific_name": "Lipotes vexillifer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 12125, + "scientific_name": "Lissodelphis borealis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12126, + "scientific_name": "Lissodelphis peronii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44698, + "scientific_name": "Lissonycteris angolensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12142, + "scientific_name": "Litocranius walleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12246, + "scientific_name": "Lobodon carcinophaga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12263, + "scientific_name": "Lonchophylla bokermanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 88149262, + "scientific_name": "Lonchophylla cadenai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136348, + "scientific_name": "Lonchophylla chocoana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136706, + "scientific_name": "Lonchophylla concava", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12264, + "scientific_name": "Lonchophylla dekeyseri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 88150313, + "scientific_name": "Lonchophylla fornicata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12265, + "scientific_name": "Lonchophylla handleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12266, + "scientific_name": "Lonchophylla hesperia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12267, + "scientific_name": "Lonchophylla mordax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136735, + "scientific_name": "Lonchophylla orcesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88150966, + "scientific_name": "Lonchophylla orienticollina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88149229, + "scientific_name": "Lonchophylla pattoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88150984, + "scientific_name": "Lonchophylla peracchii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12268, + "scientific_name": "Lonchophylla robusta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12269, + "scientific_name": "Lonchophylla thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12270, + "scientific_name": "Lonchorhina aurita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12271, + "scientific_name": "Lonchorhina fernandezi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40027, + "scientific_name": "Lonchorhina inusitata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12272, + "scientific_name": "Lonchorhina marinkellei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12273, + "scientific_name": "Lonchorhina orinocensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12274, + "scientific_name": "Lonchothrix emiliae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12302, + "scientific_name": "Lontra canadensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12303, + "scientific_name": "Lontra felina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12304, + "scientific_name": "Lontra longicaudis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12305, + "scientific_name": "Lontra provocax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12308, + "scientific_name": "Lophiomys imhausi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12309, + "scientific_name": "Lophocebus albigena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 95587156, + "scientific_name": "Lophocebus albigena ssp. albigena", + "subspecies": "albigena", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 92248915, + "scientific_name": "Lophocebus albigena ssp. johnstoni", + "subspecies": "johnstoni", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 92248950, + "scientific_name": "Lophocebus albigena ssp. osmani", + "subspecies": "osmani", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 92248984, + "scientific_name": "Lophocebus albigena ssp. ugandae", + "subspecies": "ugandae", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12310, + "scientific_name": "Lophocebus aterrimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136916, + "scientific_name": "Lophocebus aterrimus ssp. aterrimus", + "subspecies": "aterrimus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12311, + "scientific_name": "Lophocebus aterrimus ssp. opdenboschi", + "subspecies": "opdenboschi", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21984, + "scientific_name": "Lophostoma brasiliense", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 99783878, + "scientific_name": "Lophostoma carrikeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21986, + "scientific_name": "Lophostoma evotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88149216, + "scientific_name": "Lophostoma kalkoae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88149174, + "scientific_name": "Lophostoma occidentalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 21987, + "scientific_name": "Lophostoma schulzi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88149202, + "scientific_name": "Lophostoma silvicolum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45058, + "scientific_name": "Lophuromys brevicaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 47992974, + "scientific_name": "Lophuromys chercherensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 45057, + "scientific_name": "Lophuromys chrysopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12349, + "scientific_name": "Lophuromys cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45056, + "scientific_name": "Lophuromys dieterleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136619, + "scientific_name": "Lophuromys eisentrauti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 47990318, + "scientific_name": "Lophuromys flavopunctatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45059, + "scientific_name": "Lophuromys huttereri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47998388, + "scientific_name": "Lophuromys kilonzoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12354, + "scientific_name": "Lophuromys luteogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47997166, + "scientific_name": "Lophuromys machangui", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 47997538, + "scientific_name": "Lophuromys makundii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12350, + "scientific_name": "Lophuromys medicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12351, + "scientific_name": "Lophuromys melanonyx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 47992929, + "scientific_name": "Lophuromys menageshae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12355, + "scientific_name": "Lophuromys nudicaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47992992, + "scientific_name": "Lophuromys pseudosikapusi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12352, + "scientific_name": "Lophuromys rahmi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 45055, + "scientific_name": "Lophuromys roseveari", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47997414, + "scientific_name": "Lophuromys sabunii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12356, + "scientific_name": "Lophuromys sikapusi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47992103, + "scientific_name": "Lophuromys simensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47996434, + "scientific_name": "Lophuromys stanleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12357, + "scientific_name": "Lophuromys woosnami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12361, + "scientific_name": "Lorentzimys nouhuysi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44722, + "scientific_name": "Loris lydekkerianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 44718, + "scientific_name": "Loris lydekkerianus ssp. grandis", + "subspecies": "grandis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44719, + "scientific_name": "Loris lydekkerianus ssp. lydekkerianus", + "subspecies": "lydekkerianus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 44720, + "scientific_name": "Loris lydekkerianus ssp. malabaricus", + "subspecies": "malabaricus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 44721, + "scientific_name": "Loris lydekkerianus ssp. nordicus", + "subspecies": "nordicus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 163020804, + "scientific_name": "Loris lydekkerianus ssp. uva", + "subspecies": "uva", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12375, + "scientific_name": "Loris tardigradus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39756, + "scientific_name": "Loris tardigradus ssp. nycticeboides", + "subspecies": "nycticeboides", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 163021284, + "scientific_name": "Loris tardigradus ssp. parvus", + "subspecies": "parvus", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39757, + "scientific_name": "Loris tardigradus ssp. tardigradus", + "subspecies": "tardigradus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 181008073, + "scientific_name": "Loxodonta africana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 181007989, + "scientific_name": "Loxodonta cyclotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 2396, + "scientific_name": "Loxodontomys micropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29434, + "scientific_name": "Loxodontomys pikumche", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10219, + "scientific_name": "Lundomys molitor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12419, + "scientific_name": "Lutra lutra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12421, + "scientific_name": "Lutra sumatrana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40503, + "scientific_name": "Lutreolina crassicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 95740145, + "scientific_name": "Lutreolina massoia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12427, + "scientific_name": "Lutrogale perspicillata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 6929, + "scientific_name": "Lycalopex culpaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41586, + "scientific_name": "Lycalopex fulvipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6927, + "scientific_name": "Lycalopex griseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6928, + "scientific_name": "Lycalopex gymnocercus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6925, + "scientific_name": "Lycalopex sechurae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 6926, + "scientific_name": "Lycalopex vetulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12436, + "scientific_name": "Lycaon pictus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16991111, + "scientific_name": "Lycaon pictus North Africa subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "North Africa subpopulation", + "category": "CR" + }, + { + "taxonid": 16991108, + "scientific_name": "Lycaon pictus West Africa subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "West Africa subpopulation", + "category": "CR" + }, + { + "taxonid": 41647, + "scientific_name": "Lyncodon patagonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12518, + "scientific_name": "Lynx canadensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12519, + "scientific_name": "Lynx lynx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 68986842, + "scientific_name": "Lynx lynx ssp. balcanicus", + "subspecies": "balcanicus", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 12520, + "scientific_name": "Lynx pardinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12521, + "scientific_name": "Lynx rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12938, + "scientific_name": "Lyroderma lyra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12548, + "scientific_name": "Macaca arctoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12549, + "scientific_name": "Macaca assamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39766, + "scientific_name": "Macaca assamensis ssp. assamensis", + "subspecies": "assamensis", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39767, + "scientific_name": "Macaca assamensis ssp. pelops", + "subspecies": "pelops", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12569, + "scientific_name": "Macaca brunnescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12550, + "scientific_name": "Macaca cyclopis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12551, + "scientific_name": "Macaca fascicularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39769, + "scientific_name": "Macaca fascicularis ssp. atriceps", + "subspecies": "atriceps", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39770, + "scientific_name": "Macaca fascicularis ssp. aurea", + "subspecies": "aurea", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39785, + "scientific_name": "Macaca fascicularis ssp. condorensis", + "subspecies": "condorensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 195351957, + "scientific_name": "Macaca fascicularis ssp. fascicularis", + "subspecies": "fascicularis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39786, + "scientific_name": "Macaca fascicularis ssp. fusca", + "subspecies": "fusca", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39787, + "scientific_name": "Macaca fascicularis ssp. karimondjawae", + "subspecies": "karimondjawae", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39788, + "scientific_name": "Macaca fascicularis ssp. lasiae", + "subspecies": "lasiae", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39790, + "scientific_name": "Macaca fascicularis ssp. tua", + "subspecies": "tua", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39791, + "scientific_name": "Macaca fascicularis ssp. umbrosa", + "subspecies": "umbrosa", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12552, + "scientific_name": "Macaca fuscata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39909, + "scientific_name": "Macaca fuscata ssp. fuscata", + "subspecies": "fuscata", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12565, + "scientific_name": "Macaca fuscata ssp. yakui", + "subspecies": "yakui", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12570, + "scientific_name": "Macaca hecki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39792, + "scientific_name": "Macaca leonina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 205889816, + "scientific_name": "Macaca leucogenys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12553, + "scientific_name": "Macaca maura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12554, + "scientific_name": "Macaca mulatta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136569, + "scientific_name": "Macaca munzala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12555, + "scientific_name": "Macaca nemestrina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12556, + "scientific_name": "Macaca nigra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 12568, + "scientific_name": "Macaca nigrescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39793, + "scientific_name": "Macaca ochreata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39794, + "scientific_name": "Macaca pagensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 12558, + "scientific_name": "Macaca radiata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39797, + "scientific_name": "Macaca radiata ssp. diluta", + "subspecies": "diluta", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39796, + "scientific_name": "Macaca radiata ssp. radiata", + "subspecies": "radiata", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39795, + "scientific_name": "Macaca siberu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12559, + "scientific_name": "Macaca silenus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12560, + "scientific_name": "Macaca sinica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39799, + "scientific_name": "Macaca sinica ssp. aurifrons", + "subspecies": "aurifrons", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39800, + "scientific_name": "Macaca sinica ssp. opisthomelas", + "subspecies": "opisthomelas", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39798, + "scientific_name": "Macaca sinica ssp. sinica", + "subspecies": "sinica", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12561, + "scientific_name": "Macaca sylvanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12562, + "scientific_name": "Macaca thibetana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12563, + "scientific_name": "Macaca tonkeana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12590, + "scientific_name": "Macroderma gigas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12592, + "scientific_name": "Macrogalidia musschenbroekii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12594, + "scientific_name": "Macroglossus minimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12595, + "scientific_name": "Macroglossus sobrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10120, + "scientific_name": "Macronycteris commersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 44687, + "scientific_name": "Macronycteris gigas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44689, + "scientific_name": "Macronycteris thomensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135485, + "scientific_name": "Macronycteris vittatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12615, + "scientific_name": "Macrophyllum macrophyllum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40560, + "scientific_name": "Macropus agilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40561, + "scientific_name": "Macropus antilopinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12620, + "scientific_name": "Macropus bernardus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40562, + "scientific_name": "Macropus dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41512, + "scientific_name": "Macropus eugenii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40563, + "scientific_name": "Macropus fuliginosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41513, + "scientific_name": "Macropus giganteus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12625, + "scientific_name": "Macropus greyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 12626, + "scientific_name": "Macropus irma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12627, + "scientific_name": "Macropus parma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40564, + "scientific_name": "Macropus parryi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40565, + "scientific_name": "Macropus robustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40566, + "scientific_name": "Macropus rufogriseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40567, + "scientific_name": "Macropus rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45369877, + "scientific_name": "Macroscelides flavicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45434566, + "scientific_name": "Macroscelides micus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45369602, + "scientific_name": "Macroscelides proboscideus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12647, + "scientific_name": "Macrotarsomys bastardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12646, + "scientific_name": "Macrotarsomys ingens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136510, + "scientific_name": "Macrotarsomys petteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12650, + "scientific_name": "Macrotis lagotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12651, + "scientific_name": "Macrotis leucura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 12652, + "scientific_name": "Macrotus californicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12653, + "scientific_name": "Macrotus waterhousii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12655, + "scientific_name": "Macruromys elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12656, + "scientific_name": "Macruromys major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12669, + "scientific_name": "Madoqua guentheri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12670, + "scientific_name": "Madoqua kirkii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12667, + "scientific_name": "Madoqua piacentinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12668, + "scientific_name": "Madoqua saltiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5512, + "scientific_name": "Madromys blanfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13233, + "scientific_name": "Makalata didelphoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6983, + "scientific_name": "Makalata macrura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13236, + "scientific_name": "Makalata obscura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12702, + "scientific_name": "Malacomys cansdalei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12703, + "scientific_name": "Malacomys edwardsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12704, + "scientific_name": "Malacomys longipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12712, + "scientific_name": "Malacothrix typica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12721, + "scientific_name": "Mallomys aroaensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12722, + "scientific_name": "Mallomys gunung", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12723, + "scientific_name": "Mallomys istapantap", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12724, + "scientific_name": "Mallomys rothschildi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13122, + "scientific_name": "Mammelomys lanosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13130, + "scientific_name": "Mammelomys rattoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12753, + "scientific_name": "Mandrillus leucophaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12756, + "scientific_name": "Mandrillus leucophaeus ssp. leucophaeus", + "subspecies": "leucophaeus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12755, + "scientific_name": "Mandrillus leucophaeus ssp. poensis", + "subspecies": "poensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12754, + "scientific_name": "Mandrillus sphinx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12761, + "scientific_name": "Manis crassicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136497, + "scientific_name": "Manis culionensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 12763, + "scientific_name": "Manis javanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 12764, + "scientific_name": "Manis pentadactyla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 12795, + "scientific_name": "Margaretamys beccarii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45957342, + "scientific_name": "Margaretamys christinae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12796, + "scientific_name": "Margaretamys elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12797, + "scientific_name": "Margaretamys parvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13296, + "scientific_name": "Marmosa alstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12812, + "scientific_name": "Marmosa andersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13297, + "scientific_name": "Marmosa constantiae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40510, + "scientific_name": "Marmosa demerarae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12814, + "scientific_name": "Marmosa lepida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40504, + "scientific_name": "Marmosa mexicana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40505, + "scientific_name": "Marmosa murina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136844, + "scientific_name": "Marmosa paraguayana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136244, + "scientific_name": "Marmosa phaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136508, + "scientific_name": "Marmosa quichua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40511, + "scientific_name": "Marmosa regina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40506, + "scientific_name": "Marmosa robinsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40507, + "scientific_name": "Marmosa rubra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12816, + "scientific_name": "Marmosa tyleriana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12815, + "scientific_name": "Marmosa xerophila", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136296, + "scientific_name": "Marmosops bishopi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 89333777, + "scientific_name": "Marmosops caucae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12817, + "scientific_name": "Marmosops cracens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136803, + "scientific_name": "Marmosops creightoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12819, + "scientific_name": "Marmosops fuscatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12820, + "scientific_name": "Marmosops handleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 89333331, + "scientific_name": "Marmosops impavidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12822, + "scientific_name": "Marmosops incanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12823, + "scientific_name": "Marmosops invictus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136364, + "scientific_name": "Marmosops juninensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136830, + "scientific_name": "Marmosops neblina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40508, + "scientific_name": "Marmosops noctivagus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136842, + "scientific_name": "Marmosops ocellatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 51221900, + "scientific_name": "Marmosops pakaraimae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12824, + "scientific_name": "Marmosops parvidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136278, + "scientific_name": "Marmosops paulensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136573, + "scientific_name": "Marmosops pinheiroi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12829, + "scientific_name": "Marmota baibacina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12830, + "scientific_name": "Marmota bobak", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42455, + "scientific_name": "Marmota broweri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42456, + "scientific_name": "Marmota caligata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12831, + "scientific_name": "Marmota camtschatica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12825, + "scientific_name": "Marmota caudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42457, + "scientific_name": "Marmota flaviventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12826, + "scientific_name": "Marmota himalayana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12835, + "scientific_name": "Marmota marmota", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12827, + "scientific_name": "Marmota menzbieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42458, + "scientific_name": "Marmota monax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42459, + "scientific_name": "Marmota olympus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12832, + "scientific_name": "Marmota sibirica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12828, + "scientific_name": "Marmota vancouverensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41648, + "scientific_name": "Martes americana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41649, + "scientific_name": "Martes flavigula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29672, + "scientific_name": "Martes foina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12847, + "scientific_name": "Martes gwatkinsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12848, + "scientific_name": "Martes martes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41650, + "scientific_name": "Martes melampus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41651, + "scientific_name": "Martes pennanti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41652, + "scientific_name": "Martes zibellina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12855, + "scientific_name": "Massoutiera mzabi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18563, + "scientific_name": "Mastacomys fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 45060, + "scientific_name": "Mastomys awashensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12865, + "scientific_name": "Mastomys coucha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12866, + "scientific_name": "Mastomys erythroleucus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45061, + "scientific_name": "Mastomys huberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45092, + "scientific_name": "Mastomys kollmannspergeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12868, + "scientific_name": "Mastomys natalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12863, + "scientific_name": "Mastomys pernanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12869, + "scientific_name": "Mastomys shortridgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12891, + "scientific_name": "Maxomys alticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12892, + "scientific_name": "Maxomys baeodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12893, + "scientific_name": "Maxomys bartelsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12894, + "scientific_name": "Maxomys dollmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12895, + "scientific_name": "Maxomys hellwaldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12896, + "scientific_name": "Maxomys hylomyoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12897, + "scientific_name": "Maxomys inas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12898, + "scientific_name": "Maxomys inflatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12899, + "scientific_name": "Maxomys moi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12900, + "scientific_name": "Maxomys musschenbroekii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12901, + "scientific_name": "Maxomys ochraceiventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12902, + "scientific_name": "Maxomys pagensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12903, + "scientific_name": "Maxomys panglima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12904, + "scientific_name": "Maxomys rajah", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12905, + "scientific_name": "Maxomys surifer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45958508, + "scientific_name": "Maxomys tajuddinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12906, + "scientific_name": "Maxomys wattsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12907, + "scientific_name": "Maxomys whiteheadi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 29619, + "scientific_name": "Mazama americana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41023, + "scientific_name": "Mazama bororo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136301, + "scientific_name": "Mazama bricenii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12913, + "scientific_name": "Mazama chunyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 29620, + "scientific_name": "Mazama gouazoubira", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29621, + "scientific_name": "Mazama nana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136708, + "scientific_name": "Mazama nemorivaga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29622, + "scientific_name": "Mazama pandora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12914, + "scientific_name": "Mazama rufina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136290, + "scientific_name": "Mazama temama", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12937, + "scientific_name": "Megadendromus nikolausi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12939, + "scientific_name": "Megaderma spasma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12940, + "scientific_name": "Megadontomys cryophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12941, + "scientific_name": "Megadontomys nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12942, + "scientific_name": "Megadontomys thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12946, + "scientific_name": "Megaerops ecaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12945, + "scientific_name": "Megaerops kusnotoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12947, + "scientific_name": "Megaerops niphanae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12948, + "scientific_name": "Megaerops wetmorei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 84459322, + "scientific_name": "Megaloglossus azagnyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84462869, + "scientific_name": "Megaloglossus woermanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12980, + "scientific_name": "Megalomys desmarestii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 12981, + "scientific_name": "Megalomys luciae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 136657, + "scientific_name": "Megaoryzomys curioi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 13006, + "scientific_name": "Megaptera novaeangliae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 132835, + "scientific_name": "Megaptera novaeangliae Arabian Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Arabian Sea subpopulation", + "category": "EN" + }, + { + "taxonid": 132832, + "scientific_name": "Megaptera novaeangliae Oceania subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Oceania subpopulation", + "category": "EN" + }, + { + "taxonid": 41454, + "scientific_name": "Megasorex gigas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13046, + "scientific_name": "Melanomys caliginosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13047, + "scientific_name": "Melanomys robustulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13048, + "scientific_name": "Melanomys zunigae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 13079, + "scientific_name": "Melasmothrix naso", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136242, + "scientific_name": "Meles anakuma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136385, + "scientific_name": "Meles leucurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29673, + "scientific_name": "Meles meles", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41629, + "scientific_name": "Mellivora capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 68369199, + "scientific_name": "Melogale cucphuongensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13110, + "scientific_name": "Melogale everetti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41626, + "scientific_name": "Melogale moschata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41697, + "scientific_name": "Melogale orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41627, + "scientific_name": "Melogale personata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13114, + "scientific_name": "Melomys aerosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136431, + "scientific_name": "Melomys arcium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136604, + "scientific_name": "Melomys bannisteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13115, + "scientific_name": "Melomys bougainville", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13116, + "scientific_name": "Melomys burtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13117, + "scientific_name": "Melomys capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136715, + "scientific_name": "Melomys caurinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13118, + "scientific_name": "Melomys cervinipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136467, + "scientific_name": "Melomys cooperae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136818, + "scientific_name": "Melomys dollmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13120, + "scientific_name": "Melomys fraterculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136719, + "scientific_name": "Melomys frigicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136673, + "scientific_name": "Melomys fulgens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136482, + "scientific_name": "Melomys howi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13123, + "scientific_name": "Melomys leucogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136764, + "scientific_name": "Melomys lutillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136522, + "scientific_name": "Melomys matambuai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13128, + "scientific_name": "Melomys obiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136359, + "scientific_name": "Melomys paveli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13132, + "scientific_name": "Melomys rubicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 13133, + "scientific_name": "Melomys rufescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136320, + "scientific_name": "Melomys talaudium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13141, + "scientific_name": "Melonycteris fardoulisi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13139, + "scientific_name": "Melonycteris melanops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13140, + "scientific_name": "Melonycteris woodfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13143, + "scientific_name": "Melursus ursinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13144, + "scientific_name": "Menetes berdmorei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41634, + "scientific_name": "Mephitis macroura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41635, + "scientific_name": "Mephitis mephitis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13159, + "scientific_name": "Meriones arimalius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13160, + "scientific_name": "Meriones chengi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13161, + "scientific_name": "Meriones crassus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13162, + "scientific_name": "Meriones dahli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136460, + "scientific_name": "Meriones grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13163, + "scientific_name": "Meriones hurrianae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13164, + "scientific_name": "Meriones libycus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13165, + "scientific_name": "Meriones meridianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13166, + "scientific_name": "Meriones persicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13167, + "scientific_name": "Meriones rex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13168, + "scientific_name": "Meriones sacramenti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42666, + "scientific_name": "Meriones shawi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13169, + "scientific_name": "Meriones tamariscinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13170, + "scientific_name": "Meriones tristrami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13171, + "scientific_name": "Meriones unguiculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13172, + "scientific_name": "Meriones vinogradovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13173, + "scientific_name": "Meriones zarudnyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40612, + "scientific_name": "Mesechinus dauuricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13209, + "scientific_name": "Mesechinus hughi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13211, + "scientific_name": "Mesembriomys gouldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13212, + "scientific_name": "Mesembriomys macrurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13215, + "scientific_name": "Mesocapromys angelcabrerai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 13216, + "scientific_name": "Mesocapromys auritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13217, + "scientific_name": "Mesocapromys nanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 13218, + "scientific_name": "Mesocapromys sanfelipensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 13219, + "scientific_name": "Mesocricetus auratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13220, + "scientific_name": "Mesocricetus brandti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13221, + "scientific_name": "Mesocricetus newtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13222, + "scientific_name": "Mesocricetus raddei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13234, + "scientific_name": "Mesomys hispidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13235, + "scientific_name": "Mesomys leniceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136284, + "scientific_name": "Mesomys occultus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13237, + "scientific_name": "Mesomys stimulax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13240, + "scientific_name": "Mesophylla macconnelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13241, + "scientific_name": "Mesoplodon bidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13242, + "scientific_name": "Mesoplodon bowdoini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13243, + "scientific_name": "Mesoplodon carlhubbsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13244, + "scientific_name": "Mesoplodon densirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13245, + "scientific_name": "Mesoplodon europaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 127827012, + "scientific_name": "Mesoplodon ginkgodens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13247, + "scientific_name": "Mesoplodon grayi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13248, + "scientific_name": "Mesoplodon hectori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 127826787, + "scientific_name": "Mesoplodon hotaula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13249, + "scientific_name": "Mesoplodon layardii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13250, + "scientific_name": "Mesoplodon mirus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41759, + "scientific_name": "Mesoplodon perrini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13251, + "scientific_name": "Mesoplodon peruvianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13252, + "scientific_name": "Mesoplodon stejnegeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41760, + "scientific_name": "Mesoplodon traversii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40509, + "scientific_name": "Metachirus nudicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 570, + "scientific_name": "Micaelamys granti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 573, + "scientific_name": "Micaelamys namaquensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41580, + "scientific_name": "Mico acariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41520, + "scientific_name": "Mico argentatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39910, + "scientific_name": "Mico chrysoleucos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42691, + "scientific_name": "Mico emiliae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41521, + "scientific_name": "Mico humeralifer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39911, + "scientific_name": "Mico intermedius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39912, + "scientific_name": "Mico leucippe", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39914, + "scientific_name": "Mico marcai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41583, + "scientific_name": "Mico mauesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136294, + "scientific_name": "Mico melanurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 172269376, + "scientific_name": "Mico munduruku", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39913, + "scientific_name": "Mico nigriceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136804, + "scientific_name": "Mico rondoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42692, + "scientific_name": "Mico saterei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 210363264, + "scientific_name": "Mico schneideri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136468, + "scientific_name": "Microakodontomys transitorius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13319, + "scientific_name": "Microcavia australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13320, + "scientific_name": "Microcavia niata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13321, + "scientific_name": "Microcavia shiptoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16971390, + "scientific_name": "Microcebus arnholdi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41573, + "scientific_name": "Microcebus berthae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136537, + "scientific_name": "Microcebus bongolavensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 163314140, + "scientific_name": "Microcebus boraha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136347, + "scientific_name": "Microcebus danfossi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 163313085, + "scientific_name": "Microcebus ganzhorni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16971461, + "scientific_name": "Microcebus gerpi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136637, + "scientific_name": "Microcebus griseorufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136458, + "scientific_name": "Microcebus jollyae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 196429436, + "scientific_name": "Microcebus jonahi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 210364856, + "scientific_name": "Microcebus lehilahytsara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16971425, + "scientific_name": "Microcebus macarthurii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136206, + "scientific_name": "Microcebus mamiratra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 163313848, + "scientific_name": "Microcebus manitatra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16971364, + "scientific_name": "Microcebus margotmarshae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 46251646, + "scientific_name": "Microcebus marohita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 163314248, + "scientific_name": "Microcebus murinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13325, + "scientific_name": "Microcebus myoxinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39751, + "scientific_name": "Microcebus ravelobensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 59544947, + "scientific_name": "Microcebus rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41572, + "scientific_name": "Microcebus sambiranensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 163314538, + "scientific_name": "Microcebus simmonsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 163024481, + "scientific_name": "Microcebus tanosi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41571, + "scientific_name": "Microcebus tavaratra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13332, + "scientific_name": "Microdillus peeli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42606, + "scientific_name": "Microdipodops megacephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42607, + "scientific_name": "Microdipodops pallidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 54007828, + "scientific_name": "Microgale brevicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40586, + "scientific_name": "Microgale cowani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40587, + "scientific_name": "Microgale dobsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62012, + "scientific_name": "Microgale drouhardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13356, + "scientific_name": "Microgale dryas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 62013, + "scientific_name": "Microgale fotsifotsy", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13343, + "scientific_name": "Microgale gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 54008309, + "scientific_name": "Microgale grandidieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62014, + "scientific_name": "Microgale gymnorhyncha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62015, + "scientific_name": "Microgale jenkinsae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136628, + "scientific_name": "Microgale jobihely", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13344, + "scientific_name": "Microgale longicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62016, + "scientific_name": "Microgale majori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29462, + "scientific_name": "Microgale monticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 62017, + "scientific_name": "Microgale nasoloi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13349, + "scientific_name": "Microgale parvula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13350, + "scientific_name": "Microgale principula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41314, + "scientific_name": "Microgale pusilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62018, + "scientific_name": "Microgale soricoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62019, + "scientific_name": "Microgale taiva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41315, + "scientific_name": "Microgale talazaci", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13355, + "scientific_name": "Microgale thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48004865, + "scientific_name": "Microhydromys argenteus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48002425, + "scientific_name": "Microhydromys richardsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13373, + "scientific_name": "Micromys minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 76776686, + "scientific_name": "Micronomus norfolkensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40028, + "scientific_name": "Micronycteris brosseti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88120333, + "scientific_name": "Micronycteris buriri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88120398, + "scientific_name": "Micronycteris giovanniae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13378, + "scientific_name": "Micronycteris hirsuta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136207, + "scientific_name": "Micronycteris matses", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13379, + "scientific_name": "Micronycteris megalotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136424, + "scientific_name": "Micronycteris microtis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13380, + "scientific_name": "Micronycteris minuta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40029, + "scientific_name": "Micronycteris sanborni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13383, + "scientific_name": "Micronycteris schmidtorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88132568, + "scientific_name": "Micronycteris yatesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136538, + "scientific_name": "Microperoryctes aplini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 84783217, + "scientific_name": "Microperoryctes longicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13389, + "scientific_name": "Microperoryctes murina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13390, + "scientific_name": "Microperoryctes papuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13393, + "scientific_name": "Micropotamogale lamottei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13394, + "scientific_name": "Micropotamogale ruwenzorii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13401, + "scientific_name": "Micropteropus intermedius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13402, + "scientific_name": "Micropteropus pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13407, + "scientific_name": "Microryzomys altissimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13408, + "scientific_name": "Microryzomys minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13409, + "scientific_name": "Microsciurus alfari", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13410, + "scientific_name": "Microsciurus flaviventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13411, + "scientific_name": "Microsciurus mimulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13412, + "scientific_name": "Microsciurus santanderensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13425, + "scientific_name": "Microtus abbreviatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13426, + "scientific_name": "Microtus agrestis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136237, + "scientific_name": "Microtus anatolicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13488, + "scientific_name": "Microtus arvalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13461, + "scientific_name": "Microtus bavaricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136536, + "scientific_name": "Microtus brachycercus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13417, + "scientific_name": "Microtus breweri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13418, + "scientific_name": "Microtus cabrerae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13427, + "scientific_name": "Microtus californicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42625, + "scientific_name": "Microtus canicaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42626, + "scientific_name": "Microtus chrotorrhinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23041, + "scientific_name": "Microtus clarkei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13428, + "scientific_name": "Microtus daghestanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136535, + "scientific_name": "Microtus dogramacii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13493, + "scientific_name": "Microtus duodecimcostatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112465222, + "scientific_name": "Microtus elbeyli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13429, + "scientific_name": "Microtus evoronensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13462, + "scientific_name": "Microtus felteni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13430, + "scientific_name": "Microtus fortis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39315, + "scientific_name": "Microtus gerbei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13431, + "scientific_name": "Microtus gregalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13432, + "scientific_name": "Microtus guatemalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13463, + "scientific_name": "Microtus guentheri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13433, + "scientific_name": "Microtus hyperboreus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13438, + "scientific_name": "Microtus ilaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112465090, + "scientific_name": "Microtus irani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13437, + "scientific_name": "Microtus kermanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 23042, + "scientific_name": "Microtus kikuchii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13454, + "scientific_name": "Microtus levis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136498, + "scientific_name": "Microtus liechtensteini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13440, + "scientific_name": "Microtus limnophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42627, + "scientific_name": "Microtus longicaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13494, + "scientific_name": "Microtus lusitanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136354, + "scientific_name": "Microtus majori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13442, + "scientific_name": "Microtus maximowiczii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13443, + "scientific_name": "Microtus mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13444, + "scientific_name": "Microtus middendorffii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42629, + "scientific_name": "Microtus miurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13445, + "scientific_name": "Microtus mongolicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42630, + "scientific_name": "Microtus montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13446, + "scientific_name": "Microtus montebelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13447, + "scientific_name": "Microtus mujanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13490, + "scientific_name": "Microtus multiplex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13448, + "scientific_name": "Microtus nasarovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13449, + "scientific_name": "Microtus oaxacensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42631, + "scientific_name": "Microtus ochrogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13451, + "scientific_name": "Microtus oeconomus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42632, + "scientific_name": "Microtus oregoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136216, + "scientific_name": "Microtus paradoxus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13452, + "scientific_name": "Microtus pennsylvanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42633, + "scientific_name": "Microtus pinetorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136565, + "scientific_name": "Microtus qazvinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13453, + "scientific_name": "Microtus quasiater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42634, + "scientific_name": "Microtus richardsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13455, + "scientific_name": "Microtus sachalinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13491, + "scientific_name": "Microtus savii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13456, + "scientific_name": "Microtus schelkovnikovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136391, + "scientific_name": "Microtus schidlovskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13458, + "scientific_name": "Microtus socialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13489, + "scientific_name": "Microtus subterraneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13464, + "scientific_name": "Microtus tatricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13486, + "scientific_name": "Microtus thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13487, + "scientific_name": "Microtus townsendii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13459, + "scientific_name": "Microtus transcaspicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42635, + "scientific_name": "Microtus umbrosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42628, + "scientific_name": "Microtus xanthognathus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13522, + "scientific_name": "Millardia gleadowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13523, + "scientific_name": "Millardia kathleenae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13524, + "scientific_name": "Millardia kondana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13525, + "scientific_name": "Millardia meltada", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13556, + "scientific_name": "Mimetillus moloneyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13559, + "scientific_name": "Mimon bennettii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136561, + "scientific_name": "Mimon cozumelae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15597, + "scientific_name": "Mindomys hammondi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 81629770, + "scientific_name": "Miniopterus aelleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44859, + "scientific_name": "Miniopterus africanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 81633128, + "scientific_name": "Miniopterus ambohitrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13562, + "scientific_name": "Miniopterus australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81629758, + "scientific_name": "Miniopterus brachytragos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81633146, + "scientific_name": "Miniopterus egeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13563, + "scientific_name": "Miniopterus fraterculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13564, + "scientific_name": "Miniopterus fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 81633094, + "scientific_name": "Miniopterus gleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81633105, + "scientific_name": "Miniopterus griffithsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136752, + "scientific_name": "Miniopterus griveaudi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13565, + "scientific_name": "Miniopterus inflatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136579, + "scientific_name": "Miniopterus macrocneme", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81633156, + "scientific_name": "Miniopterus maghrebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13566, + "scientific_name": "Miniopterus magnater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81629764, + "scientific_name": "Miniopterus mahafaliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40039, + "scientific_name": "Miniopterus majori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81629742, + "scientific_name": "Miniopterus manavi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13567, + "scientific_name": "Miniopterus medius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13568, + "scientific_name": "Miniopterus minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44862, + "scientific_name": "Miniopterus natalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136310, + "scientific_name": "Miniopterus newtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 81633088, + "scientific_name": "Miniopterus pallidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136233, + "scientific_name": "Miniopterus paululus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81633135, + "scientific_name": "Miniopterus petersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13569, + "scientific_name": "Miniopterus pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13570, + "scientific_name": "Miniopterus robustior", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 81633057, + "scientific_name": "Miniopterus schreibersii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136827, + "scientific_name": "Miniopterus shortridgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136401, + "scientific_name": "Miniopterus sororculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13571, + "scientific_name": "Miniopterus tristis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41570, + "scientific_name": "Miopithecus ogouensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13572, + "scientific_name": "Miopithecus talapoin", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18655, + "scientific_name": "Mirimiri acrodonta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 13581, + "scientific_name": "Mirounga angustirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13583, + "scientific_name": "Mirounga leonina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13584, + "scientific_name": "Mirza coquereli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 48266217, + "scientific_name": "Mirzamys louiseae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48265836, + "scientific_name": "Mirzamys norahae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136684, + "scientific_name": "Mirza zaza", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13604, + "scientific_name": "Mogera etigo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41465, + "scientific_name": "Mogera imaizumii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41463, + "scientific_name": "Mogera insularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41466, + "scientific_name": "Mogera robusta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13603, + "scientific_name": "Mogera tokudae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14563, + "scientific_name": "Mogera uchidai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41467, + "scientific_name": "Mogera wogura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13638, + "scientific_name": "Molossops aequatorianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13640, + "scientific_name": "Molossops mattogrossensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13641, + "scientific_name": "Molossops neglectus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13643, + "scientific_name": "Molossops temminckii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88087329, + "scientific_name": "Molossus alvarezi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13645, + "scientific_name": "Molossus aztecus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88087507, + "scientific_name": "Molossus bondae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 102208365, + "scientific_name": "Molossus coibensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88087340, + "scientific_name": "Molossus currentium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13648, + "scientific_name": "Molossus molossus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13649, + "scientific_name": "Molossus pretiosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13644, + "scientific_name": "Molossus rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13650, + "scientific_name": "Molossus sinaloae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13653, + "scientific_name": "Monachus monachus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 120868935, + "scientific_name": "Monachus monachus Eastern Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Eastern Mediterranean subpopulation", + "category": "EN" + }, + { + "taxonid": 51343071, + "scientific_name": "Monodelphis adusta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96866849, + "scientific_name": "Monodelphis americana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40513, + "scientific_name": "Monodelphis brevicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13693, + "scientific_name": "Monodelphis dimidiata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40514, + "scientific_name": "Monodelphis domestica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13694, + "scientific_name": "Monodelphis emiliae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 97249272, + "scientific_name": "Monodelphis glirina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199833, + "scientific_name": "Monodelphis handleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13695, + "scientific_name": "Monodelphis iheringi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13696, + "scientific_name": "Monodelphis kunsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13698, + "scientific_name": "Monodelphis osgoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136516, + "scientific_name": "Monodelphis palliolata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 51342998, + "scientific_name": "Monodelphis peruviana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136392, + "scientific_name": "Monodelphis reigi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136404, + "scientific_name": "Monodelphis ronaldi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 97249078, + "scientific_name": "Monodelphis scalops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13703, + "scientific_name": "Monodelphis unistriata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 13704, + "scientific_name": "Monodon monoceros", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13719, + "scientific_name": "Monophyllus plethodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13720, + "scientific_name": "Monophyllus redmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136539, + "scientific_name": "Monticolomys koopmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 67363010, + "scientific_name": "Mops bakarii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13837, + "scientific_name": "Mops brachypterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13838, + "scientific_name": "Mops condylurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13839, + "scientific_name": "Mops congicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13840, + "scientific_name": "Mops demonstrator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40038, + "scientific_name": "Mops leucogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40024, + "scientific_name": "Mops leucostigma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13841, + "scientific_name": "Mops midas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13842, + "scientific_name": "Mops mops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13843, + "scientific_name": "Mops nanulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13844, + "scientific_name": "Mops niangarae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13845, + "scientific_name": "Mops niveiventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13846, + "scientific_name": "Mops petersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 4318, + "scientific_name": "Mops pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13847, + "scientific_name": "Mops sarasinorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13848, + "scientific_name": "Mops spurrelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13849, + "scientific_name": "Mops thersites", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13850, + "scientific_name": "Mops trevori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13877, + "scientific_name": "Mormoops blainvillei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13878, + "scientific_name": "Mormoops megalophylla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 71733227, + "scientific_name": "Mormopterus acetabulosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13881, + "scientific_name": "Mormopterus doriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 71727235, + "scientific_name": "Mormopterus francoismoutoui", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13882, + "scientific_name": "Mormopterus jugularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13883, + "scientific_name": "Mormopterus kalinowskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13884, + "scientific_name": "Mormopterus minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13887, + "scientific_name": "Mormopterus phrudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136585, + "scientific_name": "Moschiola indica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136799, + "scientific_name": "Moschiola kathygre", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41779, + "scientific_name": "Moschiola meminna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136643, + "scientific_name": "Moschus anhuiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13894, + "scientific_name": "Moschus berezovskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13895, + "scientific_name": "Moschus chrysogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136750, + "scientific_name": "Moschus cupreus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13896, + "scientific_name": "Moschus fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13901, + "scientific_name": "Moschus leucogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13897, + "scientific_name": "Moschus moschiferus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13904, + "scientific_name": "Mosia nigrescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13922, + "scientific_name": "Mungos gambianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41621, + "scientific_name": "Mungos mungo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13923, + "scientific_name": "Mungotictis decemlineata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42189, + "scientific_name": "Muntiacus atherodes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13924, + "scientific_name": "Muntiacus crinifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13927, + "scientific_name": "Muntiacus feae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13926, + "scientific_name": "Muntiacus gongshanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136831, + "scientific_name": "Muntiacus montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42190, + "scientific_name": "Muntiacus muntjak", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136293, + "scientific_name": "Muntiacus puhoatensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136479, + "scientific_name": "Muntiacus putaoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42191, + "scientific_name": "Muntiacus reevesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13928, + "scientific_name": "Muntiacus rooseveltorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44704, + "scientific_name": "Muntiacus truongsonensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136551, + "scientific_name": "Muntiacus vaginalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44703, + "scientific_name": "Muntiacus vuquangensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 1589, + "scientific_name": "Murexia habbema", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13930, + "scientific_name": "Murexia longicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1591, + "scientific_name": "Murexia melanurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1587, + "scientific_name": "Murexia naso", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13931, + "scientific_name": "Murexia rothschildi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 13935, + "scientific_name": "Muriculus imberbis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13936, + "scientific_name": "Murina aenea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 84487907, + "scientific_name": "Murina annamitica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13937, + "scientific_name": "Murina aurata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 84487939, + "scientific_name": "Murina balaensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 84488085, + "scientific_name": "Murina beelzebub", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 84488443, + "scientific_name": "Murina bicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84500863, + "scientific_name": "Murina chrysochaetes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 154196798, + "scientific_name": "Murina cyclotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84557696, + "scientific_name": "Murina eleryi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84561002, + "scientific_name": "Murina feae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84500852, + "scientific_name": "Murina fionae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13939, + "scientific_name": "Murina florium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13940, + "scientific_name": "Murina fusca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 84500832, + "scientific_name": "Murina gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84562293, + "scientific_name": "Murina harpioloides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 99712630, + "scientific_name": "Murina harrisoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136409, + "scientific_name": "Murina hilgendorfi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13942, + "scientific_name": "Murina huttoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84547975, + "scientific_name": "Murina jaintiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13943, + "scientific_name": "Murina leucogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84500876, + "scientific_name": "Murina lorelieae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 84548064, + "scientific_name": "Murina pluvialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13944, + "scientific_name": "Murina puta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84500842, + "scientific_name": "Murina recondita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13945, + "scientific_name": "Murina rozendaali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 29485, + "scientific_name": "Murina ryukyuana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 84501698, + "scientific_name": "Murina shuipuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13947, + "scientific_name": "Murina suilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13948, + "scientific_name": "Murina tenebrosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 84560827, + "scientific_name": "Murina tubinaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 84562332, + "scientific_name": "Murina ussuriensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84562267, + "scientific_name": "Murina walstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13952, + "scientific_name": "Mus baoulei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13953, + "scientific_name": "Mus booduga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13954, + "scientific_name": "Mus bufo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13955, + "scientific_name": "Mus callewaerti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13992, + "scientific_name": "Muscardinus avellanarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13956, + "scientific_name": "Mus caroli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13957, + "scientific_name": "Mus cervicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13958, + "scientific_name": "Mus cookii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13959, + "scientific_name": "Mus crociduroides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136641, + "scientific_name": "Mus cypriacus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13960, + "scientific_name": "Mus famulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13961, + "scientific_name": "Mus fernandoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136280, + "scientific_name": "Mus fragilicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13962, + "scientific_name": "Mus goundae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13963, + "scientific_name": "Mus haussa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13964, + "scientific_name": "Mus indutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13966, + "scientific_name": "Mus macedonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13967, + "scientific_name": "Mus mahomet", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13968, + "scientific_name": "Mus mattheyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13969, + "scientific_name": "Mus mayori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13970, + "scientific_name": "Mus minutoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135725, + "scientific_name": "Mus musculoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13972, + "scientific_name": "Mus musculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13973, + "scientific_name": "Mus neavei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14003, + "scientific_name": "Musonycteris harrisoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13975, + "scientific_name": "Mus oubanguii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13976, + "scientific_name": "Mus pahari", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13977, + "scientific_name": "Mus phillipsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13978, + "scientific_name": "Mus platythrix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13979, + "scientific_name": "Mus saxicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112041975, + "scientific_name": "Musseromys anacuao", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 112041990, + "scientific_name": "Musseromys beneficus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48298233, + "scientific_name": "Musseromys gulantang", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 112042008, + "scientific_name": "Musseromys inopinatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13980, + "scientific_name": "Mus setulosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13981, + "scientific_name": "Mus setzeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13982, + "scientific_name": "Mus shortridgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13983, + "scientific_name": "Mus sorella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13984, + "scientific_name": "Mus spicilegus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13985, + "scientific_name": "Mus spretus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14025, + "scientific_name": "Mustela africana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41653, + "scientific_name": "Mustela altaica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 29674, + "scientific_name": "Mustela erminea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29679, + "scientific_name": "Mustela eversmanii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14026, + "scientific_name": "Mustela felipei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41654, + "scientific_name": "Mustela frenata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41656, + "scientific_name": "Mustela itatsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41655, + "scientific_name": "Mustela kathiah", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14018, + "scientific_name": "Mustela lutreola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 14019, + "scientific_name": "Mustela lutreolina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14020, + "scientific_name": "Mustela nigripes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 70207409, + "scientific_name": "Mustela nivalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41657, + "scientific_name": "Mustela nudipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41658, + "scientific_name": "Mustela putorius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70207817, + "scientific_name": "Mustela russelliana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41659, + "scientific_name": "Mustela sibirica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14027, + "scientific_name": "Mustela strigidorsa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41660, + "scientific_name": "Mustela subpalmata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70207949, + "scientific_name": "Mustela tonkinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13986, + "scientific_name": "Mus tenellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13987, + "scientific_name": "Mus terricolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13988, + "scientific_name": "Mus triton", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13989, + "scientific_name": "Mus vulcani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41628, + "scientific_name": "Mydaus javanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14055, + "scientific_name": "Mydaus marchei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42670, + "scientific_name": "Mylomys dybowskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45199, + "scientific_name": "Mylomys rex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14085, + "scientific_name": "Myocastor coypus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16899, + "scientific_name": "Myodes andersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42616, + "scientific_name": "Myodes californicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4972, + "scientific_name": "Myodes centralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42617, + "scientific_name": "Myodes gapperi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4973, + "scientific_name": "Myodes glareolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7804, + "scientific_name": "Myodes regulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39591, + "scientific_name": "Myodes rex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4974, + "scientific_name": "Myodes rufocanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4975, + "scientific_name": "Myodes rutilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7805, + "scientific_name": "Myodes shanseius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16900, + "scientific_name": "Myodes smithii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136449, + "scientific_name": "Myoictis leucura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14086, + "scientific_name": "Myoictis melas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136839, + "scientific_name": "Myoictis wallacei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136829, + "scientific_name": "Myoictis wavicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14088, + "scientific_name": "Myomimus personatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14087, + "scientific_name": "Myomimus roachi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14089, + "scientific_name": "Myomimus setzeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45091, + "scientific_name": "Myomyscus angolensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45200, + "scientific_name": "Myomyscus brockmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45097, + "scientific_name": "Myomyscus verreauxii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14096, + "scientific_name": "Myomyscus yemeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14097, + "scientific_name": "Myonycteris brachycephala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 84463728, + "scientific_name": "Myonycteris leptodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14098, + "scientific_name": "Myonycteris relicta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84463104, + "scientific_name": "Myonycteris torquata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14100, + "scientific_name": "Myoprocta acouchy", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136663, + "scientific_name": "Myoprocta pratti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14102, + "scientific_name": "Myopterus daubentonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14103, + "scientific_name": "Myopterus whitleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14104, + "scientific_name": "Myopus schisticolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14105, + "scientific_name": "Myosciurus pumilio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41380, + "scientific_name": "Myosorex babaulti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14111, + "scientific_name": "Myosorex blarina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 45954374, + "scientific_name": "Myosorex bururiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 110660763, + "scientific_name": "Myosorex cafer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14106, + "scientific_name": "Myosorex eisentrauti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 14107, + "scientific_name": "Myosorex geata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 45954382, + "scientific_name": "Myosorex gnoskei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 45954378, + "scientific_name": "Myosorex jejei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 112042073, + "scientific_name": "Myosorex kabogoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45047, + "scientific_name": "Myosorex kihaulei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14108, + "scientific_name": "Myosorex longicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 110661822, + "scientific_name": "Myosorex meesteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14112, + "scientific_name": "Myosorex okuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14113, + "scientific_name": "Myosorex rumpii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14110, + "scientific_name": "Myosorex schalleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14114, + "scientific_name": "Myosorex sclateri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 110662121, + "scientific_name": "Myosorex tenuis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41382, + "scientific_name": "Myosorex varius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45048, + "scientific_name": "Myosorex zinki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14116, + "scientific_name": "Myospalax aspalax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14119, + "scientific_name": "Myospalax myospalax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14120, + "scientific_name": "Myospalax psilurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85735326, + "scientific_name": "Myotis adversus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14139, + "scientific_name": "Myotis aelleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14140, + "scientific_name": "Myotis albescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136680, + "scientific_name": "Myotis alcathoe", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14141, + "scientific_name": "Myotis altarium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44863, + "scientific_name": "Myotis anjouanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136279, + "scientific_name": "Myotis annamiticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85342605, + "scientific_name": "Myotis annatessae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14142, + "scientific_name": "Myotis annectans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14143, + "scientific_name": "Myotis atacamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14144, + "scientific_name": "Myotis ater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136553, + "scientific_name": "Myotis aurascens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14145, + "scientific_name": "Myotis auriculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14146, + "scientific_name": "Myotis australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14147, + "scientific_name": "Myotis austroriparius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85342628, + "scientific_name": "Myotis badius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14123, + "scientific_name": "Myotis bechsteinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14124, + "scientific_name": "Myotis blythii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14148, + "scientific_name": "Myotis bocagii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14149, + "scientific_name": "Myotis bombinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 85568289, + "scientific_name": "Myotis borneoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85566997, + "scientific_name": "Myotis brandtii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136219, + "scientific_name": "Myotis bucharensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14150, + "scientific_name": "Myotis californicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14126, + "scientific_name": "Myotis capaccinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14151, + "scientific_name": "Myotis chiloensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14152, + "scientific_name": "Myotis chinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14153, + "scientific_name": "Myotis ciliolabrum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14154, + "scientific_name": "Myotis cobanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29420, + "scientific_name": "Myotis csorbai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14127, + "scientific_name": "Myotis dasycneme", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 85342710, + "scientific_name": "Myotis daubentonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136250, + "scientific_name": "Myotis davidii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136678, + "scientific_name": "Myotis dieteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88151417, + "scientific_name": "Myotis diminutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136204, + "scientific_name": "Myotis dinellii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14155, + "scientific_name": "Myotis dominicensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14156, + "scientific_name": "Myotis elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14129, + "scientific_name": "Myotis emarginatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85733126, + "scientific_name": "Myotis escalerai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14157, + "scientific_name": "Myotis evotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85568302, + "scientific_name": "Myotis federatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85735587, + "scientific_name": "Myotis fimbriatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14159, + "scientific_name": "Myotis findleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 85736120, + "scientific_name": "Myotis formosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14161, + "scientific_name": "Myotis fortidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85566806, + "scientific_name": "Myotis frater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40035, + "scientific_name": "Myotis gomantongensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14163, + "scientific_name": "Myotis goudoti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14132, + "scientific_name": "Myotis grisescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14164, + "scientific_name": "Myotis hasseltii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14165, + "scientific_name": "Myotis hermani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14166, + "scientific_name": "Myotis horsfieldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14168, + "scientific_name": "Myotis ikonnikovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85342688, + "scientific_name": "Myotis indochinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14169, + "scientific_name": "Myotis insularum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88151563, + "scientific_name": "Myotis izecksohni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14170, + "scientific_name": "Myotis keaysi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14171, + "scientific_name": "Myotis keenii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136429, + "scientific_name": "Myotis laniger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88151601, + "scientific_name": "Myotis lavali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14172, + "scientific_name": "Myotis leibii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14174, + "scientific_name": "Myotis levis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85566977, + "scientific_name": "Myotis longicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14175, + "scientific_name": "Myotis longipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14176, + "scientific_name": "Myotis lucifugus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14177, + "scientific_name": "Myotis macrodactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136697, + "scientific_name": "Myotis macropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14178, + "scientific_name": "Myotis macrotarsus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 76435251, + "scientific_name": "Myotis martiniquensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136784, + "scientific_name": "Myotis melanorhinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136770, + "scientific_name": "Myotis moluccarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85567622, + "scientific_name": "Myotis montivagus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14182, + "scientific_name": "Myotis morrisi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85537578, + "scientific_name": "Myotis muricola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14133, + "scientific_name": "Myotis myotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14134, + "scientific_name": "Myotis mystacinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85733032, + "scientific_name": "Myotis nattereri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14184, + "scientific_name": "Myotis nesopolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14185, + "scientific_name": "Myotis nigricans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136495, + "scientific_name": "Myotis nipalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 76435059, + "scientific_name": "Myotis nyctor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136650, + "scientific_name": "Myotis occultus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14186, + "scientific_name": "Myotis oreias", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14187, + "scientific_name": "Myotis oxyotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14189, + "scientific_name": "Myotis peninsularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14190, + "scientific_name": "Myotis pequinius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85342726, + "scientific_name": "Myotis petax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85568321, + "scientific_name": "Myotis peytoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14193, + "scientific_name": "Myotis pilosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14191, + "scientific_name": "Myotis planiceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14192, + "scientific_name": "Myotis pruinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44864, + "scientific_name": "Myotis punicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14194, + "scientific_name": "Myotis ridleyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14195, + "scientific_name": "Myotis riparius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14196, + "scientific_name": "Myotis rosseti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14197, + "scientific_name": "Myotis ruber", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 85735909, + "scientific_name": "Myotis rufoniger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136411, + "scientific_name": "Myotis rufopictus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14198, + "scientific_name": "Myotis schaubi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14199, + "scientific_name": "Myotis scotti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 85342651, + "scientific_name": "Myotis secundus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14201, + "scientific_name": "Myotis septentrionalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 85567062, + "scientific_name": "Myotis sibiricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14202, + "scientific_name": "Myotis sicarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14203, + "scientific_name": "Myotis siligorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14204, + "scientific_name": "Myotis simus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14136, + "scientific_name": "Myotis sodalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 85342662, + "scientific_name": "Myotis soror", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14205, + "scientific_name": "Myotis stalkeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14206, + "scientific_name": "Myotis thysanodes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14207, + "scientific_name": "Myotis tricolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14208, + "scientific_name": "Myotis velifer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14209, + "scientific_name": "Myotis vivesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14210, + "scientific_name": "Myotis volans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85736011, + "scientific_name": "Myotis weberi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14211, + "scientific_name": "Myotis welwitschii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29484, + "scientific_name": "Myotis yanbarensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 14213, + "scientific_name": "Myotis yumanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14222, + "scientific_name": "Myrmecobius fasciatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14224, + "scientific_name": "Myrmecophaga tridactyla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14256, + "scientific_name": "Mysateles melanurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14258, + "scientific_name": "Mysateles prehensilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14260, + "scientific_name": "Mystacina robusta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 14261, + "scientific_name": "Mystacina tuberculata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14262, + "scientific_name": "Mystromys albicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14288, + "scientific_name": "Myzopoda aurita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136465, + "scientific_name": "Myzopoda schliemanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14294, + "scientific_name": "Naemorhedus baileyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14295, + "scientific_name": "Naemorhedus caudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14296, + "scientific_name": "Naemorhedus goral", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41589, + "scientific_name": "Nandinia binotata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8968, + "scientific_name": "Nanger dama", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 8971, + "scientific_name": "Nanger granti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 51187222, + "scientific_name": "Nanger granti ssp. granti", + "subspecies": "granti", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 51187228, + "scientific_name": "Nanger granti ssp. notata", + "subspecies": "notata", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 51187225, + "scientific_name": "Nanger granti ssp. petersii", + "subspecies": "petersii", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 63541, + "scientific_name": "Nanger soemmerringii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14325, + "scientific_name": "Nannosciurus melanotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14326, + "scientific_name": "Nannospalax ehrenbergi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14328, + "scientific_name": "Nannospalax leucodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14327, + "scientific_name": "Nannospalax xanthodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14333, + "scientific_name": "Nanonycteris veldkampii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42612, + "scientific_name": "Napaeozapus insignis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14352, + "scientific_name": "Nasalis larvatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41683, + "scientific_name": "Nasua narica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41684, + "scientific_name": "Nasua nasua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 72261777, + "scientific_name": "Nasuella meridensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 72261737, + "scientific_name": "Nasuella olivacea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136448, + "scientific_name": "Natalus espiritosantensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136824, + "scientific_name": "Natalus jamaicensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136548, + "scientific_name": "Natalus major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 123984355, + "scientific_name": "Natalus mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136777, + "scientific_name": "Natalus primus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14360, + "scientific_name": "Natalus stramineus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14362, + "scientific_name": "Natalus tumidirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136727, + "scientific_name": "Neacomys dubosti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14386, + "scientific_name": "Neacomys guianae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136570, + "scientific_name": "Neacomys minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136655, + "scientific_name": "Neacomys musseri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136352, + "scientific_name": "Neacomys paracou", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14387, + "scientific_name": "Neacomys pictus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14388, + "scientific_name": "Neacomys spinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42649, + "scientific_name": "Neacomys tenuipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1087, + "scientific_name": "Neamblysomus gunningi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 1089, + "scientific_name": "Neamblysomus julianae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 62010, + "scientific_name": "Neamblysomus julianae Bronberg Ridge subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Bronberg Ridge subpopulation", + "category": "CR" + }, + { + "taxonid": 2857, + "scientific_name": "Necromys amoenus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136665, + "scientific_name": "Necromys benefactus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2858, + "scientific_name": "Necromys lactens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2859, + "scientific_name": "Necromys lasiurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136481, + "scientific_name": "Necromys lenguarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2860, + "scientific_name": "Necromys obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2861, + "scientific_name": "Necromys punctulatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 2862, + "scientific_name": "Necromys temchuki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 765, + "scientific_name": "Necromys urichi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41455, + "scientific_name": "Nectogale elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136756, + "scientific_name": "Nectomys apicalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 115555721, + "scientific_name": "Nectomys grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14473, + "scientific_name": "Nectomys palmipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14474, + "scientific_name": "Nectomys rattus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14475, + "scientific_name": "Nectomys squamipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14486, + "scientific_name": "Nelsonia goldmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14487, + "scientific_name": "Nelsonia neotomodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136554, + "scientific_name": "Neodon forresti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13435, + "scientific_name": "Neodon irene", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13436, + "scientific_name": "Neodon juldaschi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45959213, + "scientific_name": "Neodon linzhiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13457, + "scientific_name": "Neodon sikimensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136603, + "scientific_name": "Neofelis diardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136945, + "scientific_name": "Neofelis diardi ssp. borneensis", + "subspecies": "borneensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136866, + "scientific_name": "Neofelis diardi ssp. diardi", + "subspecies": "diardi", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14519, + "scientific_name": "Neofelis nebulosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14520, + "scientific_name": "Neofiber alleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10588, + "scientific_name": "Neohylomys hainanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 727, + "scientific_name": "Neomicroxus bogotensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 741, + "scientific_name": "Neomicroxus latebricola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13654, + "scientific_name": "Neomonachus schauinslandi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13655, + "scientific_name": "Neomonachus tropicalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 29657, + "scientific_name": "Neomys anomalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29658, + "scientific_name": "Neomys fodiens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29659, + "scientific_name": "Neomys teres", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13382, + "scientific_name": "Neonycteris pusilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14541, + "scientific_name": "Neophascogale lorentzii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14549, + "scientific_name": "Neophoca cinerea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41754, + "scientific_name": "Neophocaena asiaeorientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 43205774, + "scientific_name": "Neophocaena asiaeorientalis ssp. asiaeorientalis", + "subspecies": "asiaeorientalis", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 198920, + "scientific_name": "Neophocaena phocaenoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14560, + "scientific_name": "Neopteryx frosti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44917, + "scientific_name": "Neoromicia brunnea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 44918, + "scientific_name": "Neoromicia capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44919, + "scientific_name": "Neoromicia flavescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44920, + "scientific_name": "Neoromicia guineensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44921, + "scientific_name": "Neoromicia helios", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 95558146, + "scientific_name": "Neoromicia isabella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136820, + "scientific_name": "Neoromicia malagasyensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40033, + "scientific_name": "Neoromicia matroka", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44922, + "scientific_name": "Neoromicia melckorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44923, + "scientific_name": "Neoromicia nana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44924, + "scientific_name": "Neoromicia rendalli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 67359364, + "scientific_name": "Neoromicia robertsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 67359375, + "scientific_name": "Neoromicia roseveari", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44925, + "scientific_name": "Neoromicia somalica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44926, + "scientific_name": "Neoromicia tenuipinnis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44927, + "scientific_name": "Neoromicia zuluensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42568, + "scientific_name": "Neotamias alpinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42569, + "scientific_name": "Neotamias amoenus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21356, + "scientific_name": "Neotamias bulleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21364, + "scientific_name": "Neotamias canipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42570, + "scientific_name": "Neotamias cinereicollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42571, + "scientific_name": "Neotamias dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21357, + "scientific_name": "Neotamias durangae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21358, + "scientific_name": "Neotamias merriami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42572, + "scientific_name": "Neotamias minimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21359, + "scientific_name": "Neotamias obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42573, + "scientific_name": "Neotamias ochrogenys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21355, + "scientific_name": "Neotamias palmeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42574, + "scientific_name": "Neotamias panamintinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42575, + "scientific_name": "Neotamias quadrimaculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42576, + "scientific_name": "Neotamias quadrivittatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42577, + "scientific_name": "Neotamias ruficaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42578, + "scientific_name": "Neotamias rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42579, + "scientific_name": "Neotamias senex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42580, + "scientific_name": "Neotamias siskiyou", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42581, + "scientific_name": "Neotamias sonomae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42582, + "scientific_name": "Neotamias speciosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42584, + "scientific_name": "Neotamias townsendii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42585, + "scientific_name": "Neotamias umbrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10590, + "scientific_name": "Neotetracus sinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14582, + "scientific_name": "Neotoma albigula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14583, + "scientific_name": "Neotoma angustapalata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 117189944, + "scientific_name": "Neotoma bryanti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14576, + "scientific_name": "Neotoma bryanti ssp. anthonyi", + "subspecies": "anthonyi", + "rank": "ssp.", + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14577, + "scientific_name": "Neotoma bryanti ssp. bunkeri", + "subspecies": "bunkeri", + "rank": "ssp.", + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14580, + "scientific_name": "Neotoma bryanti ssp. martinensis", + "subspecies": "martinensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14585, + "scientific_name": "Neotoma chrysomelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42673, + "scientific_name": "Neotoma cinerea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14586, + "scientific_name": "Neotoma devia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42650, + "scientific_name": "Neotoma floridana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14587, + "scientific_name": "Neotoma fuscipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14588, + "scientific_name": "Neotoma goldmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 116989038, + "scientific_name": "Neotoma insularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 116988741, + "scientific_name": "Neotoma lepida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136793, + "scientific_name": "Neotoma leucodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14597, + "scientific_name": "Neotoma macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14581, + "scientific_name": "Neotoma magister", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14590, + "scientific_name": "Neotoma mexicana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14591, + "scientific_name": "Neotoma micropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14592, + "scientific_name": "Neotoma nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 14593, + "scientific_name": "Neotoma palatina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14594, + "scientific_name": "Neotoma phenax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42651, + "scientific_name": "Neotoma stephensi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14600, + "scientific_name": "Neotomodon alstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14601, + "scientific_name": "Neotomys ebriosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14603, + "scientific_name": "Neotragus batesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14602, + "scientific_name": "Neotragus pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40784, + "scientific_name": "Neovison macrodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 41661, + "scientific_name": "Neovison vison", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15584, + "scientific_name": "Nephelomys albigularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15586, + "scientific_name": "Nephelomys auriventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136833, + "scientific_name": "Nephelomys caracolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15593, + "scientific_name": "Nephelomys devius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15600, + "scientific_name": "Nephelomys keaysi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15604, + "scientific_name": "Nephelomys levipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136328, + "scientific_name": "Nephelomys meridensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14660, + "scientific_name": "Nesokia bunnii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14661, + "scientific_name": "Nesokia indica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14662, + "scientific_name": "Nesolagus netscheri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41209, + "scientific_name": "Nesolagus timminsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136475, + "scientific_name": "Nesomys audeberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136330, + "scientific_name": "Nesomys lambertoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14671, + "scientific_name": "Nesomys rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41313, + "scientific_name": "Nesophontes edithae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14672, + "scientific_name": "Nesophontes hypomicrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 136381, + "scientific_name": "Nesophontes major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14673, + "scientific_name": "Nesophontes micrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14674, + "scientific_name": "Nesophontes paramicrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14676, + "scientific_name": "Nesophontes zamicrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 20757, + "scientific_name": "Nesoromys ceramicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14706, + "scientific_name": "Nesoryzomys darwini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14707, + "scientific_name": "Nesoryzomys fernandinae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14708, + "scientific_name": "Nesoryzomys indefessus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 40765, + "scientific_name": "Nesoryzomys narboroughi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14709, + "scientific_name": "Nesoryzomys swarthi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14604, + "scientific_name": "Nesotragus moschatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41468, + "scientific_name": "Neurotrichus gibbsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136236, + "scientific_name": "Neusticomys ferreirai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14740, + "scientific_name": "Neusticomys monticolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14741, + "scientific_name": "Neusticomys mussoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14742, + "scientific_name": "Neusticomys oyapocki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14743, + "scientific_name": "Neusticomys peruviensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14744, + "scientific_name": "Neusticomys venezuelae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 9917, + "scientific_name": "Nilgiritragus hylocrius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40766, + "scientific_name": "Nilopegamys plumbeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 40529, + "scientific_name": "Ningaui ridei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40530, + "scientific_name": "Ningaui timealeyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40531, + "scientific_name": "Ningaui yvonneae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14812, + "scientific_name": "Niviventer andersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14813, + "scientific_name": "Niviventer brahma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136512, + "scientific_name": "Niviventer cameroni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14814, + "scientific_name": "Niviventer confucianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14815, + "scientific_name": "Niviventer coninga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14816, + "scientific_name": "Niviventer cremoriventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14817, + "scientific_name": "Niviventer culturatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14818, + "scientific_name": "Niviventer eha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14819, + "scientific_name": "Niviventer excelsior", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136747, + "scientific_name": "Niviventer fraternus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14820, + "scientific_name": "Niviventer fulvescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14821, + "scientific_name": "Niviventer hinpoon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14822, + "scientific_name": "Niviventer langbianis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14823, + "scientific_name": "Niviventer lepturus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14824, + "scientific_name": "Niviventer niviventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14825, + "scientific_name": "Niviventer rapit", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14826, + "scientific_name": "Niviventer tenaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14829, + "scientific_name": "Noctilio albiventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14830, + "scientific_name": "Noctilio leporinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 120659170, + "scientific_name": "Nomascus annamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39775, + "scientific_name": "Nomascus concolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 160304839, + "scientific_name": "Nomascus concolor ssp. concolor", + "subspecies": "concolor", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39894, + "scientific_name": "Nomascus concolor ssp. lu", + "subspecies": "lu", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 128073282, + "scientific_name": "Nomascus gabriellae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41643, + "scientific_name": "Nomascus hainanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39895, + "scientific_name": "Nomascus leucogenys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41642, + "scientific_name": "Nomascus nasutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39896, + "scientific_name": "Nomascus siki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136692, + "scientific_name": "Noronhomys vespuccii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14854, + "scientific_name": "Notiomys edwardsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136666, + "scientific_name": "Notiosorex cockrumi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41456, + "scientific_name": "Notiosorex crawfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136273, + "scientific_name": "Notiosorex evotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136688, + "scientific_name": "Notiosorex villai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20477, + "scientific_name": "Notocitellus adocetus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20479, + "scientific_name": "Notocitellus annulatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14867, + "scientific_name": "Notomys alexis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14861, + "scientific_name": "Notomys amplus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14862, + "scientific_name": "Notomys aquilo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14868, + "scientific_name": "Notomys cervinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14863, + "scientific_name": "Notomys fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14864, + "scientific_name": "Notomys longicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14865, + "scientific_name": "Notomys macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14869, + "scientific_name": "Notomys mitchellii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14866, + "scientific_name": "Notomys mordax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 45958541, + "scientific_name": "Notomys robustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 14876, + "scientific_name": "Notopteris macdonaldi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136519, + "scientific_name": "Notopteris neocaledonica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14878, + "scientific_name": "Notoryctes caurinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14879, + "scientific_name": "Notoryctes typhlops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14921, + "scientific_name": "Nyctalus aviator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14922, + "scientific_name": "Nyctalus azoreum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136765, + "scientific_name": "Nyctalus furvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14918, + "scientific_name": "Nyctalus lasiopterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14919, + "scientific_name": "Nyctalus leisleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14923, + "scientific_name": "Nyctalus montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14920, + "scientific_name": "Nyctalus noctula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136828, + "scientific_name": "Nyctalus plancyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14925, + "scientific_name": "Nyctereutes procyonoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14926, + "scientific_name": "Nycteris arge", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14927, + "scientific_name": "Nycteris aurita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14928, + "scientific_name": "Nycteris gambiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14929, + "scientific_name": "Nycteris grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14930, + "scientific_name": "Nycteris hispida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14931, + "scientific_name": "Nycteris intermedia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14932, + "scientific_name": "Nycteris javanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14933, + "scientific_name": "Nycteris macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40022, + "scientific_name": "Nycteris madagascariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14934, + "scientific_name": "Nycteris major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14935, + "scientific_name": "Nycteris nana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44695, + "scientific_name": "Nycteris parisii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14936, + "scientific_name": "Nycteris thebaica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14937, + "scientific_name": "Nycteris tragata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 44696, + "scientific_name": "Nycteris vinsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14939, + "scientific_name": "Nycteris woodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 163015864, + "scientific_name": "Nycticebus bancanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39758, + "scientific_name": "Nycticebus bengalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 163015906, + "scientific_name": "Nycticebus borneanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 163017685, + "scientific_name": "Nycticebus coucang", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 163029192, + "scientific_name": "Nycticebus coucang ssp. insularis", + "subspecies": "insularis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 163019804, + "scientific_name": "Nycticebus hilleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39761, + "scientific_name": "Nycticebus javanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 163015583, + "scientific_name": "Nycticebus kayan", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 163013860, + "scientific_name": "Nycticebus menagensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 205915373, + "scientific_name": "Nycticebus menagensis ssp. insularis", + "subspecies": "insularis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 205915351, + "scientific_name": "Nycticebus menagensis ssp. natunae", + "subspecies": "natunae", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14941, + "scientific_name": "Nycticebus pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41533, + "scientific_name": "Nycticeinops schlieffeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136562, + "scientific_name": "Nycticeius aenobarbus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136386, + "scientific_name": "Nycticeius cubanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14944, + "scientific_name": "Nycticeius humeralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14358, + "scientific_name": "Nyctiellus lepidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14954, + "scientific_name": "Nyctimene aello", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14962, + "scientific_name": "Nyctimene albiventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14963, + "scientific_name": "Nyctimene cephalotes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14964, + "scientific_name": "Nyctimene certans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14955, + "scientific_name": "Nyctimene cyclotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14956, + "scientific_name": "Nyctimene draconilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136441, + "scientific_name": "Nyctimene keasti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14965, + "scientific_name": "Nyctimene major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14958, + "scientific_name": "Nyctimene malaitensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14959, + "scientific_name": "Nyctimene masalai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14960, + "scientific_name": "Nyctimene minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14953, + "scientific_name": "Nyctimene rabori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 14966, + "scientific_name": "Nyctimene robinsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14961, + "scientific_name": "Nyctimene sanctacrucis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 14967, + "scientific_name": "Nyctimene vizcaccia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14993, + "scientific_name": "Nyctinomops aurispinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14994, + "scientific_name": "Nyctinomops femorosaccus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14995, + "scientific_name": "Nyctinomops laticaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14996, + "scientific_name": "Nyctinomops macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14999, + "scientific_name": "Nyctomys sumichrasti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15000, + "scientific_name": "Nyctophilus arnhemensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85289369, + "scientific_name": "Nyctophilus bifax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85289516, + "scientific_name": "Nyctophilus corbeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 85289826, + "scientific_name": "Nyctophilus daedalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15003, + "scientific_name": "Nyctophilus geoffroyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15004, + "scientific_name": "Nyctophilus gouldi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15005, + "scientific_name": "Nyctophilus heran", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15006, + "scientific_name": "Nyctophilus howensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 85289614, + "scientific_name": "Nyctophilus major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15007, + "scientific_name": "Nyctophilus microdon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15008, + "scientific_name": "Nyctophilus microtis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136807, + "scientific_name": "Nyctophilus nebulosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 15009, + "scientific_name": "Nyctophilus sherrini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 85289876, + "scientific_name": "Nyctophilus shirleyae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15011, + "scientific_name": "Nyctophilus walkeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41255, + "scientific_name": "Ochotona alpina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41986, + "scientific_name": "Ochotona argentata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41256, + "scientific_name": "Ochotona cansus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41257, + "scientific_name": "Ochotona collaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87948071, + "scientific_name": "Ochotona coreana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41258, + "scientific_name": "Ochotona curzoniae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41259, + "scientific_name": "Ochotona dauurica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41260, + "scientific_name": "Ochotona erythrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15048, + "scientific_name": "Ochotona forresti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41261, + "scientific_name": "Ochotona gloveri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40800, + "scientific_name": "Ochotona hoffmanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 87948061, + "scientific_name": "Ochotona hyperborea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15050, + "scientific_name": "Ochotona iliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15046, + "scientific_name": "Ochotona koslowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41264, + "scientific_name": "Ochotona ladacensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41265, + "scientific_name": "Ochotona macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87948094, + "scientific_name": "Ochotona mantchurica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15051, + "scientific_name": "Ochotona nubrica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 99892252, + "scientific_name": "Ochotona opaca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 99890206, + "scientific_name": "Ochotona pallasii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41267, + "scientific_name": "Ochotona princeps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15052, + "scientific_name": "Ochotona pusilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41268, + "scientific_name": "Ochotona roylei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41269, + "scientific_name": "Ochotona rufescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41270, + "scientific_name": "Ochotona rutila", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87948175, + "scientific_name": "Ochotona syrinx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41271, + "scientific_name": "Ochotona thibetana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15053, + "scientific_name": "Ochotona thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41503, + "scientific_name": "Ochotona turuchanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42674, + "scientific_name": "Ochrotomys nuttalli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15087, + "scientific_name": "Octodon bridgesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15088, + "scientific_name": "Octodon degus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15089, + "scientific_name": "Octodon lunatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15090, + "scientific_name": "Octodon pacificus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 15091, + "scientific_name": "Octodontomys gliroides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15093, + "scientific_name": "Octomys mimax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15106, + "scientific_name": "Odobenus rosmarus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 61963499, + "scientific_name": "Odobenus rosmarus ssp. divergens", + "subspecies": "divergens", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15108, + "scientific_name": "Odobenus rosmarus ssp. rosmarus", + "subspecies": "rosmarus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42393, + "scientific_name": "Odocoileus hemionus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42394, + "scientific_name": "Odocoileus virginianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136624, + "scientific_name": "Oecomys auyantepui", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15131, + "scientific_name": "Oecomys bicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136358, + "scientific_name": "Oecomys catherinae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15132, + "scientific_name": "Oecomys cleberi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 47766841, + "scientific_name": "Oecomys concolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15134, + "scientific_name": "Oecomys flavicans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15135, + "scientific_name": "Oecomys mamorae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15136, + "scientific_name": "Oecomys paricola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15137, + "scientific_name": "Oecomys phaeotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15138, + "scientific_name": "Oecomys rex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15139, + "scientific_name": "Oecomys roberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15140, + "scientific_name": "Oecomys rutilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15141, + "scientific_name": "Oecomys speciosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15142, + "scientific_name": "Oecomys superans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15143, + "scientific_name": "Oecomys trinitatis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15164, + "scientific_name": "Oenomys hypoxanthus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15165, + "scientific_name": "Oenomys ornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15188, + "scientific_name": "Okapia johnstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15189, + "scientific_name": "Olallamys albicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15190, + "scientific_name": "Olallamys edax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15241, + "scientific_name": "Oligoryzomys andinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15242, + "scientific_name": "Oligoryzomys arenalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136530, + "scientific_name": "Oligoryzomys brendae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15243, + "scientific_name": "Oligoryzomys chacoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15244, + "scientific_name": "Oligoryzomys delticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15245, + "scientific_name": "Oligoryzomys destructor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15246, + "scientific_name": "Oligoryzomys eliurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15247, + "scientific_name": "Oligoryzomys flavescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136728, + "scientific_name": "Oligoryzomys fornesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15248, + "scientific_name": "Oligoryzomys fulvescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15249, + "scientific_name": "Oligoryzomys griseolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15250, + "scientific_name": "Oligoryzomys longicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15251, + "scientific_name": "Oligoryzomys magellanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15252, + "scientific_name": "Oligoryzomys microtis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136336, + "scientific_name": "Oligoryzomys moojeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15253, + "scientific_name": "Oligoryzomys nigripes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136425, + "scientific_name": "Oligoryzomys rupestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29418, + "scientific_name": "Oligoryzomys stramineus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15254, + "scientific_name": "Oligoryzomys vegetus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15255, + "scientific_name": "Oligoryzomys victus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 15269, + "scientific_name": "Ommatophoca rossii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15324, + "scientific_name": "Ondatra zibethicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15330, + "scientific_name": "Onychogalea fraenata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15331, + "scientific_name": "Onychogalea lunata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 40568, + "scientific_name": "Onychogalea unguifera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15337, + "scientific_name": "Onychomys arenicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15338, + "scientific_name": "Onychomys leucogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15339, + "scientific_name": "Onychomys torridus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15419, + "scientific_name": "Orcaella brevirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44556, + "scientific_name": "Orcaella brevirostris Ayeyarwady River subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Ayeyarwady River subpopulation", + "category": "CR" + }, + { + "taxonid": 123095978, + "scientific_name": "Orcaella brevirostris Iloilo-Guimaras Subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Iloilo-Guimaras Subpopulation", + "category": "CR" + }, + { + "taxonid": 39428, + "scientific_name": "Orcaella brevirostris Mahakam River subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mahakam River subpopulation", + "category": "CR" + }, + { + "taxonid": 44187, + "scientific_name": "Orcaella brevirostris Malampaya Sound subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Malampaya Sound subpopulation", + "category": "CR" + }, + { + "taxonid": 44555, + "scientific_name": "Orcaella brevirostris Mekong River subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mekong River subpopulation", + "category": "CR" + }, + { + "taxonid": 44557, + "scientific_name": "Orcaella brevirostris Songkhla Lake subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Songkhla Lake subpopulation", + "category": "CR" + }, + { + "taxonid": 136315, + "scientific_name": "Orcaella heinsohni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15421, + "scientific_name": "Orcinus orca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 132948040, + "scientific_name": "Orcinus orca Strait of Gibraltar subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Strait of Gibraltar subpopulation", + "category": "CR" + }, + { + "taxonid": 42680, + "scientific_name": "Oreamnos americanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15587, + "scientific_name": "Oreoryzomys balneator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15485, + "scientific_name": "Oreotragus oreotragus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15484, + "scientific_name": "Oreotragus oreotragus ssp. porteousi", + "subspecies": "porteousi", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40488, + "scientific_name": "Ornithorhynchus anatinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15544, + "scientific_name": "Orthogeomys cavator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15546, + "scientific_name": "Orthogeomys cuniculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42590, + "scientific_name": "Orthogeomys grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15548, + "scientific_name": "Orthogeomys heterodus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15549, + "scientific_name": "Orthogeomys hispidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42593, + "scientific_name": "Orthogeomys underwoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41504, + "scientific_name": "Orycteropus afer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41291, + "scientific_name": "Oryctolagus cuniculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15571, + "scientific_name": "Oryx beisa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136871, + "scientific_name": "Oryx beisa ssp. beisa", + "subspecies": "beisa", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15572, + "scientific_name": "Oryx beisa ssp. callotis", + "subspecies": "callotis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15568, + "scientific_name": "Oryx dammah", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EW" + }, + { + "taxonid": 15573, + "scientific_name": "Oryx gazella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15569, + "scientific_name": "Oryx leucoryx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136540, + "scientific_name": "Oryzomys antillarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 15592, + "scientific_name": "Oryzomys couesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15594, + "scientific_name": "Oryzomys dimidiatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 115554360, + "scientific_name": "Oryzomys gorgasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15583, + "scientific_name": "Oryzomys nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 42675, + "scientific_name": "Oryzomys palustris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40589, + "scientific_name": "Oryzorictes hova", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40591, + "scientific_name": "Oryzorictes tetradactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15629, + "scientific_name": "Osgoodomys banderanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41665, + "scientific_name": "Otaria byronia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15640, + "scientific_name": "Otocolobus manul", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15642, + "scientific_name": "Otocyon megalotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15643, + "scientific_name": "Otolemur crassicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 91980457, + "scientific_name": "Otolemur crassicaudatus ssp. argentatus", + "subspecies": "argentatus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136881, + "scientific_name": "Otolemur crassicaudatus ssp. crassicaudatus", + "subspecies": "crassicaudatus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136874, + "scientific_name": "Otolemur crassicaudatus ssp. kirkii", + "subspecies": "kirkii", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 91991178, + "scientific_name": "Otolemur crassicaudatus ssp. monteiri", + "subspecies": "monteiri", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15644, + "scientific_name": "Otolemur garnettii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136855, + "scientific_name": "Otolemur garnettii ssp. garnettii", + "subspecies": "garnettii", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136911, + "scientific_name": "Otolemur garnettii ssp. kikuyuensis", + "subspecies": "kikuyuensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136900, + "scientific_name": "Otolemur garnettii ssp. lasiotis", + "subspecies": "lasiotis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136859, + "scientific_name": "Otolemur garnettii ssp. panganiensis", + "subspecies": "panganiensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15645, + "scientific_name": "Otomops formosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 95558305, + "scientific_name": "Otomops harrisoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15647, + "scientific_name": "Otomops johnstonei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136564, + "scientific_name": "Otomops madagascariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15648, + "scientific_name": "Otomops martiensseni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15649, + "scientific_name": "Otomops papuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15650, + "scientific_name": "Otomops secundus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15646, + "scientific_name": "Otomops wroughtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15651, + "scientific_name": "Otomys anchietae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15652, + "scientific_name": "Otomys angoniensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 110662638, + "scientific_name": "Otomys auratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 45069, + "scientific_name": "Otomys barbouri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 45071, + "scientific_name": "Otomys burtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 48008221, + "scientific_name": "Otomys cheesmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 45065, + "scientific_name": "Otomys cuanzensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45063, + "scientific_name": "Otomys dartmouthi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15653, + "scientific_name": "Otomys denti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48009551, + "scientific_name": "Otomys fortior", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 48011421, + "scientific_name": "Otomys helleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 110662669, + "scientific_name": "Otomys irroratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45064, + "scientific_name": "Otomys jacksoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 111949037, + "scientific_name": "Otomys karoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45067, + "scientific_name": "Otomys lacustris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15655, + "scientific_name": "Otomys laminatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15657, + "scientific_name": "Otomys occidentalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 48014975, + "scientific_name": "Otomys simiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15659, + "scientific_name": "Otomys sloggetti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48016232, + "scientific_name": "Otomys thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15660, + "scientific_name": "Otomys tropicalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48006730, + "scientific_name": "Otomys typus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15662, + "scientific_name": "Otomys unisulcatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45068, + "scientific_name": "Otomys uzungwensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 48018096, + "scientific_name": "Otomys yaldeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 48018185, + "scientific_name": "Otomys zinki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 85294528, + "scientific_name": "Otonycteris hemprichii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85295233, + "scientific_name": "Otonycteris leucophaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15664, + "scientific_name": "Otonyctomys hatti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15665, + "scientific_name": "Otopteropus cartilagonodus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20481, + "scientific_name": "Otospermophilus beecheyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20480, + "scientific_name": "Otospermophilus beecheyi ssp. atricapillus", + "subspecies": "atricapillus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 20495, + "scientific_name": "Otospermophilus variegatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15666, + "scientific_name": "Ototylomys phyllotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15730, + "scientific_name": "Ourebia ourebi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15731, + "scientific_name": "Ourebia ourebi ssp. haggardi", + "subspecies": "haggardi", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15732, + "scientific_name": "Ourebia ourebi ssp. kenyae", + "subspecies": "kenyae", + "rank": "ssp.", + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 29684, + "scientific_name": "Ovibos moschatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15733, + "scientific_name": "Ovis ammon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15735, + "scientific_name": "Ovis canadensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39250, + "scientific_name": "Ovis dalli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 54940218, + "scientific_name": "Ovis gmelini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15740, + "scientific_name": "Ovis nivicola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 54940655, + "scientific_name": "Ovis vignei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136205, + "scientific_name": "Oxymycterus amazonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15783, + "scientific_name": "Oxymycterus angularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136725, + "scientific_name": "Oxymycterus caparoae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136813, + "scientific_name": "Oxymycterus dasytrichus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15784, + "scientific_name": "Oxymycterus delator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15793, + "scientific_name": "Oxymycterus hiska", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15785, + "scientific_name": "Oxymycterus hispidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15786, + "scientific_name": "Oxymycterus hucucha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15788, + "scientific_name": "Oxymycterus inca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136453, + "scientific_name": "Oxymycterus josei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15789, + "scientific_name": "Oxymycterus nasutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 115590985, + "scientific_name": "Oxymycterus paramensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136613, + "scientific_name": "Oxymycterus quaestor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15791, + "scientific_name": "Oxymycterus roberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15792, + "scientific_name": "Oxymycterus rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45959327, + "scientific_name": "Oxymycterus wayku", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13880, + "scientific_name": "Ozimops beccarii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 71536513, + "scientific_name": "Ozimops cobourgianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 71532803, + "scientific_name": "Ozimops halli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 71532724, + "scientific_name": "Ozimops kitcheneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 82345325, + "scientific_name": "Ozimops loriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 71531227, + "scientific_name": "Ozimops lumsdenae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 71534469, + "scientific_name": "Ozimops petersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 71732146, + "scientific_name": "Ozimops planiceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 71533043, + "scientific_name": "Ozimops ridei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15803, + "scientific_name": "Ozotoceros bezoarticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15865, + "scientific_name": "Pachyuromys duprasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41671, + "scientific_name": "Pagophilus groenlandicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41692, + "scientific_name": "Paguma larvata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136532, + "scientific_name": "Palaeopropithecus ingens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 15917, + "scientific_name": "Palawanomys furvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15932, + "scientific_name": "Pan paniscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15951, + "scientific_name": "Panthera leo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15952, + "scientific_name": "Panthera leo ssp. persica", + "subspecies": "persica", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 68933833, + "scientific_name": "Panthera leo West Africa subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "West Africa subpopulation", + "category": "CR" + }, + { + "taxonid": 15953, + "scientific_name": "Panthera onca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15954, + "scientific_name": "Panthera pardus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 124159083, + "scientific_name": "Panthera pardus ssp. delacouri", + "subspecies": "delacouri", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 15959, + "scientific_name": "Panthera pardus ssp. kotiya", + "subspecies": "kotiya", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15962, + "scientific_name": "Panthera pardus ssp. melas", + "subspecies": "melas", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15955, + "scientific_name": "Panthera tigris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22732, + "scientific_name": "Panthera uncia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15967, + "scientific_name": "Pantholops hodgsonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 15933, + "scientific_name": "Pan troglodytes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40014, + "scientific_name": "Pan troglodytes ssp. ellioti", + "subspecies": "ellioti", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15937, + "scientific_name": "Pan troglodytes ssp. schweinfurthii", + "subspecies": "schweinfurthii", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15936, + "scientific_name": "Pan troglodytes ssp. troglodytes", + "subspecies": "troglodytes", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 15935, + "scientific_name": "Pan troglodytes ssp. verus", + "subspecies": "verus", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 15975, + "scientific_name": "Papagomys armandvillei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40647, + "scientific_name": "Papio anubis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92250442, + "scientific_name": "Papio cynocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136898, + "scientific_name": "Papio cynocephalus ssp. cynocephalus", + "subspecies": "cynocephalus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136862, + "scientific_name": "Papio cynocephalus ssp. ibeanus", + "subspecies": "ibeanus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16019, + "scientific_name": "Papio hamadryas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136848, + "scientific_name": "Papio kindae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16018, + "scientific_name": "Papio papio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16022, + "scientific_name": "Papio ursinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136870, + "scientific_name": "Papio ursinus ssp. griseipes", + "subspecies": "griseipes", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92250358, + "scientific_name": "Papio ursinus ssp. ruacana", + "subspecies": "ruacana", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136856, + "scientific_name": "Papio ursinus ssp. ursinus", + "subspecies": "ursinus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92474664, + "scientific_name": "Pappogeomys bulleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16023, + "scientific_name": "Pappogeomys bulleri ssp. alcorni", + "subspecies": "alcorni", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16042, + "scientific_name": "Paracrocidura graueri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16043, + "scientific_name": "Paracrocidura maxima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41383, + "scientific_name": "Paracrocidura schoutedeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41622, + "scientific_name": "Paracynictis selousi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16074, + "scientific_name": "Paradipus ctenodactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41693, + "scientific_name": "Paradoxurus hermaphroditus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16104, + "scientific_name": "Paradoxurus jerdoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41694, + "scientific_name": "Paradoxurus zeylonensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40606, + "scientific_name": "Paraechinus aethiopicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40610, + "scientific_name": "Paraechinus hypomelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40609, + "scientific_name": "Paraechinus micropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39594, + "scientific_name": "Paraechinus nudiventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136212, + "scientific_name": "Paragalago cocos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 91970347, + "scientific_name": "Paragalago granti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40651, + "scientific_name": "Paragalago orinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40652, + "scientific_name": "Paragalago rondoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 8790, + "scientific_name": "Paragalago zanzibaricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136903, + "scientific_name": "Paragalago zanzibaricus ssp. udzungwensis", + "subspecies": "udzungwensis", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136924, + "scientific_name": "Paragalago zanzibaricus ssp. zanzibaricus", + "subspecies": "zanzibaricus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 10276, + "scientific_name": "Parahyaena brunnea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16114, + "scientific_name": "Parahydromys asper", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16121, + "scientific_name": "Paraleptomys rufilatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16122, + "scientific_name": "Paraleptomys wilhelmina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136701, + "scientific_name": "Paramelomys gressitti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13124, + "scientific_name": "Paramelomys levipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13125, + "scientific_name": "Paramelomys lorentzii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13126, + "scientific_name": "Paramelomys mollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13127, + "scientific_name": "Paramelomys moncktoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136324, + "scientific_name": "Paramelomys naso", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13129, + "scientific_name": "Paramelomys platyops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13131, + "scientific_name": "Paramelomys rubex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136718, + "scientific_name": "Paramelomys steini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16138, + "scientific_name": "Parantechinus apicalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16174, + "scientific_name": "Paranyctimene raptor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136836, + "scientific_name": "Paranyctimene tenax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41469, + "scientific_name": "Parascalops breweri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41470, + "scientific_name": "Parascaptor leucura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17341, + "scientific_name": "Parastrellus hesperus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40025, + "scientific_name": "Paratriaenops auritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 81060220, + "scientific_name": "Paratriaenops furculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81068840, + "scientific_name": "Paratriaenops pauliani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16203, + "scientific_name": "Paraxerus alexandri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16204, + "scientific_name": "Paraxerus boehmi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16205, + "scientific_name": "Paraxerus cepapi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16206, + "scientific_name": "Paraxerus cooperi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16207, + "scientific_name": "Paraxerus flavovittis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16208, + "scientific_name": "Paraxerus lucifer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16209, + "scientific_name": "Paraxerus ochraceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16210, + "scientific_name": "Paraxerus palliatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16211, + "scientific_name": "Paraxerus poensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16202, + "scientific_name": "Paraxerus vexillarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16212, + "scientific_name": "Paraxerus vincenti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16218, + "scientific_name": "Pardofelis marmorata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7671, + "scientific_name": "Paremballonura atrata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136835, + "scientific_name": "Paremballonura tiavato", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16270, + "scientific_name": "Parotomys brantsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16271, + "scientific_name": "Parotomys littledalei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16375, + "scientific_name": "Paruromys dominator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 90386442, + "scientific_name": "Pattonomys carrikeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 90386462, + "scientific_name": "Pattonomys flavidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 39314, + "scientific_name": "Pattonomys occasius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 90386776, + "scientific_name": "Pattonomys punctatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 90386452, + "scientific_name": "Pattonomys semivillosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 46205590, + "scientific_name": "Paucidentomys vermidax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16426, + "scientific_name": "Paulamys naso", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41777, + "scientific_name": "Pecari tajacu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16458, + "scientific_name": "Pectinator spekei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16467, + "scientific_name": "Pedetes capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136621, + "scientific_name": "Pedetes surdaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16484, + "scientific_name": "Pelea capreolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16508, + "scientific_name": "Pelomys campanae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16509, + "scientific_name": "Pelomys fallax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16506, + "scientific_name": "Pelomys hopkinsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16507, + "scientific_name": "Pelomys isseli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16510, + "scientific_name": "Pelomys minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199838, + "scientific_name": "Pennatomys nivalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 16559, + "scientific_name": "Pentalagus furnessi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16563, + "scientific_name": "Penthetor lucasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16564, + "scientific_name": "Peponocephala electra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16569, + "scientific_name": "Perameles bougainville", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16570, + "scientific_name": "Perameles eremiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 16572, + "scientific_name": "Perameles gunnii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40554, + "scientific_name": "Perameles nasuta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17366, + "scientific_name": "Perimyotis subflavus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136852, + "scientific_name": "Perodicticus edwardsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136875, + "scientific_name": "Perodicticus ibeanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 95706286, + "scientific_name": "Perodicticus ibeanus ssp. ibeanus", + "subspecies": "ibeanus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136932, + "scientific_name": "Perodicticus ibeanus ssp. stockleyi", + "subspecies": "stockleyi", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 91995408, + "scientific_name": "Perodicticus potto", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 91995465, + "scientific_name": "Perodicticus potto ssp. juju", + "subspecies": "juju", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136847, + "scientific_name": "Perodicticus potto ssp. potto", + "subspecies": "potto", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16631, + "scientific_name": "Perognathus alticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16633, + "scientific_name": "Perognathus amplus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42608, + "scientific_name": "Perognathus fasciatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16634, + "scientific_name": "Perognathus flavescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16635, + "scientific_name": "Perognathus flavus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42609, + "scientific_name": "Perognathus inornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16636, + "scientific_name": "Perognathus longimembris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16637, + "scientific_name": "Perognathus merriami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42610, + "scientific_name": "Perognathus parvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42652, + "scientific_name": "Peromyscus attwateri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16651, + "scientific_name": "Peromyscus aztecus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136323, + "scientific_name": "Peromyscus beatae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16652, + "scientific_name": "Peromyscus boylii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16653, + "scientific_name": "Peromyscus bullatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16654, + "scientific_name": "Peromyscus californicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16655, + "scientific_name": "Peromyscus caniceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16656, + "scientific_name": "Peromyscus crinitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16657, + "scientific_name": "Peromyscus dickeyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16658, + "scientific_name": "Peromyscus difficilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16659, + "scientific_name": "Peromyscus eremicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16660, + "scientific_name": "Peromyscus eva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136412, + "scientific_name": "Peromyscus fraterculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16661, + "scientific_name": "Peromyscus furvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 42653, + "scientific_name": "Peromyscus gossypinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16662, + "scientific_name": "Peromyscus grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16663, + "scientific_name": "Peromyscus gratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16664, + "scientific_name": "Peromyscus guardia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16665, + "scientific_name": "Peromyscus guatemalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16666, + "scientific_name": "Peromyscus gymnotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16667, + "scientific_name": "Peromyscus hooperi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136416, + "scientific_name": "Peromyscus hylocetes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16668, + "scientific_name": "Peromyscus interparietalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 135164, + "scientific_name": "Peromyscus keeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16669, + "scientific_name": "Peromyscus leucopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16670, + "scientific_name": "Peromyscus levipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16671, + "scientific_name": "Peromyscus madrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16672, + "scientific_name": "Peromyscus maniculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16673, + "scientific_name": "Peromyscus mayensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16674, + "scientific_name": "Peromyscus megalops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16675, + "scientific_name": "Peromyscus mekisturus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16676, + "scientific_name": "Peromyscus melanocarpus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16677, + "scientific_name": "Peromyscus melanophrys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16678, + "scientific_name": "Peromyscus melanotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16679, + "scientific_name": "Peromyscus melanurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16680, + "scientific_name": "Peromyscus merriami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16681, + "scientific_name": "Peromyscus mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16682, + "scientific_name": "Peromyscus nasutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16683, + "scientific_name": "Peromyscus ochraventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16684, + "scientific_name": "Peromyscus pectoralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16645, + "scientific_name": "Peromyscus pembertoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 16685, + "scientific_name": "Peromyscus perfulvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42654, + "scientific_name": "Peromyscus polionotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16686, + "scientific_name": "Peromyscus polius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16687, + "scientific_name": "Peromyscus pseudocrinitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136710, + "scientific_name": "Peromyscus sagax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136576, + "scientific_name": "Peromyscus schmidlyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16688, + "scientific_name": "Peromyscus sejugis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16689, + "scientific_name": "Peromyscus simulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16690, + "scientific_name": "Peromyscus slevini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16691, + "scientific_name": "Peromyscus spicilegus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16692, + "scientific_name": "Peromyscus stephani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16693, + "scientific_name": "Peromyscus stirtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16694, + "scientific_name": "Peromyscus truei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16695, + "scientific_name": "Peromyscus winkelmanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16696, + "scientific_name": "Peromyscus yucatanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16697, + "scientific_name": "Peromyscus zarhynchus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16707, + "scientific_name": "Peropteryx kappleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16708, + "scientific_name": "Peropteryx leucoptera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16709, + "scientific_name": "Peropteryx macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85822291, + "scientific_name": "Peropteryx pallidoptera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136790, + "scientific_name": "Peropteryx trinitatis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16710, + "scientific_name": "Peroryctes broadbenti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16711, + "scientific_name": "Peroryctes raffrayana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16714, + "scientific_name": "Petaurillus emiliae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16715, + "scientific_name": "Petaurillus hosei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16716, + "scientific_name": "Petaurillus kinlochii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16718, + "scientific_name": "Petaurista alborufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16719, + "scientific_name": "Petaurista elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16720, + "scientific_name": "Petaurista leucogenys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16721, + "scientific_name": "Petaurista magnificus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45959013, + "scientific_name": "Petaurista mechukaensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45959040, + "scientific_name": "Petaurista mishmiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16722, + "scientific_name": "Petaurista nobilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16723, + "scientific_name": "Petaurista petaurista", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16724, + "scientific_name": "Petaurista philippensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16725, + "scientific_name": "Petaurista xanthotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40579, + "scientific_name": "Petauroides volans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16726, + "scientific_name": "Petaurus abidi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16730, + "scientific_name": "Petaurus australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16732, + "scientific_name": "Petaurus biacensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16731, + "scientific_name": "Petaurus breviceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16727, + "scientific_name": "Petaurus gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16728, + "scientific_name": "Petaurus norfolcensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16733, + "scientific_name": "Petinomys crinitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16734, + "scientific_name": "Petinomys fuscocapillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16735, + "scientific_name": "Petinomys genibarbis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16736, + "scientific_name": "Petinomys hageni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16737, + "scientific_name": "Petinomys lugens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136439, + "scientific_name": "Petinomys mindanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16739, + "scientific_name": "Petinomys setosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16740, + "scientific_name": "Petinomys vordermanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42679, + "scientific_name": "Petrodromus tetradactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40569, + "scientific_name": "Petrogale assimilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40570, + "scientific_name": "Petrogale brachyotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16744, + "scientific_name": "Petrogale burbidgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16752, + "scientific_name": "Petrogale coenensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16761, + "scientific_name": "Petrogale concinna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41514, + "scientific_name": "Petrogale godmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41515, + "scientific_name": "Petrogale herberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41516, + "scientific_name": "Petrogale inornata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16751, + "scientific_name": "Petrogale lateralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136509, + "scientific_name": "Petrogale mareeba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16746, + "scientific_name": "Petrogale penicillata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16747, + "scientific_name": "Petrogale persephone", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136463, + "scientific_name": "Petrogale purpureicollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41517, + "scientific_name": "Petrogale rothschildi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16753, + "scientific_name": "Petrogale sharmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16750, + "scientific_name": "Petrogale xanthopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16776, + "scientific_name": "Petromus typicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16777, + "scientific_name": "Petromyscus barbouri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16778, + "scientific_name": "Petromyscus collinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16779, + "scientific_name": "Petromyscus monticularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16780, + "scientific_name": "Petromyscus shortridgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40580, + "scientific_name": "Petropseudes dahli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41767, + "scientific_name": "Phacochoerus aethiopicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41768, + "scientific_name": "Phacochoerus africanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16799, + "scientific_name": "Phaenomys ferrugineus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13439, + "scientific_name": "Phaiomys leucurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16858, + "scientific_name": "Phalanger alexandrae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16853, + "scientific_name": "Phalanger carmelitae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16856, + "scientific_name": "Phalanger gymnotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16857, + "scientific_name": "Phalanger intercastellanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16846, + "scientific_name": "Phalanger lullulae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136200, + "scientific_name": "Phalanger matabiru", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16851, + "scientific_name": "Phalanger matanim", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136450, + "scientific_name": "Phalanger mimicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16847, + "scientific_name": "Phalanger orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16854, + "scientific_name": "Phalanger ornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16852, + "scientific_name": "Phalanger rothschildi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16855, + "scientific_name": "Phalanger sericeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16850, + "scientific_name": "Phalanger vestitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16875, + "scientific_name": "Phaner electromontis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16872, + "scientific_name": "Phaner furcifer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16874, + "scientific_name": "Phaner pallescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16873, + "scientific_name": "Phaner parienti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 16887, + "scientific_name": "Pharotis imogene", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 16888, + "scientific_name": "Phascogale calura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16889, + "scientific_name": "Phascogale pirata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16890, + "scientific_name": "Phascogale tapoatafa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 16892, + "scientific_name": "Phascolarctos cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16893, + "scientific_name": "Phascolosorex doriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16894, + "scientific_name": "Phascolosorex dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12766, + "scientific_name": "Phataginus tetradactyla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 12767, + "scientific_name": "Phataginus tricuspis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42636, + "scientific_name": "Phenacomys intermedius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42637, + "scientific_name": "Phenacomys ungava", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40515, + "scientific_name": "Philander andersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136227, + "scientific_name": "Philander deltae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136375, + "scientific_name": "Philander frenatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136501, + "scientific_name": "Philander mcilhennyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136202, + "scientific_name": "Philander mondolfii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199832, + "scientific_name": "Philander olrogi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40516, + "scientific_name": "Philander opossum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4142, + "scientific_name": "Philantomba maxwellii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4143, + "scientific_name": "Philantomba monticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88418111, + "scientific_name": "Philantomba walteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 16981, + "scientific_name": "Philetor brachypterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17003, + "scientific_name": "Phloeomys cumingi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17004, + "scientific_name": "Phloeomys pallidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17023, + "scientific_name": "Phoca largha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17026, + "scientific_name": "Phocarctos hookeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 17013, + "scientific_name": "Phoca vitulina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17021, + "scientific_name": "Phoca vitulina ssp. concolor", + "subspecies": "concolor", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17018, + "scientific_name": "Phoca vitulina ssp. mellonae", + "subspecies": "mellonae", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 17022, + "scientific_name": "Phoca vitulina ssp. richardii", + "subspecies": "richardii", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17014, + "scientific_name": "Phoca vitulina ssp. stejnegeri", + "subspecies": "stejnegeri", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17020, + "scientific_name": "Phoca vitulina ssp. vitulina", + "subspecies": "vitulina", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41715, + "scientific_name": "Phocoena dioptrica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17027, + "scientific_name": "Phocoena phocoena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17031, + "scientific_name": "Phocoena phocoena Baltic Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Baltic Sea subpopulation", + "category": "CR" + }, + { + "taxonid": 17030, + "scientific_name": "Phocoena phocoena ssp. relicta", + "subspecies": "relicta", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 17028, + "scientific_name": "Phocoena sinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 17029, + "scientific_name": "Phocoena spinipinnis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 17032, + "scientific_name": "Phocoenoides dalli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17035, + "scientific_name": "Phodopus campbelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17036, + "scientific_name": "Phodopus roborovskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17037, + "scientific_name": "Phodopus sungorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10967, + "scientific_name": "Phoniscus aerosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 10970, + "scientific_name": "Phoniscus atrox", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 10976, + "scientific_name": "Phoniscus jagorii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10982, + "scientific_name": "Phoniscus papuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 17168, + "scientific_name": "Phylloderma stenops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6977, + "scientific_name": "Phyllomys blainvillii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6978, + "scientific_name": "Phyllomys brasiliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6980, + "scientific_name": "Phyllomys dasythrix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136682, + "scientific_name": "Phyllomys kerri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6982, + "scientific_name": "Phyllomys lamarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136400, + "scientific_name": "Phyllomys lundi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136274, + "scientific_name": "Phyllomys mantiqueirensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136704, + "scientific_name": "Phyllomys medius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6984, + "scientific_name": "Phyllomys nigrispinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136801, + "scientific_name": "Phyllomys pattoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47792718, + "scientific_name": "Phyllomys sulinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6989, + "scientific_name": "Phyllomys thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 6990, + "scientific_name": "Phyllomys unicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 17173, + "scientific_name": "Phyllonycteris aphylla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 17175, + "scientific_name": "Phyllonycteris poeyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17176, + "scientific_name": "Phyllops falcatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17216, + "scientific_name": "Phyllostomus discolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17217, + "scientific_name": "Phyllostomus elongatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17218, + "scientific_name": "Phyllostomus hastatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17219, + "scientific_name": "Phyllostomus latifolius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45959348, + "scientific_name": "Phyllotis alisosiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17220, + "scientific_name": "Phyllotis amicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17221, + "scientific_name": "Phyllotis andium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136674, + "scientific_name": "Phyllotis anitae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17222, + "scientific_name": "Phyllotis bonariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 17223, + "scientific_name": "Phyllotis caprinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17224, + "scientific_name": "Phyllotis darwini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17225, + "scientific_name": "Phyllotis definitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 17226, + "scientific_name": "Phyllotis gerbillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17227, + "scientific_name": "Phyllotis haggardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136629, + "scientific_name": "Phyllotis limatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17228, + "scientific_name": "Phyllotis magister", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17229, + "scientific_name": "Phyllotis osgoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17230, + "scientific_name": "Phyllotis osilae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17231, + "scientific_name": "Phyllotis wolffsohni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17232, + "scientific_name": "Phyllotis xanthopygus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41755, + "scientific_name": "Physeter macrocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 16370739, + "scientific_name": "Physeter macrocephalus Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mediterranean subpopulation", + "category": "EN" + }, + { + "taxonid": 161247840, + "scientific_name": "Piliocolobus badius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40009, + "scientific_name": "Piliocolobus badius ssp. badius", + "subspecies": "badius", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18247, + "scientific_name": "Piliocolobus badius ssp. temminckii", + "subspecies": "temminckii", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18250, + "scientific_name": "Piliocolobus bouvieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41024, + "scientific_name": "Piliocolobus epieni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18252, + "scientific_name": "Piliocolobus foai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40015, + "scientific_name": "Piliocolobus gordonorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39992, + "scientific_name": "Piliocolobus kirkii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18261, + "scientific_name": "Piliocolobus langi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18262, + "scientific_name": "Piliocolobus lulindicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18255, + "scientific_name": "Piliocolobus oustaleti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40648, + "scientific_name": "Piliocolobus parmentieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41025, + "scientific_name": "Piliocolobus pennantii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41026, + "scientific_name": "Piliocolobus preussi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136939, + "scientific_name": "Piliocolobus rufomitratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 92657343, + "scientific_name": "Piliocolobus semlikiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18256, + "scientific_name": "Piliocolobus tephrosceles", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18257, + "scientific_name": "Piliocolobus tholloni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18248, + "scientific_name": "Piliocolobus waldroni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 17320, + "scientific_name": "Pipistrellus abramus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17321, + "scientific_name": "Pipistrellus adamsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17323, + "scientific_name": "Pipistrellus aero", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85333758, + "scientific_name": "Pipistrellus aladdin", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44851, + "scientific_name": "Pipistrellus anchietae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17326, + "scientific_name": "Pipistrellus angulatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17332, + "scientific_name": "Pipistrellus ceylonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17334, + "scientific_name": "Pipistrellus collinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17335, + "scientific_name": "Pipistrellus coromandra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44853, + "scientific_name": "Pipistrellus crassulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17340, + "scientific_name": "Pipistrellus endoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 85736277, + "scientific_name": "Pipistrellus grandidieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136209, + "scientific_name": "Pipistrellus hanaki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136741, + "scientific_name": "Pipistrellus hesperidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17342, + "scientific_name": "Pipistrellus imbricatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17343, + "scientific_name": "Pipistrellus inexspectatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17344, + "scientific_name": "Pipistrellus javanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17314, + "scientific_name": "Pipistrellus kuhlii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17315, + "scientific_name": "Pipistrellus maderensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 17350, + "scientific_name": "Pipistrellus minahassae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136769, + "scientific_name": "Pipistrellus murrayi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 17353, + "scientific_name": "Pipistrellus nanulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17316, + "scientific_name": "Pipistrellus nathusii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17355, + "scientific_name": "Pipistrellus papuanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17356, + "scientific_name": "Pipistrellus paterculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17358, + "scientific_name": "Pipistrellus permixtus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85333513, + "scientific_name": "Pipistrellus pipistrellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136649, + "scientific_name": "Pipistrellus pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136646, + "scientific_name": "Pipistrellus raceyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17361, + "scientific_name": "Pipistrellus rueppellii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17362, + "scientific_name": "Pipistrellus rusticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17364, + "scientific_name": "Pipistrellus stenopterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17365, + "scientific_name": "Pipistrellus sturdeei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 186170680, + "scientific_name": "Pipistrellus tenuis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17369, + "scientific_name": "Pipistrellus wattsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17370, + "scientific_name": "Pipistrellus westralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17400, + "scientific_name": "Pithecheir melanurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136834, + "scientific_name": "Pithecheirops otion", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17401, + "scientific_name": "Pithecheir parvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17402, + "scientific_name": "Pithecia aequatorialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41567, + "scientific_name": "Pithecia albicans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70609874, + "scientific_name": "Pithecia cazuzai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 43943, + "scientific_name": "Pithecia chrysocephala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70606542, + "scientific_name": "Pithecia hirsuta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70609849, + "scientific_name": "Pithecia inusta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70610758, + "scientific_name": "Pithecia irrorata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 70609893, + "scientific_name": "Pithecia isabela", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17407, + "scientific_name": "Pithecia milleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 70610693, + "scientific_name": "Pithecia mittermeieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 70609726, + "scientific_name": "Pithecia monachus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39955, + "scientific_name": "Pithecia napensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70610729, + "scientific_name": "Pithecia pissinattii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 43942, + "scientific_name": "Pithecia pithecia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70610711, + "scientific_name": "Pithecia rylandsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 43946, + "scientific_name": "Pithecia vanzolinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17460, + "scientific_name": "Plagiodontia aedium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 17462, + "scientific_name": "Plagiodontia ipnaeum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 40533, + "scientific_name": "Planigale gilesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40534, + "scientific_name": "Planigale ingrami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40535, + "scientific_name": "Planigale maculata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17474, + "scientific_name": "Planigale novaeguineae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40536, + "scientific_name": "Planigale tenuirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17481, + "scientific_name": "Platacanthomys lasiurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 17487, + "scientific_name": "Platalina genovensium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41756, + "scientific_name": "Platanista gangetica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41757, + "scientific_name": "Platanista minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44692, + "scientific_name": "Platymops setiger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136203, + "scientific_name": "Platyrrhinus albericoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88160255, + "scientific_name": "Platyrrhinus angustirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88160364, + "scientific_name": "Platyrrhinus aquilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17566, + "scientific_name": "Platyrrhinus aurarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17567, + "scientific_name": "Platyrrhinus brachycephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17568, + "scientific_name": "Platyrrhinus chocoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 88160389, + "scientific_name": "Platyrrhinus dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88160339, + "scientific_name": "Platyrrhinus fusciventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88159886, + "scientific_name": "Platyrrhinus helleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88160214, + "scientific_name": "Platyrrhinus incarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17571, + "scientific_name": "Platyrrhinus infuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136232, + "scientific_name": "Platyrrhinus ismaeli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 17565, + "scientific_name": "Platyrrhinus lineatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136577, + "scientific_name": "Platyrrhinus masu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136378, + "scientific_name": "Platyrrhinus matapalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136317, + "scientific_name": "Platyrrhinus nigellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88160517, + "scientific_name": "Platyrrhinus nitelinea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17572, + "scientific_name": "Platyrrhinus recifinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 95908089, + "scientific_name": "Platyrrhinus umbratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 17574, + "scientific_name": "Platyrrhinus vittatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85534953, + "scientific_name": "Plecotus ariel", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85535522, + "scientific_name": "Plecotus auritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85533333, + "scientific_name": "Plecotus austriacus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 44930, + "scientific_name": "Plecotus balensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44931, + "scientific_name": "Plecotus christii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 85537505, + "scientific_name": "Plecotus homochrous", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136473, + "scientific_name": "Plecotus kolombatovici", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85535146, + "scientific_name": "Plecotus kozlovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136229, + "scientific_name": "Plecotus macrobullaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136598, + "scientific_name": "Plecotus ognevi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136664, + "scientific_name": "Plecotus sacrimontis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136503, + "scientific_name": "Plecotus sardus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 85535363, + "scientific_name": "Plecotus strelkovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17601, + "scientific_name": "Plecotus taivanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 215482954, + "scientific_name": "Plecotus teneriffae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 85535176, + "scientific_name": "Plecotus turkmenicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85535265, + "scientific_name": "Plecotus wardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136815, + "scientific_name": "Plecturocebus aureipalatii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41560, + "scientific_name": "Plecturocebus baptista", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41561, + "scientific_name": "Plecturocebus bernhardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41558, + "scientific_name": "Plecturocebus brunneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41552, + "scientific_name": "Plecturocebus caligatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14699281, + "scientific_name": "Plecturocebus caquetensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41557, + "scientific_name": "Plecturocebus cinerascens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 127530593, + "scientific_name": "Plecturocebus cupreus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41553, + "scientific_name": "Plecturocebus discolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41548, + "scientific_name": "Plecturocebus donacophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3549, + "scientific_name": "Plecturocebus dubius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172272064, + "scientific_name": "Plecturocebus grovesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41559, + "scientific_name": "Plecturocebus hoffmannsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 127530569, + "scientific_name": "Plecturocebus miltoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41550, + "scientific_name": "Plecturocebus modestus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41556, + "scientific_name": "Plecturocebus moloch", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3553, + "scientific_name": "Plecturocebus oenanthe", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 3554, + "scientific_name": "Plecturocebus olallae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39928, + "scientific_name": "Plecturocebus ornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41549, + "scientific_name": "Plecturocebus pallescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172274032, + "scientific_name": "Plecturocebus parecis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41555, + "scientific_name": "Plecturocebus stephennashi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 127530624, + "scientific_name": "Plecturocebus toppini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 127530581, + "scientific_name": "Plecturocebus urubambensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70330181, + "scientific_name": "Plecturocebus vieirai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 17618, + "scientific_name": "Plerotes anchietae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17829, + "scientific_name": "Podogymnura aureospinula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 17828, + "scientific_name": "Podogymnura truei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17830, + "scientific_name": "Podomys floridanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 17831, + "scientific_name": "Podoxymys roraimae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41662, + "scientific_name": "Poecilogale albinucha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41292, + "scientific_name": "Poelagus marjorita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136660, + "scientific_name": "Pogonomelomys brassi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17877, + "scientific_name": "Pogonomelomys bruijnii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17878, + "scientific_name": "Pogonomelomys mayeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17882, + "scientific_name": "Pogonomys championi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136763, + "scientific_name": "Pogonomys fergussoniensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 17883, + "scientific_name": "Pogonomys loriae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17884, + "scientific_name": "Pogonomys macrourus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17885, + "scientific_name": "Pogonomys sylvestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44165, + "scientific_name": "Poiana leightoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41704, + "scientific_name": "Poiana richardsonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41787, + "scientific_name": "Poliocitellus franklinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 121097935, + "scientific_name": "Pongo abelii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 17975, + "scientific_name": "Pongo pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 63544, + "scientific_name": "Pongo pygmaeus ssp. morio", + "subspecies": "morio", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39781, + "scientific_name": "Pongo pygmaeus ssp. pygmaeus", + "subspecies": "pygmaeus", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39782, + "scientific_name": "Pongo pygmaeus ssp. wurmbii", + "subspecies": "wurmbii", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 120588639, + "scientific_name": "Pongo tapanuliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 17978, + "scientific_name": "Pontoporia blainvillei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41761, + "scientific_name": "Pontoporia blainvillei Rio Grande do Sul/Uruguay subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Rio Grande do Sul/Uruguay subpopulation", + "category": "VU" + }, + { + "taxonid": 21172, + "scientific_name": "Porcula salvania", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41770, + "scientific_name": "Potamochoerus larvatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41771, + "scientific_name": "Potamochoerus porcus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18095, + "scientific_name": "Potamogale velox", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18107, + "scientific_name": "Potorous gilbertii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18102, + "scientific_name": "Potorous longipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18103, + "scientific_name": "Potorous platyops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 41511, + "scientific_name": "Potorous tridactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41679, + "scientific_name": "Potos flavus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48018659, + "scientific_name": "Praomys coetzeei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45094, + "scientific_name": "Praomys daltoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41210, + "scientific_name": "Praomys degraaffi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18114, + "scientific_name": "Praomys delectorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45095, + "scientific_name": "Praomys derooi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18113, + "scientific_name": "Praomys hartwigi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18115, + "scientific_name": "Praomys jacksoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45089, + "scientific_name": "Praomys lukolelae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18116, + "scientific_name": "Praomys minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18117, + "scientific_name": "Praomys misonnei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18118, + "scientific_name": "Praomys morio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18119, + "scientific_name": "Praomys mutoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41211, + "scientific_name": "Praomys obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 45072, + "scientific_name": "Praomys petteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18120, + "scientific_name": "Praomys rostratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48018502, + "scientific_name": "Praomys tullbergi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45090, + "scientific_name": "Praomys verschureni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 39812, + "scientific_name": "Presbytis bicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 39808, + "scientific_name": "Presbytis canicrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39803, + "scientific_name": "Presbytis chrysomelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136857, + "scientific_name": "Presbytis chrysomelas ssp. chrysomelas", + "subspecies": "chrysomelas", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39804, + "scientific_name": "Presbytis chrysomelas ssp. cruciger", + "subspecies": "cruciger", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 210369485, + "scientific_name": "Presbytis comata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39801, + "scientific_name": "Presbytis femoralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18133, + "scientific_name": "Presbytis fredericae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18127, + "scientific_name": "Presbytis frontata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 175648870, + "scientific_name": "Presbytis hosei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39811, + "scientific_name": "Presbytis melalophos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39813, + "scientific_name": "Presbytis mitrata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136500, + "scientific_name": "Presbytis natunae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39805, + "scientific_name": "Presbytis percura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39815, + "scientific_name": "Presbytis potenziani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39806, + "scientific_name": "Presbytis robinsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18131, + "scientific_name": "Presbytis rubicunda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39818, + "scientific_name": "Presbytis rubicunda ssp. carimatae", + "subspecies": "carimatae", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39819, + "scientific_name": "Presbytis rubicunda ssp. chrysea", + "subspecies": "chrysea", + "rank": "ssp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 39820, + "scientific_name": "Presbytis rubicunda ssp. ignita", + "subspecies": "ignita", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39817, + "scientific_name": "Presbytis rubicunda ssp. rubicunda", + "subspecies": "rubicunda", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136919, + "scientific_name": "Presbytis rubicunda ssp. rubida", + "subspecies": "rubida", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39810, + "scientific_name": "Presbytis sabana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18134, + "scientific_name": "Presbytis siamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39822, + "scientific_name": "Presbytis siamensis ssp. cana", + "subspecies": "cana", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39824, + "scientific_name": "Presbytis siamensis ssp. paenulata", + "subspecies": "paenulata", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39825, + "scientific_name": "Presbytis siamensis ssp. rhionis", + "subspecies": "rhionis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39821, + "scientific_name": "Presbytis siamensis ssp. siamensis", + "subspecies": "siamensis", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39816, + "scientific_name": "Presbytis siberu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136912, + "scientific_name": "Presbytis sumatranus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18132, + "scientific_name": "Presbytis thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18144, + "scientific_name": "Priodontes maximus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18146, + "scientific_name": "Prionailurus bengalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18151, + "scientific_name": "Prionailurus bengalensis ssp. iriomotensis", + "subspecies": "iriomotensis", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136889, + "scientific_name": "Prionailurus bengalensis ssp. rabori", + "subspecies": "rabori", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18148, + "scientific_name": "Prionailurus planiceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18149, + "scientific_name": "Prionailurus rubiginosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18150, + "scientific_name": "Prionailurus viverrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41705, + "scientific_name": "Prionodon linsang", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41706, + "scientific_name": "Prionodon pardicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18164, + "scientific_name": "Prionomys batesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18232, + "scientific_name": "Procapra gutturosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18231, + "scientific_name": "Procapra picticaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18230, + "scientific_name": "Procapra przewalskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41766, + "scientific_name": "Procavia capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18245, + "scientific_name": "Procolobus verus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41685, + "scientific_name": "Procyon cancrivorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41686, + "scientific_name": "Procyon lotor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18267, + "scientific_name": "Procyon pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18275, + "scientific_name": "Proechimys brevicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18276, + "scientific_name": "Proechimys canicollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18278, + "scientific_name": "Proechimys chrysaeolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18279, + "scientific_name": "Proechimys cuvieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18280, + "scientific_name": "Proechimys decumanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 29463, + "scientific_name": "Proechimys echinothrix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29466, + "scientific_name": "Proechimys gardneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18282, + "scientific_name": "Proechimys goeldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18284, + "scientific_name": "Proechimys guairae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18277, + "scientific_name": "Proechimys guyannensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18287, + "scientific_name": "Proechimys hoplomyoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29464, + "scientific_name": "Proechimys kulinae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18289, + "scientific_name": "Proechimys longicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18291, + "scientific_name": "Proechimys mincae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18293, + "scientific_name": "Proechimys oconnelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29465, + "scientific_name": "Proechimys pattoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18296, + "scientific_name": "Proechimys quadruplicatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18294, + "scientific_name": "Proechimys roberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18297, + "scientific_name": "Proechimys semispinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18299, + "scientific_name": "Proechimys simonsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18300, + "scientific_name": "Proechimys steerei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18301, + "scientific_name": "Proechimys trinitatis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18305, + "scientific_name": "Proedromys bedfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136459, + "scientific_name": "Proedromys liangshanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18338, + "scientific_name": "Prolagus sardus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 9674, + "scientific_name": "Prolemur simus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18339, + "scientific_name": "Prometheomys schaposchnikowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88087651, + "scientific_name": "Promops centralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88087551, + "scientific_name": "Promops davisoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18341, + "scientific_name": "Promops nasutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41293, + "scientific_name": "Pronolagus crassicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41294, + "scientific_name": "Pronolagus randensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41295, + "scientific_name": "Pronolagus rupestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136713, + "scientific_name": "Pronolagus saundersiae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18360, + "scientific_name": "Propithecus candidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18355, + "scientific_name": "Propithecus coquereli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18356, + "scientific_name": "Propithecus coronatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18357, + "scientific_name": "Propithecus deckenii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18358, + "scientific_name": "Propithecus diadema", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18359, + "scientific_name": "Propithecus edwardsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18361, + "scientific_name": "Propithecus perrieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18352, + "scientific_name": "Propithecus tattersalli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18354, + "scientific_name": "Propithecus verreauxi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18362, + "scientific_name": "Prosciurillus abstrusus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 112300360, + "scientific_name": "Prosciurillus alstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 112297404, + "scientific_name": "Prosciurillus leucomus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18364, + "scientific_name": "Prosciurillus murinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136574, + "scientific_name": "Prosciurillus rosenbergii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112298450, + "scientific_name": "Prosciurillus topapuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18365, + "scientific_name": "Prosciurillus weberi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18372, + "scientific_name": "Proteles cristata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13119, + "scientific_name": "Protochromys fellowsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18385, + "scientific_name": "Protoxerus aubinnii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18386, + "scientific_name": "Protoxerus stangeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18418, + "scientific_name": "Psammomys obesus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18419, + "scientific_name": "Psammomys vexillaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40636, + "scientific_name": "Pseudantechinus bilarni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40537, + "scientific_name": "Pseudantechinus macdonnellensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18447, + "scientific_name": "Pseudantechinus mimulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40538, + "scientific_name": "Pseudantechinus ningbing", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136620, + "scientific_name": "Pseudantechinus roryi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40539, + "scientific_name": "Pseudantechinus woolleyae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 46205597, + "scientific_name": "Pseudoberylmys muongbangensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18492, + "scientific_name": "Pseudocheirus occidentalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 40581, + "scientific_name": "Pseudocheirus peregrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18503, + "scientific_name": "Pseudochirops albertisii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18502, + "scientific_name": "Pseudochirops archeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18504, + "scientific_name": "Pseudochirops corinnae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40582, + "scientific_name": "Pseudochirops coronatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18505, + "scientific_name": "Pseudochirops cupreus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40638, + "scientific_name": "Pseudochirulus canescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18507, + "scientific_name": "Pseudochirulus caroli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18508, + "scientific_name": "Pseudochirulus cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40639, + "scientific_name": "Pseudochirulus forbesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18509, + "scientific_name": "Pseudochirulus herbertensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136699, + "scientific_name": "Pseudochirulus larvatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40640, + "scientific_name": "Pseudochirulus mayeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40641, + "scientific_name": "Pseudochirulus schlegeli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 45958680, + "scientific_name": "Pseudohydromys berniceae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48020754, + "scientific_name": "Pseudohydromys carlae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48265607, + "scientific_name": "Pseudohydromys eleanorae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48019838, + "scientific_name": "Pseudohydromys ellermani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14528, + "scientific_name": "Pseudohydromys fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136523, + "scientific_name": "Pseudohydromys germani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48265359, + "scientific_name": "Pseudohydromys murinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42646, + "scientific_name": "Pseudohydromys musseri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48266448, + "scientific_name": "Pseudohydromys occidentalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45958683, + "scientific_name": "Pseudohydromys patriciae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48020705, + "scientific_name": "Pseudohydromys pumehanae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45958686, + "scientific_name": "Pseudohydromys sandrae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 61513537, + "scientific_name": "Pseudois nayaur", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18535, + "scientific_name": "Pseudois nayaur ssp. schaeferi", + "subspecies": "schaeferi", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18558, + "scientific_name": "Pseudomys albocinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18559, + "scientific_name": "Pseudomys apodemoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 75927882, + "scientific_name": "Pseudomys auritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 75927871, + "scientific_name": "Pseudomys australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42647, + "scientific_name": "Pseudomys bolami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136808, + "scientific_name": "Pseudomys calabyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42648, + "scientific_name": "Pseudomys chapmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18561, + "scientific_name": "Pseudomys delicatulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18562, + "scientific_name": "Pseudomys desertor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18549, + "scientific_name": "Pseudomys fieldi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18550, + "scientific_name": "Pseudomys fumeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18564, + "scientific_name": "Pseudomys glaucus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 18551, + "scientific_name": "Pseudomys gouldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 18565, + "scientific_name": "Pseudomys gracilicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18566, + "scientific_name": "Pseudomys hermannsburgensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18567, + "scientific_name": "Pseudomys higginsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18568, + "scientific_name": "Pseudomys johnsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18570, + "scientific_name": "Pseudomys nanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18552, + "scientific_name": "Pseudomys novaehollandiae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18553, + "scientific_name": "Pseudomys occidentalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18554, + "scientific_name": "Pseudomys oralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18571, + "scientific_name": "Pseudomys patrius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18555, + "scientific_name": "Pseudomys pilligaensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18557, + "scientific_name": "Pseudomys shortridgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18596, + "scientific_name": "Pseudorca crassidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18597, + "scientific_name": "Pseudoryx nghetinhensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18598, + "scientific_name": "Pseudoryzomys simplex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18653, + "scientific_name": "Ptenochirus jagori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18654, + "scientific_name": "Ptenochirus minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18656, + "scientific_name": "Pteralopex anceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18657, + "scientific_name": "Pteralopex atrata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136587, + "scientific_name": "Pteralopex flanneryi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18658, + "scientific_name": "Pteralopex pulchra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 29473, + "scientific_name": "Pteralopex taki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18703, + "scientific_name": "Pteromyscus pulverulentus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18701, + "scientific_name": "Pteromys momonga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18702, + "scientific_name": "Pteromys volans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18705, + "scientific_name": "Pteronotus davyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18706, + "scientific_name": "Pteronotus gymnonotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18707, + "scientific_name": "Pteronotus macleayii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88018392, + "scientific_name": "Pteronotus mesoamericanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136610, + "scientific_name": "Pteronotus paraguanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 88017638, + "scientific_name": "Pteronotus parnellii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18709, + "scientific_name": "Pteronotus personatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18710, + "scientific_name": "Pteronotus quadridens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88018592, + "scientific_name": "Pteronotus rubiginosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18711, + "scientific_name": "Pteronura brasiliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18713, + "scientific_name": "Pteropus admiralitatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18714, + "scientific_name": "Pteropus aldabrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18715, + "scientific_name": "Pteropus alecto", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84882966, + "scientific_name": "Pteropus allenorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 18716, + "scientific_name": "Pteropus anetianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136504, + "scientific_name": "Pteropus aruensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18718, + "scientific_name": "Pteropus brunneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 18719, + "scientific_name": "Pteropus caniceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 84891540, + "scientific_name": "Pteropus capistratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 99688187, + "scientific_name": "Pteropus chrysoproctus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136397, + "scientific_name": "Pteropus cognatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18721, + "scientific_name": "Pteropus conspicillatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 84931267, + "scientific_name": "Pteropus coxi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 18722, + "scientific_name": "Pteropus dasymallus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 84883915, + "scientific_name": "Pteropus ennisae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18723, + "scientific_name": "Pteropus faunulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18724, + "scientific_name": "Pteropus fundatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18725, + "scientific_name": "Pteropus giganteus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18726, + "scientific_name": "Pteropus gilliardorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18727, + "scientific_name": "Pteropus griseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18728, + "scientific_name": "Pteropus howensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18729, + "scientific_name": "Pteropus hypomelanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136841, + "scientific_name": "Pteropus intermedius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136528, + "scientific_name": "Pteropus keyensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18732, + "scientific_name": "Pteropus livingstonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18733, + "scientific_name": "Pteropus lombocensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18773, + "scientific_name": "Pteropus loochoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18734, + "scientific_name": "Pteropus lylei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18735, + "scientific_name": "Pteropus macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18736, + "scientific_name": "Pteropus mahaganus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 188566753, + "scientific_name": "Pteropus mariannus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18739, + "scientific_name": "Pteropus melanopogon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18740, + "scientific_name": "Pteropus melanotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18741, + "scientific_name": "Pteropus molossinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18742, + "scientific_name": "Pteropus neohibernicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18743, + "scientific_name": "Pteropus niger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18744, + "scientific_name": "Pteropus nitendiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18745, + "scientific_name": "Pteropus ocularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18746, + "scientific_name": "Pteropus ornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 85043053, + "scientific_name": "Pteropus pelagicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 118093652, + "scientific_name": "Pteropus pelewensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136387, + "scientific_name": "Pteropus pelewensis ssp. pelewensis", + "subspecies": "pelewensis", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136246, + "scientific_name": "Pteropus pelewensis ssp. yapensis", + "subspecies": "yapensis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18747, + "scientific_name": "Pteropus personatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18749, + "scientific_name": "Pteropus pilosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 18750, + "scientific_name": "Pteropus pohlei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18751, + "scientific_name": "Pteropus poliocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18752, + "scientific_name": "Pteropus pselaphon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18753, + "scientific_name": "Pteropus pumilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18754, + "scientific_name": "Pteropus rayneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136685, + "scientific_name": "Pteropus rennelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18755, + "scientific_name": "Pteropus rodricensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18756, + "scientific_name": "Pteropus rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18757, + "scientific_name": "Pteropus samoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18758, + "scientific_name": "Pteropus scapulatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18759, + "scientific_name": "Pteropus seychellensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18760, + "scientific_name": "Pteropus speciosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18761, + "scientific_name": "Pteropus subniger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 18762, + "scientific_name": "Pteropus temminckii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18763, + "scientific_name": "Pteropus tokudae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 18764, + "scientific_name": "Pteropus tonganus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18765, + "scientific_name": "Pteropus tuberculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136531, + "scientific_name": "Pteropus ualanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 18766, + "scientific_name": "Pteropus vampyrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18767, + "scientific_name": "Pteropus vetulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18768, + "scientific_name": "Pteropus voeltzkowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 18769, + "scientific_name": "Pteropus woodfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41491, + "scientific_name": "Ptilocercus lowii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18847, + "scientific_name": "Pudu mephistophiles", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18848, + "scientific_name": "Pudu puda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18868, + "scientific_name": "Puma concolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136287, + "scientific_name": "Punomys kofordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 18880, + "scientific_name": "Punomys lemminus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41669, + "scientific_name": "Pusa caspica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41672, + "scientific_name": "Pusa hispida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41673, + "scientific_name": "Pusa hispida ssp. botnica", + "subspecies": "botnica", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61382318, + "scientific_name": "Pusa hispida ssp. hispida", + "subspecies": "hispida", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41674, + "scientific_name": "Pusa hispida ssp. ladogensis", + "subspecies": "ladogensis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41677, + "scientific_name": "Pusa hispida ssp. ochotensis", + "subspecies": "ochotensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41675, + "scientific_name": "Pusa hispida ssp. saimensis", + "subspecies": "saimensis", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41676, + "scientific_name": "Pusa sibirica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39827, + "scientific_name": "Pygathrix cinerea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39826, + "scientific_name": "Pygathrix nemaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39828, + "scientific_name": "Pygathrix nigripes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 18942, + "scientific_name": "Pygeretmus platyurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18943, + "scientific_name": "Pygeretmus pumilio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18944, + "scientific_name": "Pygeretmus zhitkovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18945, + "scientific_name": "Pygoderma bilabiatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29742, + "scientific_name": "Rangifer tarandus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19308, + "scientific_name": "Raphicerus campestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19306, + "scientific_name": "Raphicerus melanotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19307, + "scientific_name": "Raphicerus sharpei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19320, + "scientific_name": "Rattus adustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19361, + "scientific_name": "Rattus andamanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19321, + "scientific_name": "Rattus annandalei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136526, + "scientific_name": "Rattus arfakiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19322, + "scientific_name": "Rattus argentiventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136730, + "scientific_name": "Rattus arrogans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19323, + "scientific_name": "Rattus baluensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136580, + "scientific_name": "Rattus blangorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19324, + "scientific_name": "Rattus bontanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19325, + "scientific_name": "Rattus burrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19326, + "scientific_name": "Rattus colletti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112139816, + "scientific_name": "Rattus detentus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19327, + "scientific_name": "Rattus elaphinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19328, + "scientific_name": "Rattus enganus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19329, + "scientific_name": "Rattus everetti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19330, + "scientific_name": "Rattus exulans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19331, + "scientific_name": "Rattus feliceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19333, + "scientific_name": "Rattus fuscipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19318, + "scientific_name": "Rattus giluwensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19334, + "scientific_name": "Rattus hainaldi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19335, + "scientific_name": "Rattus hoffmanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19336, + "scientific_name": "Rattus hoogerwerfi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19337, + "scientific_name": "Rattus jobiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19338, + "scientific_name": "Rattus koopmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19339, + "scientific_name": "Rattus korinchi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19340, + "scientific_name": "Rattus leucopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19341, + "scientific_name": "Rattus losea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19342, + "scientific_name": "Rattus lugens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19343, + "scientific_name": "Rattus lutreolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19344, + "scientific_name": "Rattus macleari", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 19345, + "scientific_name": "Rattus marmosurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19346, + "scientific_name": "Rattus mindorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19347, + "scientific_name": "Rattus mollicomulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19348, + "scientific_name": "Rattus montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19349, + "scientific_name": "Rattus mordax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19350, + "scientific_name": "Rattus morotaiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19351, + "scientific_name": "Rattus nativitatis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 45958849, + "scientific_name": "Rattus nikenii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20758, + "scientific_name": "Rattus niobe", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19352, + "scientific_name": "Rattus nitidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19353, + "scientific_name": "Rattus norvegicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19354, + "scientific_name": "Rattus novaeguineae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136785, + "scientific_name": "Rattus omichlodes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19355, + "scientific_name": "Rattus osgoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19356, + "scientific_name": "Rattus palmarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19357, + "scientific_name": "Rattus pelurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136632, + "scientific_name": "Rattus pococki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19358, + "scientific_name": "Rattus praetor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19370, + "scientific_name": "Rattus pyctoris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19359, + "scientific_name": "Rattus ranjiniae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19360, + "scientific_name": "Rattus rattus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20759, + "scientific_name": "Rattus richardsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136700, + "scientific_name": "Rattus salocco", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136517, + "scientific_name": "Rattus satarae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19362, + "scientific_name": "Rattus simalurensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19363, + "scientific_name": "Rattus sordidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19364, + "scientific_name": "Rattus steini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19365, + "scientific_name": "Rattus stoicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19366, + "scientific_name": "Rattus tanezumi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19319, + "scientific_name": "Rattus tawitawiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19367, + "scientific_name": "Rattus timorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19368, + "scientific_name": "Rattus tiomanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19369, + "scientific_name": "Rattus tunneyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20760, + "scientific_name": "Rattus vandeuseni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 20761, + "scientific_name": "Rattus verecundus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19371, + "scientific_name": "Rattus villosissimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19372, + "scientific_name": "Rattus xanthurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19376, + "scientific_name": "Ratufa affinis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19377, + "scientific_name": "Ratufa bicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19378, + "scientific_name": "Ratufa indica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19381, + "scientific_name": "Ratufa macroura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19390, + "scientific_name": "Redunca arundinum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19391, + "scientific_name": "Redunca fulvorufula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19389, + "scientific_name": "Redunca fulvorufula ssp. adamauae", + "subspecies": "adamauae", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19393, + "scientific_name": "Redunca fulvorufula ssp. chanleri", + "subspecies": "chanleri", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19394, + "scientific_name": "Redunca fulvorufula ssp. fulvorufula", + "subspecies": "fulvorufula", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19392, + "scientific_name": "Redunca redunca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19399, + "scientific_name": "Reithrodon auritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136821, + "scientific_name": "Reithrodontomys bakeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19402, + "scientific_name": "Reithrodontomys brevirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19403, + "scientific_name": "Reithrodontomys burti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19404, + "scientific_name": "Reithrodontomys chrysopsis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19405, + "scientific_name": "Reithrodontomys creper", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19406, + "scientific_name": "Reithrodontomys darienensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19407, + "scientific_name": "Reithrodontomys fulvescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19408, + "scientific_name": "Reithrodontomys gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19409, + "scientific_name": "Reithrodontomys hirsutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42678, + "scientific_name": "Reithrodontomys humulis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19410, + "scientific_name": "Reithrodontomys megalotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19411, + "scientific_name": "Reithrodontomys mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19412, + "scientific_name": "Reithrodontomys microdon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19413, + "scientific_name": "Reithrodontomys montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45959367, + "scientific_name": "Reithrodontomys musseri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19414, + "scientific_name": "Reithrodontomys paradoxus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19401, + "scientific_name": "Reithrodontomys raviventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19415, + "scientific_name": "Reithrodontomys rodriguezi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19416, + "scientific_name": "Reithrodontomys spectabilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 19417, + "scientific_name": "Reithrodontomys sumichrasti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19418, + "scientific_name": "Reithrodontomys tenuirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19419, + "scientific_name": "Reithrodontomys zacatecae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136583, + "scientific_name": "Reithrodon typicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112166182, + "scientific_name": "Rhabdomys bechuanae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112168645, + "scientific_name": "Rhabdomys dilectus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112168732, + "scientific_name": "Rhabdomys intermedius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112168517, + "scientific_name": "Rhabdomys pumilio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136521, + "scientific_name": "Rhagomys longilingua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19454, + "scientific_name": "Rhagomys rufescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19474, + "scientific_name": "Rheithrosciurus macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19484, + "scientific_name": "Rheomys mexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19485, + "scientific_name": "Rheomys raptor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19486, + "scientific_name": "Rheomys thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19487, + "scientific_name": "Rheomys underwoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19495, + "scientific_name": "Rhinoceros sondaicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 19496, + "scientific_name": "Rhinoceros unicornis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19520, + "scientific_name": "Rhinolophus acuminatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19521, + "scientific_name": "Rhinolophus adami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19522, + "scientific_name": "Rhinolophus affinis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19523, + "scientific_name": "Rhinolophus alcyone", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84372137, + "scientific_name": "Rhinolophus arcuatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40023, + "scientific_name": "Rhinolophus beddomei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84372084, + "scientific_name": "Rhinolophus belligerator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19515, + "scientific_name": "Rhinolophus blasii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19526, + "scientific_name": "Rhinolophus bocharicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19527, + "scientific_name": "Rhinolophus borneensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19528, + "scientific_name": "Rhinolophus canuti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19529, + "scientific_name": "Rhinolophus capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19530, + "scientific_name": "Rhinolophus celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84372474, + "scientific_name": "Rhinolophus chiewkweeae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19531, + "scientific_name": "Rhinolophus clivosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19532, + "scientific_name": "Rhinolophus coelophyllus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19533, + "scientific_name": "Rhinolophus cognatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 64587154, + "scientific_name": "Rhinolophus cohenae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40037, + "scientific_name": "Rhinolophus convexus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19535, + "scientific_name": "Rhinolophus creaghi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 67369846, + "scientific_name": "Rhinolophus damarensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 67369483, + "scientific_name": "Rhinolophus darlingi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19537, + "scientific_name": "Rhinolophus deckenii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19538, + "scientific_name": "Rhinolophus denti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19539, + "scientific_name": "Rhinolophus eloquens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19516, + "scientific_name": "Rhinolophus euryale", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 84372418, + "scientific_name": "Rhinolophus euryotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19517, + "scientific_name": "Rhinolophus ferrumequinum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136644, + "scientific_name": "Rhinolophus formosae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19541, + "scientific_name": "Rhinolophus fumigatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19542, + "scientific_name": "Rhinolophus guineensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 64586080, + "scientific_name": "Rhinolophus hildebrandtii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44781, + "scientific_name": "Rhinolophus hilli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 44782, + "scientific_name": "Rhinolophus hillorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19518, + "scientific_name": "Rhinolophus hipposideros", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84372666, + "scientific_name": "Rhinolophus huananus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84376286, + "scientific_name": "Rhinolophus indorouxii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19545, + "scientific_name": "Rhinolophus inops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 82347204, + "scientific_name": "Rhinolophus kahuzi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19577, + "scientific_name": "Rhinolophus keyensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19546, + "scientific_name": "Rhinolophus landeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19547, + "scientific_name": "Rhinolophus lepidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19548, + "scientific_name": "Rhinolophus luctus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 64588047, + "scientific_name": "Rhinolophus mabuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19549, + "scientific_name": "Rhinolophus maclaudi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19550, + "scientific_name": "Rhinolophus macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136410, + "scientific_name": "Rhinolophus madurensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 44783, + "scientific_name": "Rhinolophus maendeleo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19551, + "scientific_name": "Rhinolophus malayanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19552, + "scientific_name": "Rhinolophus marshalli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84372245, + "scientific_name": "Rhinolophus mcintyrei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19553, + "scientific_name": "Rhinolophus megaphyllus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19519, + "scientific_name": "Rhinolophus mehelyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 84384558, + "scientific_name": "Rhinolophus microglobosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19554, + "scientific_name": "Rhinolophus mitratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136248, + "scientific_name": "Rhinolophus montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 64589126, + "scientific_name": "Rhinolophus mossambicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19556, + "scientific_name": "Rhinolophus nereis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19557, + "scientific_name": "Rhinolophus osgoodi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19558, + "scientific_name": "Rhinolophus paradoxolophus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19559, + "scientific_name": "Rhinolophus pearsonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85707170, + "scientific_name": "Rhinolophus perditus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19560, + "scientific_name": "Rhinolophus philippinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84372306, + "scientific_name": "Rhinolophus proconsulis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 85707059, + "scientific_name": "Rhinolophus pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19562, + "scientific_name": "Rhinolophus rex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136496, + "scientific_name": "Rhinolophus robinsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 84379218, + "scientific_name": "Rhinolophus rouxii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19564, + "scientific_name": "Rhinolophus rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 44784, + "scientific_name": "Rhinolophus ruwenzorii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44785, + "scientific_name": "Rhinolophus sakejiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 82347791, + "scientific_name": "Rhinolophus schnitzleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19565, + "scientific_name": "Rhinolophus sedulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19566, + "scientific_name": "Rhinolophus shameli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136631, + "scientific_name": "Rhinolophus shortridgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136651, + "scientific_name": "Rhinolophus siamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19567, + "scientific_name": "Rhinolophus silvestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19568, + "scientific_name": "Rhinolophus simulator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41529, + "scientific_name": "Rhinolophus sinicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 64588371, + "scientific_name": "Rhinolophus smithersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 84383122, + "scientific_name": "Rhinolophus stheno", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19570, + "scientific_name": "Rhinolophus subbadius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19571, + "scientific_name": "Rhinolophus subrufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19572, + "scientific_name": "Rhinolophus swinnyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84372447, + "scientific_name": "Rhinolophus tatar", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 82348077, + "scientific_name": "Rhinolophus thailandensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19573, + "scientific_name": "Rhinolophus thomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19574, + "scientific_name": "Rhinolophus trifoliatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19575, + "scientific_name": "Rhinolophus virgo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 82346260, + "scientific_name": "Rhinolophus willardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 82348701, + "scientific_name": "Rhinolophus xinanzhongguoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19576, + "scientific_name": "Rhinolophus yunanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44786, + "scientific_name": "Rhinolophus ziama", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19589, + "scientific_name": "Rhinonicteris aurantia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19591, + "scientific_name": "Rhinophylla alethina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19592, + "scientific_name": "Rhinophylla fischerae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19593, + "scientific_name": "Rhinophylla pumilio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19594, + "scientific_name": "Rhinopithecus avunculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 19597, + "scientific_name": "Rhinopithecus bieti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19595, + "scientific_name": "Rhinopithecus brelichi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 19596, + "scientific_name": "Rhinopithecus roxellana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39830, + "scientific_name": "Rhinopithecus roxellana ssp. hubeiensis", + "subspecies": "hubeiensis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39831, + "scientific_name": "Rhinopithecus roxellana ssp. qinlingensis", + "subspecies": "qinlingensis", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39829, + "scientific_name": "Rhinopithecus roxellana ssp. roxellana", + "subspecies": "roxellana", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13508501, + "scientific_name": "Rhinopithecus strykeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 82345555, + "scientific_name": "Rhinopoma cystops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 82345696, + "scientific_name": "Rhinopoma hadramauticum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 82345477, + "scientific_name": "Rhinopoma hardwickii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19601, + "scientific_name": "Rhinopoma macinnesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19600, + "scientific_name": "Rhinopoma microphyllum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19602, + "scientific_name": "Rhinopoma muscatellum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42460, + "scientific_name": "Rhinosciurus laticaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 113476528, + "scientific_name": "Rhipidomys albujai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19605, + "scientific_name": "Rhipidomys austrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136357, + "scientific_name": "Rhipidomys cariri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19606, + "scientific_name": "Rhipidomys caucensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19607, + "scientific_name": "Rhipidomys couesi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136195, + "scientific_name": "Rhipidomys emiliae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19608, + "scientific_name": "Rhipidomys fulviventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136759, + "scientific_name": "Rhipidomys gardneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47778330, + "scientific_name": "Rhipidomys ipukensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48297964, + "scientific_name": "Rhipidomys itoan", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19609, + "scientific_name": "Rhipidomys latimanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19610, + "scientific_name": "Rhipidomys leucodactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19611, + "scientific_name": "Rhipidomys macconnelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136422, + "scientific_name": "Rhipidomys macrurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19612, + "scientific_name": "Rhipidomys mastacalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136210, + "scientific_name": "Rhipidomys modicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47778059, + "scientific_name": "Rhipidomys nitela", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19614, + "scientific_name": "Rhipidomys ochrogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 48297988, + "scientific_name": "Rhipidomys tribei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19616, + "scientific_name": "Rhipidomys venezuelae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19617, + "scientific_name": "Rhipidomys venustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19618, + "scientific_name": "Rhipidomys wetzeli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19645, + "scientific_name": "Rhizomys pruinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19646, + "scientific_name": "Rhizomys sinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19647, + "scientific_name": "Rhizomys sumatrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136810, + "scientific_name": "Rhogeessa aeneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88151726, + "scientific_name": "Rhogeessa bickhami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19680, + "scientific_name": "Rhogeessa genowaysi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136220, + "scientific_name": "Rhogeessa hussoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88151760, + "scientific_name": "Rhogeessa io", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88151749, + "scientific_name": "Rhogeessa menchuae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19682, + "scientific_name": "Rhogeessa minutilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19683, + "scientific_name": "Rhogeessa mira", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19684, + "scientific_name": "Rhogeessa parvula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19685, + "scientific_name": "Rhogeessa tumida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88151777, + "scientific_name": "Rhogeessa velilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19686, + "scientific_name": "Rhombomys opimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19705, + "scientific_name": "Rhynchocyon chrysopygus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19709, + "scientific_name": "Rhynchocyon cirnei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19708, + "scientific_name": "Rhynchocyon petersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136309, + "scientific_name": "Rhynchocyon udzungwensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41623, + "scientific_name": "Rhynchogale melleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19710, + "scientific_name": "Rhyncholestes raphanurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19711, + "scientific_name": "Rhynchomeles prattorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136724, + "scientific_name": "Rhynchomys banahao", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19712, + "scientific_name": "Rhynchomys isarogensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19713, + "scientific_name": "Rhynchomys soricoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136489, + "scientific_name": "Rhynchomys tapulao", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19714, + "scientific_name": "Rhynchonycteris naso", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7935, + "scientific_name": "Rhyneptesicus nasutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19742, + "scientific_name": "Romerolagus diazi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 29730, + "scientific_name": "Rousettus aegyptiacus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19754, + "scientific_name": "Rousettus amplexicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19755, + "scientific_name": "Rousettus celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19758, + "scientific_name": "Rousettus lanosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19756, + "scientific_name": "Rousettus leschenaultii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136593, + "scientific_name": "Rousettus linduensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19750, + "scientific_name": "Rousettus madagascariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19757, + "scientific_name": "Rousettus obliviosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19751, + "scientific_name": "Rousettus spinalatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19762, + "scientific_name": "Rubrisciurus rubriventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4257, + "scientific_name": "Rucervus duvaucelii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 4265, + "scientific_name": "Rucervus eldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4288, + "scientific_name": "Rucervus schomburgki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 136791, + "scientific_name": "Rungwecebus kipunji", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19771, + "scientific_name": "Rupicapra pyrenaica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39255, + "scientific_name": "Rupicapra rupicapra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4273, + "scientific_name": "Rusa alfredi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4274, + "scientific_name": "Rusa marianna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41789, + "scientific_name": "Rusa timorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41790, + "scientific_name": "Rusa unicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19790, + "scientific_name": "Ruwenzorisorex suncoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19799, + "scientific_name": "Saccolaimus flaviventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19800, + "scientific_name": "Saccolaimus mixtus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19801, + "scientific_name": "Saccolaimus peli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19802, + "scientific_name": "Saccolaimus saccolaimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136420, + "scientific_name": "Saccopteryx antioquensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19804, + "scientific_name": "Saccopteryx bilineata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19805, + "scientific_name": "Saccopteryx canescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19806, + "scientific_name": "Saccopteryx gymnura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19807, + "scientific_name": "Saccopteryx leptura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19808, + "scientific_name": "Saccostomus campestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19809, + "scientific_name": "Saccostomus mearnsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40644, + "scientific_name": "Saguinus bicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41522, + "scientific_name": "Saguinus geoffroyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39948, + "scientific_name": "Saguinus imperator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19827, + "scientific_name": "Saguinus imperator ssp. imperator", + "subspecies": "imperator", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43962, + "scientific_name": "Saguinus imperator ssp. subgrisescens", + "subspecies": "subgrisescens", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41523, + "scientific_name": "Saguinus inustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41524, + "scientific_name": "Saguinus labiatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43959, + "scientific_name": "Saguinus labiatus ssp. labiatus", + "subspecies": "labiatus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43961, + "scientific_name": "Saguinus labiatus ssp. rufiventer", + "subspecies": "rufiventer", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43960, + "scientific_name": "Saguinus labiatus ssp. thomasi", + "subspecies": "thomasi", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19819, + "scientific_name": "Saguinus leucopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 42695, + "scientific_name": "Saguinus martinsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136888, + "scientific_name": "Saguinus martinsi ssp. martinsi", + "subspecies": "martinsi", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 43963, + "scientific_name": "Saguinus martinsi ssp. ochraceus", + "subspecies": "ochraceus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 135429, + "scientific_name": "Saguinus melanoleucus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41525, + "scientific_name": "Saguinus midas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41526, + "scientific_name": "Saguinus mystax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43956, + "scientific_name": "Saguinus mystax ssp. mystax", + "subspecies": "mystax", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43957, + "scientific_name": "Saguinus mystax ssp. pileatus", + "subspecies": "pileatus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43958, + "scientific_name": "Saguinus mystax ssp. pluto", + "subspecies": "pluto", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 160901052, + "scientific_name": "Saguinus niger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19823, + "scientific_name": "Saguinus oedipus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 70610874, + "scientific_name": "Saguinus ursulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19832, + "scientific_name": "Saiga tatarica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 19833, + "scientific_name": "Saiga tatarica ssp. mongolica", + "subspecies": "mongolica", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19834, + "scientific_name": "Saiga tatarica ssp. tatarica", + "subspecies": "tatarica", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41536, + "scientific_name": "Saimiri boliviensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43964, + "scientific_name": "Saimiri boliviensis ssp. boliviensis", + "subspecies": "boliviensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43965, + "scientific_name": "Saimiri boliviensis ssp. peruviensis", + "subspecies": "peruviensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 160940148, + "scientific_name": "Saimiri cassiquiarensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43969, + "scientific_name": "Saimiri cassiquiarensis ssp. albigena", + "subspecies": "albigena", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 43970, + "scientific_name": "Saimiri cassiquiarensis ssp. cassiquiarensis", + "subspecies": "cassiquiarensis", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43971, + "scientific_name": "Saimiri cassiquiarensis ssp. macrodon", + "subspecies": "macrodon", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70610928, + "scientific_name": "Saimiri collinsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19836, + "scientific_name": "Saimiri oerstedii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19841, + "scientific_name": "Saimiri oerstedii ssp. citrinellus", + "subspecies": "citrinellus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19840, + "scientific_name": "Saimiri oerstedii ssp. oerstedii", + "subspecies": "oerstedii", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 43968, + "scientific_name": "Saimiri sciureus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41538, + "scientific_name": "Saimiri ustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19839, + "scientific_name": "Saimiri vanzolinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 19852, + "scientific_name": "Salanoia concolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136228, + "scientific_name": "Salinomys delicatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19866, + "scientific_name": "Salpingotulus michaelis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19863, + "scientific_name": "Salpingotus crassicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19864, + "scientific_name": "Salpingotus heptneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19865, + "scientific_name": "Salpingotus kozlovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19867, + "scientific_name": "Salpingotus pallidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6664, + "scientific_name": "Santamartamys rufodorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 172351505, + "scientific_name": "Sapajus apella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43933, + "scientific_name": "Sapajus apella ssp. apella", + "subspecies": "apella", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4079, + "scientific_name": "Sapajus apella ssp. margaritae", + "subspecies": "margaritae", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136366, + "scientific_name": "Sapajus cay", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136253, + "scientific_name": "Sapajus flavius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136346, + "scientific_name": "Sapajus libidinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136717, + "scientific_name": "Sapajus nigritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 160945956, + "scientific_name": "Sapajus nigritus ssp. cucullatus", + "subspecies": "cucullatus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 160946025, + "scientific_name": "Sapajus nigritus ssp. nigritus", + "subspecies": "nigritus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42697, + "scientific_name": "Sapajus robustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 4074, + "scientific_name": "Sapajus xanthosternos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 40540, + "scientific_name": "Sarcophilus harrisii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44693, + "scientific_name": "Sauromys petrophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136806, + "scientific_name": "Saxatilomys paulinae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41471, + "scientific_name": "Scalopus aquaticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41472, + "scientific_name": "Scapanulus oweni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41473, + "scientific_name": "Scapanus latimanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41474, + "scientific_name": "Scapanus orarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41475, + "scientific_name": "Scapanus townsendii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136549, + "scientific_name": "Scapteromys aquaticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19945, + "scientific_name": "Scapteromys tumidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41476, + "scientific_name": "Scaptochirus moschatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41477, + "scientific_name": "Scaptonyx fusicaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47783095, + "scientific_name": "Scarturus elater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 854, + "scientific_name": "Scarturus euphratica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47781395, + "scientific_name": "Scarturus toussi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 860, + "scientific_name": "Scarturus vinogradovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136326, + "scientific_name": "Scarturus williamsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19997, + "scientific_name": "Sciurillus pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8785, + "scientific_name": "Sciurocheirus alleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 40001, + "scientific_name": "Sciurocheirus alleni ssp. alleni", + "subspecies": "alleni", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136854, + "scientific_name": "Sciurocheirus alleni ssp. cameronensis", + "subspecies": "cameronensis", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136214, + "scientific_name": "Sciurocheirus gabonensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 91979463, + "scientific_name": "Sciurocheirus makandensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19998, + "scientific_name": "Sciurotamias davidianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19999, + "scientific_name": "Sciurotamias forresti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42461, + "scientific_name": "Sciurus aberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20003, + "scientific_name": "Sciurus aestuans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20004, + "scientific_name": "Sciurus alleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20000, + "scientific_name": "Sciurus anomalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20005, + "scientific_name": "Sciurus arizonensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20006, + "scientific_name": "Sciurus aureogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42462, + "scientific_name": "Sciurus carolinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20007, + "scientific_name": "Sciurus colliaei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20001, + "scientific_name": "Sciurus deppei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20008, + "scientific_name": "Sciurus flammifer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20009, + "scientific_name": "Sciurus gilvigularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20010, + "scientific_name": "Sciurus granatensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20011, + "scientific_name": "Sciurus griseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20012, + "scientific_name": "Sciurus ignitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20013, + "scientific_name": "Sciurus igniventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20014, + "scientific_name": "Sciurus lis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20015, + "scientific_name": "Sciurus nayaritensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20016, + "scientific_name": "Sciurus niger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20017, + "scientific_name": "Sciurus oculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20018, + "scientific_name": "Sciurus pucheranii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20019, + "scientific_name": "Sciurus pyrrhinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20020, + "scientific_name": "Sciurus richmondi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20021, + "scientific_name": "Sciurus sanborni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20022, + "scientific_name": "Sciurus spadiceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20023, + "scientific_name": "Sciurus stramineus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20024, + "scientific_name": "Sciurus variegatoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20025, + "scientific_name": "Sciurus vulgaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20026, + "scientific_name": "Sciurus yucatanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20033, + "scientific_name": "Scleronycteris ega", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20036, + "scientific_name": "Scolomys melanops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20037, + "scientific_name": "Scolomys ucayalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14946, + "scientific_name": "Scoteanax rueppellii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20052, + "scientific_name": "Scotinomys teguina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20053, + "scientific_name": "Scotinomys xerampelinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20054, + "scientific_name": "Scotoecus albofuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20055, + "scientific_name": "Scotoecus hirundo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20056, + "scientific_name": "Scotoecus pallidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20058, + "scientific_name": "Scotomanes ornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84466436, + "scientific_name": "Scotonycteris bergmansi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84466273, + "scientific_name": "Scotonycteris occidentalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84464403, + "scientific_name": "Scotonycteris zenkeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 84466713, + "scientific_name": "Scotophilus andrewreborii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20064, + "scientific_name": "Scotophilus borbonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20065, + "scientific_name": "Scotophilus celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136612, + "scientific_name": "Scotophilus collinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20066, + "scientific_name": "Scotophilus dinganii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84466810, + "scientific_name": "Scotophilus ejetai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20067, + "scientific_name": "Scotophilus heathii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20068, + "scientific_name": "Scotophilus kuhlii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20069, + "scientific_name": "Scotophilus leucogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84466826, + "scientific_name": "Scotophilus livingstonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136774, + "scientific_name": "Scotophilus marovaza", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20070, + "scientific_name": "Scotophilus nigrita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44934, + "scientific_name": "Scotophilus nucella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20071, + "scientific_name": "Scotophilus nux", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20072, + "scientific_name": "Scotophilus robustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136675, + "scientific_name": "Scotophilus tandrefana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 84466859, + "scientific_name": "Scotophilus trujilloi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20073, + "scientific_name": "Scotophilus viridis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14942, + "scientific_name": "Scotorepens balstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14943, + "scientific_name": "Scotorepens greyii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14945, + "scientific_name": "Scotorepens orion", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14947, + "scientific_name": "Scotorepens sanborni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17338, + "scientific_name": "Scotozous dormeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41449, + "scientific_name": "Scutisorex somereni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 112390882, + "scientific_name": "Scutisorex thori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20089, + "scientific_name": "Sekeetamys calurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20102, + "scientific_name": "Selevinia betpakdalaensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 39833, + "scientific_name": "Semnopithecus ajax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39832, + "scientific_name": "Semnopithecus entellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39837, + "scientific_name": "Semnopithecus hector", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 167543916, + "scientific_name": "Semnopithecus hypoleucos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44723, + "scientific_name": "Semnopithecus hypoleucos ssp. achates", + "subspecies": "achates", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 167541339, + "scientific_name": "Semnopithecus hypoleucos ssp. hypoleucos", + "subspecies": "hypoleucos", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 167541667, + "scientific_name": "Semnopithecus hypoleucos ssp. iulus", + "subspecies": "iulus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44694, + "scientific_name": "Semnopithecus johnii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 167546892, + "scientific_name": "Semnopithecus priam", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39834, + "scientific_name": "Semnopithecus priam ssp. anchises", + "subspecies": "anchises", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39839, + "scientific_name": "Semnopithecus priam ssp. priam", + "subspecies": "priam", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39841, + "scientific_name": "Semnopithecus priam ssp. thersites", + "subspecies": "thersites", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39840, + "scientific_name": "Semnopithecus schistaceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22042, + "scientific_name": "Semnopithecus vetulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39843, + "scientific_name": "Semnopithecus vetulus ssp. monticola", + "subspecies": "monticola", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39844, + "scientific_name": "Semnopithecus vetulus ssp. nestor", + "subspecies": "nestor", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39845, + "scientific_name": "Semnopithecus vetulus ssp. philbricki", + "subspecies": "philbricki", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39842, + "scientific_name": "Semnopithecus vetulus ssp. vetulus", + "subspecies": "vetulus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40594, + "scientific_name": "Setifer setosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 71529901, + "scientific_name": "Setirostris eleryi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20165, + "scientific_name": "Setonix brachyurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20185, + "scientific_name": "Sicista armenica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 20184, + "scientific_name": "Sicista betulina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20186, + "scientific_name": "Sicista caucasica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20187, + "scientific_name": "Sicista caudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20188, + "scientific_name": "Sicista concolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20189, + "scientific_name": "Sicista kazbegica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 20196, + "scientific_name": "Sicista kluchorica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 110500058, + "scientific_name": "Sicista loriger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20190, + "scientific_name": "Sicista napaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20191, + "scientific_name": "Sicista pseudonapaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20192, + "scientific_name": "Sicista severtzovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20193, + "scientific_name": "Sicista strandi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 91934441, + "scientific_name": "Sicista subtilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20195, + "scientific_name": "Sicista tianshanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92332716, + "scientific_name": "Sicista trizona", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 115591937, + "scientific_name": "Sigmodon alleni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20210, + "scientific_name": "Sigmodon alstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20211, + "scientific_name": "Sigmodon arizonae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20212, + "scientific_name": "Sigmodon fulviventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136426, + "scientific_name": "Sigmodon hirsutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20213, + "scientific_name": "Sigmodon hispidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20214, + "scientific_name": "Sigmodon inopinatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20215, + "scientific_name": "Sigmodon leucotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20216, + "scientific_name": "Sigmodon mascotensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20217, + "scientific_name": "Sigmodon ochrognathus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20218, + "scientific_name": "Sigmodon peruanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136559, + "scientific_name": "Sigmodon toltecus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20221, + "scientific_name": "Sigmodontomys alfari", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20229, + "scientific_name": "Simias concolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39846, + "scientific_name": "Simias concolor ssp. concolor", + "subspecies": "concolor", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39847, + "scientific_name": "Simias concolor ssp. siberu", + "subspecies": "siberu", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 20296, + "scientific_name": "Sminthopsis archeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40551, + "scientific_name": "Sminthopsis bindi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20295, + "scientific_name": "Sminthopsis butleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40541, + "scientific_name": "Sminthopsis crassicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40542, + "scientific_name": "Sminthopsis dolichura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20290, + "scientific_name": "Sminthopsis douglasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20294, + "scientific_name": "Sminthopsis fuliginosus ssp. aitkeni", + "subspecies": "aitkeni", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 40543, + "scientific_name": "Sminthopsis gilberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41509, + "scientific_name": "Sminthopsis granulipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41510, + "scientific_name": "Sminthopsis griseoventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40544, + "scientific_name": "Sminthopsis hirtipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20297, + "scientific_name": "Sminthopsis leucopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40545, + "scientific_name": "Sminthopsis longicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40546, + "scientific_name": "Sminthopsis macroura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40547, + "scientific_name": "Sminthopsis murina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40548, + "scientific_name": "Sminthopsis ooldea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20293, + "scientific_name": "Sminthopsis psammophila", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40549, + "scientific_name": "Sminthopsis virginiae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40550, + "scientific_name": "Sminthopsis youngsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12762, + "scientific_name": "Smutsia gigantea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 12765, + "scientific_name": "Smutsia temminckii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20322, + "scientific_name": "Solenodon marcanoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 20321, + "scientific_name": "Solenodon paradoxus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20332, + "scientific_name": "Solisorex pearsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 20333, + "scientific_name": "Solomys ponceleti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 20334, + "scientific_name": "Solomys salamonis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20335, + "scientific_name": "Solomys salebrosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20336, + "scientific_name": "Solomys sapientis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136642, + "scientific_name": "Sommeromys macrorhinos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 135161, + "scientific_name": "Sooretamys angouya", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41384, + "scientific_name": "Sorex alaskanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29660, + "scientific_name": "Sorex alpinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136814, + "scientific_name": "Sorex antinorii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29661, + "scientific_name": "Sorex araneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41385, + "scientific_name": "Sorex arcticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20396, + "scientific_name": "Sorex arizonae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41386, + "scientific_name": "Sorex asper", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41387, + "scientific_name": "Sorex bairdi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41388, + "scientific_name": "Sorex bedfordiae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41389, + "scientific_name": "Sorex bendirii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41390, + "scientific_name": "Sorex buchariensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29662, + "scientific_name": "Sorex caecutiens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41391, + "scientific_name": "Sorex camtschatica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20383, + "scientific_name": "Sorex cansulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41392, + "scientific_name": "Sorex cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29663, + "scientific_name": "Sorex coronatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20384, + "scientific_name": "Sorex cylindricauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41393, + "scientific_name": "Sorex daphaenodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41394, + "scientific_name": "Sorex dispar", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41395, + "scientific_name": "Sorex emarginatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20385, + "scientific_name": "Sorex excelsus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41396, + "scientific_name": "Sorex fumeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41398, + "scientific_name": "Sorex gracillimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29664, + "scientific_name": "Sorex granarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41399, + "scientific_name": "Sorex haydeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20386, + "scientific_name": "Sorex hosonoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41400, + "scientific_name": "Sorex hoyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29665, + "scientific_name": "Sorex isodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136339, + "scientific_name": "Sorex ixtlanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20390, + "scientific_name": "Sorex jacksoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20387, + "scientific_name": "Sorex kozlovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20388, + "scientific_name": "Sorex leucogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41401, + "scientific_name": "Sorex longirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41402, + "scientific_name": "Sorex lyelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20392, + "scientific_name": "Sorex macrodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136779, + "scientific_name": "Sorex maritimensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136656, + "scientific_name": "Sorex mediopua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41403, + "scientific_name": "Sorex merriami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20397, + "scientific_name": "Sorex milleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 29666, + "scientific_name": "Sorex minutissimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29667, + "scientific_name": "Sorex minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41404, + "scientific_name": "Sorex mirabilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41405, + "scientific_name": "Sorex monticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41406, + "scientific_name": "Sorex nanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136608, + "scientific_name": "Sorex neomexicanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20393, + "scientific_name": "Sorex oreopolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136698, + "scientific_name": "Sorex orizabae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41408, + "scientific_name": "Sorex ornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41409, + "scientific_name": "Sorex pacificus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41410, + "scientific_name": "Sorex palustris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41411, + "scientific_name": "Sorex planiceps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41412, + "scientific_name": "Sorex portenkoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41413, + "scientific_name": "Sorex preblei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20391, + "scientific_name": "Sorex pribilofensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 29668, + "scientific_name": "Sorex raddei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41414, + "scientific_name": "Sorex roboratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136282, + "scientific_name": "Sorex rohweri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20411, + "scientific_name": "Sorex samniticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41415, + "scientific_name": "Sorex satunini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41416, + "scientific_name": "Sorex saussurei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20394, + "scientific_name": "Sorex sclateri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41417, + "scientific_name": "Sorex shinto", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20389, + "scientific_name": "Sorex sinalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41418, + "scientific_name": "Sorex sonomae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20395, + "scientific_name": "Sorex stizodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41419, + "scientific_name": "Sorex tenellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41420, + "scientific_name": "Sorex thibetanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41421, + "scientific_name": "Sorex trowbridgii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41422, + "scientific_name": "Sorex tundrensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41423, + "scientific_name": "Sorex ugyunak", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41424, + "scientific_name": "Sorex unguiculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41425, + "scientific_name": "Sorex vagrans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41426, + "scientific_name": "Sorex ventralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136811, + "scientific_name": "Sorex veraecrucis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41427, + "scientific_name": "Sorex veraepacis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29670, + "scientific_name": "Sorex volnuchini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136542, + "scientific_name": "Sorex yukonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136618, + "scientific_name": "Soricomys kalinga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 46205609, + "scientific_name": "Soricomys leonardocoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 47808962, + "scientific_name": "Soricomys montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29459, + "scientific_name": "Soricomys musseri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41434, + "scientific_name": "Soriculus nigrescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 190871, + "scientific_name": "Sotalia fluviatilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 181359, + "scientific_name": "Sotalia guianensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 82031425, + "scientific_name": "Sousa chinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 133710, + "scientific_name": "Sousa chinensis ssp. taiwanensis", + "subspecies": "taiwanensis", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 82031633, + "scientific_name": "Sousa plumbea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 82031667, + "scientific_name": "Sousa sahulensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20425, + "scientific_name": "Sousa teuszii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 20427, + "scientific_name": "Spalacopus cyanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 97250195, + "scientific_name": "Spalax antiquus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 20428, + "scientific_name": "Spalax arenarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 20429, + "scientific_name": "Spalax giganteus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 97249856, + "scientific_name": "Spalax graecus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 97250154, + "scientific_name": "Spalax istricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 20430, + "scientific_name": "Spalax microphthalmus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136581, + "scientific_name": "Spalax uralensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42655, + "scientific_name": "Spalax zemni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20468, + "scientific_name": "Speothos venaticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20471, + "scientific_name": "Spermophilopsis leptodactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20478, + "scientific_name": "Spermophilus alashanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136490, + "scientific_name": "Spermophilus brevicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20472, + "scientific_name": "Spermophilus citellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 20482, + "scientific_name": "Spermophilus dauricus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20483, + "scientific_name": "Spermophilus erythrogenys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20484, + "scientific_name": "Spermophilus fulvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20486, + "scientific_name": "Spermophilus major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42470, + "scientific_name": "Spermophilus musicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136231, + "scientific_name": "Spermophilus pallidicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20490, + "scientific_name": "Spermophilus pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136455, + "scientific_name": "Spermophilus ralli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20491, + "scientific_name": "Spermophilus relictus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20492, + "scientific_name": "Spermophilus suslicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136590, + "scientific_name": "Spermophilus taurensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20496, + "scientific_name": "Spermophilus xanthoprymnus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20521, + "scientific_name": "Sphaerias blanfordi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20599, + "scientific_name": "Sphaeronycteris toxophyllum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20637, + "scientific_name": "Spilocuscus kraemeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20636, + "scientific_name": "Spilocuscus maculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20638, + "scientific_name": "Spilocuscus papuensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20639, + "scientific_name": "Spilocuscus rufoniger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136443, + "scientific_name": "Spilocuscus wilsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136636, + "scientific_name": "Spilogale angustifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136797, + "scientific_name": "Spilogale gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41636, + "scientific_name": "Spilogale putorius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41637, + "scientific_name": "Spilogale pygmaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20688, + "scientific_name": "Srilankamys ohiensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136625, + "scientific_name": "Steatomys bocagei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20718, + "scientific_name": "Steatomys caurinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20719, + "scientific_name": "Steatomys cuppedius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20717, + "scientific_name": "Steatomys jacksoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20720, + "scientific_name": "Steatomys krebsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136513, + "scientific_name": "Steatomys opimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20721, + "scientific_name": "Steatomys parvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20722, + "scientific_name": "Steatomys pratensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20729, + "scientific_name": "Stenella attenuata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20730, + "scientific_name": "Stenella clymene", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20731, + "scientific_name": "Stenella coeruleoalba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 210188066, + "scientific_name": "Stenella coeruleoalba Gulf of Corinth subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Gulf of Corinth subpopulation", + "category": "EN" + }, + { + "taxonid": 16674437, + "scientific_name": "Stenella coeruleoalba Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mediterranean subpopulation", + "category": "LC" + }, + { + "taxonid": 20732, + "scientific_name": "Stenella frontalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20733, + "scientific_name": "Stenella longirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 133712, + "scientific_name": "Stenella longirostris ssp. orientalis", + "subspecies": "orientalis", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20738, + "scientific_name": "Steno bredanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 160158217, + "scientific_name": "Steno bredanensis Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mediterranean subpopulation", + "category": "NT" + }, + { + "taxonid": 45093, + "scientific_name": "Stenocephalemys albipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20740, + "scientific_name": "Stenocephalemys albocaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20741, + "scientific_name": "Stenocephalemys griseicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45096, + "scientific_name": "Stenocephalemys ruppi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20743, + "scientific_name": "Stenoderma rufum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20863, + "scientific_name": "Stochomys longicaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20890, + "scientific_name": "Strigocuscus celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20892, + "scientific_name": "Strigocuscus pelengensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88154322, + "scientific_name": "Sturnira angeli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20949, + "scientific_name": "Sturnira aratathomasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88152001, + "scientific_name": "Sturnira bakeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20950, + "scientific_name": "Sturnira bidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20951, + "scientific_name": "Sturnira bogotensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88152206, + "scientific_name": "Sturnira burtonlimi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20952, + "scientific_name": "Sturnira erythromos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88154577, + "scientific_name": "Sturnira hondurensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88159599, + "scientific_name": "Sturnira koopmanhilli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 88159688, + "scientific_name": "Sturnira lilium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88159722, + "scientific_name": "Sturnira ludovici", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20955, + "scientific_name": "Sturnira luisi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20956, + "scientific_name": "Sturnira magna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136591, + "scientific_name": "Sturnira mistratensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20957, + "scientific_name": "Sturnira mordax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20958, + "scientific_name": "Sturnira nana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136494, + "scientific_name": "Sturnira oporaphilum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88154376, + "scientific_name": "Sturnira parvidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88154558, + "scientific_name": "Sturnira paulsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 88159664, + "scientific_name": "Sturnira perla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136778, + "scientific_name": "Sturnira sorianoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20960, + "scientific_name": "Sturnira tildae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136534, + "scientific_name": "Styloctenium mindorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21100, + "scientific_name": "Styloctenium wallacei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 21101, + "scientific_name": "Stylodipus andrewsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21102, + "scientific_name": "Stylodipus sungorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21103, + "scientific_name": "Stylodipus telum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85537971, + "scientific_name": "Submyotodon latirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136224, + "scientific_name": "Suncus aequatorius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21141, + "scientific_name": "Suncus ater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21142, + "scientific_name": "Suncus dayi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 90389138, + "scientific_name": "Suncus etruscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21143, + "scientific_name": "Suncus fellowesgordoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21144, + "scientific_name": "Suncus hosei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45954392, + "scientific_name": "Suncus hututsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41437, + "scientific_name": "Suncus infinitesimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41438, + "scientific_name": "Suncus lixus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21145, + "scientific_name": "Suncus malayanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41446, + "scientific_name": "Suncus megalura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21146, + "scientific_name": "Suncus mertensi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21147, + "scientific_name": "Suncus montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41440, + "scientific_name": "Suncus murinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21140, + "scientific_name": "Suncus remyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41441, + "scientific_name": "Suncus stoliczkanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41442, + "scientific_name": "Suncus varilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21148, + "scientific_name": "Suncus zeylanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21150, + "scientific_name": "Sundamys infraluteus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21151, + "scientific_name": "Sundamys maxi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21152, + "scientific_name": "Sundamys muelleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21153, + "scientific_name": "Sundasciurus brookei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42565, + "scientific_name": "Sundasciurus davensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21154, + "scientific_name": "Sundasciurus fraterculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21155, + "scientific_name": "Sundasciurus hippurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42566, + "scientific_name": "Sundasciurus hoogstraali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21156, + "scientific_name": "Sundasciurus jentinki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21157, + "scientific_name": "Sundasciurus juvencus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21158, + "scientific_name": "Sundasciurus lowii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42567, + "scientific_name": "Sundasciurus mindanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21159, + "scientific_name": "Sundasciurus moellendorffi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 21160, + "scientific_name": "Sundasciurus philippinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21161, + "scientific_name": "Sundasciurus rabori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21162, + "scientific_name": "Sundasciurus samarensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21163, + "scientific_name": "Sundasciurus steerii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21164, + "scientific_name": "Sundasciurus tenuis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21134, + "scientific_name": "Surdisorex norae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21135, + "scientific_name": "Surdisorex polulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45954401, + "scientific_name": "Surdisorex schlitteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41624, + "scientific_name": "Suricata suricatta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21177, + "scientific_name": "Sus ahoenobarbus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41772, + "scientific_name": "Sus barbatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21171, + "scientific_name": "Sus barbatus ssp. oi", + "subspecies": "oi", + "rank": "ssp.", + "subpopulation": null, + "category": "LR/nt" + }, + { + "taxonid": 21178, + "scientific_name": "Sus bucculentus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 21175, + "scientific_name": "Sus cebifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41773, + "scientific_name": "Sus celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136340, + "scientific_name": "Sus oliveri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21176, + "scientific_name": "Sus philippensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41775, + "scientific_name": "Sus scrofa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21174, + "scientific_name": "Sus verrucosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 84697083, + "scientific_name": "Sus verrucosus ssp. blouchi", + "subspecies": "blouchi", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21185, + "scientific_name": "Syconycteris australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21184, + "scientific_name": "Syconycteris carolinae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 21183, + "scientific_name": "Syconycteris hobbit", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21203, + "scientific_name": "Sylvicapra grimmia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 142541491, + "scientific_name": "Sylvilagus andinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41296, + "scientific_name": "Sylvilagus aquaticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41297, + "scientific_name": "Sylvilagus audubonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41302, + "scientific_name": "Sylvilagus bachmani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87491102, + "scientific_name": "Sylvilagus brasiliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41309, + "scientific_name": "Sylvilagus cognatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21211, + "scientific_name": "Sylvilagus cunicularius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21209, + "scientific_name": "Sylvilagus dicei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41299, + "scientific_name": "Sylvilagus floridanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 87491157, + "scientific_name": "Sylvilagus gabbi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21206, + "scientific_name": "Sylvilagus graysoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21207, + "scientific_name": "Sylvilagus insonus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21210, + "scientific_name": "Sylvilagus mansuetus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41300, + "scientific_name": "Sylvilagus nuttallii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41301, + "scientific_name": "Sylvilagus obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 41303, + "scientific_name": "Sylvilagus palustris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41310, + "scientific_name": "Sylvilagus robustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 142642715, + "scientific_name": "Sylvilagus sanctaemartae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 142542759, + "scientific_name": "Sylvilagus tapetillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21212, + "scientific_name": "Sylvilagus transitionalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41311, + "scientific_name": "Sylvilagus varynaensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45954406, + "scientific_name": "Sylvisorex akaibei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45051, + "scientific_name": "Sylvisorex camerunensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 48294480, + "scientific_name": "Sylvisorex corbeti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41443, + "scientific_name": "Sylvisorex granti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21216, + "scientific_name": "Sylvisorex howelli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21220, + "scientific_name": "Sylvisorex isabellae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41444, + "scientific_name": "Sylvisorex johnstoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45050, + "scientific_name": "Sylvisorex konganensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41445, + "scientific_name": "Sylvisorex lunaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 21221, + "scientific_name": "Sylvisorex morio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 48294467, + "scientific_name": "Sylvisorex ollula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21222, + "scientific_name": "Sylvisorex oriundus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45049, + "scientific_name": "Sylvisorex pluvialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 45954439, + "scientific_name": "Sylvisorex silvanorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21219, + "scientific_name": "Sylvisorex vulcanorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39779, + "scientific_name": "Symphalangus syndactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42638, + "scientific_name": "Synaptomys borealis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42639, + "scientific_name": "Synaptomys cooperi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21251, + "scientific_name": "Syncerus caffer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 21260, + "scientific_name": "Syntheosciurus brochus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41312, + "scientific_name": "Tachyglossus aculeatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21293, + "scientific_name": "Tachyoryctes macrocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21299, + "scientific_name": "Tachyoryctes splendens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21312, + "scientific_name": "Tadarida aegyptiaca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21314, + "scientific_name": "Tadarida brasiliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21316, + "scientific_name": "Tadarida fulminans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136716, + "scientific_name": "Tadarida insignis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40036, + "scientific_name": "Tadarida latouchei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21317, + "scientific_name": "Tadarida lobata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21311, + "scientific_name": "Tadarida teniotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21318, + "scientific_name": "Tadarida ventralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21328, + "scientific_name": "Taeromys arcuatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21329, + "scientific_name": "Taeromys callitrichus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21330, + "scientific_name": "Taeromys celebensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21331, + "scientific_name": "Taeromys hamatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136654, + "scientific_name": "Taeromys microbullatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21332, + "scientific_name": "Taeromys punicans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21333, + "scientific_name": "Taeromys taerae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41478, + "scientific_name": "Talpa altaica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41479, + "scientific_name": "Talpa caeca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41480, + "scientific_name": "Talpa caucasica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135458, + "scientific_name": "Talpa davidiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41481, + "scientific_name": "Talpa europaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41482, + "scientific_name": "Talpa levantis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41483, + "scientific_name": "Talpa occidentalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41484, + "scientific_name": "Talpa romana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41485, + "scientific_name": "Talpa stankovici", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21349, + "scientific_name": "Tamandua mexicana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21350, + "scientific_name": "Tamandua tetradactyla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42586, + "scientific_name": "Tamiasciurus douglasii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42587, + "scientific_name": "Tamiasciurus hudsonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21378, + "scientific_name": "Tamiasciurus mearnsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42583, + "scientific_name": "Tamias striatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21380, + "scientific_name": "Tamiops maritimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21379, + "scientific_name": "Tamiops mcclellandii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21381, + "scientific_name": "Tamiops rodolphii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21382, + "scientific_name": "Tamiops swinhoei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20222, + "scientific_name": "Tanyuromys aphrastus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136772, + "scientific_name": "Tapecomys primus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21453, + "scientific_name": "Taphozous achates", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21452, + "scientific_name": "Taphozous australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 21454, + "scientific_name": "Taphozous georgianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21455, + "scientific_name": "Taphozous hamiltoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21456, + "scientific_name": "Taphozous hildegardeae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21457, + "scientific_name": "Taphozous hilli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21458, + "scientific_name": "Taphozous kapalgensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21459, + "scientific_name": "Taphozous longimanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21460, + "scientific_name": "Taphozous mauritianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21461, + "scientific_name": "Taphozous melanopogon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21462, + "scientific_name": "Taphozous nudiventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21463, + "scientific_name": "Taphozous perforatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21465, + "scientific_name": "Taphozous theobaldi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21466, + "scientific_name": "Taphozous troughtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21471, + "scientific_name": "Tapirus bairdii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21472, + "scientific_name": "Tapirus indicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21473, + "scientific_name": "Tapirus pinchaque", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21474, + "scientific_name": "Tapirus terrestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40583, + "scientific_name": "Tarsipes rostratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21489, + "scientific_name": "Tarsius dentatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 162369593, + "scientific_name": "Tarsius fuscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136319, + "scientific_name": "Tarsius lariang", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 162337005, + "scientific_name": "Tarsius niemitzi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21494, + "scientific_name": "Tarsius pelengensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21490, + "scientific_name": "Tarsius pumilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21493, + "scientific_name": "Tarsius sangirensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 162336422, + "scientific_name": "Tarsius spectrumgurskyae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 162336881, + "scientific_name": "Tarsius supriatnai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 162369551, + "scientific_name": "Tarsius tarsier", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 179234, + "scientific_name": "Tarsius tumpara", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 195277, + "scientific_name": "Tarsius wallacei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21495, + "scientific_name": "Tarsomys apoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21496, + "scientific_name": "Tarsomys echinatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21500, + "scientific_name": "Tasmacetus shepherdi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21507, + "scientific_name": "Tateomys macrocercus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21508, + "scientific_name": "Tateomys rhinogradoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21514, + "scientific_name": "Tatera indica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21521, + "scientific_name": "Taterillus arenarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21522, + "scientific_name": "Taterillus congicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21523, + "scientific_name": "Taterillus emini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21524, + "scientific_name": "Taterillus gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21526, + "scientific_name": "Taterillus lacustris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21527, + "scientific_name": "Taterillus petteri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21528, + "scientific_name": "Taterillus pygargus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45077, + "scientific_name": "Taterillus tranieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41663, + "scientific_name": "Taxidea taxus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41778, + "scientific_name": "Tayassu pecari", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40595, + "scientific_name": "Tenrec ecaudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21661, + "scientific_name": "Tetracerus quadricornis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40031, + "scientific_name": "Thainycteris aureocollaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21690, + "scientific_name": "Thallomys loringi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21691, + "scientific_name": "Thallomys nigricauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21692, + "scientific_name": "Thallomys paedulcus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21693, + "scientific_name": "Thallomys shortridgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21694, + "scientific_name": "Thalpomys cerradensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21695, + "scientific_name": "Thalpomys lasiotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21703, + "scientific_name": "Thamnomys kempi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 45078, + "scientific_name": "Thamnomys schoutedeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21702, + "scientific_name": "Thamnomys venustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 750, + "scientific_name": "Thaptomys nigrita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21744, + "scientific_name": "Theropithecus gelada", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136849, + "scientific_name": "Theropithecus gelada ssp. gelada", + "subspecies": "gelada", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40010, + "scientific_name": "Theropithecus gelada ssp. obscurus", + "subspecies": "obscurus", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 46675319, + "scientific_name": "Thomasomys andersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136667, + "scientific_name": "Thomasomys apeco", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96801180, + "scientific_name": "Thomasomys aureus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96790651, + "scientific_name": "Thomasomys auricularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 96791089, + "scientific_name": "Thomasomys australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21770, + "scientific_name": "Thomasomys baeops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21771, + "scientific_name": "Thomasomys bombycinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136413, + "scientific_name": "Thomasomys caudivarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96791166, + "scientific_name": "Thomasomys cinereiventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21773, + "scientific_name": "Thomasomys cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136822, + "scientific_name": "Thomasomys cinnameus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96792191, + "scientific_name": "Thomasomys contradictus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 96790818, + "scientific_name": "Thomasomys daphne", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96792239, + "scientific_name": "Thomasomys dispar", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21775, + "scientific_name": "Thomasomys eleusis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 96799858, + "scientific_name": "Thomasomys emeritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136345, + "scientific_name": "Thomasomys erro", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96800350, + "scientific_name": "Thomasomys fumeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21776, + "scientific_name": "Thomasomys gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136762, + "scientific_name": "Thomasomys hudsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21777, + "scientific_name": "Thomasomys hylophilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21778, + "scientific_name": "Thomasomys incanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21779, + "scientific_name": "Thomasomys ischyrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21780, + "scientific_name": "Thomasomys kalinowskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21781, + "scientific_name": "Thomasomys ladewi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96799835, + "scientific_name": "Thomasomys laniger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136480, + "scientific_name": "Thomasomys macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21783, + "scientific_name": "Thomasomys monochromos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 96801038, + "scientific_name": "Thomasomys nicefori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21784, + "scientific_name": "Thomasomys niveipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21785, + "scientific_name": "Thomasomys notatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136575, + "scientific_name": "Thomasomys onkiro", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21786, + "scientific_name": "Thomasomys oreas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21787, + "scientific_name": "Thomasomys paramorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 96800866, + "scientific_name": "Thomasomys popayanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136312, + "scientific_name": "Thomasomys praetor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 96801288, + "scientific_name": "Thomasomys princeps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 96789732, + "scientific_name": "Thomasomys pyrrhonotus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21790, + "scientific_name": "Thomasomys rosalinda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21791, + "scientific_name": "Thomasomys silvestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21792, + "scientific_name": "Thomasomys taczanowskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136487, + "scientific_name": "Thomasomys ucucha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21793, + "scientific_name": "Thomasomys vestitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 99693990, + "scientific_name": "Thomasomys vulcani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21799, + "scientific_name": "Thomomys bottae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42594, + "scientific_name": "Thomomys bulbivorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42595, + "scientific_name": "Thomomys clusius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21809, + "scientific_name": "Thomomys idahoensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21810, + "scientific_name": "Thomomys mazama", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42596, + "scientific_name": "Thomomys monticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42597, + "scientific_name": "Thomomys talpoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42598, + "scientific_name": "Thomomys townsendii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21800, + "scientific_name": "Thomomys umbrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21815, + "scientific_name": "Thoopterus nigrescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 84463939, + "scientific_name": "Thoopterus suhaniahae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21839, + "scientific_name": "Thrichomys apereoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136355, + "scientific_name": "Thrichomys inermis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 90386381, + "scientific_name": "Thrichomys laurentius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136245, + "scientific_name": "Thrichomys pachyurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21846, + "scientific_name": "Thryonomys gregorianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21847, + "scientific_name": "Thryonomys swinderianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21866, + "scientific_name": "Thylacinus cynocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 51343307, + "scientific_name": "Thylamys cinderella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199835, + "scientific_name": "Thylamys citellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40517, + "scientific_name": "Thylamys elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199836, + "scientific_name": "Thylamys fenestrae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136653, + "scientific_name": "Thylamys karimii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21867, + "scientific_name": "Thylamys macrurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14888655, + "scientific_name": "Thylamys pallidior", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199834, + "scientific_name": "Thylamys pulchellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 201936, + "scientific_name": "Thylamys pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136243, + "scientific_name": "Thylamys tatei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40520, + "scientific_name": "Thylamys velutinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136626, + "scientific_name": "Thylamys venustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40571, + "scientific_name": "Thylogale billardierii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21874, + "scientific_name": "Thylogale browni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21870, + "scientific_name": "Thylogale brunii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21873, + "scientific_name": "Thylogale calabyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136255, + "scientific_name": "Thylogale lanatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40574, + "scientific_name": "Thylogale stigmatica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40573, + "scientific_name": "Thylogale thetis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136594, + "scientific_name": "Thyroptera devivoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21877, + "scientific_name": "Thyroptera discifera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21878, + "scientific_name": "Thyroptera lavali", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 21879, + "scientific_name": "Thyroptera tricolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88151033, + "scientific_name": "Thyroptera wynneae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 12813, + "scientific_name": "Tlacuatzin canescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21972, + "scientific_name": "Tokudaia muenninki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 21973, + "scientific_name": "Tokudaia osimensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136695, + "scientific_name": "Tokudaia tokunoshimensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21974, + "scientific_name": "Tolypeutes matacus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 21975, + "scientific_name": "Tolypeutes tricinctus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21982, + "scientific_name": "Tomopeas ravus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 21983, + "scientific_name": "Tonatia bidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41530, + "scientific_name": "Tonatia saurophila", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136342, + "scientific_name": "Tonkinomys daovantieni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 6981, + "scientific_name": "Toromys grandis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 90386329, + "scientific_name": "Toromys rhipidurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22029, + "scientific_name": "Trachops cirrhosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39848, + "scientific_name": "Trachypithecus auratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 41554, + "scientific_name": "Trachypithecus barbei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136920, + "scientific_name": "Trachypithecus crepusculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22035, + "scientific_name": "Trachypithecus cristatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136914, + "scientific_name": "Trachypithecus cristatus ssp. cristatus", + "subspecies": "cristatus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136918, + "scientific_name": "Trachypithecus cristatus ssp. vigilans", + "subspecies": "vigilans", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22043, + "scientific_name": "Trachypithecus delacouri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39853, + "scientific_name": "Trachypithecus francoisi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22037, + "scientific_name": "Trachypithecus geei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39874, + "scientific_name": "Trachypithecus germaini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 40789, + "scientific_name": "Trachypithecus hatinhensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22044, + "scientific_name": "Trachypithecus laotum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39872, + "scientific_name": "Trachypithecus leucocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 39875, + "scientific_name": "Trachypithecus margarita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39849, + "scientific_name": "Trachypithecus mauritius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22039, + "scientific_name": "Trachypithecus obscurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39857, + "scientific_name": "Trachypithecus obscurus ssp. carbo", + "subspecies": "carbo", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39859, + "scientific_name": "Trachypithecus obscurus ssp. flavicauda", + "subspecies": "flavicauda", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39860, + "scientific_name": "Trachypithecus obscurus ssp. halonifer", + "subspecies": "halonifer", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39856, + "scientific_name": "Trachypithecus obscurus ssp. obscurus", + "subspecies": "obscurus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39861, + "scientific_name": "Trachypithecus obscurus ssp. sanctorum", + "subspecies": "sanctorum", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39862, + "scientific_name": "Trachypithecus obscurus ssp. seimundi", + "subspecies": "seimundi", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39865, + "scientific_name": "Trachypithecus obscurus ssp. styx", + "subspecies": "styx", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 175862145, + "scientific_name": "Trachypithecus phayrei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136928, + "scientific_name": "Trachypithecus phayrei ssp. phayrei", + "subspecies": "phayrei", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39863, + "scientific_name": "Trachypithecus phayrei ssp. shanicus", + "subspecies": "shanicus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22041, + "scientific_name": "Trachypithecus pileatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39867, + "scientific_name": "Trachypithecus pileatus ssp. brahma", + "subspecies": "brahma", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 195360310, + "scientific_name": "Trachypithecus pileatus ssp. pileatus", + "subspecies": "pileatus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39870, + "scientific_name": "Trachypithecus pileatus ssp. tenebricus", + "subspecies": "tenebricus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39871, + "scientific_name": "Trachypithecus poliocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 196344474, + "scientific_name": "Trachypithecus popa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 205911038, + "scientific_name": "Trachypithecus selangorensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39869, + "scientific_name": "Trachypithecus shortridgei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22052, + "scientific_name": "Tragelaphus angasii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22046, + "scientific_name": "Tragelaphus buxtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44172, + "scientific_name": "Tragelaphus derbianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22056, + "scientific_name": "Tragelaphus derbianus ssp. derbianus", + "subspecies": "derbianus", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22059, + "scientific_name": "Tragelaphus derbianus ssp. gigas", + "subspecies": "gigas", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22047, + "scientific_name": "Tragelaphus eurycerus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22058, + "scientific_name": "Tragelaphus eurycerus ssp. eurycerus", + "subspecies": "eurycerus", + "rank": "ssp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22057, + "scientific_name": "Tragelaphus eurycerus ssp. isaaci", + "subspecies": "isaaci", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22053, + "scientific_name": "Tragelaphus imberbis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22055, + "scientific_name": "Tragelaphus oryx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22051, + "scientific_name": "Tragelaphus scriptus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22050, + "scientific_name": "Tragelaphus spekii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22054, + "scientific_name": "Tragelaphus strepsiceros", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41780, + "scientific_name": "Tragulus javanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136297, + "scientific_name": "Tragulus kanchil", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41781, + "scientific_name": "Tragulus napu", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22065, + "scientific_name": "Tragulus nigricans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136360, + "scientific_name": "Tragulus versicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136533, + "scientific_name": "Tragulus williamsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 15588, + "scientific_name": "Transandinomys bolivaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15615, + "scientific_name": "Transandinomys talamancae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22066, + "scientific_name": "Tremarctos ornatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 81081036, + "scientific_name": "Triaenops afer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81082829, + "scientific_name": "Triaenops parvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 81069403, + "scientific_name": "Triaenops persicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40026, + "scientific_name": "Triaenops rufus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22102, + "scientific_name": "Trichechus inunguis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22103, + "scientific_name": "Trichechus manatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22106, + "scientific_name": "Trichechus manatus ssp. latirostris", + "subspecies": "latirostris", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22105, + "scientific_name": "Trichechus manatus ssp. manatus", + "subspecies": "manatus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22104, + "scientific_name": "Trichechus senegalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 40557, + "scientific_name": "Trichosurus caninus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136256, + "scientific_name": "Trichosurus cunninghami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40585, + "scientific_name": "Trichosurus vulpecula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22132, + "scientific_name": "Trichys fasciculata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18272, + "scientific_name": "Trinomys albispinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18281, + "scientific_name": "Trinomys dimidiatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136407, + "scientific_name": "Trinomys eliasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136221, + "scientific_name": "Trinomys gratiosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18288, + "scientific_name": "Trinomys iheringi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136305, + "scientific_name": "Trinomys mirapitanga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136543, + "scientific_name": "Trinomys moojeni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136492, + "scientific_name": "Trinomys paratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 18298, + "scientific_name": "Trinomys setosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136414, + "scientific_name": "Trinomys yonenagae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 13381, + "scientific_name": "Trinycteris nicefori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22297, + "scientific_name": "Trogopterus xanthipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22431, + "scientific_name": "Tryphomys adustus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22432, + "scientific_name": "Tscherskia triton", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41492, + "scientific_name": "Tupaia belangeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22446, + "scientific_name": "Tupaia chrysogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 111873499, + "scientific_name": "Tupaia discolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41493, + "scientific_name": "Tupaia dorsalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22784, + "scientific_name": "Tupaia everetti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111873543, + "scientific_name": "Tupaia ferruginea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 111872341, + "scientific_name": "Tupaia glis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41495, + "scientific_name": "Tupaia gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111873049, + "scientific_name": "Tupaia hypochrysa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41496, + "scientific_name": "Tupaia javanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111871214, + "scientific_name": "Tupaia longipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41497, + "scientific_name": "Tupaia minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41498, + "scientific_name": "Tupaia montana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22454, + "scientific_name": "Tupaia nicobarica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 110678346, + "scientific_name": "Tupaia palawanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41499, + "scientific_name": "Tupaia picta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 111871663, + "scientific_name": "Tupaia salatana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41500, + "scientific_name": "Tupaia splendidula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41501, + "scientific_name": "Tupaia tana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41714, + "scientific_name": "Tursiops aduncus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22563, + "scientific_name": "Tursiops truncatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194300, + "scientific_name": "Tursiops truncatus Fiordland subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Fiordland subpopulation", + "category": "CR" + }, + { + "taxonid": 181208820, + "scientific_name": "Tursiops truncatus Gulf of Ambracia subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Gulf of Ambracia subpopulation", + "category": "CR" + }, + { + "taxonid": 16369383, + "scientific_name": "Tursiops truncatus Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mediterranean subpopulation", + "category": "LC" + }, + { + "taxonid": 134822416, + "scientific_name": "Tursiops truncatus ssp. gephyreus", + "subspecies": "gephyreus", + "rank": "ssp.", + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 133714, + "scientific_name": "Tursiops truncatus ssp. ponticus", + "subspecies": "ponticus", + "rank": "ssp.", + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22570, + "scientific_name": "Tylomys bullaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22571, + "scientific_name": "Tylomys fulviventer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22572, + "scientific_name": "Tylomys mirae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22573, + "scientific_name": "Tylomys nudicaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22574, + "scientific_name": "Tylomys panamensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22575, + "scientific_name": "Tylomys tumbalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22576, + "scientific_name": "Tylomys watsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22577, + "scientific_name": "Tylonycteris pachypus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85342580, + "scientific_name": "Tylonycteris pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22578, + "scientific_name": "Tylonycteris robustula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136557, + "scientific_name": "Tympanoctomys aureus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22586, + "scientific_name": "Tympanoctomys barrerae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 86051353, + "scientific_name": "Tympanoctomys kirchnerorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136714, + "scientific_name": "Tympanoctomys loschalchalerosorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22605, + "scientific_name": "Typhlomys cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22771, + "scientific_name": "Uranomys ruddi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42463, + "scientific_name": "Urocitellus armatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42464, + "scientific_name": "Urocitellus beldingi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20497, + "scientific_name": "Urocitellus brunneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42465, + "scientific_name": "Urocitellus canus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42466, + "scientific_name": "Urocitellus columbianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42467, + "scientific_name": "Urocitellus elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20498, + "scientific_name": "Urocitellus endemicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 116989381, + "scientific_name": "Urocitellus mollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 116989724, + "scientific_name": "Urocitellus nancyae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20488, + "scientific_name": "Urocitellus parryii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42561, + "scientific_name": "Urocitellus richardsonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20476, + "scientific_name": "Urocitellus townsendii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20494, + "scientific_name": "Urocitellus undulatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20475, + "scientific_name": "Urocitellus washingtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22780, + "scientific_name": "Urocyon cinereoargenteus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22781, + "scientific_name": "Urocyon littoralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22782, + "scientific_name": "Uroderma bilobatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22783, + "scientific_name": "Uroderma magnirostrum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22800, + "scientific_name": "Uromys anak", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136773, + "scientific_name": "Uromys boeadii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22801, + "scientific_name": "Uromys caudimaculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136470, + "scientific_name": "Uromys emmae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22802, + "scientific_name": "Uromys hadrourus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22803, + "scientific_name": "Uromys imperator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22804, + "scientific_name": "Uromys neobritannicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22805, + "scientific_name": "Uromys porculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22806, + "scientific_name": "Uromys rex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136493, + "scientific_name": "Uromys siebersi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 120569706, + "scientific_name": "Uromys vika", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41486, + "scientific_name": "Uropsilus andersoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 41487, + "scientific_name": "Uropsilus gracilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22809, + "scientific_name": "Uropsilus investigator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22810, + "scientific_name": "Uropsilus soricipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41489, + "scientific_name": "Urotrichus talpoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41687, + "scientific_name": "Ursus americanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41688, + "scientific_name": "Ursus arctos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22823, + "scientific_name": "Ursus maritimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22824, + "scientific_name": "Ursus thibetanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22839, + "scientific_name": "Vampyressa melissa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22841, + "scientific_name": "Vampyressa pusilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136671, + "scientific_name": "Vampyressa thyone", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22837, + "scientific_name": "Vampyriscus bidens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22838, + "scientific_name": "Vampyriscus brocki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22840, + "scientific_name": "Vampyriscus nymphaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88151904, + "scientific_name": "Vampyrodes caraccioli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 88151984, + "scientific_name": "Vampyrodes major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22843, + "scientific_name": "Vampyrum spectrum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136372, + "scientific_name": "Vandeleuria nilagirica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22844, + "scientific_name": "Vandeleuria nolthenii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22845, + "scientific_name": "Vandeleuria oleracea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22920, + "scientific_name": "Varecia rubra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22918, + "scientific_name": "Varecia variegata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136895, + "scientific_name": "Varecia variegata ssp. editorum", + "subspecies": "editorum", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136934, + "scientific_name": "Varecia variegata ssp. subcincta", + "subspecies": "subcincta", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22919, + "scientific_name": "Varecia variegata ssp. variegata", + "subspecies": "variegata", + "rank": "ssp.", + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22933, + "scientific_name": "Vernaya fulva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7913, + "scientific_name": "Vespadelus baverstocki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7919, + "scientific_name": "Vespadelus caurinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7920, + "scientific_name": "Vespadelus darlingtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7923, + "scientific_name": "Vespadelus douglasorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7924, + "scientific_name": "Vespadelus finlaysoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7938, + "scientific_name": "Vespadelus pumilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7939, + "scientific_name": "Vespadelus regulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7944, + "scientific_name": "Vespadelus troughtoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7945, + "scientific_name": "Vespadelus vulturnus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22947, + "scientific_name": "Vespertilio murinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22949, + "scientific_name": "Vespertilio sinensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22956, + "scientific_name": "Vicugna vicugna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23036, + "scientific_name": "Viverra civettina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41707, + "scientific_name": "Viverra megaspila", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 41708, + "scientific_name": "Viverra tangalunga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41709, + "scientific_name": "Viverra zibetha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41710, + "scientific_name": "Viverricula indica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165925, + "scientific_name": "Voalavo antsahabensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 29461, + "scientific_name": "Voalavo gymnocaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23043, + "scientific_name": "Volemys millicens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 23044, + "scientific_name": "Volemys musseri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40556, + "scientific_name": "Vombatus ursinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29680, + "scientific_name": "Vormela peregusna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 23049, + "scientific_name": "Vulpes bengalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23050, + "scientific_name": "Vulpes cana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23060, + "scientific_name": "Vulpes chama", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23051, + "scientific_name": "Vulpes corsac", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23061, + "scientific_name": "Vulpes ferrilata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 899, + "scientific_name": "Vulpes lagopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41587, + "scientific_name": "Vulpes macrotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23052, + "scientific_name": "Vulpes pallida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23053, + "scientific_name": "Vulpes rueppellii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23059, + "scientific_name": "Vulpes velox", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23062, + "scientific_name": "Vulpes vulpes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41588, + "scientific_name": "Vulpes zerda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 92441666, + "scientific_name": "Waiomys mamasae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 40575, + "scientific_name": "Wallabia bicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136745, + "scientific_name": "Wiedomys cerradensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 23076, + "scientific_name": "Wiedomys pyrrhorhinos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23077, + "scientific_name": "Wilfredomys oenax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 23091, + "scientific_name": "Wyulda squamicaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 23115, + "scientific_name": "Xenomys nelsoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 136515, + "scientific_name": "Xenothrix mcgregori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 23137, + "scientific_name": "Xenuromys barbatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23141, + "scientific_name": "Xeromys myoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 136321, + "scientific_name": "Xeronycteris vieirai", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20474, + "scientific_name": "Xerospermophilus mohavensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 20489, + "scientific_name": "Xerospermophilus perotensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42563, + "scientific_name": "Xerospermophilus spilosoma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20493, + "scientific_name": "Xerospermophilus tereticaudus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23144, + "scientific_name": "Xerus erythropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23145, + "scientific_name": "Xerus inauris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23146, + "scientific_name": "Xerus princeps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23147, + "scientific_name": "Xerus rutilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23178, + "scientific_name": "Zaedyus pichiy", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 136322, + "scientific_name": "Zaglossus attenboroughi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 136552, + "scientific_name": "Zaglossus bartoni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 23179, + "scientific_name": "Zaglossus bruijnii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 41666, + "scientific_name": "Zalophus californianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41667, + "scientific_name": "Zalophus japonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EX" + }, + { + "taxonid": 41668, + "scientific_name": "Zalophus wollebaeki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42613, + "scientific_name": "Zapus hudsonius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42614, + "scientific_name": "Zapus princeps", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23192, + "scientific_name": "Zapus trinotatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23197, + "scientific_name": "Zelotomys hildegardeae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23196, + "scientific_name": "Zelotomys woosnami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23204, + "scientific_name": "Zenkerella insignis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23211, + "scientific_name": "Ziphius cavirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16381144, + "scientific_name": "Ziphius cavirostris Mediterranean subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Mediterranean subpopulation", + "category": "VU" + }, + { + "taxonid": 23321, + "scientific_name": "Zygodontomys brevicauda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23322, + "scientific_name": "Zygodontomys brunneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23323, + "scientific_name": "Zygogeomys trichopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 23325, + "scientific_name": "Zyzomys argurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23326, + "scientific_name": "Zyzomys maini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 23327, + "scientific_name": "Zyzomys palatalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 23324, + "scientific_name": "Zyzomys pedunculatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 23328, + "scientific_name": "Zyzomys woodwardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/comp-group/list": { + "count": 31, + "result": [ + { + "group_name": "reef_building_corals" + }, + { + "group_name": "chameleons" + }, + { + "group_name": "mammals" + }, + { + "group_name": "mangrove_plants" + }, + { + "group_name": "seagrasses" + }, + { + "group_name": "cycads" + }, + { + "group_name": "blennies" + }, + { + "group_name": "cone_snails" + }, + { + "group_name": "magnolias" + }, + { + "group_name": "seasnakes" + }, + { + "group_name": "fw_caridean_shrimps" + }, + { + "group_name": "fw_crayfish" + }, + { + "group_name": "tunas_and_billfishes" + }, + { + "group_name": "butterfly_fishes" + }, + { + "group_name": "groupers" + }, + { + "group_name": "pufferfishes" + }, + { + "group_name": "conifers" + }, + { + "group_name": "surgeonfishes" + }, + { + "group_name": "birds" + }, + { + "group_name": "crocodiles_and_alligators" + }, + { + "group_name": "sharks_and_rays" + }, + { + "group_name": "fw_crabs" + }, + { + "group_name": "cacti" + }, + { + "group_name": "tarpons_and_ladyfishes" + }, + { + "group_name": "sturgeons" + }, + { + "group_name": "angelfishes" + }, + { + "group_name": "lobsters" + }, + { + "group_name": "amphibians" + }, + { + "group_name": "seabreams_porgies_picarels" + }, + { + "group_name": "hagfishes" + }, + { + "group_name": "wrasses_and_parrotfishes" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/country/getspecies/AZ": { + "count": 1162, + "country": "AZ", + "result": [ + { + "taxonid": 42293, + "scientific_name": "Abies nordmanniana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 196098, + "scientific_name": "Abies nordmanniana subsp. nordmanniana", + "subspecies": "nordmanniana", + "rank": "subsp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 48839409, + "scientific_name": "Ablepharus bivittatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135696, + "scientific_name": "Abramis brama", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22725044, + "scientific_name": "Acanthis flammea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19017703, + "scientific_name": "Acanthobrama microlepis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695490, + "scientific_name": "Accipiter badius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695499, + "scientific_name": "Accipiter brevipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695683, + "scientific_name": "Accipiter gentilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695624, + "scientific_name": "Accipiter nisus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 193523, + "scientific_name": "Acer campestre", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 193525, + "scientific_name": "Acer cappadocicum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 193616, + "scientific_name": "Acer hyrcanum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 193835, + "scientific_name": "Acer monspessulanum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 193853, + "scientific_name": "Acer platanoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 193856, + "scientific_name": "Acer pseudoplatanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 193888, + "scientific_name": "Acer velutinum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199866, + "scientific_name": "Achnatherum roshevitzii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 232, + "scientific_name": "Acipenser gueldenstaedtii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 246, + "scientific_name": "Acipenser gueldenstaedtii Caspian Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Caspian Sea subpopulation", + "category": "CR" + }, + { + "taxonid": 225, + "scientific_name": "Acipenser nudiventris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 250, + "scientific_name": "Acipenser nudiventris Caspian Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Caspian Sea subpopulation", + "category": "CR" + }, + { + "taxonid": 235, + "scientific_name": "Acipenser persicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 227, + "scientific_name": "Acipenser ruthenus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 182582605, + "scientific_name": "Acipenser ruthenus Caspian Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Caspian Sea subpopulation", + "category": "VU" + }, + { + "taxonid": 229, + "scientific_name": "Acipenser stellatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 254, + "scientific_name": "Acipenser stellatus Caspian Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Caspian Sea subpopulation", + "category": "CR" + }, + { + "taxonid": 104317670, + "scientific_name": "Acrocephalus arundinaceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714693, + "scientific_name": "Acrocephalus melanopogon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714741, + "scientific_name": "Acrocephalus palustris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714700, + "scientific_name": "Acrocephalus schoenobaenus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714722, + "scientific_name": "Acrocephalus scirpaceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693264, + "scientific_name": "Actitis hypoleucos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172268, + "scientific_name": "Aegilops biuncialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172247, + "scientific_name": "Aegilops columnaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19208893, + "scientific_name": "Aegilops crassa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172218, + "scientific_name": "Aegilops cylindrica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172214, + "scientific_name": "Aegilops geniculata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19208905, + "scientific_name": "Aegilops juvenalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 172178, + "scientific_name": "Aegilops kotschyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172223, + "scientific_name": "Aegilops neglecta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172145, + "scientific_name": "Aegilops peregrina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 110433063, + "scientific_name": "Aegilops peregrina var. peregrina", + "subspecies": "peregrina", + "rank": "var.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172086, + "scientific_name": "Aegilops tauschii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172127, + "scientific_name": "Aegilops triuncialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 110433393, + "scientific_name": "Aegilops triuncialis var. triuncialis", + "subspecies": "triuncialis", + "rank": "var.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172255, + "scientific_name": "Aegilops umbellulata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172098, + "scientific_name": "Aegilops ventricosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103871923, + "scientific_name": "Aegithalos caudatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22689362, + "scientific_name": "Aegolius funereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695231, + "scientific_name": "Aegypius monachus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 158694, + "scientific_name": "Aeshna affinis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165524, + "scientific_name": "Aeshna cyanea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158692, + "scientific_name": "Aeshna isoceles", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165518, + "scientific_name": "Aeshna juncea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 126819440, + "scientific_name": "Aeshna vercanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 102998555, + "scientific_name": "Alauda arvensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 104007058, + "scientific_name": "Alaudala rufescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22717298, + "scientific_name": "Alauda leucoptera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 184454, + "scientific_name": "Alburnoides eichwaldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135499, + "scientific_name": "Alburnus chalcoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19018496, + "scientific_name": "Alburnus filippii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135532, + "scientific_name": "Alburnus hohenackeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22683027, + "scientific_name": "Alcedo atthis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199873, + "scientific_name": "Alchemilla jaroschenkoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22678691, + "scientific_name": "Alectoris chukar", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 163974, + "scientific_name": "Alisma lanceolatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172192, + "scientific_name": "Allium ampeloprasum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172241, + "scientific_name": "Allium atroviolaceum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 20666191, + "scientific_name": "Allium scabriscapum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 172256, + "scientific_name": "Allium schoenoprasum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194472, + "scientific_name": "Alnus incana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194249, + "scientific_name": "Alnus subcordata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164156, + "scientific_name": "Alopecurus aequalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 98468449, + "scientific_name": "Alosa braschnikowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 135548, + "scientific_name": "Alosa caspia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 98468550, + "scientific_name": "Alosa curensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 135537, + "scientific_name": "Alosa kessleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 98470302, + "scientific_name": "Alosa saposchnikowii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 98470350, + "scientific_name": "Alosa sphaerocephala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135559, + "scientific_name": "Alosa volgensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22678652, + "scientific_name": "Ammoperdix griseogularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199895, + "scientific_name": "Anabasis eugeniae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 199896, + "scientific_name": "Anacyclus ciliatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680301, + "scientific_name": "Anas acuta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680321, + "scientific_name": "Anas crecca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680186, + "scientific_name": "Anas platyrhynchos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156754995, + "scientific_name": "Anatirostrum profundorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 59812, + "scientific_name": "Anax imperator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165488, + "scientific_name": "Anax parthenope", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156181, + "scientific_name": "Ancylus fluviatilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 189408, + "scientific_name": "Anisus kolesnikovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 155814, + "scientific_name": "Anisus leucostoma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 188871, + "scientific_name": "Anodonta cyrea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22679881, + "scientific_name": "Anser albifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22679889, + "scientific_name": "Anser anser", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22679886, + "scientific_name": "Anser erythropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22692081, + "scientific_name": "Anthropoides virgo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718501, + "scientific_name": "Anthus campestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718560, + "scientific_name": "Anthus cervinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718556, + "scientific_name": "Anthus pratensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718571, + "scientific_name": "Anthus spinoletta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718546, + "scientific_name": "Anthus trivialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164203, + "scientific_name": "Apium graveolens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1888, + "scientific_name": "Apodemus agrarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1896, + "scientific_name": "Apodemus hyrcanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 1900, + "scientific_name": "Apodemus ponticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 1905, + "scientific_name": "Apodemus uralensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135724, + "scientific_name": "Apodemus witherbyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22686856, + "scientific_name": "Apus affinis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22686800, + "scientific_name": "Apus apus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696060, + "scientific_name": "Aquila chrysaetos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696076, + "scientific_name": "Aquila fasciata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696048, + "scientific_name": "Aquila heliaca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22696038, + "scientific_name": "Aquila nipalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 200622, + "scientific_name": "Arabis armena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19181048, + "scientific_name": "Arbutus andrachne", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697043, + "scientific_name": "Ardea alba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696993, + "scientific_name": "Ardea cinerea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697031, + "scientific_name": "Ardea purpurea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697123, + "scientific_name": "Ardeola ralloides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693336, + "scientific_name": "Arenaria interpres", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 64321666, + "scientific_name": "Argentina anserina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164340, + "scientific_name": "Arundo donax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2149, + "scientific_name": "Arvicola amphibius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22689531, + "scientific_name": "Asio flammeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22689507, + "scientific_name": "Asio otus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176377, + "scientific_name": "Asparagus officinalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176392, + "scientific_name": "Asparagus verticillatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199916, + "scientific_name": "Astragalus albanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 184928963, + "scientific_name": "Astragalus austriacus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19892262, + "scientific_name": "Astragalus cephalotes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19891983, + "scientific_name": "Astragalus commixtus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19378897, + "scientific_name": "Astragalus crenatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199928, + "scientific_name": "Astragalus cuscutae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 199947, + "scientific_name": "Astragalus igniarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 199950, + "scientific_name": "Astragalus kabristanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199935, + "scientific_name": "Astragalus kubensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 199915, + "scientific_name": "Astragalus maraziensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 199924, + "scientific_name": "Astragalus schachbuzensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 199942, + "scientific_name": "Astragalus stevenianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19378961, + "scientific_name": "Astragalus tribuloides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22689328, + "scientific_name": "Athene noctua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2352, + "scientific_name": "Atherina boyeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172049, + "scientific_name": "Avena fatua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172187, + "scientific_name": "Avena hybrida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 172204, + "scientific_name": "Avena sterilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680358, + "scientific_name": "Aythya ferina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22680391, + "scientific_name": "Aythya fuligula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680398, + "scientific_name": "Aythya marila", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680373, + "scientific_name": "Aythya nyroca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 188118, + "scientific_name": "Babka gymnotrachelus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199960, + "scientific_name": "Barbarea grandiflora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 43100527, + "scientific_name": "Barbarea plantaginea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2553, + "scientific_name": "Barbastella barbastellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 85181182, + "scientific_name": "Barbastella leucomelas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135607, + "scientific_name": "Barbus ciscaucasicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 168748, + "scientific_name": "Beckmannia syzigachne", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199964, + "scientific_name": "Bellis hyrcanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2761, + "scientific_name": "Benthophiloides brauneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 156757703, + "scientific_name": "Benthophilus abdurahmanovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156755278, + "scientific_name": "Benthophilus baeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156755702, + "scientific_name": "Benthophilus ctenolepidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135682, + "scientific_name": "Benthophilus granulosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156756575, + "scientific_name": "Benthophilus grimmi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 156756692, + "scientific_name": "Benthophilus kessleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135680, + "scientific_name": "Benthophilus leobergius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156756871, + "scientific_name": "Benthophilus leptocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156757038, + "scientific_name": "Benthophilus leptorhynchus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135656, + "scientific_name": "Benthophilus macrocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156755866, + "scientific_name": "Benthophilus pinchuki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 159639612, + "scientific_name": "Benthophilus ragimovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156758702, + "scientific_name": "Benthophilus spinosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 133732509, + "scientific_name": "Berberis integerrima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194521, + "scientific_name": "Betula pubescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194832, + "scientific_name": "Betula pubescens var. litwinowii", + "subspecies": "litwinowii", + "rank": "var.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 30748, + "scientific_name": "Betula raddeana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 168750, + "scientific_name": "Bidens tripartita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199965, + "scientific_name": "Bilacunaria caspia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 39270, + "scientific_name": "Blicca bjoerkna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164449, + "scientific_name": "Blysmus compressus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44792563, + "scientific_name": "Bolivaria brachyptera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22708146, + "scientific_name": "Bombycilla garrulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697346, + "scientific_name": "Botaurus stellaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22679954, + "scientific_name": "Branta ruficollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 170103, + "scientific_name": "Brassica elongata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 121972235, + "scientific_name": "Brassica elongata subsp. integrifolia", + "subspecies": "integrifolia", + "rank": "subsp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22688927, + "scientific_name": "Bubo bubo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697109, + "scientific_name": "Bubulcus ibis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720513, + "scientific_name": "Bucanetes githagineus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720520, + "scientific_name": "Bucanetes mongolicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680455, + "scientific_name": "Bucephala clangula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 190987, + "scientific_name": "Bufo eichwaldi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 153571, + "scientific_name": "Bufotes variabilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 39421, + "scientific_name": "Bufo verrucosissimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 70401726, + "scientific_name": "Buglossoporus quercinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 158275, + "scientific_name": "Bulbostylis hispidula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 199968, + "scientific_name": "Bupleurum wittmannii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 45111439, + "scientific_name": "Burhinus oedicnemus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61695117, + "scientific_name": "Buteo buteo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695973, + "scientific_name": "Buteo lagopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22736562, + "scientific_name": "Buteo rufinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 32177, + "scientific_name": "Buxus colchica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LR/nt" + }, + { + "taxonid": 202944, + "scientific_name": "Buxus sempervirens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103766207, + "scientific_name": "Calandrella brachydactyla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165467, + "scientific_name": "Caliaeschna microstigma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693369, + "scientific_name": "Calidris alba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693427, + "scientific_name": "Calidris alpina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693363, + "scientific_name": "Calidris canutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22693464, + "scientific_name": "Calidris falcinellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693431, + "scientific_name": "Calidris ferruginea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22693379, + "scientific_name": "Calidris minuta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693468, + "scientific_name": "Calidris pugnax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693388, + "scientific_name": "Calidris temminckii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3621, + "scientific_name": "Calomyscus mystax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3623, + "scientific_name": "Calomyscus urartensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158717, + "scientific_name": "Calopteryx orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158701, + "scientific_name": "Calopteryx splendens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 118264161, + "scientific_name": "Canis aureus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3746, + "scientific_name": "Canis lupus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19025492, + "scientific_name": "Capoeta capoeta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 137745831, + "scientific_name": "Capparis spinosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3786, + "scientific_name": "Capra aegagrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 3795, + "scientific_name": "Capra cylindricornis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42395, + "scientific_name": "Capreolus capreolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22689887, + "scientific_name": "Caprimulgus europaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 3849, + "scientific_name": "Carassius carassius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43100547, + "scientific_name": "Cardamine uliginosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103764950, + "scientific_name": "Carduelis carduelis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 175266, + "scientific_name": "Carex atherodes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19617663, + "scientific_name": "Carex diluta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164014, + "scientific_name": "Carex divisa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19617705, + "scientific_name": "Carex otrubae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19617758, + "scientific_name": "Carex pseudofoetida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164262, + "scientific_name": "Carex riparia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 167845, + "scientific_name": "Carex rostrata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194274, + "scientific_name": "Carpinus betulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194499, + "scientific_name": "Carpinus orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194500, + "scientific_name": "Carpinus orientalis subsp. macrocarpa", + "subspecies": "macrocarpa", + "rank": "subsp.", + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 194501, + "scientific_name": "Carpinus orientalis subsp. orientalis", + "subspecies": "orientalis", + "rank": "subsp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200026, + "scientific_name": "Carpoceras tatianae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22720556, + "scientific_name": "Carpodacus erythrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720610, + "scientific_name": "Carpodacus rubicilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718310, + "scientific_name": "Carpospiza brachydactyla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200029, + "scientific_name": "Carum komarovii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 189439, + "scientific_name": "Caspiohydrobia gemmata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 135706, + "scientific_name": "Caspiomyzon wagneri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 135622, + "scientific_name": "Caspiosoma caspium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 202948, + "scientific_name": "Castanea sativa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19218728, + "scientific_name": "Celtis australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 79913693, + "scientific_name": "Celtis planchoniana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 79913713, + "scientific_name": "Celtis tournefortii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18963206, + "scientific_name": "Cenchrus orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200567, + "scientific_name": "Centaurea daralagoezica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 202950, + "scientific_name": "Centaurium erythraea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4166, + "scientific_name": "Cerambyx cerdo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 200052, + "scientific_name": "Cerastium szowitsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 163995, + "scientific_name": "Ceratophyllum muricatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22709936, + "scientific_name": "Cercotrichas galactotes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22711249, + "scientific_name": "Certhia brachydactyla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22735060, + "scientific_name": "Certhia familiaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 55997072, + "scientific_name": "Cervus elaphus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41788, + "scientific_name": "Cervus nippon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714445, + "scientific_name": "Cettia cetti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22727487, + "scientific_name": "Charadrius alexandrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693868, + "scientific_name": "Charadrius asiaticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693770, + "scientific_name": "Charadrius dubius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693759, + "scientific_name": "Charadrius hiaticula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693862, + "scientific_name": "Charadrius leschenaultii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4658, + "scientific_name": "Chionomys gud", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4659, + "scientific_name": "Chionomys nivalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 4660, + "scientific_name": "Chionomys roberti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694764, + "scientific_name": "Chlidonias hybrida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694782, + "scientific_name": "Chlidonias leucopterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694787, + "scientific_name": "Chlidonias niger", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720330, + "scientific_name": "Chloris chloris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135536, + "scientific_name": "Chondrostoma oxyrhynchum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16084483, + "scientific_name": "Chorthippus brunneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697691, + "scientific_name": "Ciconia ciconia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697669, + "scientific_name": "Ciconia nigra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22708156, + "scientific_name": "Cinclus cinclus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22734216, + "scientific_name": "Circaetus gallicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695344, + "scientific_name": "Circus aeruginosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22727733, + "scientific_name": "Circus cyaneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695396, + "scientific_name": "Circus macrourus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22695405, + "scientific_name": "Circus pygargus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200626, + "scientific_name": "Cirsium pugnax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696027, + "scientific_name": "Clanga clanga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22696022, + "scientific_name": "Clanga pomarina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680427, + "scientific_name": "Clangula hyemalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 155608, + "scientific_name": "Clessiniola variabilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135707, + "scientific_name": "Clupeonella caspia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 98471289, + "scientific_name": "Clupeonella engrauliformis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 98471433, + "scientific_name": "Clupeonella grimmi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 42622224, + "scientific_name": "Cobitis amphilekta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22720681, + "scientific_name": "Coccothraustes coccothraustes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5047, + "scientific_name": "Cochlicopa nitens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LR/lc" + }, + { + "taxonid": 59702, + "scientific_name": "Coenagrion australocaspicum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 165511, + "scientific_name": "Coenagrion lunulatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165520, + "scientific_name": "Coenagrion ornatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 60288, + "scientific_name": "Coenagrion ponticum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158707, + "scientific_name": "Coenagrion puella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165484, + "scientific_name": "Coenagrion pulchellum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165502, + "scientific_name": "Coenagrion scitulum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22690066, + "scientific_name": "Columba livia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22690088, + "scientific_name": "Columba oenas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22690103, + "scientific_name": "Columba palumbus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22682860, + "scientific_name": "Coracias garrulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 98201936, + "scientific_name": "Corbicula fluminalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165507, + "scientific_name": "Cordulegaster insignis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165526, + "scientific_name": "Cordulegaster picta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158702, + "scientific_name": "Cordulia aenea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 130048490, + "scientific_name": "Cornus iberica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 79914024, + "scientific_name": "Cornus mas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157284, + "scientific_name": "Coronella austriaca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22706068, + "scientific_name": "Corvus corax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22706016, + "scientific_name": "Corvus corone", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22705983, + "scientific_name": "Corvus frugilegus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22705929, + "scientific_name": "Corvus monedula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 63521, + "scientific_name": "Corylus avellana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194668, + "scientific_name": "Corylus colurna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 202959, + "scientific_name": "Cotinus coggygria", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22678944, + "scientific_name": "Coturnix coturnix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200085, + "scientific_name": "Cousinia araxena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 200090, + "scientific_name": "Cousinia daralaghezica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200084, + "scientific_name": "Cousinia gabrieljaniae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 200087, + "scientific_name": "Cousinia iljinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 200093, + "scientific_name": "Cousinia lomakinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 200088, + "scientific_name": "Cousinia macrocephala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200097, + "scientific_name": "Crambe armena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 102860169, + "scientific_name": "Crataegus meyeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 203428, + "scientific_name": "Crataegus pentagyna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 109993237, + "scientific_name": "Crataegus rhipidophylla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22692543, + "scientific_name": "Crex crex", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5528, + "scientific_name": "Cricetulus migratorius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 5596, + "scientific_name": "Crocidura armenica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 136444, + "scientific_name": "Crocidura caspica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 29651, + "scientific_name": "Crocidura leucodon", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29654, + "scientific_name": "Crocidura serezkyensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29656, + "scientific_name": "Crocidura suaveolens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 59859, + "scientific_name": "Crocothemis erythraea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164139, + "scientific_name": "Crypsis alopecuroides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164424, + "scientific_name": "Crypsis schoenoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61295, + "scientific_name": "Ctenopharyngodon idella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22683873, + "scientific_name": "Cuculus canorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103874024, + "scientific_name": "Curruca cantillans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22716910, + "scientific_name": "Curruca communis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22734793, + "scientific_name": "Curruca crassirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22734992, + "scientific_name": "Curruca curruca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22716959, + "scientific_name": "Curruca melanocephala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22716971, + "scientific_name": "Curruca mystacea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103872996, + "scientific_name": "Curruca nana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22716937, + "scientific_name": "Curruca nisoria", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22709707, + "scientific_name": "Cyanecula svecica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103761667, + "scientific_name": "Cyanistes caeruleus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61611928, + "scientific_name": "Cydonia oblonga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22679862, + "scientific_name": "Cygnus columbianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22679856, + "scientific_name": "Cygnus cygnus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22679839, + "scientific_name": "Cygnus olor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164294, + "scientific_name": "Cyperus difformis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157979, + "scientific_name": "Cyperus flavescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 175292, + "scientific_name": "Cyperus glaber", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18906981, + "scientific_name": "Cyperus odoratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158183, + "scientific_name": "Cyperus rotundus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6181, + "scientific_name": "Cyprinus carpio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 200114, + "scientific_name": "Dactylorhiza euxina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22486113, + "scientific_name": "Dactylorhiza urvilleana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164706, + "scientific_name": "Darevskia armeniaca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164713, + "scientific_name": "Darevskia caucasica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164702, + "scientific_name": "Darevskia chlorogaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164587, + "scientific_name": "Darevskia daghestanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164576, + "scientific_name": "Darevskia derjugini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 164654, + "scientific_name": "Darevskia portschinskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157245, + "scientific_name": "Darevskia praticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 164753, + "scientific_name": "Darevskia raddei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164563, + "scientific_name": "Darevskia rostombekowi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 164633, + "scientific_name": "Darevskia rudis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164707, + "scientific_name": "Darevskia valentini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172210, + "scientific_name": "Daucus carota", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103811886, + "scientific_name": "Delichon urbicum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22727124, + "scientific_name": "Dendrocopos leucotos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22681124, + "scientific_name": "Dendrocopos major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22681127, + "scientific_name": "Dendrocopos syriacus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200128, + "scientific_name": "Dianthus bicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200132, + "scientific_name": "Dianthus raddeanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200124, + "scientific_name": "Dianthus schemachensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164595, + "scientific_name": "Dolichophis schmidti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 188911, + "scientific_name": "Dreissena bugensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 188971, + "scientific_name": "Dreissena caspia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 155495, + "scientific_name": "Dreissena polymorpha", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 189369, + "scientific_name": "Dreissena rostriformis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22681076, + "scientific_name": "Dryobates minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22681382, + "scientific_name": "Dryocopus martius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 6858, + "scientific_name": "Dryomys nitedula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200139, + "scientific_name": "Dryopteris raddeana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 62774969, + "scientific_name": "Egretta garzetta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164639, + "scientific_name": "Eirenis collaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157292, + "scientific_name": "Eirenis modestus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164628, + "scientific_name": "Eirenis punctatolineatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62002626, + "scientific_name": "Elaeagnus angustifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157275, + "scientific_name": "Elaphe dione", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157265, + "scientific_name": "Elaphe sauromates", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 43100762, + "scientific_name": "Eleocharis argyrolepis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13579845, + "scientific_name": "Eleocharis mitracarpa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164353, + "scientific_name": "Eleocharis quinqueflora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7655, + "scientific_name": "Ellobius lutescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21343347, + "scientific_name": "Elymus elongatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21343956, + "scientific_name": "Elymus hispidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720909, + "scientific_name": "Emberiza buchanani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22721020, + "scientific_name": "Emberiza calandra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720894, + "scientific_name": "Emberiza cia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720878, + "scientific_name": "Emberiza citrinella", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720916, + "scientific_name": "Emberiza hortulana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720990, + "scientific_name": "Emberiza melanocephala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22721012, + "scientific_name": "Emberiza schoeniclus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7717, + "scientific_name": "Emys orbicularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LR/nt" + }, + { + "taxonid": 165515, + "scientific_name": "Epallage fatime", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164347, + "scientific_name": "Epilobium hirsutum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19619856, + "scientific_name": "Epilobium minutiflorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164450, + "scientific_name": "Epilobium parviflorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22486454, + "scientific_name": "Epipactis rechingeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 7910, + "scientific_name": "Eptesicus nilssonii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85198662, + "scientific_name": "Eptesicus ognevi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85199559, + "scientific_name": "Eptesicus serotinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 167859, + "scientific_name": "Equisetum palustre", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 203004, + "scientific_name": "Equisetum telmateia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 7951, + "scientific_name": "Equus hemionus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 157260, + "scientific_name": "Eremias arguta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164583, + "scientific_name": "Eremias pleskei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 164641, + "scientific_name": "Eremias strauchi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157286, + "scientific_name": "Eremias velox", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22717434, + "scientific_name": "Eremophila alpestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40605, + "scientific_name": "Erinaceus concolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22709675, + "scientific_name": "Erithacus rubecula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200162, + "scientific_name": "Erysimum brachycarpum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 200158, + "scientific_name": "Erysimum caspicum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 200160, + "scientific_name": "Erysimum wagifii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 158696, + "scientific_name": "Erythromma lindenii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165478, + "scientific_name": "Erythromma viridulum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157244, + "scientific_name": "Eryx jaculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47944419, + "scientific_name": "Esymus fumigatulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 157289, + "scientific_name": "Eumeces schneiderii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 68378608, + "scientific_name": "Eumodicogryllus bordigalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 79913822, + "scientific_name": "Euonymus europaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62391, + "scientific_name": "Euonymus latifolius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200167, + "scientific_name": "Euphorbia grossheimii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 79914188, + "scientific_name": "Fagus orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696487, + "scientific_name": "Falco biarmicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696495, + "scientific_name": "Falco cherrug", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22696453, + "scientific_name": "Falco columbarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696357, + "scientific_name": "Falco naumanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45354964, + "scientific_name": "Falco peregrinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696460, + "scientific_name": "Falco subbuteo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696362, + "scientific_name": "Falco tinnunculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696432, + "scientific_name": "Falco vespertinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 8540, + "scientific_name": "Felis chaus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 131299383, + "scientific_name": "Felis lybica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 181049859, + "scientific_name": "Felis silvestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200170, + "scientific_name": "Ferula caucasica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22486248, + "scientific_name": "Festuca varia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22735909, + "scientific_name": "Ficedula parva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22709319, + "scientific_name": "Ficedula semitorquata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 169008, + "scientific_name": "Fimbristylis dichotoma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 180096947, + "scientific_name": "Flavoparmelia caperata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22678719, + "scientific_name": "Francolinus francolinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164056, + "scientific_name": "Frangula alnus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 203367, + "scientific_name": "Fraxinus excelsior", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 174361, + "scientific_name": "Freyeria trochylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720030, + "scientific_name": "Fringilla coelebs", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720041, + "scientific_name": "Fringilla montifringilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200174, + "scientific_name": "Fritillaria grandiflora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22692913, + "scientific_name": "Fulica atra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 189631, + "scientific_name": "Galba schirazensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22717383, + "scientific_name": "Galerida cristata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693097, + "scientific_name": "Gallinago gallinago", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693093, + "scientific_name": "Gallinago media", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 62120190, + "scientific_name": "Gallinula chloropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103723684, + "scientific_name": "Garrulus glandarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697834, + "scientific_name": "Gavia arctica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697829, + "scientific_name": "Gavia stellata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 8976, + "scientific_name": "Gazella subgutturosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 62026481, + "scientific_name": "Gelochelidon nilotica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694136, + "scientific_name": "Glareola nordmanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22694127, + "scientific_name": "Glareola pratincola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39316, + "scientific_name": "Glis glis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157282, + "scientific_name": "Gloydius halys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19618896, + "scientific_name": "Glyceria arundinacea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 203353, + "scientific_name": "Glycyrrhiza glabra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135646, + "scientific_name": "Gobio holurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 173329988, + "scientific_name": "Gomphus schneiderii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164174, + "scientific_name": "Groenlandia densa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22692146, + "scientific_name": "Grus grus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 9568, + "scientific_name": "Gymnocephalus cernua", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695174, + "scientific_name": "Gypaetus barbatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22695219, + "scientific_name": "Gyps fulvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200198, + "scientific_name": "Gypsophila capitata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200196, + "scientific_name": "Gypsophila robusta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 200197, + "scientific_name": "Gypsophila szovitsii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 155828, + "scientific_name": "Gyraulus laevis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693613, + "scientific_name": "Haematopus ostralegus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22725846, + "scientific_name": "Halcyon smyrnensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695137, + "scientific_name": "Haliaeetus albicilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 79919017, + "scientific_name": "Halostachys belangeriana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172636580, + "scientific_name": "Hedysarum formosum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164067, + "scientific_name": "Hemarthria altissima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157285, + "scientific_name": "Hemorrhois ravergieri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200217, + "scientific_name": "Heracleum schelkovnikovii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200212, + "scientific_name": "Heracleum trachyloma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164634, + "scientific_name": "Heremites septemtaeniatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696092, + "scientific_name": "Hieraaetus pennatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 118892125, + "scientific_name": "Hierodula tenuidentata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22727969, + "scientific_name": "Himantopus himantopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 155940, + "scientific_name": "Hippeutis complanatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714916, + "scientific_name": "Hippolais icterina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714904, + "scientific_name": "Hippolais languida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 55686342, + "scientific_name": "Hippophae rhamnoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22712252, + "scientific_name": "Hirundo rustica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172229, + "scientific_name": "Hordeum brevisubulatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172092, + "scientific_name": "Hordeum bulbosum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172273, + "scientific_name": "Hordeum marinum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172094, + "scientific_name": "Hordeum murinum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10269, + "scientific_name": "Huso huso", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 10272, + "scientific_name": "Huso huso Caspian Sea subpopulation", + "subspecies": null, + "rank": null, + "subpopulation": "Caspian Sea subpopulation", + "category": "CR" + }, + { + "taxonid": 10274, + "scientific_name": "Hyaena hyaena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22694469, + "scientific_name": "Hydrocoloeus minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13581832, + "scientific_name": "Hydrocotyle ranunculoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694524, + "scientific_name": "Hydroprogne caspia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 82494309, + "scientific_name": "Hyla orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 55647, + "scientific_name": "Hyla savignyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10542, + "scientific_name": "Hyles hippophaes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 200236, + "scientific_name": "Hypericum theodori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 44856, + "scientific_name": "Hypsugo savii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 10751, + "scientific_name": "Hystrix indica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714891, + "scientific_name": "Iduna caligata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22734747, + "scientific_name": "Iduna pallida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22709758, + "scientific_name": "Irania gutturalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164697, + "scientific_name": "Iranolacerta brandtii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 200241, + "scientific_name": "Iris camillae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 44791269, + "scientific_name": "Iris polystictica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 163999, + "scientific_name": "Iris pseudacorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200246, + "scientific_name": "Isatis karjaginii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 200247, + "scientific_name": "Isatis ornithorhynchus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 165479, + "scientific_name": "Ischnura elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158572, + "scientific_name": "Ischnura fountaineae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165525, + "scientific_name": "Ischnura pumilio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22735766, + "scientific_name": "Ixobrychus minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 63495, + "scientific_name": "Juglans regia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42229, + "scientific_name": "Juniperus communis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42232, + "scientific_name": "Juniperus excelsa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16336618, + "scientific_name": "Juniperus excelsa subsp. excelsa", + "subspecies": "excelsa", + "rank": "subsp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16336635, + "scientific_name": "Juniperus excelsa subsp. polycarpos", + "subspecies": "polycarpos", + "rank": "subsp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42234, + "scientific_name": "Juniperus foetidissima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42243, + "scientific_name": "Juniperus oxycedrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16347367, + "scientific_name": "Juniperus oxycedrus subsp. oxycedrus", + "subspecies": "oxycedrus", + "rank": "subsp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42249, + "scientific_name": "Juniperus sabina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 191611, + "scientific_name": "Juniperus sabina var. sabina", + "subspecies": "sabina", + "rank": "var.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680683, + "scientific_name": "Jynx torquilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200494, + "scientific_name": "Klasea caucasica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 135608, + "scientific_name": "Knipowitschia bergi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11030, + "scientific_name": "Knipowitschia caucasica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 123435142, + "scientific_name": "Knipowitschia iljini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 135509, + "scientific_name": "Knipowitschia longecaudata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 161916, + "scientific_name": "Kosteletzkya pentacarpos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157288, + "scientific_name": "Lacerta agilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164749, + "scientific_name": "Lacerta media", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157287, + "scientific_name": "Lacerta strigata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 189493, + "scientific_name": "Laevicaspia caspia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 189262, + "scientific_name": "Laevicaspia conus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 174427, + "scientific_name": "Lampides boeticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22705001, + "scientific_name": "Lanius collurio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103718932, + "scientific_name": "Lanius excubitor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22705038, + "scientific_name": "Lanius minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22705095, + "scientific_name": "Lanius senator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22735929, + "scientific_name": "Larus cachinnans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694308, + "scientific_name": "Larus canus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694428, + "scientific_name": "Larus genei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694379, + "scientific_name": "Larus ichthyaetus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694443, + "scientific_name": "Larus melanocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694420, + "scientific_name": "Larus ridibundus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176510, + "scientific_name": "Lathyrus annuus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379015, + "scientific_name": "Lathyrus aphaca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 120073091, + "scientific_name": "Lathyrus aureus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379018, + "scientific_name": "Lathyrus blepharicarpus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 120073416, + "scientific_name": "Lathyrus chloranthus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 174708, + "scientific_name": "Lathyrus cicera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 120073522, + "scientific_name": "Lathyrus cyaneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 120073759, + "scientific_name": "Lathyrus digitatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176501, + "scientific_name": "Lathyrus hirsutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379024, + "scientific_name": "Lathyrus inconspicuus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 120074322, + "scientific_name": "Lathyrus incurvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 120074472, + "scientific_name": "Lathyrus laxiflorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379030, + "scientific_name": "Lathyrus nissolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19891853, + "scientific_name": "Lathyrus pallescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 120075014, + "scientific_name": "Lathyrus pratensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379043, + "scientific_name": "Lathyrus roseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379055, + "scientific_name": "Lathyrus setifolius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379058, + "scientific_name": "Lathyrus sphaericus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176568, + "scientific_name": "Lathyrus sylvestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176505, + "scientific_name": "Lathyrus tuberosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22681114, + "scientific_name": "Leiopicus medius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164057, + "scientific_name": "Lemna minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165516, + "scientific_name": "Lestes dryas", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165480, + "scientific_name": "Lestes macrostigma", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165492, + "scientific_name": "Lestes virens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 11873, + "scientific_name": "Leucaspius delineatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 2178, + "scientific_name": "Leuciscus aspius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22692053, + "scientific_name": "Leucogeranus leucogeranus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 165531, + "scientific_name": "Libellula depressa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693158, + "scientific_name": "Limosa lapponica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22693150, + "scientific_name": "Limosa limosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22720441, + "scientific_name": "Linaria cannabina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720438, + "scientific_name": "Linaria flavirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200274, + "scientific_name": "Linaria zangezura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165460, + "scientific_name": "Lindenia tetraphylla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 59481, + "scientific_name": "Lissotriton vulgaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714679, + "scientific_name": "Locustella fluviatilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714684, + "scientific_name": "Locustella luscinioides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22714657, + "scientific_name": "Locustella naevia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22711810, + "scientific_name": "Lophophanes cristatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172602755, + "scientific_name": "Lotus herbaceus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720646, + "scientific_name": "Loxia curvirostra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135684, + "scientific_name": "Luciobarbus brachycephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 135687, + "scientific_name": "Luciobarbus capito", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 156750169, + "scientific_name": "Luciobarbus caspius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19383456, + "scientific_name": "Luciobarbus mursa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22717411, + "scientific_name": "Lullula arborea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22709691, + "scientific_name": "Luscinia luscinia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22709696, + "scientific_name": "Luscinia megarhynchos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12419, + "scientific_name": "Lutra lutra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 12433, + "scientific_name": "Lycaena dispar", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LR/nt" + }, + { + "taxonid": 122090665, + "scientific_name": "Lycoperdon perlatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 163972, + "scientific_name": "Lycopus europaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 189802, + "scientific_name": "Lymnaea bakowskyana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22693133, + "scientific_name": "Lymnocryptes minimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12519, + "scientific_name": "Lynx lynx", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22679483, + "scientific_name": "Lyrurus mlokosiewiczi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 64317602, + "scientific_name": "Lysimachia maritima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164091, + "scientific_name": "Lythrum hyssopifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164323, + "scientific_name": "Lythrum salicaria", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157295, + "scientific_name": "Macrovipera lebetina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157253, + "scientific_name": "Malpolon insignitus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 50049710, + "scientific_name": "Malus orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 44793247, + "scientific_name": "Mantis religiosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680157, + "scientific_name": "Mareca penelope", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680149, + "scientific_name": "Mareca strepera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680339, + "scientific_name": "Marmaronetta angustirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 29672, + "scientific_name": "Martes foina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379282, + "scientific_name": "Medicago astroites", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 126657419, + "scientific_name": "Medicago biflora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 126657791, + "scientific_name": "Medicago brachycarpa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176599, + "scientific_name": "Medicago littoralis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 71716111, + "scientific_name": "Medicago papillosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 174725, + "scientific_name": "Medicago sativa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176489, + "scientific_name": "Medicago truncatula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22724836, + "scientific_name": "Melanitta fusca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22724879, + "scientific_name": "Melanitta nigra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22717288, + "scientific_name": "Melanocorypha bimaculata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22717285, + "scientific_name": "Melanocorypha calandra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22717301, + "scientific_name": "Melanocorypha yeltoniensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29673, + "scientific_name": "Meles meles", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 64317970, + "scientific_name": "Mentha arvensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164306, + "scientific_name": "Mentha longifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680465, + "scientific_name": "Mergellus albellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680492, + "scientific_name": "Mergus merganser", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680485, + "scientific_name": "Mergus serrator", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13164, + "scientific_name": "Meriones libycus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13166, + "scientific_name": "Meriones persicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13170, + "scientific_name": "Meriones tristrami", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13172, + "scientific_name": "Meriones vinogradovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22683756, + "scientific_name": "Merops apiaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22683740, + "scientific_name": "Merops persicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13220, + "scientific_name": "Mesocricetus brandti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 123435177, + "scientific_name": "Mesogobius nonultimus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 79920045, + "scientific_name": "Mespilus germanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696734, + "scientific_name": "Microcarbo pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13373, + "scientific_name": "Micromys minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13488, + "scientific_name": "Microtus arvalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13428, + "scientific_name": "Microtus daghestanicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13454, + "scientific_name": "Microtus levis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136354, + "scientific_name": "Microtus majori", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13448, + "scientific_name": "Microtus nasarovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 13456, + "scientific_name": "Microtus schelkovnikovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13458, + "scientific_name": "Microtus socialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 181568721, + "scientific_name": "Milvus migrans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695072, + "scientific_name": "Milvus milvus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 81633088, + "scientific_name": "Miniopterus pallidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22708257, + "scientific_name": "Monticola saxatilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22708286, + "scientific_name": "Monticola solitarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103819582, + "scientific_name": "Montifringilla nivalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22993, + "scientific_name": "Montivipera raddei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22718348, + "scientific_name": "Motacilla alba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718392, + "scientific_name": "Motacilla cinerea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718379, + "scientific_name": "Motacilla citreola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103822349, + "scientific_name": "Motacilla flava", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22709192, + "scientific_name": "Muscicapa striata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13966, + "scientific_name": "Mus macedonicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13972, + "scientific_name": "Mus musculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29674, + "scientific_name": "Mustela erminea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 70207409, + "scientific_name": "Mustela nivalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136553, + "scientific_name": "Myotis aurascens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14123, + "scientific_name": "Myotis bechsteinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 14124, + "scientific_name": "Myotis blythii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85566997, + "scientific_name": "Myotis brandtii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14129, + "scientific_name": "Myotis emarginatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14134, + "scientific_name": "Myotis mystacinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136495, + "scientific_name": "Myotis nipalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164335, + "scientific_name": "Myriophyllum verticillatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164322, + "scientific_name": "Najas marina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19557120, + "scientific_name": "Narthecium balansae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 164311, + "scientific_name": "Nasturtium officinale", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165594334, + "scientific_name": "Natrix natrix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157256, + "scientific_name": "Natrix tessellata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156761995, + "scientific_name": "Neogobius caspius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14524, + "scientific_name": "Neogobius melanostomus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135596, + "scientific_name": "Neogobius pallasi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29659, + "scientific_name": "Neomys teres", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22695180, + "scientific_name": "Neophron percnopterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22680348, + "scientific_name": "Netta rufina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200295, + "scientific_name": "Nonea daghestanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22693190, + "scientific_name": "Numenius arquata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22693178, + "scientific_name": "Numenius phaeopus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693185, + "scientific_name": "Numenius tenuirostris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 14918, + "scientific_name": "Nyctalus lasiopterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 14919, + "scientific_name": "Nyctalus leisleri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 14920, + "scientific_name": "Nyctalus noctula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697211, + "scientific_name": "Nycticorax nycticorax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22734803, + "scientific_name": "Oenanthe chrysopygia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710325, + "scientific_name": "Oenanthe deserti", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710292, + "scientific_name": "Oenanthe finschii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710302, + "scientific_name": "Oenanthe hispanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710333, + "scientific_name": "Oenanthe isabellina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103773898, + "scientific_name": "Oenanthe oenanthe", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710308, + "scientific_name": "Oenanthe pleschanka", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164155, + "scientific_name": "Oenanthe silaifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164293, + "scientific_name": "Oldenlandia capensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 203369, + "scientific_name": "Onoclea struthiopteris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 185666, + "scientific_name": "Onychogomphus flexuosus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 165489, + "scientific_name": "Onychogomphus forcipatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157279, + "scientific_name": "Ophisops elegans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 99011545, + "scientific_name": "Oplismenus compositus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103692938, + "scientific_name": "Oriolus oriolus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200318, + "scientific_name": "Ornithogalum hyrcanum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 158689, + "scientific_name": "Orthetrum albistylum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158698, + "scientific_name": "Orthetrum brunneum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165521, + "scientific_name": "Orthetrum cancellatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158682, + "scientific_name": "Orthetrum coerulescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 13186368, + "scientific_name": "Orthetrum coerulescens ssp. anceps", + "subspecies": "anceps", + "rank": "ssp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165470, + "scientific_name": "Orthetrum sabina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194280, + "scientific_name": "Ostrya carpinifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22691900, + "scientific_name": "Otis tarda", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15640, + "scientific_name": "Otocolobus manul", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 155019854, + "scientific_name": "Otus scops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 54940218, + "scientific_name": "Ovis gmelini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19385622, + "scientific_name": "Oxynoemacheilus bergianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19387030, + "scientific_name": "Oxynoemacheilus brandtii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19428862, + "scientific_name": "Oxynoemacheilus lenkoranensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 135495, + "scientific_name": "Oxynoemacheilus merga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22679814, + "scientific_name": "Oxyura leucocephala", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 188978, + "scientific_name": "Paladilhiopsis schakuranica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22694938, + "scientific_name": "Pandion haliaetus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 64319146, + "scientific_name": "Panicum acuminatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 59971, + "scientific_name": "Pantala flavescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 15954, + "scientific_name": "Panthera pardus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 15955, + "scientific_name": "Panthera tigris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22716776, + "scientific_name": "Panurus biarmicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200325, + "scientific_name": "Papaver talyshense", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 164611, + "scientific_name": "Paralaudakia caucasia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 194660642, + "scientific_name": "Parmelia squarrosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16249, + "scientific_name": "Parnassius apollo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 174210, + "scientific_name": "Parnassius mnemosyne", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 122552788, + "scientific_name": "Parnassius nordmanni", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22735990, + "scientific_name": "Parus major", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 169030, + "scientific_name": "Paspalum distichum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103818789, + "scientific_name": "Passer domesticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718179, + "scientific_name": "Passer hispaniolensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718270, + "scientific_name": "Passer montanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710881, + "scientific_name": "Pastor roseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697599, + "scientific_name": "Pelecanus crispus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22697590, + "scientific_name": "Pelecanus onocrotalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16494, + "scientific_name": "Pelecus cultratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172313717, + "scientific_name": "Pelobates syriacus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39422, + "scientific_name": "Pelodytes caucasicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 58705, + "scientific_name": "Pelophylax ridibundus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 16580, + "scientific_name": "Perca fluviatilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22678911, + "scientific_name": "Perdix perdix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22735965, + "scientific_name": "Periparus ater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694989, + "scientific_name": "Pernis apivorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 184425, + "scientific_name": "Persicaria amphibia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164411, + "scientific_name": "Persicaria lapathifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 175559, + "scientific_name": "Persicaria maculosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718307, + "scientific_name": "Petronia petronia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696792, + "scientific_name": "Phalacrocorax carbo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693490, + "scientific_name": "Phalaropus lobatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 45100023, + "scientific_name": "Phasianus colchicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 12659, + "scientific_name": "Phengaris arion", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LR/nt" + }, + { + "taxonid": 12662, + "scientific_name": "Phengaris nausithous", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LR/nt" + }, + { + "taxonid": 22697360, + "scientific_name": "Phoenicopterus roseus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710072, + "scientific_name": "Phoenicurus erythrogastrus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710051, + "scientific_name": "Phoenicurus ochruros", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710055, + "scientific_name": "Phoenicurus phoenicurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164494, + "scientific_name": "Phragmites australis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164759, + "scientific_name": "Phrynocephalus horvathi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 164647, + "scientific_name": "Phrynocephalus persicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 103843725, + "scientific_name": "Phylloscopus collybita", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22731553, + "scientific_name": "Phylloscopus nitidus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22715260, + "scientific_name": "Phylloscopus sibilatrix", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22728939, + "scientific_name": "Phylloscopus sindianus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103845399, + "scientific_name": "Phylloscopus trochiloides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22715240, + "scientific_name": "Phylloscopus trochilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103727048, + "scientific_name": "Pica pica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22725022, + "scientific_name": "Picus viridis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42347, + "scientific_name": "Pinus brutia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 34183, + "scientific_name": "Pinus brutia var. eldarica", + "subspecies": "eldarica", + "rank": "var.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 42418, + "scientific_name": "Pinus sylvestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17314, + "scientific_name": "Pipistrellus kuhlii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 17316, + "scientific_name": "Pipistrellus nathusii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85333513, + "scientific_name": "Pipistrellus pipistrellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136649, + "scientific_name": "Pipistrellus pygmaeus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19365844, + "scientific_name": "Pistacia atlantica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 156083, + "scientific_name": "Planorbarius corneus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 64320667, + "scientific_name": "Plantago maritima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697555, + "scientific_name": "Platalea leucorodia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 33951, + "scientific_name": "Platanus orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 157277, + "scientific_name": "Platyceps najadum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158693, + "scientific_name": "Platycnemis dealbata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158709, + "scientific_name": "Platycnemis pennipes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 85535522, + "scientific_name": "Plecotus auritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136229, + "scientific_name": "Plecotus macrobullaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22697422, + "scientific_name": "Plegadis falcinellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693727, + "scientific_name": "Pluvialis apricaria", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693749, + "scientific_name": "Pluvialis squatarola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176440, + "scientific_name": "Poa pratensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696606, + "scientific_name": "Podiceps auritus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22696602, + "scientific_name": "Podiceps cristatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696599, + "scientific_name": "Podiceps grisegena", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696610, + "scientific_name": "Podiceps nigricollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200339, + "scientific_name": "Podospermum grossheimii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 103761508, + "scientific_name": "Poecile hyrcanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103761494, + "scientific_name": "Poecile lugubris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136637664, + "scientific_name": "Polycarpon prostratum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200344, + "scientific_name": "Polygonum caspicum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 164232, + "scientific_name": "Polypogon monspeliensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200346, + "scientific_name": "Polystichum kadyrovii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 153745, + "scientific_name": "Pontastacus leptodactylus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 153702, + "scientific_name": "Pontastacus pachypus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 160251, + "scientific_name": "Pontia daplidice", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156761759, + "scientific_name": "Ponticola bathybius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19513722, + "scientific_name": "Ponticola cyrius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156763140, + "scientific_name": "Ponticola goebelii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 188114, + "scientific_name": "Ponticola gorlap", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 188116, + "scientific_name": "Ponticola syrman", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 203464, + "scientific_name": "Populus alba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19178509, + "scientific_name": "Populus euphratica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164052144, + "scientific_name": "Populus hyrcana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 63530, + "scientific_name": "Populus nigra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 61959941, + "scientific_name": "Populus tremula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 58517228, + "scientific_name": "Poronia punctata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22692792, + "scientific_name": "Porphyrio porphyrio", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164001, + "scientific_name": "Portulaca oleracea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22692676, + "scientific_name": "Porzana porzana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 167896, + "scientific_name": "Potamogeton alpinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164038, + "scientific_name": "Potamogeton lucens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164189, + "scientific_name": "Potamogeton perfoliatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164357, + "scientific_name": "Potamogeton trichoides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 134681, + "scientific_name": "Potamon ibericum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 164521, + "scientific_name": "Potentilla supina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41686, + "scientific_name": "Procyon lotor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18366, + "scientific_name": "Proserpinus proserpina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 135486, + "scientific_name": "Proterorhinus nasalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718617, + "scientific_name": "Prunella collaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22718651, + "scientific_name": "Prunella modularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 105986083, + "scientific_name": "Prunella ocularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 203256, + "scientific_name": "Prunella vulgaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172064, + "scientific_name": "Prunus avium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172162, + "scientific_name": "Prunus cerasifera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 50135950, + "scientific_name": "Prunus domestica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 50393773, + "scientific_name": "Prunus fenzliana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 172277, + "scientific_name": "Prunus laurocerasus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172121, + "scientific_name": "Prunus mahaleb", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172194, + "scientific_name": "Prunus spinosa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164615, + "scientific_name": "Psammophis lineolatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200387, + "scientific_name": "Psephellus erivanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 200374, + "scientific_name": "Psephellus karabaghensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 189051, + "scientific_name": "Pseudamnicola brusiniana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 109224220, + "scientific_name": "Pseudoceles persa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157263, + "scientific_name": "Pseudopus apodus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 166136, + "scientific_name": "Pseudorasbora parva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 66815986, + "scientific_name": "Pterocarya fraxinifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22692983, + "scientific_name": "Pterocles alchata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693002, + "scientific_name": "Pterocles orientalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22712216, + "scientific_name": "Ptyonoprogne rupestris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 18877, + "scientific_name": "Pungitius platygaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41669, + "scientific_name": "Pusa caspica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 189305, + "scientific_name": "Pyrgula abichi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189386, + "scientific_name": "Pyrgula behningi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189385, + "scientific_name": "Pyrgula cincta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189454, + "scientific_name": "Pyrgula ebersini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189070, + "scientific_name": "Pyrgula isseli", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189244, + "scientific_name": "Pyrgula kolesnikoviana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189508, + "scientific_name": "Pyrgula nossovi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189458, + "scientific_name": "Pyrgula pulla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 188922, + "scientific_name": "Pyrgula rudis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189266, + "scientific_name": "Pyrgula sowinskyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22705921, + "scientific_name": "Pyrrhocorax graculus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22705916, + "scientific_name": "Pyrrhocorax pyrrhocorax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720671, + "scientific_name": "Pyrrhula pyrrhula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 64133731, + "scientific_name": "Pyrus acutiserrata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 173010, + "scientific_name": "Pyrus communis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 173012, + "scientific_name": "Pyrus elaeagrifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 64134271, + "scientific_name": "Pyrus megrica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 200403, + "scientific_name": "Pyrus nutans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 200401, + "scientific_name": "Pyrus vsevolodovii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 200408, + "scientific_name": "Pyrus zangezura", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 78809372, + "scientific_name": "Quercus castaneifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 194176, + "scientific_name": "Quercus infectoria", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 78968730, + "scientific_name": "Quercus macranthera", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 62539, + "scientific_name": "Quercus petraea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 63532, + "scientific_name": "Quercus robur", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22725141, + "scientific_name": "Rallus aquaticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 58651, + "scientific_name": "Rana macrocnemis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164175, + "scientific_name": "Ranunculus sceleratus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19353, + "scientific_name": "Rattus norvegicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693712, + "scientific_name": "Recurvirostra avosetta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22735002, + "scientific_name": "Regulus ignicapilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22734997, + "scientific_name": "Regulus regulus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 155249960, + "scientific_name": "Remiz pendulinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 184930799, + "scientific_name": "Reseda microcarpa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 61957125, + "scientific_name": "Rhamnus cathartica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19515, + "scientific_name": "Rhinolophus blasii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19516, + "scientific_name": "Rhinolophus euryale", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 19517, + "scientific_name": "Rhinolophus ferrumequinum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19518, + "scientific_name": "Rhinolophus hipposideros", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19519, + "scientific_name": "Rhinolophus mehelyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22725105, + "scientific_name": "Rhodopechys sanguineus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 63485, + "scientific_name": "Rhus coriaria", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164637, + "scientific_name": "Rhynchocalamus melanocephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 60037, + "scientific_name": "Rhyothemis semihyalina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103815961, + "scientific_name": "Riparia riparia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19892296, + "scientific_name": "Robinia hispida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19891648, + "scientific_name": "Robinia pseudoacacia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135555, + "scientific_name": "Romanogobio ciscaucasicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19449302, + "scientific_name": "Romanogobio macropterus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176580, + "scientific_name": "Rorippa austriaca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200430, + "scientific_name": "Rosa abutalybovii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 200429, + "scientific_name": "Rosa isaevii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 200438, + "scientific_name": "Rosa jaroshenkoi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 200427, + "scientific_name": "Rosa komarovii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19743, + "scientific_name": "Rosalia alpina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 133733320, + "scientific_name": "Rosa rapinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 200428, + "scientific_name": "Rosa zakatalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 39255, + "scientific_name": "Rupicapra rupicapra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19449330, + "scientific_name": "Rutilus atropatenus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 135601, + "scientific_name": "Rutilus caspicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19782, + "scientific_name": "Rutilus frisii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19787, + "scientific_name": "Rutilus rutilus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19449338, + "scientific_name": "Rutilus sojuchbulagi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 19793, + "scientific_name": "Sabanejewia aurata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135553, + "scientific_name": "Sabanejewia caucasica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19811, + "scientific_name": "Saga pedo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 13584819, + "scientific_name": "Salix acmophylla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 203465, + "scientific_name": "Salix alba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19620273, + "scientific_name": "Salix caprea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19620468, + "scientific_name": "Salix cinerea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19620474, + "scientific_name": "Salix excelsa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 79927560, + "scientific_name": "Salix pentandra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61960615, + "scientific_name": "Salix triandra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200448, + "scientific_name": "Salvia andreji", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 163996, + "scientific_name": "Salvinia natans", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200449, + "scientific_name": "Sameraria glastifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 163967, + "scientific_name": "Samolus valerandi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20860, + "scientific_name": "Sander lucioperca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20861, + "scientific_name": "Sander marinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710156, + "scientific_name": "Saxicola rubetra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710184, + "scientific_name": "Saxicola torquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19946, + "scientific_name": "Scardinius erythrophthalmus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 47783095, + "scientific_name": "Scarturus elater", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 136326, + "scientific_name": "Scarturus williamsi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 175246, + "scientific_name": "Schoenoplectus tabernaemontani", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20000, + "scientific_name": "Sciurus anomalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20025, + "scientific_name": "Sciurus vulgaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 44393706, + "scientific_name": "Sclerochloa woronowii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693052, + "scientific_name": "Scolopax rusticola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200630, + "scientific_name": "Scorzonera czerepanovii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 19210380, + "scientific_name": "Scutellaria galericulata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200468, + "scientific_name": "Scutellaria rhomboidalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 165471, + "scientific_name": "Selysiothemis nigra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720045, + "scientific_name": "Serinus pusillus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200501, + "scientific_name": "Seseli cuneifolium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 20184, + "scientific_name": "Sicista betulina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19108751, + "scientific_name": "Silene vulgaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 40713, + "scientific_name": "Silurus glanis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103879804, + "scientific_name": "Sitta europaea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22711205, + "scientific_name": "Sitta neumayer", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22711211, + "scientific_name": "Sitta tephronota", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 175289, + "scientific_name": "Sium sisarum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19617543, + "scientific_name": "Sonchus palustris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61957558, + "scientific_name": "Sorbus aucuparia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 79921482, + "scientific_name": "Sorbus graeca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 97153711, + "scientific_name": "Sorbus roopiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 97151952, + "scientific_name": "Sorbus stankovii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 61957590, + "scientific_name": "Sorbus torminalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 79925699, + "scientific_name": "Sorbus umbellata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29667, + "scientific_name": "Sorex minutus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29668, + "scientific_name": "Sorex raddei", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41415, + "scientific_name": "Sorex satunini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29670, + "scientific_name": "Sorex volnuchini", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 167926, + "scientific_name": "Sparganium emersum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680247, + "scientific_name": "Spatula clypeata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680313, + "scientific_name": "Spatula querquedula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164054, + "scientific_name": "Spergularia media", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19891638, + "scientific_name": "Sphaerophysa salsula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157033, + "scientific_name": "Sphyradium doliolum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22690445, + "scientific_name": "Spilopelia senegalensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22720354, + "scientific_name": "Spinus spinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61205, + "scientific_name": "Squalius cephalus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19452497, + "scientific_name": "Squalius turcicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200523, + "scientific_name": "Stachys fominii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200524, + "scientific_name": "Stachys talyschensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 20745, + "scientific_name": "Stenodus leucichthys", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EW" + }, + { + "taxonid": 22694245, + "scientific_name": "Stercorarius parasiticus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694240, + "scientific_name": "Stercorarius pomarinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200529, + "scientific_name": "Sterigmostemum acanthocarpum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22694623, + "scientific_name": "Sterna hirundo", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694656, + "scientific_name": "Sternula albifrons", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200531, + "scientific_name": "Stipa karjaginii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22727811, + "scientific_name": "Streptopelia decaocto", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22690419, + "scientific_name": "Streptopelia turtur", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22725469, + "scientific_name": "Strix aluco", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22710886, + "scientific_name": "Sturnus vulgaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165491, + "scientific_name": "Stylurus ubadschii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 90389138, + "scientific_name": "Suncus etruscus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41775, + "scientific_name": "Sus scrofa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19618320, + "scientific_name": "Swertia iberica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22716901, + "scientific_name": "Sylvia atricapilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22716906, + "scientific_name": "Sylvia borin", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158690, + "scientific_name": "Sympecma fusca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165459, + "scientific_name": "Sympecma paedisca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158718, + "scientific_name": "Sympetrum arenicolor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165512, + "scientific_name": "Sympetrum depressiusculum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165501, + "scientific_name": "Sympetrum flaveolum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 60038, + "scientific_name": "Sympetrum fonscolombii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165510, + "scientific_name": "Sympetrum meridionale", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 165464, + "scientific_name": "Sympetrum pedemontanum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158691, + "scientific_name": "Sympetrum sanguineum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 158685, + "scientific_name": "Sympetrum striolatum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21257, + "scientific_name": "Syngnathus abaster", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22696545, + "scientific_name": "Tachybaptus ruficollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22686774, + "scientific_name": "Tachymarptis melba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21311, + "scientific_name": "Tadarida teniotis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680003, + "scientific_name": "Tadorna ferruginea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22680024, + "scientific_name": "Tadorna tadorna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41482, + "scientific_name": "Talpa levantis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 46102934, + "scientific_name": "Tamarix kotschyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19620778, + "scientific_name": "Tamarix octandra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21251979, + "scientific_name": "Tamarix ramosissima", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 79928441, + "scientific_name": "Tamarix smyrnensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 118130328, + "scientific_name": "Tamarix tetragyna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200544, + "scientific_name": "Tanacetum zangezuricum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 200556, + "scientific_name": "Taraxacum desertorum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 42546, + "scientific_name": "Taxus baccata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157258, + "scientific_name": "Telescopus fallax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157255, + "scientific_name": "Tenuidactylus caspius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21646, + "scientific_name": "Testudo graeca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 21651, + "scientific_name": "Testudo horsfieldii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22678664, + "scientific_name": "Tetraogallus caspius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22678661, + "scientific_name": "Tetraogallus caucasicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22691896, + "scientific_name": "Tetrax tetrax", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22694591, + "scientific_name": "Thalasseus sandvicensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200558, + "scientific_name": "Thesium maritimum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 22697510, + "scientific_name": "Threskiornis aethiopicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200564, + "scientific_name": "Thymus karamarianicus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 22711234, + "scientific_name": "Tichodroma muraria", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 203360, + "scientific_name": "Tilia cordata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 79738009, + "scientific_name": "Tilia dasystyla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 21912, + "scientific_name": "Tinca tinca", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 200577, + "scientific_name": "Tragopogon sosnowskyi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 199893, + "scientific_name": "Trifolium bobrovii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 19891967, + "scientific_name": "Trifolium canescens", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19892578, + "scientific_name": "Trifolium caucasicum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 174713, + "scientific_name": "Trifolium pratense", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379644, + "scientific_name": "Trifolium scabrum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176372, + "scientific_name": "Trifolium subterraneum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164152, + "scientific_name": "Triglochin palustris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693207, + "scientific_name": "Tringa erythropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693247, + "scientific_name": "Tringa glareola", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693220, + "scientific_name": "Tringa nebularia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693243, + "scientific_name": "Tringa ochropus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693216, + "scientific_name": "Tringa stagnatilis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693211, + "scientific_name": "Tringa totanus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 172116, + "scientific_name": "Triticum monococcum", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 39420, + "scientific_name": "Triturus karelinii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103883277, + "scientific_name": "Troglodytes troglodytes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22736108, + "scientific_name": "Turdus atrogularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22708819, + "scientific_name": "Turdus iliacus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 103888106, + "scientific_name": "Turdus merula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22708822, + "scientific_name": "Turdus philomelos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22708816, + "scientific_name": "Turdus pilaris", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 103892167, + "scientific_name": "Turdus ruficollis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22708768, + "scientific_name": "Turdus torquatus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22708829, + "scientific_name": "Turdus viscivorus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 189097, + "scientific_name": "Turricaspia dagestanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189467, + "scientific_name": "Turricaspia pullula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189280, + "scientific_name": "Turricaspia sajenkovae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 189404, + "scientific_name": "Turricaspia spasskii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 155871, + "scientific_name": "Turricaspia triton", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 189519, + "scientific_name": "Turricaspia trivialis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22486464, + "scientific_name": "Typha grossheimii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 61966807, + "scientific_name": "Ulmus glabra", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 19218731, + "scientific_name": "Ulmus minor", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22736, + "scientific_name": "Unio crassus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "EN" + }, + { + "taxonid": 22682655, + "scientific_name": "Upupa epops", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 41688, + "scientific_name": "Ursus arctos", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 156186, + "scientific_name": "Valvata piscinalis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22694053, + "scientific_name": "Vanellus gregarius", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "CR" + }, + { + "taxonid": 22694064, + "scientific_name": "Vanellus leucurus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693949, + "scientific_name": "Vanellus vanellus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 174225, + "scientific_name": "Vanessa atalanta", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164036, + "scientific_name": "Veronica anagallis-aquatica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164530, + "scientific_name": "Veronica anagalloides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 167923, + "scientific_name": "Veronica beccabunga", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 167924, + "scientific_name": "Veronica scutellata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19620739, + "scientific_name": "Veronica serpyllifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22947, + "scientific_name": "Vespertilio murinus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176124, + "scientific_name": "Vicia abbreviata", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176100, + "scientific_name": "Vicia balansae", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176111, + "scientific_name": "Vicia bithynica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176099, + "scientific_name": "Vicia ciliatula", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 180099, + "scientific_name": "Vicia ervilia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176120, + "scientific_name": "Vicia grandiflora", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176122, + "scientific_name": "Vicia hybrida", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176125, + "scientific_name": "Vicia hyrcanica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 176098, + "scientific_name": "Vicia johannis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176113, + "scientific_name": "Vicia lathyroides", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176104, + "scientific_name": "Vicia lutea", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176119, + "scientific_name": "Vicia michauxii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 176095, + "scientific_name": "Vicia narbonensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176110, + "scientific_name": "Vicia pannonica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176126, + "scientific_name": "Vicia peregrina", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176097, + "scientific_name": "Vicia sativa", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135133262, + "scientific_name": "Vicia sativa subsp. amphicarpa", + "subspecies": "amphicarpa", + "rank": "subsp.", + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 135133337, + "scientific_name": "Vicia sativa subsp. cordata", + "subspecies": "cordata", + "rank": "subsp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 135133707, + "scientific_name": "Vicia sativa subsp. nigra", + "subspecies": "nigra", + "rank": "subsp.", + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 176091, + "scientific_name": "Vicia sepium", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 19379811, + "scientific_name": "Vicia tenuifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22979, + "scientific_name": "Vimba vimba", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 23001, + "scientific_name": "Vipera dinniki", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 164679, + "scientific_name": "Vipera eriwanensis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 157268, + "scientific_name": "Vipera renardi", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 164708, + "scientific_name": "Vipera transcaucasiana", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "NT" + }, + { + "taxonid": 203350, + "scientific_name": "Vitex agnus-castus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 155517, + "scientific_name": "Viviparus viviparus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 29680, + "scientific_name": "Vormela peregusna", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 23062, + "scientific_name": "Vulpes vulpes", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22693251, + "scientific_name": "Xenus cinereus", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157274, + "scientific_name": "Xerotyphlops vermicularis", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 157251, + "scientific_name": "Zamenis hohenackeri", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 164577, + "scientific_name": "Zamenis persica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "DD" + }, + { + "taxonid": 22692663, + "scientific_name": "Zapornia parva", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 22692667, + "scientific_name": "Zapornia pusilla", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + }, + { + "taxonid": 31303, + "scientific_name": "Zelkova carpinifolia", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 39482, + "scientific_name": "Zerynthia caucasica", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "VU" + }, + { + "taxonid": 173361, + "scientific_name": "Zostera noltii", + "subspecies": null, + "rank": null, + "subpopulation": null, + "category": "LC" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/country/list": { + "count": 251, + "results": [ + { + "isocode": "UZ", + "country": "Uzbekistan" + }, + { + "isocode": "QA", + "country": "Qatar" + }, + { + "isocode": "SA", + "country": "Saudi Arabia" + }, + { + "isocode": "AF", + "country": "Afghanistan" + }, + { + "isocode": "LB", + "country": "Lebanon" + }, + { + "isocode": "BH", + "country": "Bahrain" + }, + { + "isocode": "CY", + "country": "Cyprus" + }, + { + "isocode": "SY", + "country": "Syrian Arab Republic" + }, + { + "isocode": "TJ", + "country": "Tajikistan" + }, + { + "isocode": "TM", + "country": "Turkmenistan" + }, + { + "isocode": "AE", + "country": "United Arab Emirates" + }, + { + "isocode": "IR", + "country": "Iran, Islamic Republic of" + }, + { + "isocode": "IQ", + "country": "Iraq" + }, + { + "isocode": "OM", + "country": "Oman" + }, + { + "isocode": "PK", + "country": "Pakistan" + }, + { + "isocode": "IL", + "country": "Israel" + }, + { + "isocode": "JO", + "country": "Jordan" + }, + { + "isocode": "KZ", + "country": "Kazakhstan" + }, + { + "isocode": "KW", + "country": "Kuwait" + }, + { + "isocode": "KG", + "country": "Kyrgyzstan" + }, + { + "isocode": "VN", + "country": "Viet Nam" + }, + { + "isocode": "MV", + "country": "Maldives" + }, + { + "isocode": "PH", + "country": "Philippines" + }, + { + "isocode": "BD", + "country": "Bangladesh" + }, + { + "isocode": "BT", + "country": "Bhutan" + }, + { + "isocode": "BN", + "country": "Brunei Darussalam" + }, + { + "isocode": "KH", + "country": "Cambodia" + }, + { + "isocode": "TL", + "country": "Timor-Leste" + }, + { + "isocode": "SG", + "country": "Singapore" + }, + { + "isocode": "LK", + "country": "Sri Lanka" + }, + { + "isocode": "TH", + "country": "Thailand" + }, + { + "isocode": "NP", + "country": "Nepal" + }, + { + "isocode": "LA", + "country": "Lao People's Democratic Republic" + }, + { + "isocode": "YE", + "country": "Yemen" + }, + { + "isocode": "GE", + "country": "Georgia" + }, + { + "isocode": "TR", + "country": "Turkey" + }, + { + "isocode": "AM", + "country": "Armenia" + }, + { + "isocode": "AZ", + "country": "Azerbaijan" + }, + { + "isocode": "DT", + "country": "Disputed Territory" + }, + { + "isocode": "MY", + "country": "Malaysia" + }, + { + "isocode": "IO", + "country": "British Indian Ocean Territory" + }, + { + "isocode": "IN", + "country": "India" + }, + { + "isocode": "ID", + "country": "Indonesia" + }, + { + "isocode": "MM", + "country": "Myanmar" + }, + { + "isocode": "VU", + "country": "Vanuatu" + }, + { + "isocode": "WF", + "country": "Wallis and Futuna" + }, + { + "isocode": "GU", + "country": "Guam" + }, + { + "isocode": "MH", + "country": "Marshall Islands" + }, + { + "isocode": "PN", + "country": "Pitcairn" + }, + { + "isocode": "WS", + "country": "Samoa" + }, + { + "isocode": "CX", + "country": "Christmas Island" + }, + { + "isocode": "CC", + "country": "Cocos (Keeling) Islands" + }, + { + "isocode": "FJ", + "country": "Fiji" + }, + { + "isocode": "TK", + "country": "Tokelau" + }, + { + "isocode": "TO", + "country": "Tonga" + }, + { + "isocode": "TV", + "country": "Tuvalu" + }, + { + "isocode": "NR", + "country": "Nauru" + }, + { + "isocode": "NC", + "country": "New Caledonia" + }, + { + "isocode": "NU", + "country": "Niue" + }, + { + "isocode": "NF", + "country": "Norfolk Island" + }, + { + "isocode": "MP", + "country": "Northern Mariana Islands" + }, + { + "isocode": "PW", + "country": "Palau" + }, + { + "isocode": "VA", + "country": "Holy See (Vatican City State)" + }, + { + "isocode": "MT", + "country": "Malta" + }, + { + "isocode": "MC", + "country": "Monaco" + }, + { + "isocode": "PL", + "country": "Poland" + }, + { + "isocode": "RO", + "country": "Romania" + }, + { + "isocode": "SM", + "country": "San Marino" + }, + { + "isocode": "AL", + "country": "Albania" + }, + { + "isocode": "LV", + "country": "Latvia" + }, + { + "isocode": "LI", + "country": "Liechtenstein" + }, + { + "isocode": "LT", + "country": "Lithuania" + }, + { + "isocode": "LU", + "country": "Luxembourg" + }, + { + "isocode": "BE", + "country": "Belgium" + }, + { + "isocode": "BA", + "country": "Bosnia and Herzegovina" + }, + { + "isocode": "BG", + "country": "Bulgaria" + }, + { + "isocode": "HR", + "country": "Croatia" + }, + { + "isocode": "DK", + "country": "Denmark" + }, + { + "isocode": "EE", + "country": "Estonia" + }, + { + "isocode": "FO", + "country": "Faroe Islands" + }, + { + "isocode": "FI", + "country": "Finland" + }, + { + "isocode": "GG", + "country": "Guernsey" + }, + { + "isocode": "IM", + "country": "Isle of Man" + }, + { + "isocode": "JE", + "country": "Jersey" + }, + { + "isocode": "DE", + "country": "Germany" + }, + { + "isocode": "GI", + "country": "Gibraltar" + }, + { + "isocode": "GL", + "country": "Greenland" + }, + { + "isocode": "SK", + "country": "Slovakia" + }, + { + "isocode": "SI", + "country": "Slovenia" + }, + { + "isocode": "SJ", + "country": "Svalbard and Jan Mayen" + }, + { + "isocode": "SE", + "country": "Sweden" + }, + { + "isocode": "CH", + "country": "Switzerland" + }, + { + "isocode": "AD", + "country": "Andorra" + }, + { + "isocode": "AT", + "country": "Austria" + }, + { + "isocode": "HU", + "country": "Hungary" + }, + { + "isocode": "IS", + "country": "Iceland" + }, + { + "isocode": "NL", + "country": "Netherlands" + }, + { + "isocode": "NO", + "country": "Norway" + }, + { + "isocode": "IE", + "country": "Ireland" + }, + { + "isocode": "AX", + "country": "Åland Islands" + }, + { + "isocode": "ME", + "country": "Montenegro" + }, + { + "isocode": "GY", + "country": "Guyana" + }, + { + "isocode": "FK", + "country": "Falkland Islands (Malvinas)" + }, + { + "isocode": "GF", + "country": "French Guiana" + }, + { + "isocode": "SR", + "country": "Suriname" + }, + { + "isocode": "UY", + "country": "Uruguay" + }, + { + "isocode": "PY", + "country": "Paraguay" + }, + { + "isocode": "PE", + "country": "Peru" + }, + { + "isocode": "VG", + "country": "Virgin Islands, British" + }, + { + "isocode": "VI", + "country": "Virgin Islands, U.S." + }, + { + "isocode": "GP", + "country": "Guadeloupe" + }, + { + "isocode": "HT", + "country": "Haiti" + }, + { + "isocode": "MQ", + "country": "Martinique" + }, + { + "isocode": "MS", + "country": "Montserrat" + }, + { + "isocode": "KN", + "country": "Saint Kitts and Nevis" + }, + { + "isocode": "LC", + "country": "Saint Lucia" + }, + { + "isocode": "VC", + "country": "Saint Vincent and the Grenadines" + }, + { + "isocode": "BB", + "country": "Barbados" + }, + { + "isocode": "BM", + "country": "Bermuda" + }, + { + "isocode": "KY", + "country": "Cayman Islands" + }, + { + "isocode": "CU", + "country": "Cuba" + }, + { + "isocode": "DM", + "country": "Dominica" + }, + { + "isocode": "DO", + "country": "Dominican Republic" + }, + { + "isocode": "GD", + "country": "Grenada" + }, + { + "isocode": "TT", + "country": "Trinidad and Tobago" + }, + { + "isocode": "TC", + "country": "Turks and Caicos Islands" + }, + { + "isocode": "AI", + "country": "Anguilla" + }, + { + "isocode": "AG", + "country": "Antigua and Barbuda" + }, + { + "isocode": "AW", + "country": "Aruba" + }, + { + "isocode": "BS", + "country": "Bahamas" + }, + { + "isocode": "JM", + "country": "Jamaica" + }, + { + "isocode": "EH", + "country": "Western Sahara" + }, + { + "isocode": "DZ", + "country": "Algeria" + }, + { + "isocode": "TN", + "country": "Tunisia" + }, + { + "isocode": "MA", + "country": "Morocco" + }, + { + "isocode": "ZM", + "country": "Zambia" + }, + { + "isocode": "ZW", + "country": "Zimbabwe" + }, + { + "isocode": "GN", + "country": "Guinea" + }, + { + "isocode": "LY", + "country": "Libya" + }, + { + "isocode": "GW", + "country": "Guinea-Bissau" + }, + { + "isocode": "ML", + "country": "Mali" + }, + { + "isocode": "MR", + "country": "Mauritania" + }, + { + "isocode": "YT", + "country": "Mayotte" + }, + { + "isocode": "RW", + "country": "Rwanda" + }, + { + "isocode": "RE", + "country": "Réunion" + }, + { + "isocode": "SN", + "country": "Senegal" + }, + { + "isocode": "SL", + "country": "Sierra Leone" + }, + { + "isocode": "LS", + "country": "Lesotho" + }, + { + "isocode": "LR", + "country": "Liberia" + }, + { + "isocode": "MG", + "country": "Madagascar" + }, + { + "isocode": "MW", + "country": "Malawi" + }, + { + "isocode": "BJ", + "country": "Benin" + }, + { + "isocode": "BW", + "country": "Botswana" + }, + { + "isocode": "BF", + "country": "Burkina Faso" + }, + { + "isocode": "BI", + "country": "Burundi" + }, + { + "isocode": "CM", + "country": "Cameroon" + }, + { + "isocode": "CF", + "country": "Central African Republic" + }, + { + "isocode": "TD", + "country": "Chad" + }, + { + "isocode": "KM", + "country": "Comoros" + }, + { + "isocode": "CG", + "country": "Congo" + }, + { + "isocode": "CD", + "country": "Congo, The Democratic Republic of the" + }, + { + "isocode": "CI", + "country": "Côte d'Ivoire" + }, + { + "isocode": "DJ", + "country": "Djibouti" + }, + { + "isocode": "ER", + "country": "Eritrea" + }, + { + "isocode": "ET", + "country": "Ethiopia" + }, + { + "isocode": "GA", + "country": "Gabon" + }, + { + "isocode": "GM", + "country": "Gambia" + }, + { + "isocode": "GH", + "country": "Ghana" + }, + { + "isocode": "SO", + "country": "Somalia" + }, + { + "isocode": "SD", + "country": "Sudan" + }, + { + "isocode": "TZ", + "country": "Tanzania, United Republic of" + }, + { + "isocode": "TG", + "country": "Togo" + }, + { + "isocode": "UG", + "country": "Uganda" + }, + { + "isocode": "MZ", + "country": "Mozambique" + }, + { + "isocode": "NE", + "country": "Niger" + }, + { + "isocode": "NG", + "country": "Nigeria" + }, + { + "isocode": "KE", + "country": "Kenya" + }, + { + "isocode": "GT", + "country": "Guatemala" + }, + { + "isocode": "BZ", + "country": "Belize" + }, + { + "isocode": "SV", + "country": "El Salvador" + }, + { + "isocode": "PA", + "country": "Panama" + }, + { + "isocode": "HM", + "country": "Heard Island and McDonald Islands" + }, + { + "isocode": "BV", + "country": "Bouvet Island" + }, + { + "isocode": "AQ", + "country": "Antarctica" + }, + { + "isocode": "BY", + "country": "Belarus" + }, + { + "isocode": "MN", + "country": "Mongolia" + }, + { + "isocode": "MO", + "country": "Macao" + }, + { + "isocode": "HK", + "country": "Hong Kong" + }, + { + "isocode": "KP", + "country": "Korea, Democratic People's Republic of" + }, + { + "isocode": "KR", + "country": "Korea, Republic of" + }, + { + "isocode": "PM", + "country": "Saint Pierre and Miquelon" + }, + { + "isocode": "MF", + "country": "Saint Martin (French part)" + }, + { + "isocode": "BL", + "country": "Saint Barthélemy" + }, + { + "isocode": "AS", + "country": "American Samoa" + }, + { + "isocode": "CK", + "country": "Cook Islands" + }, + { + "isocode": "PF", + "country": "French Polynesia" + }, + { + "isocode": "SB", + "country": "Solomon Islands" + }, + { + "isocode": "UM", + "country": "United States Minor Outlying Islands" + }, + { + "isocode": "AU", + "country": "Australia" + }, + { + "isocode": "NZ", + "country": "New Zealand" + }, + { + "isocode": "PG", + "country": "Papua New Guinea" + }, + { + "isocode": "KI", + "country": "Kiribati" + }, + { + "isocode": "PT", + "country": "Portugal" + }, + { + "isocode": "FR", + "country": "France" + }, + { + "isocode": "GR", + "country": "Greece" + }, + { + "isocode": "ES", + "country": "Spain" + }, + { + "isocode": "IT", + "country": "Italy" + }, + { + "isocode": "RS", + "country": "Serbia" + }, + { + "isocode": "BR", + "country": "Brazil" + }, + { + "isocode": "CL", + "country": "Chile" + }, + { + "isocode": "CO", + "country": "Colombia" + }, + { + "isocode": "EC", + "country": "Ecuador" + }, + { + "isocode": "AR", + "country": "Argentina" + }, + { + "isocode": "PR", + "country": "Puerto Rico" + }, + { + "isocode": "AN", + "country": "Netherlands Antilles" + }, + { + "isocode": "EG", + "country": "Egypt" + }, + { + "isocode": "MU", + "country": "Mauritius" + }, + { + "isocode": "SC", + "country": "Seychelles" + }, + { + "isocode": "GQ", + "country": "Equatorial Guinea" + }, + { + "isocode": "ZA", + "country": "South Africa" + }, + { + "isocode": "AO", + "country": "Angola" + }, + { + "isocode": "NA", + "country": "Namibia" + }, + { + "isocode": "MX", + "country": "Mexico" + }, + { + "isocode": "CR", + "country": "Costa Rica" + }, + { + "isocode": "HN", + "country": "Honduras" + }, + { + "isocode": "NI", + "country": "Nicaragua" + }, + { + "isocode": "GS", + "country": "South Georgia and the South Sandwich Islands" + }, + { + "isocode": "RU", + "country": "Russian Federation" + }, + { + "isocode": "UA", + "country": "Ukraine" + }, + { + "isocode": "CN", + "country": "China" + }, + { + "isocode": "TW", + "country": "Taiwan, Province of China" + }, + { + "isocode": "JP", + "country": "Japan" + }, + { + "isocode": "CA", + "country": "Canada" + }, + { + "isocode": "SH", + "country": "Saint Helena, Ascension and Tristan da Cunha" + }, + { + "isocode": "CW", + "country": "Curaçao" + }, + { + "isocode": "SX", + "country": "Sint Maarten (Dutch part)" + }, + { + "isocode": "BQ", + "country": "Bonaire, Sint Eustatius and Saba" + }, + { + "isocode": "SS", + "country": "South Sudan" + }, + { + "isocode": "TF", + "country": "French Southern Territories" + }, + { + "isocode": "FM", + "country": "Micronesia, Federated States of " + }, + { + "isocode": "VE", + "country": "Venezuela, Bolivarian Republic of" + }, + { + "isocode": "PS", + "country": "Palestine, State of" + }, + { + "isocode": "CZ", + "country": "Czechia" + }, + { + "isocode": "CV", + "country": "Cabo Verde" + }, + { + "isocode": "SZ", + "country": "Eswatini" + }, + { + "isocode": "ST", + "country": "Sao Tome and Principe" + }, + { + "isocode": "MK", + "country": "North Macedonia" + }, + { + "isocode": "BO", + "country": "Bolivia, Plurinational State of" + }, + { + "isocode": "MD", + "country": "Moldova, Republic of" + }, + { + "isocode": "GB", + "country": "United Kingdom of Great Britain and Northern Ireland" + }, + { + "isocode": "US", + "country": "United States of America" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/growth_forms/species/id/19891625": { + "id": "19891625", + "result": [ + { + "name": "Annual" + }, + { + "name": "Forb or Herb" + }, + { + "name": "Shrub - size unknown" + }, + { + "name": "Vines" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/growth_forms/species/id/63532/region/europe": { + "id": "63532", + "region_identifier": "europe", + "result": [ + { + "name": "Tree - large" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/growth_forms/species/name/Mucuna%20bracteata": { + "name": "Mucuna bracteata", + "result": [ + { + "name": "Annual" + }, + { + "name": "Forb or Herb" + }, + { + "name": "Shrub - size unknown" + }, + { + "name": "Vines" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/growth_forms/species/name/Quercus%20robur/region/europe": { + "name": "Quercus robur", + "region_identifier": "europe", + "result": [ + { + "name": "Tree - large" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/habitats/species/id/181008073": { + "id": "181008073", + "result": [ + { + "code": "1.5", + "habitat": "Forest - Subtropical/Tropical Dry", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "1.6", + "habitat": "Forest - Subtropical/Tropical Moist Lowland", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "1.7", + "habitat": "Forest - Subtropical/Tropical Mangrove Vegetation Above High Tide Level", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "1.8", + "habitat": "Forest - Subtropical/Tropical Swamp", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "1.9", + "habitat": "Forest - Subtropical/Tropical Moist Montane", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "2.1", + "habitat": "Savanna - Dry", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "2.2", + "habitat": "Savanna - Moist", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "3.5", + "habitat": "Shrubland - Subtropical/Tropical Dry", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "3.6", + "habitat": "Shrubland - Subtropical/Tropical Moist", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "4.5", + "habitat": "Grassland - Subtropical/Tropical Dry", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "4.6", + "habitat": "Grassland - Subtropical/Tropical Seasonally Wet/Flooded", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "5.1", + "habitat": "Wetlands (inland) - Permanent Rivers/Streams/Creeks (includes waterfalls)", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "5.13", + "habitat": "Wetlands (inland) - Permanent Inland Deltas", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "5.2", + "habitat": "Wetlands (inland) - Seasonal/Intermittent/Irregular Rivers/Streams/Creeks", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "5.3", + "habitat": "Wetlands (inland) - Shrub Dominated Wetlands", + "suitability": "Marginal", + "season": null, + "majorimportance": null + }, + { + "code": "8.1", + "habitat": "Desert - Hot", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "8.3", + "habitat": "Desert - Cold", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/habitats/species/id/22823/region/europe": { + "id": "22823", + "region_identifier": "europe", + "result": [ + { + "code": "12.1", + "habitat": "Marine Intertidal - Rocky Shoreline", + "suitability": "Suitable", + "season": null, + "majorimportance": null + }, + { + "code": "12.2", + "habitat": "Marine Intertidal - Sandy Shoreline and/or Beaches, Sand Bars, Spits, Etc", + "suitability": "Suitable", + "season": null, + "majorimportance": null + }, + { + "code": "12.3", + "habitat": "Marine Intertidal - Shingle and/or Pebble Shoreline and/or Beaches", + "suitability": "Suitable", + "season": null, + "majorimportance": null + }, + { + "code": "3.1", + "habitat": "Shrubland - Subarctic", + "suitability": "Marginal", + "season": null, + "majorimportance": null + }, + { + "code": "9.1", + "habitat": "Marine Neritic - Pelagic", + "suitability": "Suitable", + "season": null, + "majorimportance": null + }, + { + "code": "9.10", + "habitat": "Marine Neritic - Estuaries", + "suitability": "Suitable", + "season": null, + "majorimportance": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/habitats/species/name/Loxodonta%20africana": { + "name": "Loxodonta africana", + "result": [ + { + "code": "1.5", + "habitat": "Forest - Subtropical/Tropical Dry", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "1.6", + "habitat": "Forest - Subtropical/Tropical Moist Lowland", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "1.7", + "habitat": "Forest - Subtropical/Tropical Mangrove Vegetation Above High Tide Level", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "1.8", + "habitat": "Forest - Subtropical/Tropical Swamp", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "1.9", + "habitat": "Forest - Subtropical/Tropical Moist Montane", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "2.1", + "habitat": "Savanna - Dry", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "2.2", + "habitat": "Savanna - Moist", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "3.5", + "habitat": "Shrubland - Subtropical/Tropical Dry", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "3.6", + "habitat": "Shrubland - Subtropical/Tropical Moist", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "4.5", + "habitat": "Grassland - Subtropical/Tropical Dry", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "4.6", + "habitat": "Grassland - Subtropical/Tropical Seasonally Wet/Flooded", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "5.1", + "habitat": "Wetlands (inland) - Permanent Rivers/Streams/Creeks (includes waterfalls)", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "5.13", + "habitat": "Wetlands (inland) - Permanent Inland Deltas", + "suitability": "Suitable", + "season": null, + "majorimportance": "No" + }, + { + "code": "5.2", + "habitat": "Wetlands (inland) - Seasonal/Intermittent/Irregular Rivers/Streams/Creeks", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "5.3", + "habitat": "Wetlands (inland) - Shrub Dominated Wetlands", + "suitability": "Marginal", + "season": null, + "majorimportance": null + }, + { + "code": "8.1", + "habitat": "Desert - Hot", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + }, + { + "code": "8.3", + "habitat": "Desert - Cold", + "suitability": "Suitable", + "season": null, + "majorimportance": "Yes" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/habitats/species/name/Ursus%20maritimus/region/europe": { + "name": "Ursus maritimus", + "region_identifier": "europe", + "result": [ + { + "code": "12.1", + "habitat": "Marine Intertidal - Rocky Shoreline", + "suitability": "Suitable", + "season": null, + "majorimportance": null + }, + { + "code": "12.2", + "habitat": "Marine Intertidal - Sandy Shoreline and/or Beaches, Sand Bars, Spits, Etc", + "suitability": "Suitable", + "season": null, + "majorimportance": null + }, + { + "code": "12.3", + "habitat": "Marine Intertidal - Shingle and/or Pebble Shoreline and/or Beaches", + "suitability": "Suitable", + "season": null, + "majorimportance": null + }, + { + "code": "3.1", + "habitat": "Shrubland - Subarctic", + "suitability": "Marginal", + "season": null, + "majorimportance": null + }, + { + "code": "9.1", + "habitat": "Marine Neritic - Pelagic", + "suitability": "Suitable", + "season": null, + "majorimportance": null + }, + { + "code": "9.10", + "habitat": "Marine Neritic - Estuaries", + "suitability": "Suitable", + "season": null, + "majorimportance": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/measures/species/id/181008073": { + "id": "181008073", + "result": [ + { + "code": "1.1", + "title": "Site/area protection" + }, + { + "code": "1.2", + "title": "Resource & habitat protection" + }, + { + "code": "2.1", + "title": "Site/area management" + }, + { + "code": "3.1", + "title": "Species management" + }, + { + "code": "3.1.1", + "title": "Harvest management" + }, + { + "code": "3.1.2", + "title": "Trade management" + }, + { + "code": "3.1.3", + "title": "Limiting population growth" + }, + { + "code": "3.2", + "title": "Species recovery" + }, + { + "code": "4.1", + "title": "Formal education" + }, + { + "code": "4.2", + "title": "Training" + }, + { + "code": "4.3", + "title": "Awareness & communications" + }, + { + "code": "5.1", + "title": "Legislation" + }, + { + "code": "5.1.1", + "title": "International level" + }, + { + "code": "5.1.2", + "title": "National level" + }, + { + "code": "5.1.3", + "title": "Sub-national level" + }, + { + "code": "5.4", + "title": "Compliance and enforcement" + }, + { + "code": "5.4.1", + "title": "International level" + }, + { + "code": "5.4.2", + "title": "National level" + }, + { + "code": "5.4.3", + "title": "Sub-national level" + }, + { + "code": "6.1", + "title": "Linked enterprises & livelihood alternatives" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/measures/species/id/22823/region/europe": { + "id": "22823", + "region_identifier": "europe", + "result": [ + { + "code": "1.1", + "title": "Site/area protection" + }, + { + "code": "1.2", + "title": "Resource & habitat protection" + }, + { + "code": "2.1", + "title": "Site/area management" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/measures/species/name/Loxodonta%20africana": { + "name": "Loxodonta africana", + "result": [ + { + "code": "1.1", + "title": "Site/area protection" + }, + { + "code": "1.2", + "title": "Resource & habitat protection" + }, + { + "code": "2.1", + "title": "Site/area management" + }, + { + "code": "3.1", + "title": "Species management" + }, + { + "code": "3.1.1", + "title": "Harvest management" + }, + { + "code": "3.1.2", + "title": "Trade management" + }, + { + "code": "3.1.3", + "title": "Limiting population growth" + }, + { + "code": "3.2", + "title": "Species recovery" + }, + { + "code": "4.1", + "title": "Formal education" + }, + { + "code": "4.2", + "title": "Training" + }, + { + "code": "4.3", + "title": "Awareness & communications" + }, + { + "code": "5.1", + "title": "Legislation" + }, + { + "code": "5.1.1", + "title": "International level" + }, + { + "code": "5.1.2", + "title": "National level" + }, + { + "code": "5.1.3", + "title": "Sub-national level" + }, + { + "code": "5.4", + "title": "Compliance and enforcement" + }, + { + "code": "5.4.1", + "title": "International level" + }, + { + "code": "5.4.2", + "title": "National level" + }, + { + "code": "5.4.3", + "title": "Sub-national level" + }, + { + "code": "6.1", + "title": "Linked enterprises & livelihood alternatives" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/measures/species/name/Ursus%20maritimus/region/europe": { + "name": "Ursus maritimus", + "region_identifier": "europe", + "result": [ + { + "code": "1.1", + "title": "Site/area protection" + }, + { + "code": "1.2", + "title": "Resource & habitat protection" + }, + { + "code": "2.1", + "title": "Site/area management" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/region/list": { + "count": 10, + "results": [ + { + "name": "Northeastern Africa", + "identifier": "northeastern_africa" + }, + { + "name": "Eastern Africa", + "identifier": "eastern_africa" + }, + { + "name": "Global", + "identifier": "global" + }, + { + "name": "Western Africa", + "identifier": "western_africa" + }, + { + "name": "Northern Africa", + "identifier": "northern_africa" + }, + { + "name": "Central Africa", + "identifier": "central_africa" + }, + { + "name": "Pan-Africa", + "identifier": "pan-africa" + }, + { + "name": "Southern Africa", + "identifier": "southern_africa" + }, + { + "name": "Mediterranean", + "identifier": "mediterranean" + }, + { + "name": "Europe", + "identifier": "europe" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/Loxodonta%20africana": { + "name": "loxodonta africana", + "result": [ + { + "taxonid": 181008073, + "scientific_name": "Loxodonta africana", + "kingdom": "ANIMALIA", + "phylum": "CHORDATA", + "class": "MAMMALIA", + "order": "PROBOSCIDEA", + "family": "ELEPHANTIDAE", + "genus": "Loxodonta", + "main_common_name": "African Savanna Elephant", + "authority": "(Blumenbach, 1797)", + "published_year": 2021, + "assessment_date": "2020-11-13", + "category": "EN", + "criteria": "A2abd", + "population_trend": "Decreasing", + "marine_system": false, + "freshwater_system": false, + "terrestrial_system": true, + "assessor": "Gobush, K.S., Edwards, C.T.T, Balfour, D., Wittemyer, G., Maisels, F. & Taylor, R.D.", + "reviewer": "Selier, J. & Sibanda, N.", + "aoo_km2": null, + "eoo_km2": null, + "elevation_upper": 2500, + "elevation_lower": 0, + "depth_upper": null, + "depth_lower": null, + "errata_flag": null, + "errata_reason": null, + "amended_flag": true, + "amended_reason": "This amended version has been created because Burkina Faso has been added to the list of Countries of Occurrence and the supporting reference for the occurrence added to the Bibliography. Also a reference cited in the Trade and Use section of the assessment has been deleted and removed from the Bibliography. In addition an errata version of the Supplementary Material has been attached; an error in Figure 1 has been corrected and some additional text about the data in Tables 2 and 3 has been added." + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/Fratercula%20arctica/region/europe": { + "name": "Fratercula arctica", + "region_identifier": "europe", + "result": [ + { + "taxonid": 22694927, + "scientific_name": "Fratercula arctica", + "kingdom": "ANIMALIA", + "phylum": "CHORDATA", + "class": "AVES", + "order": "CHARADRIIFORMES", + "family": "ALCIDAE", + "genus": "Fratercula", + "main_common_name": "Atlantic Puffin", + "authority": "(Linnaeus, 1758)", + "published_year": 2021, + "assessment_date": "2020-12-18", + "category": "EN", + "criteria": "A2abcde+4abcde", + "population_trend": "Decreasing", + "marine_system": true, + "freshwater_system": false, + "terrestrial_system": true, + "assessor": "BirdLife International", + "reviewer": "Burfield, I. & Martin, R.", + "aoo_km2": null, + "eoo_km2": null, + "elevation_upper": null, + "elevation_lower": null, + "depth_upper": null, + "depth_lower": null, + "errata_flag": null, + "errata_reason": null, + "amended_flag": null, + "amended_reason": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/id/181008073": { + "name": "181008073", + "result": [ + { + "taxonid": 181008073, + "scientific_name": "Loxodonta africana", + "kingdom": "ANIMALIA", + "phylum": "CHORDATA", + "class": "MAMMALIA", + "order": "PROBOSCIDEA", + "family": "ELEPHANTIDAE", + "genus": "Loxodonta", + "main_common_name": "African Savanna Elephant", + "authority": "(Blumenbach, 1797)", + "published_year": 2021, + "assessment_date": "2020-11-13", + "category": "EN", + "criteria": "A2abd", + "population_trend": "Decreasing", + "marine_system": false, + "freshwater_system": false, + "terrestrial_system": true, + "assessor": "Gobush, K.S., Edwards, C.T.T, Balfour, D., Wittemyer, G., Maisels, F. & Taylor, R.D.", + "reviewer": "Selier, J. & Sibanda, N.", + "aoo_km2": null, + "eoo_km2": null, + "elevation_upper": 2500, + "elevation_lower": 0, + "depth_upper": null, + "depth_lower": null, + "errata_flag": null, + "errata_reason": null, + "amended_flag": true, + "amended_reason": "This amended version has been created because Burkina Faso has been added to the list of Countries of Occurrence and the supporting reference for the occurrence added to the Bibliography. Also a reference cited in the Trade and Use section of the assessment has been deleted and removed from the Bibliography. In addition an errata version of the Supplementary Material has been attached; an error in Figure 1 has been corrected and some additional text about the data in Tables 2 and 3 has been added." + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/id/22694927/region/europe": { + "name": "22694927", + "region_identifier": "europe", + "result": [ + { + "taxonid": 22694927, + "scientific_name": "Fratercula arctica", + "kingdom": "ANIMALIA", + "phylum": "CHORDATA", + "class": "AVES", + "order": "CHARADRIIFORMES", + "family": "ALCIDAE", + "genus": "Fratercula", + "main_common_name": "Atlantic Puffin", + "authority": "(Linnaeus, 1758)", + "published_year": 2021, + "assessment_date": "2020-12-18", + "category": "EN", + "criteria": "A2abcde+4abcde", + "population_trend": "Decreasing", + "marine_system": true, + "freshwater_system": false, + "terrestrial_system": true, + "assessor": "BirdLife International", + "reviewer": "Burfield, I. & Martin, R.", + "aoo_km2": null, + "eoo_km2": null, + "elevation_upper": null, + "elevation_lower": null, + "depth_upper": null, + "depth_lower": null, + "errata_flag": null, + "errata_reason": null, + "amended_flag": null, + "amended_reason": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/category/LRlc": { + "count": 512, + "category": "LR/lc", + "result": [ + { + "taxonid": 36549, + "scientific_name": "Abarema commutata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34283, + "scientific_name": "Actinodaphne malaccensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36797, + "scientific_name": "Aegiphila cordifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36799, + "scientific_name": "Aegiphila sordida", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37432, + "scientific_name": "Agarista mexicana var. pinetorum", + "subspecies": "pinetorum", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 36801, + "scientific_name": "Ageratina macbridei", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 30537, + "scientific_name": "Aglaia argentea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33711, + "scientific_name": "Aglaia elaeagnoidea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33726, + "scientific_name": "Aglaia elliptica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34362, + "scientific_name": "Aglaia lawii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33712, + "scientific_name": "Aglaia odoratissima", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34919, + "scientific_name": "Aglaia sapindina", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34765, + "scientific_name": "Aglaia tomentosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33285, + "scientific_name": "Ailanthus integrifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35204, + "scientific_name": "Aiouea acarodomatifera", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38183, + "scientific_name": "Aiphanes ulei", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34502, + "scientific_name": "Alangium griffithi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33707, + "scientific_name": "Alangium javanicum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34503, + "scientific_name": "Alangium nobile", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36592, + "scientific_name": "Albizia decandra", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36586, + "scientific_name": "Albizia niopoides var. colombiana", + "subspecies": "colombiana", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 36589, + "scientific_name": "Albizia pistaciifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34299, + "scientific_name": "Alectryon excelsus var. grandis", + "subspecies": "grandis", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 37785, + "scientific_name": "Allantospermum borneense var. borneense", + "subspecies": "borneense", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 34277, + "scientific_name": "Allophylus rhomboidalis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35888, + "scientific_name": "Alniphyllum eberhardtii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34891, + "scientific_name": "Alnus glutinosa subsp. betuloides", + "subspecies": "betuloides", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 30473, + "scientific_name": "Alphitonia marquesensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36337, + "scientific_name": "Alseodaphne ridleyi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33175, + "scientific_name": "Alstonia angustifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33194, + "scientific_name": "Alstonia macrophylla", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33231, + "scientific_name": "Alstonia pneumatophora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31985, + "scientific_name": "Alstonia rupestris", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33900, + "scientific_name": "Anadenanthera colubrina var. cebil", + "subspecies": "cebil", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 33225, + "scientific_name": "Angelesia splendens", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32937, + "scientific_name": "Anisophyllea beccariana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31772, + "scientific_name": "Anisophyllea corneri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32938, + "scientific_name": "Anisophyllea disticha", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31279, + "scientific_name": "Aralia leschenaultii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35230, + "scientific_name": "Ardisia pulverulenta", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38422, + "scientific_name": "Ardisia standleyana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 2218, + "scientific_name": "Astraea heliotropium", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38755, + "scientific_name": "Astrocaryum aculeatissimum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35103, + "scientific_name": "Astronidium fraternum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35104, + "scientific_name": "Astronidium glabrum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35105, + "scientific_name": "Astronidium ligulatum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34378, + "scientific_name": "Astronidium robustum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35107, + "scientific_name": "Astronidium saccatum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34374, + "scientific_name": "Astronidium victoriae", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38757, + "scientific_name": "Attalea oleifera", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33702, + "scientific_name": "Azima sarmentosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39000, + "scientific_name": "Bactris constanciae", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31537, + "scientific_name": "Beilschmiedia pahangensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33933, + "scientific_name": "Bhesa paniculata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33934, + "scientific_name": "Bhesa robusta", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34641, + "scientific_name": "Biancaea sappan", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33590, + "scientific_name": "Brackenridgea hookeri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 3041, + "scientific_name": "Branchinecta gigas", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37814, + "scientific_name": "Brosimum alicastrum subsp. bolivarense", + "subspecies": "bolivarense", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 37648, + "scientific_name": "Calophyllum neoebudicum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37667, + "scientific_name": "Calophyllum pisiferum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33180, + "scientific_name": "Calophyllum soulattri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32285, + "scientific_name": "Calophyllum tetrapterum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33233, + "scientific_name": "Canarium asperum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33182, + "scientific_name": "Canarium littorale", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32128, + "scientific_name": "Canarium patentinervium", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33223, + "scientific_name": "Canarium pilosum subsp. pilosum", + "subspecies": "pilosum", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 38466, + "scientific_name": "Caryota no", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32149, + "scientific_name": "Cassia afrofistula var. patentipila", + "subspecies": "patentipila", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 33501, + "scientific_name": "Cassine viburnifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34617, + "scientific_name": "Catha edulis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34749, + "scientific_name": "Cecropia obtusifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 44066, + "scientific_name": "Ceropegia decidua", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35047, + "scientific_name": "Cheirodendron bastardianum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 46580, + "scientific_name": "Chelodina novaeguineae", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36532, + "scientific_name": "Chionanthus pubescens", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34287, + "scientific_name": "Chisocheton tomentosus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35369, + "scientific_name": "Chromolucuma rubriflora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35068, + "scientific_name": "Claoxylon collenettei", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38482, + "scientific_name": "Coccothrinax gundlachii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 5047, + "scientific_name": "Cochlicopa nitens", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39239, + "scientific_name": "Cololejeunea azorica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34413, + "scientific_name": "Comarostaphylis discolor var. discolor", + "subspecies": "discolor", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 38486, + "scientific_name": "Copernicia baileyana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38490, + "scientific_name": "Copernicia rigida", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38955, + "scientific_name": "Coprosma nephelephila", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38956, + "scientific_name": "Coprosma orohenensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38957, + "scientific_name": "Coprosma reticulata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33042, + "scientific_name": "Cordia millenii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 5362, + "scientific_name": "Coregonus artedi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34895, + "scientific_name": "Cotoneaster morulus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34896, + "scientific_name": "Cotoneaster transcaucasicus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33969, + "scientific_name": "Couroupita guianensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32817, + "scientific_name": "Craibiodendron stellatum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33200, + "scientific_name": "Cratoxylum arborescens", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33936, + "scientific_name": "Cratoxylum cochinchinense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33354, + "scientific_name": "Cratoxylum formosum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33937, + "scientific_name": "Cratoxylum maingayi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 5836, + "scientific_name": "Ctenophila salaziensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33350, + "scientific_name": "Cubilia cubili", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31757, + "scientific_name": "Cyathocalyx sumatranus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35943, + "scientific_name": "Cyathostemma vietnamense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 6066, + "scientific_name": "Cylindrovertilla kingi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34751, + "scientific_name": "Cynometra insularis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35010, + "scientific_name": "Cynometra minor", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35011, + "scientific_name": "Cynometra vitiensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31098, + "scientific_name": "Cyrtandra anthropophagorum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32846, + "scientific_name": "Dacryodes costata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32844, + "scientific_name": "Dacryodes laxa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33222, + "scientific_name": "Dacryodes rostrata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39714, + "scientific_name": "Darlingtonia californica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34985, + "scientific_name": "Decaspermum vitiense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31447, + "scientific_name": "Diospyros adenophora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34519, + "scientific_name": "Diospyros apiculata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36308, + "scientific_name": "Diospyros areolata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31448, + "scientific_name": "Diospyros argentea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31449, + "scientific_name": "Diospyros bibracteata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31455, + "scientific_name": "Diospyros foxworthyi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31457, + "scientific_name": "Diospyros ismailii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34520, + "scientific_name": "Diospyros latisepala", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31827, + "scientific_name": "Diospyros nutans", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31460, + "scientific_name": "Diospyros penangiana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37847, + "scientific_name": "Diospyros ridleyi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31461, + "scientific_name": "Diospyros rufa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37845, + "scientific_name": "Diospyros scortechinii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37841, + "scientific_name": "Diospyros singaporensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36310, + "scientific_name": "Diospyros transitoria", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31463, + "scientific_name": "Diospyros trengganuensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31464, + "scientific_name": "Diospyros tristis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32338, + "scientific_name": "Dipentodon sinicus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33078, + "scientific_name": "Dipterocarpus oblongifolius", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32823, + "scientific_name": "Disepalum petelotii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39010, + "scientific_name": "Dombeya rotundifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35949, + "scientific_name": "Drepananthus filiformis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31418, + "scientific_name": "Drepananthus pahangensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31419, + "scientific_name": "Drepananthus pruniferus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33212, + "scientific_name": "Dyera costulata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35500, + "scientific_name": "Ecclinusa bullata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32158, + "scientific_name": "Elaeodendron fruticosum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 46581, + "scientific_name": "Elseya novaeguineae", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 46582, + "scientific_name": "Emydura subglobosa ssp. subglobosa", + "subspecies": "subglobosa", + "rank": "ssp.", + "subpopulation": null + }, + { + "taxonid": 37156, + "scientific_name": "Endocomia macrocoma subsp. macrocoma", + "subspecies": "macrocoma", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 33345, + "scientific_name": "Engelhardtia rigida", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33710, + "scientific_name": "Engelhardtia serrata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32652, + "scientific_name": "Engelhardtia spicata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35950, + "scientific_name": "Enicosanthellum plagioneurum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33909, + "scientific_name": "Entandrophragma excelsum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 30678, + "scientific_name": "Eschweilera pittieri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31563, + "scientific_name": "Eugenia anisosepala", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31848, + "scientific_name": "Eugenia duthieana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31847, + "scientific_name": "Eugenia flosculifera", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31846, + "scientific_name": "Eugenia glauca", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31572, + "scientific_name": "Eugenia goodenovii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34291, + "scientific_name": "Eugenia gramae-andersonii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31573, + "scientific_name": "Eugenia inasensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31574, + "scientific_name": "Eugenia jasminifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31576, + "scientific_name": "Eugenia kemamensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31577, + "scientific_name": "Eugenia kiahii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31579, + "scientific_name": "Eugenia koordersiana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31580, + "scientific_name": "Eugenia laevicaulis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31844, + "scientific_name": "Eugenia nemestrina", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31981, + "scientific_name": "Eugenia oblongifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31583, + "scientific_name": "Eugenia oreophila", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31980, + "scientific_name": "Eugenia pauper", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31979, + "scientific_name": "Eugenia pendens", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31588, + "scientific_name": "Eugenia perakensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31589, + "scientific_name": "Eugenia pergamentacea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31590, + "scientific_name": "Eugenia polita", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31592, + "scientific_name": "Eugenia prainiana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31595, + "scientific_name": "Eugenia quadribracteata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34550, + "scientific_name": "Eugenia ridleyi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34551, + "scientific_name": "Eugenia scortechinii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31601, + "scientific_name": "Eugenia symingtoniana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31607, + "scientific_name": "Eugenia variolosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31609, + "scientific_name": "Eugenia wrayi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33618, + "scientific_name": "Euonymus cochinchinensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31269, + "scientific_name": "Euonymus grandiflorus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33706, + "scientific_name": "Euonymus javanicus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33040, + "scientific_name": "Euonymus latifolius subsp. cauconis", + "subspecies": "cauconis", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 8331, + "scientific_name": "Euploea configurata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 8333, + "scientific_name": "Euploea dentiplaga", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 8334, + "scientific_name": "Euploea doretta", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 8335, + "scientific_name": "Euploea eboraci", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 8336, + "scientific_name": "Euploea eupator", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 8340, + "scientific_name": "Euploea latifasciata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32403, + "scientific_name": "Euptelea pleiosperma", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37942, + "scientific_name": "Eurya rapensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34463, + "scientific_name": "Ficus albert-smithii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34464, + "scientific_name": "Ficus amazonica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34467, + "scientific_name": "Ficus broadwayi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34469, + "scientific_name": "Ficus castellviana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34470, + "scientific_name": "Ficus catappifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34474, + "scientific_name": "Ficus greiffiana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34475, + "scientific_name": "Ficus hebetifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34477, + "scientific_name": "Ficus krukovii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34479, + "scientific_name": "Ficus lauretana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34480, + "scientific_name": "Ficus malacocarpa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34482, + "scientific_name": "Ficus matiziana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34484, + "scientific_name": "Ficus monckii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34486, + "scientific_name": "Ficus pallida", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34487, + "scientific_name": "Ficus panurensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34491, + "scientific_name": "Ficus schippii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34492, + "scientific_name": "Ficus schultesii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34493, + "scientific_name": "Ficus schumacheri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34494, + "scientific_name": "Ficus sphenophylla", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34495, + "scientific_name": "Ficus trigonata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34499, + "scientific_name": "Ficus velutina", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37927, + "scientific_name": "Fitchia rapensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 1298, + "scientific_name": "Fluvidona simsoniana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31515, + "scientific_name": "Garcinia burkillii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31516, + "scientific_name": "Garcinia cantleyana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31520, + "scientific_name": "Garcinia hendersoniana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37830, + "scientific_name": "Garcinia maingayi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36326, + "scientific_name": "Garcinia minutiflora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31522, + "scientific_name": "Garcinia monantha", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31524, + "scientific_name": "Garcinia murtonii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31525, + "scientific_name": "Garcinia opaca", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36327, + "scientific_name": "Garcinia prainiana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31526, + "scientific_name": "Garcinia pyrifera", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34529, + "scientific_name": "Garcinia scortechinii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31527, + "scientific_name": "Garcinia uniflora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34622, + "scientific_name": "Gardenia gummifera", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31044, + "scientific_name": "Gardenia hutchinsoniana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34986, + "scientific_name": "Geissois ternata var. glabrior", + "subspecies": "glabrior", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 31029, + "scientific_name": "Geissois ternata var. ternata", + "subspecies": "ternata", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 31345, + "scientific_name": "Geniostoma confertiflorum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35100, + "scientific_name": "Geniostoma quadrangulare", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35101, + "scientific_name": "Geniostoma rapense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31341, + "scientific_name": "Geniostoma uninervium", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35537, + "scientific_name": "Gesneria exserta", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35071, + "scientific_name": "Glochidion longfieldiae", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 30470, + "scientific_name": "Glochidion marchionicum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35073, + "scientific_name": "Glochidion moorei", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35074, + "scientific_name": "Glochidion myrtifolium", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35076, + "scientific_name": "Glochidion taitense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35077, + "scientific_name": "Glochidion temehaniense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31411, + "scientific_name": "Gluta capituliflora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38264, + "scientific_name": "Gluta curtisii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31412, + "scientific_name": "Gluta lanceolata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35954, + "scientific_name": "Goniothalamus chinensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 9389, + "scientific_name": "Gonospira funicula", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 9401, + "scientific_name": "Gopherus berlandieri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38734, + "scientific_name": "Guapira myrtiflora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 9532, + "scientific_name": "Gulella plantii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35565, + "scientific_name": "Heisteria maguirei", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 9786, + "scientific_name": "Helicarion australis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33902, + "scientific_name": "Helicostylis tomentosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 29624, + "scientific_name": "Hemicycla glyceia ssp. glyceia", + "subspecies": "glyceia", + "rank": "ssp.", + "subpopulation": null + }, + { + "taxonid": 34506, + "scientific_name": "Heptapleurum hullettii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31256, + "scientific_name": "Heptapleurum taiwanianum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 30472, + "scientific_name": "Hernandia nukuhivensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38333, + "scientific_name": "Homalium longifolium", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35087, + "scientific_name": "Homalium moto", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35088, + "scientific_name": "Homalium mouo", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37162, + "scientific_name": "Horsfieldia moluccana var. petiolaris", + "subspecies": "petiolaris", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 34695, + "scientific_name": "Horsfieldia parviflora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33947, + "scientific_name": "Horsfieldia wallichii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 10786, + "scientific_name": "Ideopsis klassika", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38354, + "scientific_name": "Ilex diospyroides", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38959, + "scientific_name": "Ixora moorensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38964, + "scientific_name": "Ixora setchellii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37933, + "scientific_name": "Ixora stokesii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31837, + "scientific_name": "Kayea elegans", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33589, + "scientific_name": "Kibara coriacea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 22000, + "scientific_name": "Kimberleytrachia crawfordi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35013, + "scientific_name": "Kingiodendron platycarpum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 62994, + "scientific_name": "Kirkia burgeri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35506, + "scientific_name": "Kirkia burgeri subsp. burgeri", + "subspecies": "burgeri", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 37122, + "scientific_name": "Knema attenuata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33948, + "scientific_name": "Knema conferta", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31944, + "scientific_name": "Knema elmeri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34544, + "scientific_name": "Knema furfuracea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33357, + "scientific_name": "Knema glomerata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37129, + "scientific_name": "Knema kunstleri subsp. kunstleri", + "subspecies": "kunstleri", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 37105, + "scientific_name": "Knema latericia subsp. albifolia", + "subspecies": "albifolia", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 33725, + "scientific_name": "Knema latericia subsp. ridleyi", + "subspecies": "ridleyi", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 34606, + "scientific_name": "Knema latifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37098, + "scientific_name": "Knema laurina var. heteropilis", + "subspecies": "heteropilis", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 37097, + "scientific_name": "Knema laurina var. laurina", + "subspecies": "laurina", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 31947, + "scientific_name": "Knema linguiformis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34548, + "scientific_name": "Knema malayana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31952, + "scientific_name": "Knema oblongata subsp. oblongata", + "subspecies": "oblongata", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 34549, + "scientific_name": "Knema rubens", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32944, + "scientific_name": "Knema scortechinii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37137, + "scientific_name": "Knema stenophylla subsp. longipedicellata", + "subspecies": "longipedicellata", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 37136, + "scientific_name": "Knema stenophylla subsp. stenophylla", + "subspecies": "stenophylla", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 35581, + "scientific_name": "Lacistema robustum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35582, + "scientific_name": "Lafoensia pacari", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35587, + "scientific_name": "Lecythis ollaria", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39205, + "scientific_name": "Lepidozia azorica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39194, + "scientific_name": "Leptoscyphus azoricus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 41985, + "scientific_name": "Leptothorax recedens", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36360, + "scientific_name": "Lindera reticulosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33210, + "scientific_name": "Lophopetalum javanicum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33211, + "scientific_name": "Lophopetalum wightianum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35078, + "scientific_name": "Macaranga attenuata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35081, + "scientific_name": "Macaranga venosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32294, + "scientific_name": "Maclura brasiliensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36579, + "scientific_name": "Macrosamanea consanguinea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35971, + "scientific_name": "Magnolia fordiana var. fordiana", + "subspecies": "fordiana", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 31391, + "scientific_name": "Mangifera gracilipes", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33940, + "scientific_name": "Mangifera magnifica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31395, + "scientific_name": "Mangifera parvifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31402, + "scientific_name": "Mangifera quadrifida var. quadrifida", + "subspecies": "quadrifida", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 31405, + "scientific_name": "Mangifera sylvatica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33935, + "scientific_name": "Maranthes corymbosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38018, + "scientific_name": "Mastixia arborea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33502, + "scientific_name": "Mastixia trichotoma var. maingayi", + "subspecies": "maingayi", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 34539, + "scientific_name": "Matthaea sancta", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31413, + "scientific_name": "Melanochyla nitida", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38979, + "scientific_name": "Melicope revoluta", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31529, + "scientific_name": "Mesua daphnifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31531, + "scientific_name": "Mesua kunstleri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31532, + "scientific_name": "Mesua nivenii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31533, + "scientific_name": "Mesua nuda", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31536, + "scientific_name": "Mesua wrayi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38611, + "scientific_name": "Metroxylon warburgii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36716, + "scientific_name": "Miconia tomentosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35630, + "scientific_name": "Micropholis cayennensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35646, + "scientific_name": "Micropholis sanctae-rosae", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31718, + "scientific_name": "Monoon hypogaeum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36217, + "scientific_name": "Monoon membranifolium", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 6069, + "scientific_name": "Monoplex parthenopaeum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36238, + "scientific_name": "Mundulea sericea subsp. madagascariensis", + "subspecies": "madagascariensis", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 35110, + "scientific_name": "Myoporum rapense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37240, + "scientific_name": "Myristica bialata var. brevipila", + "subspecies": "brevipila", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 33278, + "scientific_name": "Myristica cinnamomea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33236, + "scientific_name": "Myristica elliptica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37213, + "scientific_name": "Myristica fatua subsp. fatua", + "subspecies": "fatua", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 37251, + "scientific_name": "Myristica fissiflora subsp. kostermansii", + "subspecies": "kostermansii", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 34990, + "scientific_name": "Myristica gillespieana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34988, + "scientific_name": "Myristica grandifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37877, + "scientific_name": "Myristica guatteriifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37235, + "scientific_name": "Myristica guillauminiana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33237, + "scientific_name": "Myristica iners", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37259, + "scientific_name": "Myristica inutilis subsp. papuana", + "subspecies": "papuana", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 37227, + "scientific_name": "Myristica inutilis subsp. platyphylla", + "subspecies": "platyphylla", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 37215, + "scientific_name": "Myristica lancifolia subsp. lancifolia", + "subspecies": "lancifolia", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 37216, + "scientific_name": "Myristica lancifolia subsp. montana", + "subspecies": "montana", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 34989, + "scientific_name": "Myristica macrantha", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33229, + "scientific_name": "Myristica maxima", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37221, + "scientific_name": "Myristica sangowoensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37325, + "scientific_name": "Myristica tristis subsp. moluccana", + "subspecies": "moluccana", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 37222, + "scientific_name": "Myristica tristis subsp. tristis", + "subspecies": "tristis", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 35116, + "scientific_name": "Myrsine collina", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38947, + "scientific_name": "Myrsine falcata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38948, + "scientific_name": "Myrsine fasciculata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35117, + "scientific_name": "Myrsine fusca", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38949, + "scientific_name": "Myrsine grantii var. grantii", + "subspecies": "grantii", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 38950, + "scientific_name": "Myrsine niauensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38951, + "scientific_name": "Myrsine nukuhivensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38952, + "scientific_name": "Myrsine ovalis var. wilderi", + "subspecies": "wilderi", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 37931, + "scientific_name": "Myrsine rapensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39664, + "scientific_name": "Nepenthes gymnamphora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39686, + "scientific_name": "Nepenthes pectinata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34369, + "scientific_name": "Neuburgia collina", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32489, + "scientific_name": "Ocotea puberula", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37928, + "scientific_name": "Oparanthus coriaceus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37929, + "scientific_name": "Oparanthus rapensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 15455, + "scientific_name": "Oreisplanus munionga ssp. larana", + "subspecies": "larana", + "rank": "ssp.", + "subpopulation": null + }, + { + "taxonid": 32152, + "scientific_name": "Ozoroa reticulata var. mossambicensis", + "subspecies": "mossambicensis", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 36198, + "scientific_name": "Pakaraimaea dipterocarpacea subsp. nitida", + "subspecies": "nitida", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 38990, + "scientific_name": "Pandanus temehaniensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 15978, + "scientific_name": "Papilio acheron", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 16142, + "scientific_name": "Parantica crowleyi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 16146, + "scientific_name": "Parantica kirbyi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 16149, + "scientific_name": "Parantica menadensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 16155, + "scientific_name": "Parantica pumila", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 16156, + "scientific_name": "Parantica rotundata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 16163, + "scientific_name": "Parantica weiskei", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34360, + "scientific_name": "Parasenegalia visco", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33232, + "scientific_name": "Parinari costata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31797, + "scientific_name": "Payena maingayi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31774, + "scientific_name": "Pellacalyx saccardianus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37393, + "scientific_name": "Peltophorum dasyrachis var. tonkinensis", + "subspecies": "tonkinensis", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 41601, + "scientific_name": "Pelusios castanoides", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 16530, + "scientific_name": "Pelusios rhodesianus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 41602, + "scientific_name": "Pelusios subniger", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34415, + "scientific_name": "Persea pyrifolia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38736, + "scientific_name": "Piper laevigatum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38988, + "scientific_name": "Pipturus polynesicus var. polynesicus", + "subspecies": "polynesicus", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 31369, + "scientific_name": "Pistacia malayana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35008, + "scientific_name": "Pittosporum pickeringii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37932, + "scientific_name": "Pittosporum rapense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35006, + "scientific_name": "Pittosporum rhytidocarpum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38954, + "scientific_name": "Pittosporum taitense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31024, + "scientific_name": "Plerandra seemanniana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31825, + "scientific_name": "Polyalthia chrysotricha", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38249, + "scientific_name": "Polyalthia lateritia", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 30469, + "scientific_name": "Polyscias marchionensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35056, + "scientific_name": "Polyscias verrucosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31830, + "scientific_name": "Popowia fusca", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35823, + "scientific_name": "Pouteria cayennensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35842, + "scientific_name": "Pouteria franciscana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35860, + "scientific_name": "Pouteria melanopoda", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35889, + "scientific_name": "Pouteria reticulata subsp. surinamensis", + "subspecies": "surinamensis", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 35898, + "scientific_name": "Pouteria sagotiana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35899, + "scientific_name": "Pouteria scrobiculata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35906, + "scientific_name": "Pouteria tenuisepala", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35907, + "scientific_name": "Pouteria trigonosperma", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35014, + "scientific_name": "Premna protrusa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37944, + "scientific_name": "Premna tahitensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38639, + "scientific_name": "Prestoea pubens var. pubens", + "subspecies": "pubens", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 33727, + "scientific_name": "Prunus arborea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31340, + "scientific_name": "Prunus grisea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31285, + "scientific_name": "Prunus henryi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33592, + "scientific_name": "Prunus javanica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31777, + "scientific_name": "Prunus malayana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33614, + "scientific_name": "Prunus marsupialis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33722, + "scientific_name": "Prunus polystachya", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 18391, + "scientific_name": "Prymnbriareus nimberlinus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31610, + "scientific_name": "Pseudoeugenia perakiana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37840, + "scientific_name": "Pseudoeugenia singaporensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38973, + "scientific_name": "Psychotria raivavaensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 18911, + "scientific_name": "Pupilla pupula", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 18919, + "scientific_name": "Pupisoma orcula", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 18973, + "scientific_name": "Pyrgulopsis micrococcus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34508, + "scientific_name": "Radermachera pinnata subsp. acuminata", + "subspecies": "acuminata", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 35968, + "scientific_name": "Rapanea allenii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32224, + "scientific_name": "Rhaptopetalum beguei", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31465, + "scientific_name": "Rhododendron wrayi", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36017, + "scientific_name": "Rhodoleia championii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 30654, + "scientific_name": "Rinorea dasyadena", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 19855, + "scientific_name": "Salmo salar", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32130, + "scientific_name": "Santiria apiculata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32843, + "scientific_name": "Santiria griffithii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32842, + "scientific_name": "Santiria laevigata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32841, + "scientific_name": "Santiria tomentosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37004, + "scientific_name": "Sarcaulus brasiliensis subsp. gracilis", + "subspecies": "gracilis", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 31700, + "scientific_name": "Sarcotheca glomerula", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39715, + "scientific_name": "Sarracenia flava", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39717, + "scientific_name": "Sarracenia minor", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39719, + "scientific_name": "Sarracenia psittacina", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39720, + "scientific_name": "Sarracenia purpurea subsp. purpurea", + "subspecies": "purpurea", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 39722, + "scientific_name": "Sarracenia purpurea subsp. venosa", + "subspecies": "venosa", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 30765, + "scientific_name": "Saurauia pustulata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31321, + "scientific_name": "Saurauia scabrida", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39222, + "scientific_name": "Sauteria spongiosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37810, + "scientific_name": "Scaevola floribunda", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38791, + "scientific_name": "Scalesia affinis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33255, + "scientific_name": "Scaphium macropodum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31025, + "scientific_name": "Schefflera vitiensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32017, + "scientific_name": "Schinopsis balansae", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32022, + "scientific_name": "Schinopsis quebracho-colorado", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37009, + "scientific_name": "Sciodaphyllum sprucei", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34557, + "scientific_name": "Scleropyrum wallichianum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33257, + "scientific_name": "Scutinanthe brunnea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35507, + "scientific_name": "Searsia glutinosa subsp. glutinosa", + "subspecies": "glutinosa", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 20111, + "scientific_name": "Semperdon heptaptychius", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34864, + "scientific_name": "Serianthes melanesica var. melanesica", + "subspecies": "melanesica", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 20162, + "scientific_name": "Setobaudinia collingii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32097, + "scientific_name": "Shorea robusta", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32307, + "scientific_name": "Shorea siamensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33704, + "scientific_name": "Siphonodon celastrineus", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31283, + "scientific_name": "Sloanea assamica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31275, + "scientific_name": "Sloanea tomentosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35468, + "scientific_name": "Solanum endopogon subsp. guianensis", + "subspecies": "guianensis", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 34729, + "scientific_name": "Sorbus aria subsp. lanifera", + "subspecies": "lanifera", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 31273, + "scientific_name": "Sorbus wallichii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31032, + "scientific_name": "Spiraeanthemum katakata", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39197, + "scientific_name": "Stenorrhipis rhizomatica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33949, + "scientific_name": "Sterculia parviflora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31414, + "scientific_name": "Swintonia robinsonii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38279, + "scientific_name": "Swintonia spicifera", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38701, + "scientific_name": "Syagrus picrophylla", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38702, + "scientific_name": "Syagrus pseudococos", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38703, + "scientific_name": "Syagrus ruschiana", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38704, + "scientific_name": "Syagrus smithii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35000, + "scientific_name": "Syzygium diffusum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36385, + "scientific_name": "Syzygium dyerianum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34994, + "scientific_name": "Syzygium fijiense", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35001, + "scientific_name": "Syzygium purpureum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35003, + "scientific_name": "Syzygium seemannianum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36388, + "scientific_name": "Syzygium stapfianum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32024, + "scientific_name": "Tabebuia impetiginosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 34504, + "scientific_name": "Tabernaemontana corymbosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35351, + "scientific_name": "Tabernaemontana thurstonii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32376, + "scientific_name": "Tetrameles nudiflora", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 21740, + "scientific_name": "Thermosphaeroma subequalum", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32161, + "scientific_name": "Thespesiopsis mossambicensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31287, + "scientific_name": "Tilia paucicostata var. yunnanensis", + "subspecies": "yunnanensis", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 21917, + "scientific_name": "Tirumala gautama", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 22018, + "scientific_name": "Toxotes oligolepis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38984, + "scientific_name": "Trema discolor", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 36110, + "scientific_name": "Trichilia stellato-tomentosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 22135, + "scientific_name": "Tridacna crocea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37943, + "scientific_name": "Trimenia weinmanniifolia subsp. marquesensis", + "subspecies": "marquesensis", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 32174, + "scientific_name": "Triplochiton scleroxylon", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 33367, + "scientific_name": "Unonopsis velutina", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 30756, + "scientific_name": "Vachellia chiapensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 30368, + "scientific_name": "Vachellia hebeclada subsp. chobiensis", + "subspecies": "chobiensis", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 33165, + "scientific_name": "Vatica odorata subsp. odorata", + "subspecies": "odorata", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 33156, + "scientific_name": "Vatica umbonata subsp. acrocarpa", + "subspecies": "acrocarpa", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 38714, + "scientific_name": "Veitchia macdanielsii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38724, + "scientific_name": "Wallichia triandra", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 37915, + "scientific_name": "Weinmannia affinis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35061, + "scientific_name": "Weinmannia parviflora var. marquesana", + "subspecies": "marquesana", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 35062, + "scientific_name": "Weinmannia parviflora var. parviflora", + "subspecies": "parviflora", + "rank": "var.", + "subpopulation": null + }, + { + "taxonid": 35064, + "scientific_name": "Weinmannia rapensis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31035, + "scientific_name": "Weinmannia richii", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38726, + "scientific_name": "Wettinia anomala", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38728, + "scientific_name": "Wettinia drudei", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38729, + "scientific_name": "Wettinia fascicularis", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38731, + "scientific_name": "Wettinia kalbreyeri", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 38982, + "scientific_name": "Wikstroemia coriacea", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 39058, + "scientific_name": "Woodfordia fruticosa", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 32119, + "scientific_name": "Wrightia pubescens subsp. lanitii", + "subspecies": "lanitii", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 31726, + "scientific_name": "Xylopia elliptica", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 31727, + "scientific_name": "Xylopia magna", + "subspecies": null, + "rank": null, + "subpopulation": null + }, + { + "taxonid": 35089, + "scientific_name": "Xylosma suaveolens subsp. gracile", + "subspecies": "gracile", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 35090, + "scientific_name": "Xylosma suaveolens subsp. pubigerum", + "subspecies": "pubigerum", + "rank": "subsp.", + "subpopulation": null + }, + { + "taxonid": 35091, + "scientific_name": "Xylosma suaveolens subsp. suaveolens", + "subspecies": "suaveolens", + "rank": "subsp.", + "subpopulation": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/citation/Loxodonta%20africana": { + "name": "loxodonta africana", + "result": [ + { + "citation": "Gobush, K.S., Edwards, C.T.T, Balfour, D., Wittemyer, G., Maisels, F. & Taylor, R.D. 2021. Loxodonta africana. The IUCN Red List of Threatened Species 2021: e.T181008073A204401095. https://dx.doi.org/10.2305/IUCN.UK.2021-2.RLTS.T181008073A204401095.en .Accessed on 9 September 2022" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/citation/Balaena%20mysticetus/region/europe": { + "name": "Balaena mysticetus", + "region_identifier": "europe", + "result": [ + { + "citation": "Species account by IUCN SSC Cetacean Specialist Group; regional assessment by European Mammal Assessment team 2007. Balaena mysticetus. The IUCN Red List of Threatened Species 2007: e.T2467A9442304. .Accessed on 9 September 2022" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/citation/id/181008073": { + "name": "181008073", + "result": [ + { + "citation": "Gobush, K.S., Edwards, C.T.T, Balfour, D., Wittemyer, G., Maisels, F. & Taylor, R.D. 2021. Loxodonta africana. The IUCN Red List of Threatened Species 2021: e.T181008073A204401095. https://dx.doi.org/10.2305/IUCN.UK.2021-2.RLTS.T181008073A204401095.en .Accessed on 9 September 2022" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/citation/id/2467/region/europe": { + "name": "2467", + "region_identifier": "europe", + "result": [ + { + "citation": "Species account by IUCN SSC Cetacean Specialist Group; regional assessment by European Mammal Assessment team 2007. Balaena mysticetus. The IUCN Red List of Threatened Species 2007: e.T2467A9442304. .Accessed on 9 September 2022" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/common_names/Loxodonta%20africana": { + "name": "loxodonta africana", + "result": [ + { + "taxonname": "African Savanna Elephant", + "primary": true, + "language": "eng" + }, + { + "taxonname": "Savanna Elephant", + "primary": false, + "language": "eng" + }, + { + "taxonname": "African Bush Elephant", + "primary": false, + "language": "eng" + }, + { + "taxonname": "African Savannah Elephant", + "primary": false, + "language": "eng" + }, + { + "taxonname": "Savannah Elephant", + "primary": false, + "language": "eng" + }, + { + "taxonname": "Éléphant de savane", + "primary": false, + "language": "fre" + }, + { + "taxonname": "Elefante de Sabana", + "primary": false, + "language": "spa" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/countries/id/181008073": { + "name": "181008073", + "count": 26, + "result": [ + { + "code": "AO", + "country": "Angola", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "BF", + "country": "Burkina Faso", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "BI", + "country": "Burundi", + "presence": "Extinct Post-1500", + "origin": "Native", + "distribution_code": "Regionally Extinct" + }, + { + "code": "BW", + "country": "Botswana", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "CD", + "country": "Congo, The Democratic Republic of the", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "CF", + "country": "Central African Republic", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "CM", + "country": "Cameroon", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ER", + "country": "Eritrea", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ET", + "country": "Ethiopia", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "KE", + "country": "Kenya", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ML", + "country": "Mali", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "MR", + "country": "Mauritania", + "presence": "Extinct Post-1500", + "origin": "Native", + "distribution_code": "Regionally Extinct" + }, + { + "code": "MW", + "country": "Malawi", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "MZ", + "country": "Mozambique", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "NA", + "country": "Namibia", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "NG", + "country": "Nigeria", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "RW", + "country": "Rwanda", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "SO", + "country": "Somalia", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "SS", + "country": "South Sudan", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "SZ", + "country": "Eswatini", + "presence": "Extant", + "origin": "Reintroduced", + "distribution_code": "Reintroduced" + }, + { + "code": "TD", + "country": "Chad", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "TZ", + "country": "Tanzania, United Republic of", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "UG", + "country": "Uganda", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ZA", + "country": "South Africa", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ZM", + "country": "Zambia", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ZW", + "country": "Zimbabwe", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/countries/id/22823/region/europe": { + "name": "22823", + "count": 3, + "region_identifier": "europe", + "result": [ + { + "code": "NO", + "country": "Norway", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "RU", + "country": "Russian Federation", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "SJ", + "country": "Svalbard and Jan Mayen", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/countries/name/Loxodonta%20africana": { + "name": "Loxodonta africana", + "count": 26, + "result": [ + { + "code": "AO", + "country": "Angola", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "BF", + "country": "Burkina Faso", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "BI", + "country": "Burundi", + "presence": "Extinct Post-1500", + "origin": "Native", + "distribution_code": "Regionally Extinct" + }, + { + "code": "BW", + "country": "Botswana", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "CD", + "country": "Congo, The Democratic Republic of the", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "CF", + "country": "Central African Republic", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "CM", + "country": "Cameroon", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ER", + "country": "Eritrea", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ET", + "country": "Ethiopia", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "KE", + "country": "Kenya", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ML", + "country": "Mali", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "MR", + "country": "Mauritania", + "presence": "Extinct Post-1500", + "origin": "Native", + "distribution_code": "Regionally Extinct" + }, + { + "code": "MW", + "country": "Malawi", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "MZ", + "country": "Mozambique", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "NA", + "country": "Namibia", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "NG", + "country": "Nigeria", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "RW", + "country": "Rwanda", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "SO", + "country": "Somalia", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "SS", + "country": "South Sudan", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "SZ", + "country": "Eswatini", + "presence": "Extant", + "origin": "Reintroduced", + "distribution_code": "Reintroduced" + }, + { + "code": "TD", + "country": "Chad", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "TZ", + "country": "Tanzania, United Republic of", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "UG", + "country": "Uganda", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ZA", + "country": "South Africa", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ZM", + "country": "Zambia", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "ZW", + "country": "Zimbabwe", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/countries/name/Ursus%20maritimus/region/europe": { + "name": "Ursus maritimus", + "count": 3, + "region_identifier": "europe", + "result": [ + { + "code": "NO", + "country": "Norway", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "RU", + "country": "Russian Federation", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + }, + { + "code": "SJ", + "country": "Svalbard and Jan Mayen", + "presence": "Extant", + "origin": "Native", + "distribution_code": "Native" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/history/id/181008073": { + "name": "181008073", + "result": [ + { + "year": "2021", + "assess_year": "2020", + "code": "EN", + "category": "Endangered" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/history/id/22823/region/europe": { + "name": "22823", + "region_identifier": "europe", + "result": [ + { + "year": "2007", + "assess_year": "2006", + "code": "VU", + "category": "Vulnerable" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/history/name/Loxodonta%20africana": { + "name": "Loxodonta africana", + "result": [ + { + "year": "2021", + "assess_year": "2020", + "code": "EN", + "category": "Endangered" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/history/name/Ursus%20maritimus/region/europe": { + "name": "Ursus maritimus", + "region_identifier": "europe", + "result": [ + { + "year": "2007", + "assess_year": "2006", + "code": "VU", + "category": "Vulnerable" + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/narrative/Loxodonta%20africana": { + "name": "loxodonta africana", + "result": [ + { + "species_id": 181008073, + "taxonomicnotes": "Three elephant taxa remain from the sixteen elephant-like species that are known from across the planet in the Pleistocene: Asian Elephant (Elephas maximus), African Savanna Elephant (Loxodonta africana), and African Forest Elephant (Loxodonta cyclotis) (Faurby and Svenning 2015, Malhi et al. 2016). The Asian and African ancestral lineages diverged approximately seven million years ago, and the African Savanna and African Forest ancestral lineages began diverging approximately one million years later (Rohland et al. 2010, Brandt et al. 2014, Roca et al. 2015, Meyer et al. 2017, Palkopoulou et al. 2018). The Third Edition of ‘Mammal Species of the World’ (Wilson and Reeder 2005) was the first to formally designate the African elephant as these two separate species. Recent genetic findings also support this designation (Roca et al. 2007, Ishida et al. 2011, Mondol et al. 2015, Palkopoulou et al. 2018, Kim and Wasser 2019). Hybridization between the two species appears restricted and evident at only 14 of the more than 100 localities recently examined across the vast forest-savanna ecotone. In nine of these 14 localities, hybrid individuals occurred alongside non-hybrid individuals of either one species or the other and not both (i.e., three localities had hybrids and African Forest Elephants only and assigned as this species; six localities had hybrids and African Savanna Elephants only and assigned as this species). For the IUCN Red List assessments, a distribution map published in Mondol et al. (2015) and recent data by Kim and Wasser (2019) are used to assign localities as range of either L. africana or L. cyclotis.", + "rationale": "

The African Savanna Elephant (Loxodonta africana) is assessed as Endangered A2abd. Analysis of estimates from 334 localities across their global range indicates a reduction of more than 50% of the continental population in the past three generations (75 years) that is understood to be continuing and likely irreversible. The continental trend is not, however, spatially uniform; some subpopulations are increasing or stable while others are declining significantly faster than the continental rate. Many local subpopulations have been extirpated.

A generation length (GL) of 25 years is used; calculated in the standard format as the average age of mothers in the population (IUCN SPC 2019, p. 29). This figure is based on analysis of the life table of culled Savanna Elephant family groups in South Africa (Whyte 2001) and a 14-year study of Savanna Elephants in Kenya (Wittemyer et al. 2013) which generated a range of 24.1–25 years.

Subcriterion A2 is applied because some of the major causes for population reduction, such as habitat loss due to human population expansion, have not ceased and are projected to increase in coming decades as well as unlikely to be reversible. The population reduction assessment for subcriterion A2 (considering three generations back) is inferred from published survey data using a modelling approach described in the Supplementary Information document. Density and distribution estimates for the African Savanna Elephant vary in methodology, completeness, regularity, date of first survey and confidence limits. Few credible estimates exist prior to the 1970s, and there is no credible estimate for the continental population more than two generations back. For this Red List assessment, an attempt was made to model the data three generations back to 1940 (see the attached Supplementary Information for description of data that is current as of and up to the end of 2015); however, given the sparseness of information available to inform the model, such modelling was of limited value. Therefore, rather than projecting declines well beyond the available data, we made the assumption that the continental African Savanna Elephant population of three generations back (1940) was equal to that of two generations back (i.e., 1965). Additional assumptions, necessary to fill gaps in the dataset, are detailed in the attached Supplementary Information document.

Subcriterion A3 has not been applied, because although the major threats to the species are known, projecting the level of such threats 25 or more years into the future (i.e., three generations, up to a maximum of 100 years) would likely introduce high levels of uncertainty.

An assessment of population reduction according to subcriterion A4 considering two generations back and one forward is in progress by this team of Assessors (Edwards et al. in prep.). Analysis of poaching and human influence in the recent past and anticipated in the future based upon available data of two representative indices (i.e., proportion of illegal killed elephants (PIKE) and the human footprint index) are being included as covariates in the projection.

Criteria B, C and D are not relevant to the threatened status as the species currently occupies more than 20,000 km2 and there are more than 10,000 mature individuals. No quantitative analysis of the probability of extinction in the wild was conducted, and therefore criterion E does not apply.


Previous Assessments of African Elephant:
This is the first assessment of the African Savanna Elephant (Loxodonta africana) as a species separate from the African Forest Elephant (L. cyclotis).

The African Elephant, as a single species, was listed as Vulnerable (VU A2a) in the 2004 and 2008 updates of the IUCN Red List of Threatened Species, under the same IUCN Categories and Criteria used in this assessment (Version 3.1; IUCN 2001).

Previously the African Elephant, as a single species, was listed as Endangered (EN A1b) under the IUCN Categories and Criteria Version 2.3 (IUCN 1994), in an assessment conducted in 1996 by the IUCN SSC African Elephant Specialist Group.

", + "geographicrange": "

African Savanna Elephants once occurred across all of Africa (Sikes 1971) and currently are found in 24 countries (see range map). Although knowledge of African Savanna Elephant distribution varies spatially and temporally, it is evident that the species’ distribution is retracting and becoming increasingly fragmented across their range in the continent. African Savanna Elephants occupy an estimated 15% of their historic pre- agricultural range (Chase et al. 2016). African Savanna Elephants are considered nationally extirpated in Burundi and Mauritania. In Eswatini, the once extirpated population has been re-established through reintroductions that began in the 1980s. Recent range expansion is evident in Kenya and Botswana (Douglas-Hamilton 1979; Said et al. 1995; Barnes et al. 1998; Blanc et al. 2003, 2007; Thouless et al. 2016).

The species' range map associated with this assessment is complete with the exception that some small private reserves in South Africa with less than 50 elephants each are absent as they were excluded from the African Elephant Database due to concerns about the census techniques.

", + "population": "

Over the past century, African Savanna Elephant subpopulations have declined across most of their range. The African Elephant Status Report 2016 estimated a continental population of 415,428 (+/- 95% C.I. 20,111) for both African Savanna and African Forest Elephants combined and reported a continental decline of approximately 111,000 elephants since 2006 (Thouless et al. 2016). For a similar time period, following a survey of approximately 90% of their range, a decline of 30% of African Savanna Elephants was reported (Chase et al. 2016).


For further information about this species, see the attached Supplementary Information document.

", + "populationtrend": "decreasing", + "habitat": "

African Savanna Elephants are found over a wide latitudinal range between the northern tropics in Mali (16° North) to the southern temperate zone (34° South) in South Africa. They occupy a variety of habitats ranging from montane forest, miombo and mopane woodland, thicket, savanna and grasslands to arid deserts and a wide altitudinal range from mountain slopes to oceanic beaches.

See also the list of habitats.

African Savanna Elephants are capable of moving long distances and naturally do so in arid ecosystems and in response to climatic conditions (e.g., seasonality and drought). Depending on productivity, and water availability African Savanna Elephants demonstrate range residence, migratory, semi-migratory and near nomadic movement patterns in different regions of the continent. Home range sizes vary by several orders of magnitude primarily in relation to plant productivity and human activity in different ecosystems (Loarie et al. 2009, Wall et al. 2013). Thirty African Savanna Elephant subpopulations (eight of which number more than 1,000 individuals) span international boundaries, including the more than 200,000 elephants in the five-country Kavango-Zambezi Transfrontier Conservation Area (Lindsay et al. 2017, KAZA Secretariat 2018).

Ecosystem Services:
Ecosystem services provided by African Savanna Elephants vary and depend to a large extent on the ecosystem (forest, savanna, grassland or desert), specific conditions on the ground and the geographical context under consideration. In general, they play an important ecological role as bulk processors of plant material (Owen-Smith 1989). In savannas, African Savanna Elephants are manipulators of woody vegetation structure which in turn influences the tree to grass ratio with knock-on consequences for the fire regime and potentially species composition in the area (Dublin et al. 1990, Augustine and McNaughton 2004, Palmer et al. 2008, Holdo et al. 2009, Goheen et al. 2010, Pringle et al. 2016). Where they are associated with wetlands African Savanna Elephants can be important in maintaining channels and open water ways. Soil fertility can be maintained by the transport of nutrients by large herbivores from nutrient rich sources (e.g., eutrophic soils in flood plains and termite mounds) to dystrophic soils (e.g., upland miombo woodlands) (Cumming et al. 1997, Doughty et al. 2016, Malhi et al. 2016).


The charismatic nature of African Savanna Elephants plays an important role in attracting tourism into national parks. They also hold important symbolic significance within the cultures of many African communities. African Savanna Elephants are one of the few iconic species that occur in the majority of African countries, and innumerable stories, songs, and cultural traditions revolve around them.

", + "threats": "Poaching of African Savanna Elephants for ivory is a major cause of individual death and population decline (Wittemyer et al. 2014, Thouless et al. 2016). After a sustained period of intense poaching between the late 1970s and 1989, many African Savanna Elephant populations (e.g., in Kenya, Tanzania, Zambia, Uganda) experienced two to three decades of recovery. Some northern African Savanna Elephant populations, however, experienced persistent poaching pressure through the last three decades (Bouche et al. 2011, 2012). Data collected as a part of the CITES Monitoring the Illegal Killing of Elephants programme (MIKE), indicate that poaching significantly intensified across the continent starting in 2008 and peaking in 2011 – an unsustainably high level of poaching has continued into current times in some areas of the continent (CITES 2018, 2019), and may be increasing in some of the historically less-affected southern African populations (CITES 2018, 2019). Rapid land use change by humans is driving the direct loss and fragmentation of habitat for African Savanna Elephants and is an increasing threat to populations across their range (Thouless et al. 2016, Mpakairi et al. 2019). Land conversion is a product of the ongoing expansion of the human population and associated agriculture and infrastructure development, which in turn are driven by economic and technological advances. A manifestation of this trend is the reported increase in human-elephant conflict (e.g., Pozo et al. 2018). Human population growth projections suggest land conversion will accelerate rapidly in the coming decades across Africa (see https://population.un.org/wpp/Publications/) which will likely increase this threat.", + "conservationmeasures": "

The African Savanna Elephant was listed in CITES Appendix I in 1989 when all African elephants were considered a single species. Subsequently, the populations of Botswana (1997), Namibia (1997), South Africa (2000) and Zimbabwe (1997) were transferred to Appendix II, each with specific annotations. These annotations have been recently replaced by a single annotation for all four countries, with specific sub-annotations for the populations of Namibia and Zimbabwe. A separate CITES listing for each species has not occurred yet because a formal designation as two separate species (i.e., Loxodonta africana and L. cyclotis) is still in progress.

The African Elephant Action Plan (AEAP; developed and adopted by African elephant range countries) was adopted by CITES in March 2010 and is a statement by all range countries regarding the most important and immediate activities which require implementation and funding if Africa’s elephants are to be conserved. The African Elephant Fund was established to support the implementation of the African Elephant Action Plan. It should be noted that the AEAP does not distinguish different taxa of African elephant. The African Savanna Elephants which occur in transboundary populations introduce complications (e.g., matters of sovereignty) when considering national populations for CITES purposes (Lindsay et al. 2017).

A number of CITES-initiated instruments were created to monitor and combat illegal trade in ivory. The CITES MIKE programme, which was established in 2002, has 66 designated sites across African elephant range and provides the most detailed and reliable data available on continental poaching pressure (CITES 2018, 2019); this includes 39 sites in 18 range countries of the African Savanna Elephant (https://cites.org/eng/prog/mike, Accessed 16 August 2020). Eswatini, South Sudan, Central African Republic, the Democratic Republic of the Congo and Somalia do not have MIKE sites for their African Savanna Elephants. The Elephant Trade Information System (ETIS), established in 1996, is managed by TRAFFIC as a comprehensive information system for tracking illegal trade in ivory and other elephant products (CITES 2016, 2019). At a national level National Ivory Action Plans (NIAPs) are a tool designed to track significant and timely action to combat the illegal trade in ivory. Currently 24 African, Middle Eastern, and Asian countries, as identified by ETIS analyses, are required to produce and implement a NIAP (https://cites.org/eng/niaps, Accessed 16 August 2020); 11 of these are range countries of the African Savanna Elephant.

At a national level the African Savanna Elephant is subject to varying degrees of legal protection in the 23 range states, with most countries granting the species the highest protection status. Providing this protection is complicated by the fact that over half of the species’ range may extend beyond the boundaries of protected areas (Taylor 2009). This point is emphasized by the evidence that the degree of protection is an important predictor of African Savanna Elephant’s presence and density (de Boer et al. 2013).

Conservation measures usually include habitat management and protection through policy, legislation and law enforcement. Successful anti-poaching and management at a site level has contributed to the re-establishment or recovery of a number of populations of African Savanna Elephants. In instances where protection efforts have failed, the African Savanna Elephant population was reduced by 70% or more in a matter of a decade (Chase et al. 2016).

In the context where management culling was undertaken (mainly southern Africa) up until the late 1980s or early 1990s, culling has largely ceased and population density management is being attempted through actions such as translocation, contraception and range manipulation such as closure of artificial water point (Scholes and Mennell 2008). Fire management is being attempted in some transboundary situations to mitigate further habitat and/or woodland modification as a consequence of African Savanna Elephant activity (Starfield et al. 1993, Mapaure 2013, Eastment 2020). 

", + "usetrade": "Ivory: Use of African Savanna Elephant ivory is entrenched in numerous cultures across the globe, primarily for ornamental and decorative items. Historically, demand for African Savanna Elephant ivory has been high in Europe, the USA and Asia. For example, beginning in the 1920s, Japanese carvers turned to African elephant ivory as Asian supplies diminished through the 1970s when Japan accounted for about 40% of the global ivory market (Martin 1986; Nishihara 2003, 2012).

In 1989, the Convention on International Trade of Endangered Species of Wild Flora and Fauna (CITES) banned the international commercial trade of ivory in response to a steep decline in African elephants across a substantial portion of their range. Thereafter, two CITES-sanctioned sales of national ivory stockpiles occurred in 2002 and 2008 with Botswana, Zimbabwe, Namibia and South Africa selling ivory to China and Japan. At the same time, a nine-year moratorium (ending in 2017) on any new ivory sale proposals from the four African countries followed (www.cites.org). In the 2000s, Chinese demand for ivory greatly surpassed that of Japan where demand for ivory appeared to substantially decline (CITES 2014). As a consequence, prices rose steeply in China and in Africa (Wittemyer et al. 2011, 2014). Debates about the benefits and consequences of the sale of national ivory stockpiles are highly polarized with limited consensus (Stiles 2004, 't Sas-Rolfes et al. 2014, Bennett 2015, Biggs et al. 2017).

Analysis of ivory seizure data indicates that the volume of illegally trafficked ivory has increased substantially since 2006 (Underwood et al. 2013; Milliken 2016; CITES 2018, 2019). Undercover investigations and DNA forensics point to the laundering of illegal ivory in legal domestic ivory markets. Seizure analyses indicate that the majority of illegally trafficked ivory is destined for Asia, especially China, Viet Nam and Thailand (CITES 2016, 2018 and 2019; Lui 2015; Krishnasamy 2016). In response to this and other concerns, China closed its legal domestic ivory market in 2017; Hong Kong SAR took steps to do the same by 2021 (https://www.info.gov.hk/gia/general/201706/02/P2017060100655.htm), and Thailand tightened its domestic Asian Elephant ivory trade regulations in 2015 (http://www.mfa.go.th/main/en/media-center/14/52929-Thailand-Submits-First-Progress-Report-on-Implemen.html). A substantial drop in ivory prices in mainland China has been associated with this action (Vigne and Martin 2017, Meijer et al. 2018). Significant illegal ivory markets remain in several Southeast Asian countries, such as Lao PDR and Viet Nam (www.cites.org; Vigne and Martin 2017).

Non-consumptive Tourism: 
African Savanna Elephants have significant tourism draw for wildlife watching and photographic tourism throughout their range substantially contributing to local economies (Naidoo et al. 2016). Tourism operations occur in national and local government protected areas, as well as on land under private or communal tenure.

Trophy Hunting: In some range states sport hunting of African Savanna Elephants is legally permitted and forms an integral element of those countries’ wildlife management and community support programs (e.g., Naidoo et al. 2016). Botswana, Mozambique, Namibia, South Africa, Tanzania and Zimbabwe have trophy hunting industries and in 2020 applied to CITES for a combined quota of 2,404 tusks (https://cites.org/eng/resources/quotas/index.php Accessed 16 August 2020). Depending on the governance and management structures, government bodies, private operations and local communities derive revenue from trophy hunting.

Other Trade: A legal domestic trade in African Savanna Elephant hides is present in South Africa. There have been limited reports of African Savanna Elephant poaching for other body parts beyond ivory, such as meat, bone, skin and hair (Blignaut et al. 2008). International live trade in African Savanna Elephants occurs between South Africa and other countries, mainly in an effort to re-establish or fortify dwindling populations in some protected areas. Live trade in young African Savanna Elephants from Zimbabwe (Russo and Cruise 2016) and Eswatini (Madowo 2019) to Asia and elsewhere for zoological collections also occurs. Controversy surrounds these transactions as the conservation benefit to the species has been questioned. Domestic trade in African Savanna Elephants exists in South Africa at a low level for reintroduction purposes between reserves (Pretorius et al. 2018)." + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/narrative/Fratercula%20arctica/region/europe": { + "name": "Fratercula arctica", + "region_identifier": "europe", + "result": [ + { + "species_id": 22694927, + "taxonomicnotes": null, + "rationale": "European regional assessment: Endangered (EN)
EU28 regional assessment: Least Concern (LC)


In Europe, this species has an extremely large range (its extent of occurrence (EOO) is much larger than 20,000 km² and its area of occupancy (AOO) is much larger than 2,000 km²), and hence it does not approach the thresholds for Vulnerable under the range size criteria (criteria B and D2). The population size is extremely large, (much larger than 10,000 mature individuals), and hence it does not approach the thresholds for Vulnerable under the population size criteria (criteria C and D). The probability of extinction has not been calculated for this species, therefore criterion E cannot be applied. The population trend appears to be decreasing at a very rapid rate which meets the thresholds for Endangered (EN) under the population size reduction criterion (criterion A). The species is therefore assessed as such in Europe. There is not considered to be significant potential for rescue from outside the region, and therefore the final category remains unchanged. 

In the EU28, this species has a very large range (its extent of occurrence (EOO) is much larger than 20,000 km² and its area of occupancy (AOO) is much larger than 2,000 km²), and hence it does not approach the thresholds for Vulnerable under the range size criteria (criteria B and D2). The population size is extremely large, (much larger than 10,000 mature individuals), and hence it does not approach the thresholds for Vulnerable under the population size criteria (criteria C and D). The population trend appears to be increasing, and hence the species does not approach the thresholds for Vulnerable under the population size reduction criterion (criterion A). The probability of extinction has not been calculated for this species, therefore criterion E cannot be applied. For these reasons the species is evaluated as Least Concern in the EU28.", + "geographicrange": "The species can be found throughout the North Atlantic Ocean. In Europe, it occurs in north-west Greenland (to Denmark), and from north Norway down to the Canary Islands, Spain in the east (Nettleship et al. 2014), and breeds primarily in Norway and Iceland, and also notably in the United Kingdom and the Faroe Islands.", + "population": "The European breeding population is estimated at 3,700,000-4,120,000 pairs, which equates to 7,400,000-8,240,000 mature individuals. The breeding population in the EU28 is estimated at 601,000-602,000 pairs, which equates to 1,200,000-1,210,000 mature individuals. For details of national estimates, see the Supplementary Information.", + "populationtrend": "decreasing", + "habitat": "The breeding range is restricted to colder parts of the Atlantic and Arctic Oceans, with its southernmost colonies in Brittany (France).  Breeding colonies are located in Iceland, Norway, Faroe Islands, the U.K., Ireland and France on islands or high cliffs.

The species nests on grassy maritime slopes, sea cliffs and rocky slopes (Nettleship et al. 2014). During the winter the species is highly pelagic and is dispersed widely across the sea from the Azores to the western Mediterranean and Canary Islands. When feeding chicks, birds generally forage within 10 km of their colony, but may range as far as 50 to 100 km or more (Harris 1984, Rodway and Montevecchi 1996). Birds of this species are pursuit-divers that catch most of their prey within 30 m of the water surface (Piatt and Nettleship 1985). They prey on 'forage' species, including juvenile pelagic fishes, such as herring (Clupea harengus), juvenile and adult capelin (Mallotus villosus), and sand eel (Ammodytes spp.) (Barrett et al. 1987). At times, they also prey on juvenile demersal fishes, such as gadids (Harris and Hislop 1978, Martin 1989, Rodway and Montevecchi 1996). Sand eels usually form the majority of the prey fed to chicks (Corkhill 1973, Hislop and Harris 1985, Harris and Wanless 1986, Harris and Riddiford 1989, Martin 1989), and many chicks starve during periods of low sand eel abundance (Martin 1989).

Although the generation length for both EU and Europe regional assessments were calculated using the same methodology, new information arriving after the EU assessments were undertaken gave rise to an update in the generation lengths. This new information was then used for the Europe level assessments giving rise to a difference between the generation lengths used for the EU and Europe regions.", + "threats": "This species is highly susceptible to the impacts of climate change, such as sea temperature rise and shifts in prey distribution and abundance (Durant et al. 2003, Sandvik et al. 2005). This is a particularly important threat when prey species are exploited unsustainably, leading to prey reductions and subsequent unsuccessful breeding. The species is vulnerable to oil spills and other marine pollution. The species is also vulnerable to extreme weather events and storms, with large wrecks recorded following severe winter storms at sea. At the breeding colonies the species is vulnerable to invasive predators, such as rats, cats, and American Mink (Neovison vison). The species is susceptible to being caught in gillnets, although other fishing gears may also catch significant numbers. Increasing numbers of offshore wind farms may result in displacement from habitat, although the risk of collision is considered very low (Bradbury et al. 2014). The species is hunted for human consumption in Iceland, and in the Faroe Islands (Thorup et al. 2014).", + "conservationmeasures": "Conservation Actions Underway
The species is listed under the African Eurasian Waterbird Agreement. The species is included in the Action plan for seabirds in Western-Nordic areas (2010). There are 76 marine Important Bird Areas identified across the European region. Within the EU there are 40 Special Protection Areas which list this species as occurring within its boundaries.

Conservation Actions Proposed
Further identification of important sites for this species, particularly in offshore regions and designation as marine protected areas; Identify the risks of different activities on seabirds, and locations sensitive to seabirds. Continue eradication of invasive predators from breeding colonies. Management of fisheries to ensure long term sustainability of key stocks (e.g. sand eels). Establish observer schemes for bycatch and prepare National/European Community plans of action on seabird bycatch. Continue AMAP monitoring of seabird contaminants; include new contaminants and secure communication between seabird and contaminants research. Increase the level of understanding among the public of introducing hunting restrictions. Develop codes-of-conduct for more organised activities (e.g. tourism). Ensure that appropriate protection (national laws and international agreements) applies to new areas and times in cases of changes in seabird migration routes and times.", + "usetrade": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/narrative/id/181008073": { + "name": "181008073", + "result": [ + { + "species_id": 181008073, + "taxonomicnotes": "Three elephant taxa remain from the sixteen elephant-like species that are known from across the planet in the Pleistocene: Asian Elephant (Elephas maximus), African Savanna Elephant (Loxodonta africana), and African Forest Elephant (Loxodonta cyclotis) (Faurby and Svenning 2015, Malhi et al. 2016). The Asian and African ancestral lineages diverged approximately seven million years ago, and the African Savanna and African Forest ancestral lineages began diverging approximately one million years later (Rohland et al. 2010, Brandt et al. 2014, Roca et al. 2015, Meyer et al. 2017, Palkopoulou et al. 2018). The Third Edition of ‘Mammal Species of the World’ (Wilson and Reeder 2005) was the first to formally designate the African elephant as these two separate species. Recent genetic findings also support this designation (Roca et al. 2007, Ishida et al. 2011, Mondol et al. 2015, Palkopoulou et al. 2018, Kim and Wasser 2019). Hybridization between the two species appears restricted and evident at only 14 of the more than 100 localities recently examined across the vast forest-savanna ecotone. In nine of these 14 localities, hybrid individuals occurred alongside non-hybrid individuals of either one species or the other and not both (i.e., three localities had hybrids and African Forest Elephants only and assigned as this species; six localities had hybrids and African Savanna Elephants only and assigned as this species). For the IUCN Red List assessments, a distribution map published in Mondol et al. (2015) and recent data by Kim and Wasser (2019) are used to assign localities as range of either L. africana or L. cyclotis.", + "rationale": "

The African Savanna Elephant (Loxodonta africana) is assessed as Endangered A2abd. Analysis of estimates from 334 localities across their global range indicates a reduction of more than 50% of the continental population in the past three generations (75 years) that is understood to be continuing and likely irreversible. The continental trend is not, however, spatially uniform; some subpopulations are increasing or stable while others are declining significantly faster than the continental rate. Many local subpopulations have been extirpated.

A generation length (GL) of 25 years is used; calculated in the standard format as the average age of mothers in the population (IUCN SPC 2019, p. 29). This figure is based on analysis of the life table of culled Savanna Elephant family groups in South Africa (Whyte 2001) and a 14-year study of Savanna Elephants in Kenya (Wittemyer et al. 2013) which generated a range of 24.1–25 years.

Subcriterion A2 is applied because some of the major causes for population reduction, such as habitat loss due to human population expansion, have not ceased and are projected to increase in coming decades as well as unlikely to be reversible. The population reduction assessment for subcriterion A2 (considering three generations back) is inferred from published survey data using a modelling approach described in the Supplementary Information document. Density and distribution estimates for the African Savanna Elephant vary in methodology, completeness, regularity, date of first survey and confidence limits. Few credible estimates exist prior to the 1970s, and there is no credible estimate for the continental population more than two generations back. For this Red List assessment, an attempt was made to model the data three generations back to 1940 (see the attached Supplementary Information for description of data that is current as of and up to the end of 2015); however, given the sparseness of information available to inform the model, such modelling was of limited value. Therefore, rather than projecting declines well beyond the available data, we made the assumption that the continental African Savanna Elephant population of three generations back (1940) was equal to that of two generations back (i.e., 1965). Additional assumptions, necessary to fill gaps in the dataset, are detailed in the attached Supplementary Information document.

Subcriterion A3 has not been applied, because although the major threats to the species are known, projecting the level of such threats 25 or more years into the future (i.e., three generations, up to a maximum of 100 years) would likely introduce high levels of uncertainty.

An assessment of population reduction according to subcriterion A4 considering two generations back and one forward is in progress by this team of Assessors (Edwards et al. in prep.). Analysis of poaching and human influence in the recent past and anticipated in the future based upon available data of two representative indices (i.e., proportion of illegal killed elephants (PIKE) and the human footprint index) are being included as covariates in the projection.

Criteria B, C and D are not relevant to the threatened status as the species currently occupies more than 20,000 km2 and there are more than 10,000 mature individuals. No quantitative analysis of the probability of extinction in the wild was conducted, and therefore criterion E does not apply.


Previous Assessments of African Elephant:
This is the first assessment of the African Savanna Elephant (Loxodonta africana) as a species separate from the African Forest Elephant (L. cyclotis).

The African Elephant, as a single species, was listed as Vulnerable (VU A2a) in the 2004 and 2008 updates of the IUCN Red List of Threatened Species, under the same IUCN Categories and Criteria used in this assessment (Version 3.1; IUCN 2001).

Previously the African Elephant, as a single species, was listed as Endangered (EN A1b) under the IUCN Categories and Criteria Version 2.3 (IUCN 1994), in an assessment conducted in 1996 by the IUCN SSC African Elephant Specialist Group.

", + "geographicrange": "

African Savanna Elephants once occurred across all of Africa (Sikes 1971) and currently are found in 24 countries (see range map). Although knowledge of African Savanna Elephant distribution varies spatially and temporally, it is evident that the species’ distribution is retracting and becoming increasingly fragmented across their range in the continent. African Savanna Elephants occupy an estimated 15% of their historic pre- agricultural range (Chase et al. 2016). African Savanna Elephants are considered nationally extirpated in Burundi and Mauritania. In Eswatini, the once extirpated population has been re-established through reintroductions that began in the 1980s. Recent range expansion is evident in Kenya and Botswana (Douglas-Hamilton 1979; Said et al. 1995; Barnes et al. 1998; Blanc et al. 2003, 2007; Thouless et al. 2016).

The species' range map associated with this assessment is complete with the exception that some small private reserves in South Africa with less than 50 elephants each are absent as they were excluded from the African Elephant Database due to concerns about the census techniques.

", + "population": "

Over the past century, African Savanna Elephant subpopulations have declined across most of their range. The African Elephant Status Report 2016 estimated a continental population of 415,428 (+/- 95% C.I. 20,111) for both African Savanna and African Forest Elephants combined and reported a continental decline of approximately 111,000 elephants since 2006 (Thouless et al. 2016). For a similar time period, following a survey of approximately 90% of their range, a decline of 30% of African Savanna Elephants was reported (Chase et al. 2016).


For further information about this species, see the attached Supplementary Information document.

", + "populationtrend": "decreasing", + "habitat": "

African Savanna Elephants are found over a wide latitudinal range between the northern tropics in Mali (16° North) to the southern temperate zone (34° South) in South Africa. They occupy a variety of habitats ranging from montane forest, miombo and mopane woodland, thicket, savanna and grasslands to arid deserts and a wide altitudinal range from mountain slopes to oceanic beaches.

See also the list of habitats.

African Savanna Elephants are capable of moving long distances and naturally do so in arid ecosystems and in response to climatic conditions (e.g., seasonality and drought). Depending on productivity, and water availability African Savanna Elephants demonstrate range residence, migratory, semi-migratory and near nomadic movement patterns in different regions of the continent. Home range sizes vary by several orders of magnitude primarily in relation to plant productivity and human activity in different ecosystems (Loarie et al. 2009, Wall et al. 2013). Thirty African Savanna Elephant subpopulations (eight of which number more than 1,000 individuals) span international boundaries, including the more than 200,000 elephants in the five-country Kavango-Zambezi Transfrontier Conservation Area (Lindsay et al. 2017, KAZA Secretariat 2018).

Ecosystem Services:
Ecosystem services provided by African Savanna Elephants vary and depend to a large extent on the ecosystem (forest, savanna, grassland or desert), specific conditions on the ground and the geographical context under consideration. In general, they play an important ecological role as bulk processors of plant material (Owen-Smith 1989). In savannas, African Savanna Elephants are manipulators of woody vegetation structure which in turn influences the tree to grass ratio with knock-on consequences for the fire regime and potentially species composition in the area (Dublin et al. 1990, Augustine and McNaughton 2004, Palmer et al. 2008, Holdo et al. 2009, Goheen et al. 2010, Pringle et al. 2016). Where they are associated with wetlands African Savanna Elephants can be important in maintaining channels and open water ways. Soil fertility can be maintained by the transport of nutrients by large herbivores from nutrient rich sources (e.g., eutrophic soils in flood plains and termite mounds) to dystrophic soils (e.g., upland miombo woodlands) (Cumming et al. 1997, Doughty et al. 2016, Malhi et al. 2016).


The charismatic nature of African Savanna Elephants plays an important role in attracting tourism into national parks. They also hold important symbolic significance within the cultures of many African communities. African Savanna Elephants are one of the few iconic species that occur in the majority of African countries, and innumerable stories, songs, and cultural traditions revolve around them.

", + "threats": "Poaching of African Savanna Elephants for ivory is a major cause of individual death and population decline (Wittemyer et al. 2014, Thouless et al. 2016). After a sustained period of intense poaching between the late 1970s and 1989, many African Savanna Elephant populations (e.g., in Kenya, Tanzania, Zambia, Uganda) experienced two to three decades of recovery. Some northern African Savanna Elephant populations, however, experienced persistent poaching pressure through the last three decades (Bouche et al. 2011, 2012). Data collected as a part of the CITES Monitoring the Illegal Killing of Elephants programme (MIKE), indicate that poaching significantly intensified across the continent starting in 2008 and peaking in 2011 – an unsustainably high level of poaching has continued into current times in some areas of the continent (CITES 2018, 2019), and may be increasing in some of the historically less-affected southern African populations (CITES 2018, 2019). Rapid land use change by humans is driving the direct loss and fragmentation of habitat for African Savanna Elephants and is an increasing threat to populations across their range (Thouless et al. 2016, Mpakairi et al. 2019). Land conversion is a product of the ongoing expansion of the human population and associated agriculture and infrastructure development, which in turn are driven by economic and technological advances. A manifestation of this trend is the reported increase in human-elephant conflict (e.g., Pozo et al. 2018). Human population growth projections suggest land conversion will accelerate rapidly in the coming decades across Africa (see https://population.un.org/wpp/Publications/) which will likely increase this threat.", + "conservationmeasures": "

The African Savanna Elephant was listed in CITES Appendix I in 1989 when all African elephants were considered a single species. Subsequently, the populations of Botswana (1997), Namibia (1997), South Africa (2000) and Zimbabwe (1997) were transferred to Appendix II, each with specific annotations. These annotations have been recently replaced by a single annotation for all four countries, with specific sub-annotations for the populations of Namibia and Zimbabwe. A separate CITES listing for each species has not occurred yet because a formal designation as two separate species (i.e., Loxodonta africana and L. cyclotis) is still in progress.

The African Elephant Action Plan (AEAP; developed and adopted by African elephant range countries) was adopted by CITES in March 2010 and is a statement by all range countries regarding the most important and immediate activities which require implementation and funding if Africa’s elephants are to be conserved. The African Elephant Fund was established to support the implementation of the African Elephant Action Plan. It should be noted that the AEAP does not distinguish different taxa of African elephant. The African Savanna Elephants which occur in transboundary populations introduce complications (e.g., matters of sovereignty) when considering national populations for CITES purposes (Lindsay et al. 2017).

A number of CITES-initiated instruments were created to monitor and combat illegal trade in ivory. The CITES MIKE programme, which was established in 2002, has 66 designated sites across African elephant range and provides the most detailed and reliable data available on continental poaching pressure (CITES 2018, 2019); this includes 39 sites in 18 range countries of the African Savanna Elephant (https://cites.org/eng/prog/mike, Accessed 16 August 2020). Eswatini, South Sudan, Central African Republic, the Democratic Republic of the Congo and Somalia do not have MIKE sites for their African Savanna Elephants. The Elephant Trade Information System (ETIS), established in 1996, is managed by TRAFFIC as a comprehensive information system for tracking illegal trade in ivory and other elephant products (CITES 2016, 2019). At a national level National Ivory Action Plans (NIAPs) are a tool designed to track significant and timely action to combat the illegal trade in ivory. Currently 24 African, Middle Eastern, and Asian countries, as identified by ETIS analyses, are required to produce and implement a NIAP (https://cites.org/eng/niaps, Accessed 16 August 2020); 11 of these are range countries of the African Savanna Elephant.

At a national level the African Savanna Elephant is subject to varying degrees of legal protection in the 23 range states, with most countries granting the species the highest protection status. Providing this protection is complicated by the fact that over half of the species’ range may extend beyond the boundaries of protected areas (Taylor 2009). This point is emphasized by the evidence that the degree of protection is an important predictor of African Savanna Elephant’s presence and density (de Boer et al. 2013).

Conservation measures usually include habitat management and protection through policy, legislation and law enforcement. Successful anti-poaching and management at a site level has contributed to the re-establishment or recovery of a number of populations of African Savanna Elephants. In instances where protection efforts have failed, the African Savanna Elephant population was reduced by 70% or more in a matter of a decade (Chase et al. 2016).

In the context where management culling was undertaken (mainly southern Africa) up until the late 1980s or early 1990s, culling has largely ceased and population density management is being attempted through actions such as translocation, contraception and range manipulation such as closure of artificial water point (Scholes and Mennell 2008). Fire management is being attempted in some transboundary situations to mitigate further habitat and/or woodland modification as a consequence of African Savanna Elephant activity (Starfield et al. 1993, Mapaure 2013, Eastment 2020). 

", + "usetrade": "Ivory: Use of African Savanna Elephant ivory is entrenched in numerous cultures across the globe, primarily for ornamental and decorative items. Historically, demand for African Savanna Elephant ivory has been high in Europe, the USA and Asia. For example, beginning in the 1920s, Japanese carvers turned to African elephant ivory as Asian supplies diminished through the 1970s when Japan accounted for about 40% of the global ivory market (Martin 1986; Nishihara 2003, 2012).

In 1989, the Convention on International Trade of Endangered Species of Wild Flora and Fauna (CITES) banned the international commercial trade of ivory in response to a steep decline in African elephants across a substantial portion of their range. Thereafter, two CITES-sanctioned sales of national ivory stockpiles occurred in 2002 and 2008 with Botswana, Zimbabwe, Namibia and South Africa selling ivory to China and Japan. At the same time, a nine-year moratorium (ending in 2017) on any new ivory sale proposals from the four African countries followed (www.cites.org). In the 2000s, Chinese demand for ivory greatly surpassed that of Japan where demand for ivory appeared to substantially decline (CITES 2014). As a consequence, prices rose steeply in China and in Africa (Wittemyer et al. 2011, 2014). Debates about the benefits and consequences of the sale of national ivory stockpiles are highly polarized with limited consensus (Stiles 2004, 't Sas-Rolfes et al. 2014, Bennett 2015, Biggs et al. 2017).

Analysis of ivory seizure data indicates that the volume of illegally trafficked ivory has increased substantially since 2006 (Underwood et al. 2013; Milliken 2016; CITES 2018, 2019). Undercover investigations and DNA forensics point to the laundering of illegal ivory in legal domestic ivory markets. Seizure analyses indicate that the majority of illegally trafficked ivory is destined for Asia, especially China, Viet Nam and Thailand (CITES 2016, 2018 and 2019; Lui 2015; Krishnasamy 2016). In response to this and other concerns, China closed its legal domestic ivory market in 2017; Hong Kong SAR took steps to do the same by 2021 (https://www.info.gov.hk/gia/general/201706/02/P2017060100655.htm), and Thailand tightened its domestic Asian Elephant ivory trade regulations in 2015 (http://www.mfa.go.th/main/en/media-center/14/52929-Thailand-Submits-First-Progress-Report-on-Implemen.html). A substantial drop in ivory prices in mainland China has been associated with this action (Vigne and Martin 2017, Meijer et al. 2018). Significant illegal ivory markets remain in several Southeast Asian countries, such as Lao PDR and Viet Nam (www.cites.org; Vigne and Martin 2017).

Non-consumptive Tourism: 
African Savanna Elephants have significant tourism draw for wildlife watching and photographic tourism throughout their range substantially contributing to local economies (Naidoo et al. 2016). Tourism operations occur in national and local government protected areas, as well as on land under private or communal tenure.

Trophy Hunting: In some range states sport hunting of African Savanna Elephants is legally permitted and forms an integral element of those countries’ wildlife management and community support programs (e.g., Naidoo et al. 2016). Botswana, Mozambique, Namibia, South Africa, Tanzania and Zimbabwe have trophy hunting industries and in 2020 applied to CITES for a combined quota of 2,404 tusks (https://cites.org/eng/resources/quotas/index.php Accessed 16 August 2020). Depending on the governance and management structures, government bodies, private operations and local communities derive revenue from trophy hunting.

Other Trade: A legal domestic trade in African Savanna Elephant hides is present in South Africa. There have been limited reports of African Savanna Elephant poaching for other body parts beyond ivory, such as meat, bone, skin and hair (Blignaut et al. 2008). International live trade in African Savanna Elephants occurs between South Africa and other countries, mainly in an effort to re-establish or fortify dwindling populations in some protected areas. Live trade in young African Savanna Elephants from Zimbabwe (Russo and Cruise 2016) and Eswatini (Madowo 2019) to Asia and elsewhere for zoological collections also occurs. Controversy surrounds these transactions as the conservation benefit to the species has been questioned. Domestic trade in African Savanna Elephants exists in South Africa at a low level for reintroduction purposes between reserves (Pretorius et al. 2018)." + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/narrative/id/2467/region/europe": { + "name": "2467", + "region_identifier": "europe", + "result": [ + { + "species_id": 2467, + "taxonomicnotes": "The taxonomy is not in doubt. There are five traditionally recognised geographical populations. The species was once commonly known in the North Atlantic and adjacent Arctic as the Greenland right whale. However, the common name bowhead whale is now used almost exclusively for the species.", + "rationale": "This species is assessed as Not Applicable as it is of marginal occurrence in the European Mammal Assessment region.", + "geographicrange": "Bowhead whales are found only in Arctic and subarctic regions. They spend much of their lives in and near the pack ice, migrating to the high arctic in summer, and retreating southward in winter with the advancing ice edge (Moore and Reeves 1993). The IWC recognises five stocks: Bering-Chukchi-Beaufort Sea; Hudson Bay-Fox Basin; Davis Strait-Baffin Bay; Spitsbergen; and the Okhotsk Sea (Rugh et al. 2003). The Spitsbergen stock extends from the east coast of Greenland across the Greenland Sea, the Barents Sea and the Kara Sea as far as Severnaya Zemlya, and going as far south as the ice front, exceptionally reaching Iceland and the coast of Finnmark (Norway).", + "population": "Current population size
The range-wide abundance is not known with precision but numbers over 10,000 individuals, with 10,500 (8,200-13,500) (in 2001) in the Bering-Chukchi-Beaufort Seas (Zeh and Punt 2005), and a provisional estimate of 7,300 (3,100-16,900) for a part of the range of the Hudson Bay-Foxe Basin and Baffin Bay-Davis Strait stocks (Cosens et al. 2006). There are no reliable abundance estimates for the small Okhotsk Sea and Spitsbergen stocks.

Population trends
The Bering-Chukchi-Beaufort (BCB) population has been monitored for more than 30 years and has been increasing over this period at an estimated rate of 3.4% (1.7%-5%) per year in the presence of subsistence hunting (Zeh and Punt 2005). No quantitative estimates of trends in the other bowhead populations are available, but Inuit hunters and elders report that they are observing more bowheads in the eastern Canadian Arctic than they did in the 1960s-1970s, and that the geographic distribution of the whales has expanded in recent years. No estimates of population trend are available for the Svalbard-Barents Sea and Okhotsk Sea stocks.

Pre-whaling population sizes
All bowhead populations were severely depleted by commercial whaling, which was established in the north-eastern Atlantic by 1611 (Ross 1993). Basque whalers took bowheads in the north-west Atlantic (Labrador) in the 16th century, but ambiguities over the species identity of whales taken in early commercial whaling make pre-1600 catch records difficult to interpret. Minimum pre-whaling stock sizes are estimated to have been 24,000 for the Svalbard-Barents Sea stock, 12,000 for the Hudson Bay-Foxe Basin and Baffin Bay-Davis Strait stocks, and 3,000 for the Okhotsk Sea stock (Woodby and Botkin 1993). The Spitsbergen and Okhotsk Sea stocks are at a small fraction of their pre-whaling levels.

Demographic parameters
A high longevity (>100 years) is suggested by biochemical methods and the finding of old-fashioned stone harpoon heads in harvested animals (George et al. 1999). If this high longevity is confirmed, it would be among the longest known for a mammal.", + "populationtrend": "unknown", + "habitat": "The seasonal distribution is strongly influenced by pack ice (Moore and Reeves 1993). During the winter they occur in areas near the ice edge, in polynyas, and in areas of unconsolidated pack ice. During the spring these whales use leads and cracks in the ice to penetrate areas that were inaccessible during the winter due to heavy ice coverage. During the summer and autumn they concentrate in areas where zooplankton production is high or where large-scale biophysical processes create local concentrations of calanoid copepods (Finley 1990, Finley et al. 1998).

Small to medium-sized crustaceans, especially krill and copepods, form the bulk of the bowhead's diet (Lowry et al. 2004). They also feed on mysids and gammarid amphipods, and the diet includes at least 60 species. Bowheads skim feed at the surface and feed in the water column. It has recently been suggested that they also feed near the bottom, but probably do not directly ingest sediments as gray whales routinely do. During surface skim feeding, coordinated group patterns have been observed, including whales feeding in echelon (V-shaped) formation.", + "threats": "Heavy commercial hunting, beginning in the 1500s, depleted all populations of bowheads. The Bering-Chukchi-Beaufort Sea stock has recovered substantially since the end of commercial hunting in the early 20th century to around 10,000 animals, while recent provisional estimates of the Hudson Bay-Foxe Basin and Baffin Bay-Davis Strait stocks suggest that a significant recovery has probably occurred. There is no reliable evidence of recovery of the Svalbard-Barents Sea and Okhotsk Sea stocks.

Limited aboriginal subsistence whaling on the BCB stock (by native peoples of Alaska and Chukotka) is permitted by the IWC on the basis of advice from its Scientific Committee (most recently under its new aboriginal subsistence whaling management procedure). These takes have not impeded the recovery of the stock. Very small takes by indigenous hunters are allowed in Canadian waters, so far too few to seriously impede recovery of the stocks, but there will be pressure to increase these takes given the recent, higher population estimates for the eastern Canadian Arctic.

There has been concern since the 1970s that disturbance from oil and gas exploration and extraction activities in the Arctic region might affect bowhead whales. There is also evidence of incidental mortality and serious injury caused by entanglement in fishing gear and ship strikes (Philo et al. 1992, 1993; Finley 2000). Environmental threats, such as pollution (Bratton et al. 1993), and disturbance from tourist traffic (Finley 2000) may affect bowhead whales but the impacts have not yet been well characterized or quantified.

During this century, a profound reduction in the extent of sea ice in the Arctic is expected, and possibly a complete disappearance in summer, as mean Arctic temperatures rise faster than the global average (Anonymous 2005). The implications of this for bowhead whales are unclear but warrant monitoring.", + "conservationmeasures": "The International Whaling Commission has protected bowhead whales from commercial whaling since its inception in 1946. All range states except Canada are members of the IWC. Limited aboriginal subsistence whaling is allowed by the IWC on bowhead whales from the BCB stock on the basis of scientific advice. Indigenous hunting in Canada is co-managed by the national government and regional bodies created under land-claim agreements.", + "usetrade": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/species/synonym/Loxodonta%20africana": { + "name": "loxodonta africana", + "count": 3, + "result": [ + { + "accepted_id": 181007989, + "accepted_name": "Loxodonta cyclotis", + "authority": "Matschie, 1900", + "synonym": "Loxodonta africana", + "syn_authority": null + }, + { + "accepted_id": 181008073, + "accepted_name": "Loxodonta africana", + "authority": "(Blumenbach, 1797)", + "synonym": "Elephas africana", + "syn_authority": "Blumenbach, 1797" + }, + { + "accepted_id": 181008073, + "accepted_name": "Loxodonta africana", + "authority": "(Blumenbach, 1797)", + "synonym": "Loxodonta africana", + "syn_authority": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/speciescount": { + "count": "150754", + "note1": "Above total includes species, subspecies and subpopulation", + "speciescount": "147517", + "note2": "Above total includes species only" + }, + "https://apiv3.iucnredlist.org/api/v3/speciescount/region/europe": { + "count": "16232", + "note1": "Above total includes species, subspecies and subpopulation", + "speciescount": "16132", + "note2": "Above total includes species only", + "region_identifier": "europe" + }, + "https://apiv3.iucnredlist.org/api/v3/threats/species/id/181008073": { + "id": "181008073", + "result": [ + { + "code": "1.1", + "title": "Housing & urban areas", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "11.2", + "title": "Droughts", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": null + }, + { + "code": "11.5", + "title": "Other impacts", + "timing": "Ongoing", + "scope": "Whole (>90%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "1.2", + "title": "Commercial & industrial areas", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "1.3", + "title": "Tourism & recreation areas", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1", + "title": "Annual & perennial non-timber crops", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1", + "title": "Annual & perennial non-timber crops", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1.1", + "title": "Shifting agriculture", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1.2", + "title": "Small-holder farming", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1.3", + "title": "Agro-industry farming", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.2", + "title": "Wood & pulp plantations", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.2", + "title": "Wood & pulp plantations", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.2.1", + "title": "Small-holder plantations", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.2.2", + "title": "Agro-industry plantations", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3", + "title": "Livestock farming & ranching", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Causing/Could cause fluctuations", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3", + "title": "Livestock farming & ranching", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3.1", + "title": "Nomadic grazing", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Causing/Could cause fluctuations", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3.2", + "title": "Small-holder grazing, ranching or farming", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3.3", + "title": "Agro-industry grazing, ranching or farming", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "3.1", + "title": "Oil & gas drilling", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "3.2", + "title": "Mining & quarrying", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Negligible declines", + "score": "Low Impact: 4", + "invasive": null + }, + { + "code": "4.1", + "title": "Roads & railroads", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": null + }, + { + "code": "4.2", + "title": "Utility & service lines", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Causing/Could cause fluctuations", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "5.1", + "title": "Hunting & trapping terrestrial animals", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Negligible declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "5.1", + "title": "Hunting & trapping terrestrial animals", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Rapid Declines", + "score": "Medium Impact: 7", + "invasive": null + }, + { + "code": "5.1", + "title": "Hunting & trapping terrestrial animals", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": null + }, + { + "code": "5.1.1", + "title": "Intentional use (species is the target)", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Rapid Declines", + "score": "Medium Impact: 7", + "invasive": null + }, + { + "code": "5.1.2", + "title": "Unintentional effects (species is not the target)", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": null + }, + { + "code": "5.1.3", + "title": "Persecution/control", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Negligible declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "5.3", + "title": "Logging & wood harvesting", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "5.3.3", + "title": "Unintentional effects: (subsistence/small scale) [harvest]", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "5.3.4", + "title": "Unintentional effects: (large scale) [harvest]", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "6.1", + "title": "Recreational activities", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "6.2", + "title": "War, civil unrest & military exercises", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "7.1", + "title": "Fire & fire suppression", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "7.1.3", + "title": "Trend Unknown/Unrecorded", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "7.2", + "title": "Dams & water management/use", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "7.2.11", + "title": "Dams (size unknown)", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "8.1", + "title": "Invasive non-native/alien species/diseases", + "timing": "Ongoing", + "scope": null, + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "8.1.1", + "title": "Unspecified species", + "timing": "Ongoing", + "scope": null, + "severity": "Unknown", + "score": "Unknown", + "invasive": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/threats/species/id/2467/region/europe": { + "id": "2467", + "region_identifier": "europe", + "result": [ + { + "code": "9.2", + "title": "Industrial & military effluents", + "timing": "Ongoing", + "scope": null, + "severity": null, + "score": null, + "invasive": null + }, + { + "code": "9.2.3", + "title": "Type Unknown/Unrecorded", + "timing": "Ongoing", + "scope": null, + "severity": null, + "score": null, + "invasive": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/threats/species/name/Loxodonta%20africana": { + "name": "Loxodonta africana", + "result": [ + { + "code": "1.1", + "title": "Housing & urban areas", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "11.2", + "title": "Droughts", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": null + }, + { + "code": "11.5", + "title": "Other impacts", + "timing": "Ongoing", + "scope": "Whole (>90%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "1.2", + "title": "Commercial & industrial areas", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "1.3", + "title": "Tourism & recreation areas", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1", + "title": "Annual & perennial non-timber crops", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1", + "title": "Annual & perennial non-timber crops", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1.1", + "title": "Shifting agriculture", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1.2", + "title": "Small-holder farming", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.1.3", + "title": "Agro-industry farming", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.2", + "title": "Wood & pulp plantations", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.2", + "title": "Wood & pulp plantations", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.2.1", + "title": "Small-holder plantations", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "2.2.2", + "title": "Agro-industry plantations", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3", + "title": "Livestock farming & ranching", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Causing/Could cause fluctuations", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3", + "title": "Livestock farming & ranching", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3.1", + "title": "Nomadic grazing", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Causing/Could cause fluctuations", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3.2", + "title": "Small-holder grazing, ranching or farming", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "2.3.3", + "title": "Agro-industry grazing, ranching or farming", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "3.1", + "title": "Oil & gas drilling", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "3.2", + "title": "Mining & quarrying", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Negligible declines", + "score": "Low Impact: 4", + "invasive": null + }, + { + "code": "4.1", + "title": "Roads & railroads", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": null + }, + { + "code": "4.2", + "title": "Utility & service lines", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Causing/Could cause fluctuations", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "5.1", + "title": "Hunting & trapping terrestrial animals", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Negligible declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "5.1", + "title": "Hunting & trapping terrestrial animals", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Rapid Declines", + "score": "Medium Impact: 7", + "invasive": null + }, + { + "code": "5.1", + "title": "Hunting & trapping terrestrial animals", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": null + }, + { + "code": "5.1.1", + "title": "Intentional use (species is the target)", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Rapid Declines", + "score": "Medium Impact: 7", + "invasive": null + }, + { + "code": "5.1.2", + "title": "Unintentional effects (species is not the target)", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": null + }, + { + "code": "5.1.3", + "title": "Persecution/control", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Negligible declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "5.3", + "title": "Logging & wood harvesting", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "5.3.3", + "title": "Unintentional effects: (subsistence/small scale) [harvest]", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "5.3.4", + "title": "Unintentional effects: (large scale) [harvest]", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "6.1", + "title": "Recreational activities", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "6.2", + "title": "War, civil unrest & military exercises", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "7.1", + "title": "Fire & fire suppression", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "7.1.3", + "title": "Trend Unknown/Unrecorded", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "7.2", + "title": "Dams & water management/use", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "7.2.11", + "title": "Dams (size unknown)", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "8.1", + "title": "Invasive non-native/alien species/diseases", + "timing": "Ongoing", + "scope": null, + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "8.1.1", + "title": "Unspecified species", + "timing": "Ongoing", + "scope": null, + "severity": "Unknown", + "score": "Unknown", + "invasive": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/threats/species/name/Fratercula%20arctica/region/europe": { + "name": "Fratercula arctica", + "region_identifier": "europe", + "result": [ + { + "code": "11.1", + "title": "Habitat shifting & alteration", + "timing": "Ongoing", + "scope": "Unknown", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "11.3", + "title": "Temperature extremes", + "timing": "Ongoing", + "scope": "Unknown", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "11.4", + "title": "Storms & flooding", + "timing": "Ongoing", + "scope": "Unknown", + "severity": "Rapid Declines", + "score": "Unknown", + "invasive": null + }, + { + "code": "11.5", + "title": "Other impacts", + "timing": "Ongoing", + "scope": "Unknown", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "3.3", + "title": "Renewable energy", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Causing/Could cause fluctuations", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "5.1", + "title": "Hunting & trapping terrestrial animals", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "5.1.1", + "title": "Intentional use (species is the target)", + "timing": "Ongoing", + "scope": "Minority (<50%)", + "severity": "Slow, Significant Declines", + "score": "Low Impact: 5", + "invasive": null + }, + { + "code": "5.4", + "title": "Fishing & harvesting aquatic resources", + "timing": "Ongoing", + "scope": "Unknown", + "severity": "Rapid Declines", + "score": "Unknown", + "invasive": null + }, + { + "code": "5.4.4", + "title": "Unintentional effects: (large scale) [harvest]", + "timing": "Ongoing", + "scope": "Unknown", + "severity": "Rapid Declines", + "score": "Unknown", + "invasive": null + }, + { + "code": "8.1", + "title": "Invasive non-native/alien species/diseases (Neovison vison)", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": "Neovison vison" + }, + { + "code": "8.1", + "title": "Invasive non-native/alien species/diseases (Unspecified Rattus)", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": "Unspecified Rattus" + }, + { + "code": "8.1.2", + "title": "Named species (Neovison vison)", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": "Neovison vison" + }, + { + "code": "8.1.2", + "title": "Named species (Unspecified Rattus)", + "timing": "Ongoing", + "scope": "Majority (50-90%)", + "severity": "Slow, Significant Declines", + "score": "Medium Impact: 6", + "invasive": "Unspecified Rattus" + }, + { + "code": "9.2", + "title": "Industrial & military effluents", + "timing": "Ongoing", + "scope": "Unknown", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + }, + { + "code": "9.2", + "title": "Industrial & military effluents", + "timing": "Past, Likely to Return", + "scope": "Unknown", + "severity": "Rapid Declines", + "score": "Past Impact", + "invasive": null + }, + { + "code": "9.2.1", + "title": "Oil spills", + "timing": "Past, Likely to Return", + "scope": "Unknown", + "severity": "Rapid Declines", + "score": "Past Impact", + "invasive": null + }, + { + "code": "9.2.3", + "title": "Type Unknown/Unrecorded", + "timing": "Ongoing", + "scope": "Unknown", + "severity": "Unknown", + "score": "Unknown", + "invasive": null + } + ] + }, + "https://apiv3.iucnredlist.org/api/v3/version": { + "version": "2022-1" + }, + "https://apiv3.iucnredlist.org/api/v3/weblink/Loxodonta%20africana": { + "rlurl": "https://www.iucnredlist.org/species/181008073/204401095", + "species": "loxodonta africana" + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/AssessmentTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/AssessmentTest.php new file mode 100644 index 0000000000..de04ddb72f --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/AssessmentTest.php @@ -0,0 +1,24 @@ + 2021, + 'code' => 'VU', + 'category' => 'Vulnerable', + 'year' => 2022, + ]); + + self::assertEquals(2021, $assessment->getAssessmentYear()); + self::assertEquals('VU', $assessment->getCategoryCode()); + self::assertEquals('Vulnerable', $assessment->getCategoryName()); + self::assertEquals(2022, $assessment->getPublicationYear()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/CitationTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/CitationTest.php new file mode 100644 index 0000000000..1d58eccf3c --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/CitationTest.php @@ -0,0 +1,18 @@ + 'Lorem ipsum dolor sit amet' + ]); + + self::assertEquals('Lorem ipsum dolor sit amet', $citation->getCitation()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/CommonNameTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/CommonNameTest.php new file mode 100644 index 0000000000..c6f35a1344 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/CommonNameTest.php @@ -0,0 +1,22 @@ + 'eng', + 'taxonname' => 'Red panda', + 'primary' => true, + ]); + + self::assertEquals('eng', $commonName->getLanguage()); + self::assertEquals('Red panda', $commonName->getName()); + self::assertTrue($commonName->isPrimary()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/ConservationMeasureTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/ConservationMeasureTest.php new file mode 100644 index 0000000000..56d0f183a2 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/ConservationMeasureTest.php @@ -0,0 +1,20 @@ + '4.2', + 'title' => 'Lorem ipsum dolor sit amet', + ]); + + self::assertEquals('4.2', $conservationMeasure->getCode()); + self::assertEquals('Lorem ipsum dolor sit amet', $conservationMeasure->getTitle()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/CountryTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/CountryTest.php new file mode 100644 index 0000000000..f7a8dfac0a --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/CountryTest.php @@ -0,0 +1,20 @@ + 'DE', + 'country' => 'Germany', + ]); + + self::assertEquals('DE', $country->getCode()); + self::assertEquals('Germany', $country->getName()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/GroupTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/GroupTest.php new file mode 100644 index 0000000000..725f80ed8c --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/GroupTest.php @@ -0,0 +1,18 @@ + 'mammals', + ]); + + self::assertEquals('mammals', $group->getCode()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/GrowthFormTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/GrowthFormTest.php new file mode 100644 index 0000000000..526bf35dcf --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/GrowthFormTest.php @@ -0,0 +1,18 @@ + 'Tree - large', + ]); + + self::assertEquals('Tree - large', $growthForm->getName()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/HabitatTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/HabitatTest.php new file mode 100644 index 0000000000..30cf3d713d --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/HabitatTest.php @@ -0,0 +1,26 @@ + '12.1', + 'habitat' => 'Marine Intertidal - Rocky Shoreline', + 'majorimportance' => 'Yes', + 'season' => 'Summer', + 'suitability' => 'Suitable', + ]); + + self::assertEquals('12.1', $habitat->getCode()); + self::assertEquals('Yes', $habitat->getMajorImportance()); + self::assertEquals('Marine Intertidal - Rocky Shoreline', $habitat->getName()); + self::assertEquals('Summer', $habitat->getSeason()); + self::assertEquals('Suitable', $habitat->getSuitability()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/NarrativeTextTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/NarrativeTextTest.php new file mode 100644 index 0000000000..b7aa0cfe93 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/NarrativeTextTest.php @@ -0,0 +1,34 @@ + 'Nullam ut odio nec', + 'geographicrange' => 'Pellentesque luctus ante', + 'habitat' => 'Mauris sagittis orci', + 'population' => 'In dictum enim eget', + 'populationtrend' => 'Vivamus a sapien a tortor', + 'rationale' => 'In dictum enim eget mauris', + 'taxonomicnotes' => 'Maecenas pretium augue', + 'threats' => 'Donec vitae elit laoreet', + 'usetrade' => 'Cras feugiat diam', + ]); + + self::assertEquals('Nullam ut odio nec', $narrativeText->getConservationMeasures()); + self::assertEquals('Pellentesque luctus ante', $narrativeText->getGeographicRange()); + self::assertEquals('Mauris sagittis orci', $narrativeText->getHabitat()); + self::assertEquals('In dictum enim eget', $narrativeText->getPopulation()); + self::assertEquals('Vivamus a sapien a tortor', $narrativeText->getPopulationTrend()); + self::assertEquals('In dictum enim eget mauris', $narrativeText->getRationale()); + self::assertEquals('Maecenas pretium augue', $narrativeText->getTaxonomicNotes()); + self::assertEquals('Donec vitae elit laoreet', $narrativeText->getThreats()); + self::assertEquals('Cras feugiat diam', $narrativeText->getUseTrade()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/OccurrenceTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/OccurrenceTest.php new file mode 100644 index 0000000000..9d0db86934 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/OccurrenceTest.php @@ -0,0 +1,26 @@ + 'BI', + 'country' => 'Burundi', + 'distribution_code' => 'Regionally Extinct', + 'origin' => 'Native', + 'presence' => 'Regionally Extinct', + ]); + + self::assertEquals('BI', $occurrence->getCountryCode()); + self::assertEquals('Burundi', $occurrence->getCountryName()); + self::assertEquals('Regionally Extinct', $occurrence->getDistributionCode()); + self::assertEquals('Native', $occurrence->getOrigin()); + self::assertEquals('Regionally Extinct', $occurrence->getPresence()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/RegionTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/RegionTest.php new file mode 100644 index 0000000000..269086f71f --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/RegionTest.php @@ -0,0 +1,20 @@ + 'europe', + 'name' => 'Europe', + ]); + + self::assertEquals('europe', $region->getIdentifier()); + self::assertEquals('Europe', $region->getName()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/SpeciesDetailsTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/SpeciesDetailsTest.php new file mode 100644 index 0000000000..55d3381693 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/SpeciesDetailsTest.php @@ -0,0 +1,80 @@ + true, + 'amended_reason' => '', + 'aoo_km2' => 24000, + 'assessment_date' => '2020-11-13', + 'assessor' => 'John Doe', + 'authority' => '(Blumenbach, 1797)', + 'category' => 'EN', + 'class' => 'MAMMALIA', + 'criteria' => 'A2abd', + 'depth_lower' => 5000, + 'depth_upper' => 0, + 'elevation_lower' => 100, + 'elevation_upper' => 3200, + 'eoo_km2' => 48250, + 'errata_flag' => true, + 'errata_reason' => 'Vestibulum eget augue tempor', + 'family' => 'ELEPHANTIDAE', + 'freshwater_system' => true, + 'genus' => 'Loxodonta', + 'kingdom' => 'ANIMALIA', + 'main_common_name' => 'African Savanna Elephant', + 'marine_system' => true, + 'order' => 'PROBOSCIDEA', + 'phylum' => 'CHORDATA', + 'population_trend' => 'Decreasing', + 'published_year' => 2022, + 'reviewer' => 'Jane Doe', + 'scientific_name' => 'Loxodonta africana', + 'taxonid' => 181008073, + 'terrestrial_system' => true, + ]); + + self::assertTrue($speciesDetails->isAmended()); + self::assertEquals('', $speciesDetails->getAmendedReason()); + self::assertEquals(24000, $speciesDetails->getAOO()); + self::assertEquals('2020-11-13', $speciesDetails->getAssessmentDate()); + self::assertEquals('John Doe', $speciesDetails->getAssessor()); + self::assertEquals('(Blumenbach, 1797)', $speciesDetails->getAuthority()); + self::assertEquals('EN', $speciesDetails->getCategory()); + self::assertEquals('MAMMALIA', $speciesDetails->getClass()); + self::assertEquals('A2abd', $speciesDetails->getCriteria()); + self::assertEquals(5000, $speciesDetails->getDepthLower()); + self::assertEquals(0, $speciesDetails->getDepthUpper()); + self::assertEquals(100, $speciesDetails->getElevationLower()); + self::assertEquals(3200, $speciesDetails->getElevationUpper()); + self::assertEquals(48250, $speciesDetails->getEOO()); + self::assertTrue($speciesDetails->isErrata()); + self::assertEquals('Vestibulum eget augue tempor', $speciesDetails->getErrataReason()); + self::assertEquals('ELEPHANTIDAE', $speciesDetails->getFamily()); + self::assertTrue($speciesDetails->isFreshwaterSystem()); + self::assertEquals('Loxodonta', $speciesDetails->getGenus()); + self::assertEquals('ANIMALIA', $speciesDetails->getKingdom()); + self::assertEquals('African Savanna Elephant', $speciesDetails->getMainCommonName()); + self::assertTrue($speciesDetails->isMarineSystem()); + self::assertEquals('PROBOSCIDEA', $speciesDetails->getOrder()); + self::assertEquals('CHORDATA', $speciesDetails->getPhylum()); + self::assertEquals('Decreasing', $speciesDetails->getPopulationTrend()); + self::assertEquals(2022, $speciesDetails->getPublicationYear()); + self::assertEquals('Jane Doe', $speciesDetails->getReviewer()); + self::assertEquals('Loxodonta africana', $speciesDetails->getScientificName()); + self::assertTrue($speciesDetails->isTerrestrialSystem()); + self::assertEquals(181008073, $speciesDetails->getTaxonId()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/SpeciesTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/SpeciesTest.php new file mode 100644 index 0000000000..7ba7421d97 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/SpeciesTest.php @@ -0,0 +1,28 @@ + 'LR/lc', + 'scientific_name' => 'Agarista mexicana var. pinetorum', + 'subpopulation' => 'nothingii', + 'subspecies' => 'pinetorum', + 'rank' => 'var.', + 'taxonid' => 37432, + ]); + + self::assertEquals('LR/lc', $species->getCategory()); + self::assertEquals('Agarista mexicana var. pinetorum', $species->getScientificName()); + self::assertEquals('nothingii', $species->getSubpopulation()); + self::assertEquals('pinetorum', $species->getSubspeciesName()); + self::assertEquals('var.', $species->getSubspeciesRank()); + self::assertEquals(37432, $species->getTaxonId()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/SynonymTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/SynonymTest.php new file mode 100644 index 0000000000..e6656b1e34 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/SynonymTest.php @@ -0,0 +1,26 @@ + 181008073, + 'accepted_name' => 'Loxodonta africana', + 'authority' => '(Blumenbach, 1797)', + 'synonym' => 'Elephas africana', + 'syn_authority' => 'Blumenbach, 1797', + ]); + + self::assertEquals(181008073, $synonym->getAcceptedId()); + self::assertEquals('Loxodonta africana', $synonym->getAcceptedName()); + self::assertEquals('(Blumenbach, 1797)', $synonym->getAcceptedNameAuthority()); + self::assertEquals('Elephas africana', $synonym->getSynonym()); + self::assertEquals('Blumenbach, 1797', $synonym->getSynonymAuthority()); + } +} diff --git a/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/ThreatTest.php b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/ThreatTest.php new file mode 100644 index 0000000000..dcfb394789 --- /dev/null +++ b/sites/all/libraries/vendor/jbroutier/iucn-api-client/tests/Unit/ThreatTest.php @@ -0,0 +1,30 @@ + '5.1', + 'invasive' => 'Homo sapiens', + 'scope' => 'Majority (50-90%)', + 'score' => 'Low Impact: 5', + 'severity' => 'Negligible declines', + 'timing' => 'Ongoing', + 'title' => 'Hunting & trapping terrestrial animals', + ]); + + self::assertEquals('5.1', $threat->getCode()); + self::assertEquals('Homo sapiens', $threat->getInvasive()); + self::assertEquals('Majority (50-90%)', $threat->getScope()); + self::assertEquals('Low Impact: 5', $threat->getScore()); + self::assertEquals('Negligible declines', $threat->getSeverity()); + self::assertEquals('Ongoing', $threat->getTiming()); + self::assertEquals('Hunting & trapping terrestrial animals', $threat->getTitle()); + } +} diff --git a/sites/all/libraries/vendor/michelf/php-markdown/.gitignore b/sites/all/libraries/vendor/michelf/php-markdown/.gitignore deleted file mode 100644 index 5bd6475b79..0000000000 --- a/sites/all/libraries/vendor/michelf/php-markdown/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*~ -/composer.lock -/vendor/ diff --git a/sites/all/libraries/vendor/psr/container/LICENSE b/sites/all/libraries/vendor/psr/container/LICENSE new file mode 100644 index 0000000000..2877a4894e --- /dev/null +++ b/sites/all/libraries/vendor/psr/container/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2016 container-interop +Copyright (c) 2016 PHP Framework Interoperability Group + +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/sites/all/libraries/vendor/psr/container/README.md b/sites/all/libraries/vendor/psr/container/README.md new file mode 100644 index 0000000000..1b9d9e5708 --- /dev/null +++ b/sites/all/libraries/vendor/psr/container/README.md @@ -0,0 +1,13 @@ +Container interface +============== + +This repository holds all interfaces related to [PSR-11 (Container Interface)][psr-url]. + +Note that this is not a Container implementation of its own. It is merely abstractions that describe the components of a Dependency Injection Container. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-11/ +[package-url]: https://packagist.org/packages/psr/container +[implementation-url]: https://packagist.org/providers/psr/container-implementation + diff --git a/sites/all/libraries/vendor/psr/container/composer.json b/sites/all/libraries/vendor/psr/container/composer.json new file mode 100644 index 0000000000..017f41ea69 --- /dev/null +++ b/sites/all/libraries/vendor/psr/container/composer.json @@ -0,0 +1,22 @@ +{ + "name": "psr/container", + "type": "library", + "description": "Common Container Interface (PHP FIG PSR-11)", + "keywords": ["psr", "psr-11", "container", "container-interop", "container-interface"], + "homepage": "https://github.com/php-fig/container", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=7.4.0" + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + } +} diff --git a/sites/all/libraries/vendor/psr/container/src/ContainerExceptionInterface.php b/sites/all/libraries/vendor/psr/container/src/ContainerExceptionInterface.php new file mode 100644 index 0000000000..0f213f2fed --- /dev/null +++ b/sites/all/libraries/vendor/psr/container/src/ContainerExceptionInterface.php @@ -0,0 +1,12 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } +} diff --git a/sites/all/libraries/vendor/psr/log/Psr/Log/InvalidArgumentException.php b/sites/all/libraries/vendor/psr/log/Psr/Log/InvalidArgumentException.php new file mode 100644 index 0000000000..67f852d1db --- /dev/null +++ b/sites/all/libraries/vendor/psr/log/Psr/Log/InvalidArgumentException.php @@ -0,0 +1,7 @@ +logger = $logger; + } +} diff --git a/sites/all/libraries/vendor/psr/log/Psr/Log/LoggerInterface.php b/sites/all/libraries/vendor/psr/log/Psr/Log/LoggerInterface.php new file mode 100644 index 0000000000..2206cfde41 --- /dev/null +++ b/sites/all/libraries/vendor/psr/log/Psr/Log/LoggerInterface.php @@ -0,0 +1,125 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + abstract public function log($level, $message, array $context = array()); +} diff --git a/sites/all/libraries/vendor/psr/log/Psr/Log/NullLogger.php b/sites/all/libraries/vendor/psr/log/Psr/Log/NullLogger.php new file mode 100644 index 0000000000..c8f7293b1c --- /dev/null +++ b/sites/all/libraries/vendor/psr/log/Psr/Log/NullLogger.php @@ -0,0 +1,30 @@ +logger) { }` + * blocks. + */ +class NullLogger extends AbstractLogger +{ + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + public function log($level, $message, array $context = array()) + { + // noop + } +} diff --git a/sites/all/libraries/vendor/psr/log/Psr/Log/Test/DummyTest.php b/sites/all/libraries/vendor/psr/log/Psr/Log/Test/DummyTest.php new file mode 100644 index 0000000000..9638c11018 --- /dev/null +++ b/sites/all/libraries/vendor/psr/log/Psr/Log/Test/DummyTest.php @@ -0,0 +1,18 @@ + ". + * + * Example ->error('Foo') would yield "error Foo". + * + * @return string[] + */ + abstract public function getLogs(); + + public function testImplements() + { + $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); + } + + /** + * @dataProvider provideLevelsAndMessages + */ + public function testLogsAtAllLevels($level, $message) + { + $logger = $this->getLogger(); + $logger->{$level}($message, array('user' => 'Bob')); + $logger->log($level, $message, array('user' => 'Bob')); + + $expected = array( + $level.' message of level '.$level.' with context: Bob', + $level.' message of level '.$level.' with context: Bob', + ); + $this->assertEquals($expected, $this->getLogs()); + } + + public function provideLevelsAndMessages() + { + return array( + LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), + LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), + LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), + LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), + LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), + LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), + LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), + LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'), + ); + } + + /** + * @expectedException \Psr\Log\InvalidArgumentException + */ + public function testThrowsOnInvalidLevel() + { + $logger = $this->getLogger(); + $logger->log('invalid level', 'Foo'); + } + + public function testContextReplacement() + { + $logger = $this->getLogger(); + $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); + + $expected = array('info {Message {nothing} Bob Bar a}'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testObjectCastToString() + { + if (method_exists($this, 'createPartialMock')) { + $dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString')); + } else { + $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString')); + } + $dummy->expects($this->once()) + ->method('__toString') + ->will($this->returnValue('DUMMY')); + + $this->getLogger()->warning($dummy); + + $expected = array('warning DUMMY'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testContextCanContainAnything() + { + $closed = fopen('php://memory', 'r'); + fclose($closed); + + $context = array( + 'bool' => true, + 'null' => null, + 'string' => 'Foo', + 'int' => 0, + 'float' => 0.5, + 'nested' => array('with object' => new DummyTest), + 'object' => new \DateTime, + 'resource' => fopen('php://memory', 'r'), + 'closed' => $closed, + ); + + $this->getLogger()->warning('Crazy context data', $context); + + $expected = array('warning Crazy context data'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testContextExceptionKeyCanBeExceptionOrOtherValues() + { + $logger = $this->getLogger(); + $logger->warning('Random message', array('exception' => 'oops')); + $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); + + $expected = array( + 'warning Random message', + 'critical Uncaught Exception!' + ); + $this->assertEquals($expected, $this->getLogs()); + } +} diff --git a/sites/all/libraries/vendor/psr/log/Psr/Log/Test/TestLogger.php b/sites/all/libraries/vendor/psr/log/Psr/Log/Test/TestLogger.php new file mode 100644 index 0000000000..1be3230496 --- /dev/null +++ b/sites/all/libraries/vendor/psr/log/Psr/Log/Test/TestLogger.php @@ -0,0 +1,147 @@ + $level, + 'message' => $message, + 'context' => $context, + ]; + + $this->recordsByLevel[$record['level']][] = $record; + $this->records[] = $record; + } + + public function hasRecords($level) + { + return isset($this->recordsByLevel[$level]); + } + + public function hasRecord($record, $level) + { + if (is_string($record)) { + $record = ['message' => $record]; + } + return $this->hasRecordThatPasses(function ($rec) use ($record) { + if ($rec['message'] !== $record['message']) { + return false; + } + if (isset($record['context']) && $rec['context'] !== $record['context']) { + return false; + } + return true; + }, $level); + } + + public function hasRecordThatContains($message, $level) + { + return $this->hasRecordThatPasses(function ($rec) use ($message) { + return strpos($rec['message'], $message) !== false; + }, $level); + } + + public function hasRecordThatMatches($regex, $level) + { + return $this->hasRecordThatPasses(function ($rec) use ($regex) { + return preg_match($regex, $rec['message']) > 0; + }, $level); + } + + public function hasRecordThatPasses(callable $predicate, $level) + { + if (!isset($this->recordsByLevel[$level])) { + return false; + } + foreach ($this->recordsByLevel[$level] as $i => $rec) { + if (call_user_func($predicate, $rec, $i)) { + return true; + } + } + return false; + } + + public function __call($method, $args) + { + if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { + $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; + $level = strtolower($matches[2]); + if (method_exists($this, $genericMethod)) { + $args[] = $level; + return call_user_func_array([$this, $genericMethod], $args); + } + } + throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()'); + } + + public function reset() + { + $this->records = []; + $this->recordsByLevel = []; + } +} diff --git a/sites/all/libraries/vendor/psr/log/README.md b/sites/all/libraries/vendor/psr/log/README.md new file mode 100644 index 0000000000..a9f20c437b --- /dev/null +++ b/sites/all/libraries/vendor/psr/log/README.md @@ -0,0 +1,58 @@ +PSR Log +======= + +This repository holds all interfaces/classes/traits related to +[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md). + +Note that this is not a logger of its own. It is merely an interface that +describes a logger. See the specification for more details. + +Installation +------------ + +```bash +composer require psr/log +``` + +Usage +----- + +If you need a logger, you can use the interface like this: + +```php +logger = $logger; + } + + public function doSomething() + { + if ($this->logger) { + $this->logger->info('Doing work'); + } + + try { + $this->doSomethingElse(); + } catch (Exception $exception) { + $this->logger->error('Oh no!', array('exception' => $exception)); + } + + // do something useful + } +} +``` + +You can then pick one of the implementations of the interface to get a logger. + +If you want to implement the interface, you can require this package and +implement `Psr\Log\LoggerInterface` in your code. Please read the +[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +for details. diff --git a/sites/all/libraries/vendor/psr/log/composer.json b/sites/all/libraries/vendor/psr/log/composer.json new file mode 100644 index 0000000000..ca05695377 --- /dev/null +++ b/sites/all/libraries/vendor/psr/log/composer.json @@ -0,0 +1,26 @@ +{ + "name": "psr/log", + "description": "Common interface for logging libraries", + "keywords": ["psr", "psr-3", "log"], + "homepage": "https://github.com/php-fig/log", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + } +} diff --git a/sites/all/libraries/vendor/symfony/deprecation-contracts/CHANGELOG.md b/sites/all/libraries/vendor/symfony/deprecation-contracts/CHANGELOG.md new file mode 100644 index 0000000000..7932e26132 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/deprecation-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/sites/all/libraries/vendor/symfony/deprecation-contracts/LICENSE b/sites/all/libraries/vendor/symfony/deprecation-contracts/LICENSE new file mode 100644 index 0000000000..406242ff28 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/deprecation-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020-2022 Fabien Potencier + +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/sites/all/libraries/vendor/symfony/deprecation-contracts/README.md b/sites/all/libraries/vendor/symfony/deprecation-contracts/README.md new file mode 100644 index 0000000000..4957933a6c --- /dev/null +++ b/sites/all/libraries/vendor/symfony/deprecation-contracts/README.md @@ -0,0 +1,26 @@ +Symfony Deprecation Contracts +============================= + +A generic function and convention to trigger deprecation notices. + +This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices. + +By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component, +the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments. + +The function requires at least 3 arguments: + - the name of the Composer package that is triggering the deprecation + - the version of the package that introduced the deprecation + - the message of the deprecation + - more arguments can be provided: they will be inserted in the message using `printf()` formatting + +Example: +```php +trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin'); +``` + +This will generate the following message: +`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.` + +While not necessarily recommended, the deprecation notices can be completely ignored by declaring an empty +`function trigger_deprecation() {}` in your application. diff --git a/sites/all/libraries/vendor/symfony/deprecation-contracts/composer.json b/sites/all/libraries/vendor/symfony/deprecation-contracts/composer.json new file mode 100644 index 0000000000..cc7cc12372 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/deprecation-contracts/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony/deprecation-contracts", + "type": "library", + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/sites/all/libraries/vendor/symfony/deprecation-contracts/function.php b/sites/all/libraries/vendor/symfony/deprecation-contracts/function.php new file mode 100644 index 0000000000..d4371504a0 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/deprecation-contracts/function.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!function_exists('trigger_deprecation')) { + /** + * Triggers a silenced deprecation notice. + * + * @param string $package The name of the Composer package that is triggering the deprecation + * @param string $version The version of the package that introduced the deprecation + * @param string $message The message of the deprecation + * @param mixed ...$args Values to insert in the message using printf() formatting + * + * @author Nicolas Grekas + */ + function trigger_deprecation(string $package, string $version, string $message, ...$args): void + { + @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/CHANGELOG.md b/sites/all/libraries/vendor/symfony/http-client-contracts/CHANGELOG.md new file mode 100644 index 0000000000..7932e26132 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/ChunkInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/ChunkInterface.php new file mode 100644 index 0000000000..0800cb3665 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/ChunkInterface.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * The interface of chunks returned by ResponseStreamInterface::current(). + * + * When the chunk is first, last or timeout, the content MUST be empty. + * When an unchecked timeout or a network error occurs, a TransportExceptionInterface + * MUST be thrown by the destructor unless one was already thrown by another method. + * + * @author Nicolas Grekas + */ +interface ChunkInterface +{ + /** + * Tells when the idle timeout has been reached. + * + * @throws TransportExceptionInterface on a network error + */ + public function isTimeout(): bool; + + /** + * Tells when headers just arrived. + * + * @throws TransportExceptionInterface on a network error or when the idle timeout is reached + */ + public function isFirst(): bool; + + /** + * Tells when the body just completed. + * + * @throws TransportExceptionInterface on a network error or when the idle timeout is reached + */ + public function isLast(): bool; + + /** + * Returns a [status code, headers] tuple when a 1xx status code was just received. + * + * @throws TransportExceptionInterface on a network error or when the idle timeout is reached + */ + public function getInformationalStatus(): ?array; + + /** + * Returns the content of the response chunk. + * + * @throws TransportExceptionInterface on a network error or when the idle timeout is reached + */ + public function getContent(): string; + + /** + * Returns the offset of the chunk in the response body. + */ + public function getOffset(): int; + + /** + * In case of error, returns the message that describes it. + */ + public function getError(): ?string; +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/ClientExceptionInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/ClientExceptionInterface.php new file mode 100644 index 0000000000..22d2b456a6 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/ClientExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a 4xx response is returned. + * + * @author Nicolas Grekas + */ +interface ClientExceptionInterface extends HttpExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/DecodingExceptionInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/DecodingExceptionInterface.php new file mode 100644 index 0000000000..971a7a29b3 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/DecodingExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a content-type cannot be decoded to the expected representation. + * + * @author Nicolas Grekas + */ +interface DecodingExceptionInterface extends ExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/ExceptionInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..e553b47a1d --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * The base interface for all exceptions in the contract. + * + * @author Nicolas Grekas + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/HttpExceptionInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/HttpExceptionInterface.php new file mode 100644 index 0000000000..17865ed367 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/HttpExceptionInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * Base interface for HTTP-related exceptions. + * + * @author Anton Chernikov + */ +interface HttpExceptionInterface extends ExceptionInterface +{ + public function getResponse(): ResponseInterface; +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/RedirectionExceptionInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/RedirectionExceptionInterface.php new file mode 100644 index 0000000000..edd9b8a9bb --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/RedirectionExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a 3xx response is returned and the "max_redirects" option has been reached. + * + * @author Nicolas Grekas + */ +interface RedirectionExceptionInterface extends HttpExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/ServerExceptionInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/ServerExceptionInterface.php new file mode 100644 index 0000000000..9bfe1354b5 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/ServerExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a 5xx response is returned. + * + * @author Nicolas Grekas + */ +interface ServerExceptionInterface extends HttpExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/TimeoutExceptionInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/TimeoutExceptionInterface.php new file mode 100644 index 0000000000..08acf9fb6d --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/TimeoutExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When an idle timeout occurs. + * + * @author Nicolas Grekas + */ +interface TimeoutExceptionInterface extends TransportExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/TransportExceptionInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/TransportExceptionInterface.php new file mode 100644 index 0000000000..0c8d131a05 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Exception/TransportExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When any error happens at the transport level. + * + * @author Nicolas Grekas + */ +interface TransportExceptionInterface extends ExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/HttpClientInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/HttpClientInterface.php new file mode 100644 index 0000000000..158c1a7d06 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/HttpClientInterface.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\Test\HttpClientTestCase; + +/** + * Provides flexible methods for requesting HTTP resources synchronously or asynchronously. + * + * @see HttpClientTestCase for a reference test suite + * + * @method static withOptions(array $options) Returns a new instance of the client with new default options + * + * @author Nicolas Grekas + */ +interface HttpClientInterface +{ + public const OPTIONS_DEFAULTS = [ + 'auth_basic' => null, // array|string - an array containing the username as first value, and optionally the + // password as the second one; or string like username:password - enabling HTTP Basic + // authentication (RFC 7617) + 'auth_bearer' => null, // string - a token enabling HTTP Bearer authorization (RFC 6750) + 'query' => [], // string[] - associative array of query string values to merge with the request's URL + 'headers' => [], // iterable|string[]|string[][] - headers names provided as keys or as part of values + 'body' => '', // array|string|resource|\Traversable|\Closure - the callback SHOULD yield a string + // smaller than the amount requested as argument; the empty string signals EOF; if + // an array is passed, it is meant as a form payload of field names and values + 'json' => null, // mixed - if set, implementations MUST set the "body" option to the JSON-encoded + // value and set the "content-type" header to a JSON-compatible value if it is not + // explicitly defined in the headers option - typically "application/json" + 'user_data' => null, // mixed - any extra data to attach to the request (scalar, callable, object...) that + // MUST be available via $response->getInfo('user_data') - not used internally + 'max_redirects' => 20, // int - the maximum number of redirects to follow; a value lower than or equal to 0 + // means redirects should not be followed; "Authorization" and "Cookie" headers MUST + // NOT follow except for the initial host name + 'http_version' => null, // string - defaults to the best supported version, typically 1.1 or 2.0 + 'base_uri' => null, // string - the URI to resolve relative URLs, following rules in RFC 3986, section 2 + 'buffer' => true, // bool|resource|\Closure - whether the content of the response should be buffered or not, + // or a stream resource where the response body should be written, + // or a closure telling if/where the response should be buffered based on its headers + 'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info) - throwing any exceptions MUST abort + // the request; it MUST be called on DNS resolution, on arrival of headers and on + // completion; it SHOULD be called on upload/download of data and at least 1/s + 'resolve' => [], // string[] - a map of host to IP address that SHOULD replace DNS resolution + 'proxy' => null, // string - by default, the proxy-related env vars handled by curl SHOULD be honored + 'no_proxy' => null, // string - a comma separated list of hosts that do not require a proxy to be reached + 'timeout' => null, // float - the idle timeout - defaults to ini_get('default_socket_timeout') + 'max_duration' => 0, // float - the maximum execution time for the request+response as a whole; + // a value lower than or equal to 0 means it is unlimited + 'bindto' => '0', // string - the interface or the local socket to bind to + 'verify_peer' => true, // see https://php.net/context.ssl for the following options + 'verify_host' => true, + 'cafile' => null, + 'capath' => null, + 'local_cert' => null, + 'local_pk' => null, + 'passphrase' => null, + 'ciphers' => null, + 'peer_fingerprint' => null, + 'capture_peer_cert_chain' => false, + 'extra' => [], // array - additional options that can be ignored if unsupported, unlike regular options + ]; + + /** + * Requests an HTTP resource. + * + * Responses MUST be lazy, but their status code MUST be + * checked even if none of their public methods are called. + * + * Implementations are not required to support all options described above; they can also + * support more custom options; but in any case, they MUST throw a TransportExceptionInterface + * when an unsupported option is passed. + * + * @throws TransportExceptionInterface When an unsupported option is passed + */ + public function request(string $method, string $url, array $options = []): ResponseInterface; + + /** + * Yields responses chunk by chunk as they complete. + * + * @param ResponseInterface|iterable $responses One or more responses created by the current HTTP client + * @param float|null $timeout The idle timeout before yielding timeout chunks + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface; +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/LICENSE b/sites/all/libraries/vendor/symfony/http-client-contracts/LICENSE new file mode 100644 index 0000000000..74cdc2dbf6 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +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/sites/all/libraries/vendor/symfony/http-client-contracts/README.md b/sites/all/libraries/vendor/symfony/http-client-contracts/README.md new file mode 100644 index 0000000000..03b3a69b70 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/README.md @@ -0,0 +1,9 @@ +Symfony HttpClient Contracts +============================ + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful - and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/ResponseInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/ResponseInterface.php new file mode 100644 index 0000000000..df7148816e --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/ResponseInterface.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * A (lazily retrieved) HTTP response. + * + * @author Nicolas Grekas + */ +interface ResponseInterface +{ + /** + * Gets the HTTP status code of the response. + * + * @throws TransportExceptionInterface when a network error occurs + */ + public function getStatusCode(): int; + + /** + * Gets the HTTP headers of the response. + * + * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes + * + * @return string[][] The headers of the response keyed by header names in lowercase + * + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function getHeaders(bool $throw = true): array; + + /** + * Gets the response body as a string. + * + * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes + * + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function getContent(bool $throw = true): string; + + /** + * Gets the response body decoded as array, typically from a JSON payload. + * + * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes + * + * @throws DecodingExceptionInterface When the body cannot be decoded to an array + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function toArray(bool $throw = true): array; + + /** + * Closes the response stream and all related buffers. + * + * No further chunk will be yielded after this method has been called. + */ + public function cancel(): void; + + /** + * Returns info coming from the transport layer. + * + * This method SHOULD NOT throw any ExceptionInterface and SHOULD be non-blocking. + * The returned info is "live": it can be empty and can change from one call to + * another, as the request/response progresses. + * + * The following info MUST be returned: + * - canceled (bool) - true if the response was canceled using ResponseInterface::cancel(), false otherwise + * - error (string|null) - the error message when the transfer was aborted, null otherwise + * - http_code (int) - the last response code or 0 when it is not known yet + * - http_method (string) - the HTTP verb of the last request + * - redirect_count (int) - the number of redirects followed while executing the request + * - redirect_url (string|null) - the resolved location of redirect responses, null otherwise + * - response_headers (array) - an array modelled after the special $http_response_header variable + * - start_time (float) - the time when the request was sent or 0.0 when it's pending + * - url (string) - the last effective URL of the request + * - user_data (mixed) - the value of the "user_data" request option, null if not set + * + * When the "capture_peer_cert_chain" option is true, the "peer_certificate_chain" + * attribute SHOULD list the peer certificates as an array of OpenSSL X.509 resources. + * + * Other info SHOULD be named after curl_getinfo()'s associative return value. + * + * @return mixed An array of all available info, or one of them when $type is + * provided, or null when an unsupported type is requested + */ + public function getInfo(string $type = null); +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/ResponseStreamInterface.php b/sites/all/libraries/vendor/symfony/http-client-contracts/ResponseStreamInterface.php new file mode 100644 index 0000000000..fa3e5db6c8 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/ResponseStreamInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +/** + * Yields response chunks, returned by HttpClientInterface::stream(). + * + * @author Nicolas Grekas + * + * @extends \Iterator + */ +interface ResponseStreamInterface extends \Iterator +{ + public function key(): ResponseInterface; + + public function current(): ChunkInterface; +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Test/Fixtures/web/index.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Test/Fixtures/web/index.php new file mode 100644 index 0000000000..30a7049758 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Test/Fixtures/web/index.php @@ -0,0 +1,192 @@ + $v) { + switch ($k) { + default: + if (0 !== strpos($k, 'HTTP_')) { + continue 2; + } + // no break + case 'SERVER_NAME': + case 'SERVER_PROTOCOL': + case 'REQUEST_URI': + case 'REQUEST_METHOD': + case 'PHP_AUTH_USER': + case 'PHP_AUTH_PW': + $vars[$k] = $v; + } +} + +$json = json_encode($vars, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); + +switch ($vars['REQUEST_URI']) { + default: + exit; + + case '/head': + header('Content-Length: '.strlen($json), true); + break; + + case '/': + case '/?a=a&b=b': + case 'http://127.0.0.1:8057/': + case 'http://localhost:8057/': + ob_start('ob_gzhandler'); + break; + + case '/103': + header('HTTP/1.1 103 Early Hints'); + header('Link: ; rel=preload; as=style', false); + header('Link: ; rel=preload; as=script', false); + flush(); + usleep(1000); + echo "HTTP/1.1 200 OK\r\n"; + echo "Date: Fri, 26 May 2017 10:02:11 GMT\r\n"; + echo "Content-Length: 13\r\n"; + echo "\r\n"; + echo 'Here the body'; + exit; + + case '/404': + header('Content-Type: application/json', true, 404); + break; + + case '/404-gzipped': + header('Content-Type: text/plain', true, 404); + ob_start('ob_gzhandler'); + @ob_flush(); + flush(); + usleep(300000); + echo 'some text'; + exit; + + case '/301': + if ('Basic Zm9vOmJhcg==' === $vars['HTTP_AUTHORIZATION']) { + header('Location: http://127.0.0.1:8057/302', true, 301); + } + break; + + case '/301/bad-tld': + header('Location: http://foo.example.', true, 301); + break; + + case '/301/invalid': + header('Location: //?foo=bar', true, 301); + break; + + case '/302': + if (!isset($vars['HTTP_AUTHORIZATION'])) { + header('Location: http://localhost:8057/', true, 302); + } + break; + + case '/302/relative': + header('Location: ..', true, 302); + break; + + case '/304': + header('Content-Length: 10', true, 304); + echo '12345'; + + return; + + case '/307': + header('Location: http://localhost:8057/post', true, 307); + break; + + case '/length-broken': + header('Content-Length: 1000'); + break; + + case '/post': + $output = json_encode($_POST + ['REQUEST_METHOD' => $vars['REQUEST_METHOD']], \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); + header('Content-Type: application/json', true); + header('Content-Length: '.strlen($output)); + echo $output; + exit; + + case '/timeout-header': + usleep(300000); + break; + + case '/timeout-body': + echo '<1>'; + @ob_flush(); + flush(); + usleep(500000); + echo '<2>'; + exit; + + case '/timeout-long': + ignore_user_abort(false); + sleep(1); + while (true) { + echo '<1>'; + @ob_flush(); + flush(); + usleep(500); + } + exit; + + case '/chunked': + header('Transfer-Encoding: chunked'); + echo "8\r\nSymfony \r\n5\r\nis aw\r\n6\r\nesome!\r\n0\r\n\r\n"; + exit; + + case '/chunked-broken': + header('Transfer-Encoding: chunked'); + echo "8\r\nSymfony \r\n5\r\nis aw\r\n6\r\ne"; + exit; + + case '/gzip-broken': + header('Content-Encoding: gzip'); + echo str_repeat('-', 1000); + exit; + + case '/max-duration': + ignore_user_abort(false); + while (true) { + echo '<1>'; + @ob_flush(); + flush(); + usleep(500); + } + exit; + + case '/json': + header('Content-Type: application/json'); + echo json_encode([ + 'documents' => [ + ['id' => '/json/1'], + ['id' => '/json/2'], + ['id' => '/json/3'], + ], + ]); + exit; + + case '/json/1': + case '/json/2': + case '/json/3': + header('Content-Type: application/json'); + echo json_encode([ + 'title' => $vars['REQUEST_URI'], + ]); + + exit; +} + +header('Content-Type: application/json', true); + +echo $json; diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php new file mode 100644 index 0000000000..7acd6b79c1 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php @@ -0,0 +1,1137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Test; + +use PHPUnit\Framework\TestCase; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TimeoutExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * A reference test suite for HttpClientInterface implementations. + */ +abstract class HttpClientTestCase extends TestCase +{ + public static function setUpBeforeClass(): void + { + TestHttpServer::start(); + } + + abstract protected function getHttpClient(string $testCase): HttpClientInterface; + + public function testGetRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'headers' => ['Foo' => 'baR'], + 'user_data' => $data = new \stdClass(), + ]); + + $this->assertSame([], $response->getInfo('response_headers')); + $this->assertSame($data, $response->getInfo()['user_data']); + $this->assertSame(200, $response->getStatusCode()); + + $info = $response->getInfo(); + $this->assertNull($info['error']); + $this->assertSame(0, $info['redirect_count']); + $this->assertSame('HTTP/1.1 200 OK', $info['response_headers'][0]); + $this->assertSame('Host: localhost:8057', $info['response_headers'][1]); + $this->assertSame('http://localhost:8057/', $info['url']); + + $headers = $response->getHeaders(); + + $this->assertSame('localhost:8057', $headers['host'][0]); + $this->assertSame(['application/json'], $headers['content-type']); + + $body = json_decode($response->getContent(), true); + $this->assertSame($body, $response->toArray()); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertSame('baR', $body['HTTP_FOO']); + + $response = $client->request('GET', 'http://localhost:8057/length-broken'); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testHeadRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('HEAD', 'http://localhost:8057/head', [ + 'headers' => ['Foo' => 'baR'], + 'user_data' => $data = new \stdClass(), + 'buffer' => false, + ]); + + $this->assertSame([], $response->getInfo('response_headers')); + $this->assertSame(200, $response->getStatusCode()); + + $info = $response->getInfo(); + $this->assertSame('HTTP/1.1 200 OK', $info['response_headers'][0]); + $this->assertSame('Host: localhost:8057', $info['response_headers'][1]); + + $headers = $response->getHeaders(); + + $this->assertSame('localhost:8057', $headers['host'][0]); + $this->assertSame(['application/json'], $headers['content-type']); + $this->assertTrue(0 < $headers['content-length'][0]); + + $this->assertSame('', $response->getContent()); + } + + public function testNonBufferedGetRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'buffer' => false, + 'headers' => ['Foo' => 'baR'], + ]); + + $body = $response->toArray(); + $this->assertSame('baR', $body['HTTP_FOO']); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testBufferSink() + { + $sink = fopen('php://temp', 'w+'); + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'buffer' => $sink, + 'headers' => ['Foo' => 'baR'], + ]); + + $body = $response->toArray(); + $this->assertSame('baR', $body['HTTP_FOO']); + + rewind($sink); + $sink = stream_get_contents($sink); + $this->assertSame($sink, $response->getContent()); + } + + public function testConditionalBuffering() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057'); + $firstContent = $response->getContent(); + $secondContent = $response->getContent(); + + $this->assertSame($firstContent, $secondContent); + + $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () { return false; }]); + $response->getContent(); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testReentrantBufferCallback() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () use (&$response) { + $response->cancel(); + + return true; + }]); + + $this->assertSame(200, $response->getStatusCode()); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testThrowingBufferCallback() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () { + throw new \Exception('Boo.'); + }]); + + $this->assertSame(200, $response->getStatusCode()); + + $this->expectException(TransportExceptionInterface::class); + $this->expectExceptionMessage('Boo'); + $response->getContent(); + } + + public function testUnsupportedOption() + { + $client = $this->getHttpClient(__FUNCTION__); + + $this->expectException(\InvalidArgumentException::class); + $client->request('GET', 'http://localhost:8057', [ + 'capture_peer_cert' => 1.0, + ]); + } + + public function testHttpVersion() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'http_version' => 1.0, + ]); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('HTTP/1.0 200 OK', $response->getInfo('response_headers')[0]); + + $body = $response->toArray(); + + $this->assertSame('HTTP/1.0', $body['SERVER_PROTOCOL']); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('/', $body['REQUEST_URI']); + } + + public function testChunkedEncoding() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/chunked'); + + $this->assertSame(['chunked'], $response->getHeaders()['transfer-encoding']); + $this->assertSame('Symfony is awesome!', $response->getContent()); + + $response = $client->request('GET', 'http://localhost:8057/chunked-broken'); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testClientError() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/404'); + + $client->stream($response)->valid(); + + $this->assertSame(404, $response->getInfo('http_code')); + + try { + $response->getHeaders(); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + } + + try { + $response->getContent(); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + } + + $this->assertSame(404, $response->getStatusCode()); + $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']); + $this->assertNotEmpty($response->getContent(false)); + + $response = $client->request('GET', 'http://localhost:8057/404'); + + try { + foreach ($client->stream($response) as $chunk) { + $this->assertTrue($chunk->isFirst()); + } + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + } + } + + public function testIgnoreErrors() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/404'); + + $this->assertSame(404, $response->getStatusCode()); + } + + public function testDnsError() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/301/bad-tld'); + + try { + $response->getStatusCode(); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + try { + $response->getStatusCode(); + $this->fail(TransportExceptionInterface::class.' still expected'); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + $response = $client->request('GET', 'http://localhost:8057/301/bad-tld'); + + try { + foreach ($client->stream($response) as $r => $chunk) { + } + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + $this->assertSame($response, $r); + $this->assertNotNull($chunk->getError()); + + $this->expectException(TransportExceptionInterface::class); + foreach ($client->stream($response) as $chunk) { + } + } + + public function testInlineAuth() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://foo:bar%3Dbar@localhost:8057'); + + $body = $response->toArray(); + + $this->assertSame('foo', $body['PHP_AUTH_USER']); + $this->assertSame('bar=bar', $body['PHP_AUTH_PW']); + } + + public function testBadRequestBody() + { + $client = $this->getHttpClient(__FUNCTION__); + + $this->expectException(TransportExceptionInterface::class); + + $response = $client->request('POST', 'http://localhost:8057/', [ + 'body' => function () { yield []; }, + ]); + + $response->getStatusCode(); + } + + public function test304() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/304', [ + 'headers' => ['If-Match' => '"abc"'], + 'buffer' => false, + ]); + + $this->assertSame(304, $response->getStatusCode()); + $this->assertSame('', $response->getContent(false)); + } + + /** + * @testWith [[]] + * [["Content-Length: 7"]] + */ + public function testRedirects(array $headers = []) + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('POST', 'http://localhost:8057/301', [ + 'auth_basic' => 'foo:bar', + 'headers' => $headers, + 'body' => function () { + yield 'foo=bar'; + }, + ]); + + $body = $response->toArray(); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('Basic Zm9vOmJhcg==', $body['HTTP_AUTHORIZATION']); + $this->assertSame('http://localhost:8057/', $response->getInfo('url')); + + $this->assertSame(2, $response->getInfo('redirect_count')); + $this->assertNull($response->getInfo('redirect_url')); + + $expected = [ + 'HTTP/1.1 301 Moved Permanently', + 'Location: http://127.0.0.1:8057/302', + 'Content-Type: application/json', + 'HTTP/1.1 302 Found', + 'Location: http://localhost:8057/', + 'Content-Type: application/json', + 'HTTP/1.1 200 OK', + 'Content-Type: application/json', + ]; + + $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) { + return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true) && 'Content-Encoding: gzip' !== $h; + })); + + $this->assertSame($expected, $filteredHeaders); + } + + public function testInvalidRedirect() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/301/invalid'); + + $this->assertSame(301, $response->getStatusCode()); + $this->assertSame(['//?foo=bar'], $response->getHeaders(false)['location']); + $this->assertSame(0, $response->getInfo('redirect_count')); + $this->assertNull($response->getInfo('redirect_url')); + + $this->expectException(RedirectionExceptionInterface::class); + $response->getHeaders(); + } + + public function testRelativeRedirects() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/302/relative'); + + $body = $response->toArray(); + + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertNull($response->getInfo('redirect_url')); + + $response = $client->request('GET', 'http://localhost:8057/302/relative', [ + 'max_redirects' => 0, + ]); + + $this->assertSame(302, $response->getStatusCode()); + $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url')); + } + + public function testRedirect307() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/307', [ + 'body' => function () { + yield 'foo=bar'; + }, + 'max_redirects' => 0, + ]); + + $this->assertSame(307, $response->getStatusCode()); + + $response = $client->request('POST', 'http://localhost:8057/307', [ + 'body' => 'foo=bar', + ]); + + $body = $response->toArray(); + + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testMaxRedirects() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/301', [ + 'max_redirects' => 1, + 'auth_basic' => 'foo:bar', + ]); + + try { + $response->getHeaders(); + $this->fail(RedirectionExceptionInterface::class.' expected'); + } catch (RedirectionExceptionInterface $e) { + } + + $this->assertSame(302, $response->getStatusCode()); + $this->assertSame(1, $response->getInfo('redirect_count')); + $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url')); + + $expected = [ + 'HTTP/1.1 301 Moved Permanently', + 'Location: http://127.0.0.1:8057/302', + 'Content-Type: application/json', + 'HTTP/1.1 302 Found', + 'Location: http://localhost:8057/', + 'Content-Type: application/json', + ]; + + $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) { + return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true); + })); + + $this->assertSame($expected, $filteredHeaders); + } + + public function testStream() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057'); + $chunks = $client->stream($response); + $result = []; + + foreach ($chunks as $r => $chunk) { + if ($chunk->isTimeout()) { + $result[] = 't'; + } elseif ($chunk->isLast()) { + $result[] = 'l'; + } elseif ($chunk->isFirst()) { + $result[] = 'f'; + } + } + + $this->assertSame($response, $r); + $this->assertSame(['f', 'l'], $result); + + $chunk = null; + $i = 0; + + foreach ($client->stream($response) as $chunk) { + ++$i; + } + + $this->assertSame(1, $i); + $this->assertTrue($chunk->isLast()); + } + + public function testAddToStream() + { + $client = $this->getHttpClient(__FUNCTION__); + + $r1 = $client->request('GET', 'http://localhost:8057'); + + $completed = []; + + $pool = [$r1]; + + while ($pool) { + $chunks = $client->stream($pool); + $pool = []; + + foreach ($chunks as $r => $chunk) { + if (!$chunk->isLast()) { + continue; + } + + if ($r1 === $r) { + $r2 = $client->request('GET', 'http://localhost:8057'); + $pool[] = $r2; + } + + $completed[] = $r; + } + } + + $this->assertSame([$r1, $r2], $completed); + } + + public function testCompleteTypeError() + { + $client = $this->getHttpClient(__FUNCTION__); + + $this->expectException(\TypeError::class); + $client->stream(123); + } + + public function testOnProgress() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'headers' => ['Content-Length' => 14], + 'body' => 'foo=0123456789', + 'on_progress' => function (...$state) use (&$steps) { $steps[] = $state; }, + ]); + + $body = $response->toArray(); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + $this->assertSame([0, 0], \array_slice($steps[0], 0, 2)); + $lastStep = \array_slice($steps, -1)[0]; + $this->assertSame([57, 57], \array_slice($lastStep, 0, 2)); + $this->assertSame('http://localhost:8057/post', $steps[0][2]['url']); + } + + public function testPostJson() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'json' => ['foo' => 'bar'], + ]); + + $body = $response->toArray(); + + $this->assertStringContainsString('json', $body['content-type']); + unset($body['content-type']); + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testPostArray() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => ['foo' => 'bar'], + ]); + + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $response->toArray()); + } + + public function testPostResource() + { + $client = $this->getHttpClient(__FUNCTION__); + + $h = fopen('php://temp', 'w+'); + fwrite($h, 'foo=0123456789'); + rewind($h); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => $h, + ]); + + $body = $response->toArray(); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testPostCallback() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => function () { + yield 'foo'; + yield ''; + yield '='; + yield '0123456789'; + }, + ]); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $response->toArray()); + } + + public function testCancel() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-header'); + + $response->cancel(); + $this->expectException(TransportExceptionInterface::class); + $response->getHeaders(); + } + + public function testInfoOnCanceledResponse() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057/timeout-header'); + + $this->assertFalse($response->getInfo('canceled')); + $response->cancel(); + $this->assertTrue($response->getInfo('canceled')); + } + + public function testCancelInStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/404'); + + foreach ($client->stream($response) as $chunk) { + $response->cancel(); + } + + $this->expectException(TransportExceptionInterface::class); + + foreach ($client->stream($response) as $chunk) { + } + } + + public function testOnProgressCancel() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ + 'on_progress' => function ($dlNow) { + if (0 < $dlNow) { + throw new \Exception('Aborting the request.'); + } + }, + ]); + + try { + foreach ($client->stream([$response]) as $chunk) { + } + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + $this->assertSame('Aborting the request.', $e->getPrevious()->getMessage()); + } + + $this->assertNotNull($response->getInfo('error')); + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testOnProgressError() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ + 'on_progress' => function ($dlNow) { + if (0 < $dlNow) { + throw new \Error('BUG.'); + } + }, + ]); + + try { + foreach ($client->stream([$response]) as $chunk) { + } + $this->fail('Error expected'); + } catch (\Error $e) { + $this->assertSame('BUG.', $e->getMessage()); + } + + $this->assertNotNull($response->getInfo('error')); + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testResolve() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://symfony.com:8057/', [ + 'resolve' => ['symfony.com' => '127.0.0.1'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame(200, $client->request('GET', 'http://symfony.com:8057/')->getStatusCode()); + + $response = null; + $this->expectException(TransportExceptionInterface::class); + $client->request('GET', 'http://symfony.com:8057/', ['timeout' => 1]); + } + + public function testIdnResolve() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://0-------------------------------------------------------------0.com:8057/', [ + 'resolve' => ['0-------------------------------------------------------------0.com' => '127.0.0.1'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + + $response = $client->request('GET', 'http://Bücher.example:8057/', [ + 'resolve' => ['xn--bcher-kva.example' => '127.0.0.1'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + } + + public function testNotATimeout() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-header', [ + 'timeout' => 0.9, + ]); + sleep(1); + $this->assertSame(200, $response->getStatusCode()); + } + + public function testTimeoutOnAccess() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-header', [ + 'timeout' => 0.1, + ]); + + $this->expectException(TransportExceptionInterface::class); + $response->getHeaders(); + } + + public function testTimeoutIsNotAFatalError() + { + usleep(300000); // wait for the previous test to release the server + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ + 'timeout' => 0.25, + ]); + + try { + $response->getContent(); + $this->fail(TimeoutExceptionInterface::class.' expected'); + } catch (TimeoutExceptionInterface $e) { + } + + for ($i = 0; $i < 10; ++$i) { + try { + $this->assertSame('<1><2>', $response->getContent()); + break; + } catch (TimeoutExceptionInterface $e) { + } + } + + if (10 === $i) { + throw $e; + } + } + + public function testTimeoutOnStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + + $this->assertSame(200, $response->getStatusCode()); + $chunks = $client->stream([$response], 0.2); + + $result = []; + + foreach ($chunks as $r => $chunk) { + if ($chunk->isTimeout()) { + $result[] = 't'; + } else { + $result[] = $chunk->getContent(); + } + } + + $this->assertSame(['<1>', 't'], $result); + + $chunks = $client->stream([$response]); + + foreach ($chunks as $r => $chunk) { + $this->assertSame('<2>', $chunk->getContent()); + $this->assertSame('<1><2>', $r->getContent()); + + return; + } + + $this->fail('The response should have completed'); + } + + public function testUncheckedTimeoutThrows() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + $chunks = $client->stream([$response], 0.1); + + $this->expectException(TransportExceptionInterface::class); + + foreach ($chunks as $r => $chunk) { + } + } + + public function testTimeoutWithActiveConcurrentStream() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $streamingResponse = $client->request('GET', 'http://localhost:8067/max-duration'); + $blockingResponse = $client->request('GET', 'http://localhost:8077/timeout-body', [ + 'timeout' => 0.25, + ]); + + $this->assertSame(200, $streamingResponse->getStatusCode()); + $this->assertSame(200, $blockingResponse->getStatusCode()); + + $this->expectException(TransportExceptionInterface::class); + + try { + $blockingResponse->getContent(); + } finally { + $p1->stop(); + $p2->stop(); + } + } + + public function testTimeoutOnInitialize() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $start = microtime(true); + $responses = []; + + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + + try { + foreach ($responses as $response) { + try { + $response->getContent(); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + } + } + $responses = []; + + $duration = microtime(true) - $start; + + $this->assertLessThan(1.0, $duration); + } finally { + $p1->stop(); + $p2->stop(); + } + } + + public function testTimeoutOnDestruct() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $start = microtime(true); + $responses = []; + + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + + try { + while ($response = array_shift($responses)) { + try { + unset($response); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + } + } + + $duration = microtime(true) - $start; + + $this->assertLessThan(1.0, $duration); + } finally { + $p1->stop(); + $p2->stop(); + } + } + + public function testDestruct() + { + $client = $this->getHttpClient(__FUNCTION__); + + $start = microtime(true); + $client->request('GET', 'http://localhost:8057/timeout-long'); + $client = null; + $duration = microtime(true) - $start; + + $this->assertGreaterThan(1, $duration); + $this->assertLessThan(4, $duration); + } + + public function testGetContentAfterDestruct() + { + $client = $this->getHttpClient(__FUNCTION__); + + try { + $client->request('GET', 'http://localhost:8057/404'); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + $this->assertSame('GET', $e->getResponse()->toArray(false)['REQUEST_METHOD']); + } + } + + public function testGetEncodedContentAfterDestruct() + { + $client = $this->getHttpClient(__FUNCTION__); + + try { + $client->request('GET', 'http://localhost:8057/404-gzipped'); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + $this->assertSame('some text', $e->getResponse()->getContent(false)); + } + } + + public function testProxy() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/', [ + 'proxy' => 'http://localhost:8057', + ]); + + $body = $response->toArray(); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); + + $response = $client->request('GET', 'http://localhost:8057/', [ + 'proxy' => 'http://foo:b%3Dar@localhost:8057', + ]); + + $body = $response->toArray(); + $this->assertSame('Basic Zm9vOmI9YXI=', $body['HTTP_PROXY_AUTHORIZATION']); + + $_SERVER['http_proxy'] = 'http://localhost:8057'; + try { + $response = $client->request('GET', 'http://localhost:8057/'); + $body = $response->toArray(); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); + } finally { + unset($_SERVER['http_proxy']); + } + } + + public function testNoProxy() + { + putenv('no_proxy='.$_SERVER['no_proxy'] = 'example.com, localhost'); + + try { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/', [ + 'proxy' => 'http://localhost:8057', + ]); + + $body = $response->toArray(); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertSame('GET', $body['REQUEST_METHOD']); + } finally { + putenv('no_proxy'); + unset($_SERVER['no_proxy']); + } + } + + /** + * @requires extension zlib + */ + public function testAutoEncodingRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057'); + + $this->assertSame(200, $response->getStatusCode()); + + $headers = $response->getHeaders(); + + $this->assertSame(['Accept-Encoding'], $headers['vary']); + $this->assertStringContainsString('gzip', $headers['content-encoding'][0]); + + $body = $response->toArray(); + + $this->assertStringContainsString('gzip', $body['HTTP_ACCEPT_ENCODING']); + } + + public function testBaseUri() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', '../404', [ + 'base_uri' => 'http://localhost:8057/abc/', + ]); + + $this->assertSame(404, $response->getStatusCode()); + $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']); + } + + public function testQuery() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/?a=a', [ + 'query' => ['b' => 'b'], + ]); + + $body = $response->toArray(); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('/?a=a&b=b', $body['REQUEST_URI']); + } + + public function testInformationalResponse() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/103'); + + $this->assertSame('Here the body', $response->getContent()); + $this->assertSame(200, $response->getStatusCode()); + } + + public function testInformationalResponseStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/103'); + + $chunks = []; + foreach ($client->stream($response) as $chunk) { + $chunks[] = $chunk; + } + + $this->assertSame(103, $chunks[0]->getInformationalStatus()[0]); + $this->assertSame(['; rel=preload; as=style', '; rel=preload; as=script'], $chunks[0]->getInformationalStatus()[1]['link']); + $this->assertTrue($chunks[1]->isFirst()); + $this->assertSame('Here the body', $chunks[2]->getContent()); + $this->assertTrue($chunks[3]->isLast()); + $this->assertNull($chunks[3]->getInformationalStatus()); + + $this->assertSame(['date', 'content-length'], array_keys($response->getHeaders())); + $this->assertContains('Link: ; rel=preload; as=style', $response->getInfo('response_headers')); + } + + /** + * @requires extension zlib + */ + public function testUserlandEncodingRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'headers' => ['Accept-Encoding' => 'gzip'], + ]); + + $headers = $response->getHeaders(); + + $this->assertSame(['Accept-Encoding'], $headers['vary']); + $this->assertStringContainsString('gzip', $headers['content-encoding'][0]); + + $body = $response->getContent(); + $this->assertSame("\x1F", $body[0]); + + $body = json_decode(gzdecode($body), true); + $this->assertSame('gzip', $body['HTTP_ACCEPT_ENCODING']); + } + + /** + * @requires extension zlib + */ + public function testGzipBroken() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/gzip-broken'); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testMaxDuration() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/max-duration', [ + 'max_duration' => 0.1, + ]); + + $start = microtime(true); + + try { + $response->getContent(); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + $duration = microtime(true) - $start; + + $this->assertLessThan(10, $duration); + } + + public function testWithOptions() + { + $client = $this->getHttpClient(__FUNCTION__); + if (!method_exists($client, 'withOptions')) { + $this->markTestSkipped(sprintf('Not implementing "%s::withOptions()" is deprecated.', get_debug_type($client))); + } + + $client2 = $client->withOptions(['base_uri' => 'http://localhost:8057/']); + + $this->assertNotSame($client, $client2); + $this->assertSame(\get_class($client), \get_class($client2)); + + $response = $client2->request('GET', '/'); + $this->assertSame(200, $response->getStatusCode()); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/Test/TestHttpServer.php b/sites/all/libraries/vendor/symfony/http-client-contracts/Test/TestHttpServer.php new file mode 100644 index 0000000000..55a744aef4 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/Test/TestHttpServer.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Test; + +use Symfony\Component\Process\PhpExecutableFinder; +use Symfony\Component\Process\Process; + +class TestHttpServer +{ + private static $process = []; + + /** + * @return Process + */ + public static function start(int $port = 8057) + { + if (isset(self::$process[$port])) { + self::$process[$port]->stop(); + } else { + register_shutdown_function(static function () use ($port) { + self::$process[$port]->stop(); + }); + } + + $finder = new PhpExecutableFinder(); + $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:'.$port])); + $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); + $process->start(); + self::$process[$port] = $process; + + do { + usleep(50000); + } while (!@fopen('http://127.0.0.1:'.$port, 'r')); + + return $process; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client-contracts/composer.json b/sites/all/libraries/vendor/symfony/http-client-contracts/composer.json new file mode 100644 index 0000000000..b76cab852f --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client-contracts/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/http-client-contracts", + "type": "library", + "description": "Generic abstractions related to HTTP clients", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/AmpHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/AmpHttpClient.php new file mode 100644 index 0000000000..96a5e0aa4f --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/AmpHttpClient.php @@ -0,0 +1,176 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Amp\CancelledException; +use Amp\Http\Client\DelegateHttpClient; +use Amp\Http\Client\InterceptedHttpClient; +use Amp\Http\Client\PooledHttpClient; +use Amp\Http\Client\Request; +use Amp\Http\Tunnel\Http1TunnelConnector; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\AmpClientState; +use Symfony\Component\HttpClient\Response\AmpResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; +use Symfony\Contracts\Service\ResetInterface; + +if (!interface_exists(DelegateHttpClient::class)) { + throw new \LogicException('You cannot use "Symfony\Component\HttpClient\AmpHttpClient" as the "amphp/http-client" package is not installed. Try running "composer require amphp/http-client".'); +} + +/** + * A portable implementation of the HttpClientInterface contracts based on Amp's HTTP client. + * + * @author Nicolas Grekas + */ +final class AmpHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface +{ + use HttpClientTrait; + use LoggerAwareTrait; + + private $defaultOptions = self::OPTIONS_DEFAULTS; + private static $emptyDefaults = self::OPTIONS_DEFAULTS; + + /** @var AmpClientState */ + private $multi; + + /** + * @param array $defaultOptions Default requests' options + * @param callable $clientConfigurator A callable that builds a {@see DelegateHttpClient} from a {@see PooledHttpClient}; + * passing null builds an {@see InterceptedHttpClient} with 2 retries on failures + * @param int $maxHostConnections The maximum number of connections to a single host + * @param int $maxPendingPushes The maximum number of pushed responses to accept in the queue + * + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + */ + public function __construct(array $defaultOptions = [], callable $clientConfigurator = null, int $maxHostConnections = 6, int $maxPendingPushes = 50) + { + $this->defaultOptions['buffer'] = $this->defaultOptions['buffer'] ?? \Closure::fromCallable([__CLASS__, 'shouldBuffer']); + + if ($defaultOptions) { + [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions); + } + + $this->multi = new AmpClientState($clientConfigurator, $maxHostConnections, $maxPendingPushes, $this->logger); + } + + /** + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + * + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions); + + $options['proxy'] = self::getProxy($options['proxy'], $url, $options['no_proxy']); + + if (null !== $options['proxy'] && !class_exists(Http1TunnelConnector::class)) { + throw new \LogicException('You cannot use the "proxy" option as the "amphp/http-tunnel" package is not installed. Try running "composer require amphp/http-tunnel".'); + } + + if ($options['bindto']) { + if (0 === strpos($options['bindto'], 'if!')) { + throw new TransportException(__CLASS__.' cannot bind to network interfaces, use e.g. CurlHttpClient instead.'); + } + if (0 === strpos($options['bindto'], 'host!')) { + $options['bindto'] = substr($options['bindto'], 5); + } + } + + if (('' !== $options['body'] || 'POST' === $method || isset($options['normalized_headers']['content-length'])) && !isset($options['normalized_headers']['content-type'])) { + $options['headers'][] = 'Content-Type: application/x-www-form-urlencoded'; + } + + if (!isset($options['normalized_headers']['user-agent'])) { + $options['headers'][] = 'User-Agent: Symfony HttpClient/Amp'; + } + + if (0 < $options['max_duration']) { + $options['timeout'] = min($options['max_duration'], $options['timeout']); + } + + if ($options['resolve']) { + $this->multi->dnsCache = $options['resolve'] + $this->multi->dnsCache; + } + + if ($options['peer_fingerprint'] && !isset($options['peer_fingerprint']['pin-sha256'])) { + throw new TransportException(__CLASS__.' supports only "pin-sha256" fingerprints.'); + } + + $request = new Request(implode('', $url), $method); + + if ($options['http_version']) { + switch ((float) $options['http_version']) { + case 1.0: $request->setProtocolVersions(['1.0']); break; + case 1.1: $request->setProtocolVersions(['1.1', '1.0']); break; + default: $request->setProtocolVersions(['2', '1.1', '1.0']); break; + } + } + + foreach ($options['headers'] as $v) { + $h = explode(': ', $v, 2); + $request->addHeader($h[0], $h[1]); + } + + $request->setTcpConnectTimeout(1000 * $options['timeout']); + $request->setTlsHandshakeTimeout(1000 * $options['timeout']); + $request->setTransferTimeout(1000 * $options['max_duration']); + if (method_exists($request, 'setInactivityTimeout')) { + $request->setInactivityTimeout(0); + } + + if ('' !== $request->getUri()->getUserInfo() && !$request->hasHeader('authorization')) { + $auth = explode(':', $request->getUri()->getUserInfo(), 2); + $auth = array_map('rawurldecode', $auth) + [1 => '']; + $request->setHeader('Authorization', 'Basic '.base64_encode(implode(':', $auth))); + } + + return new AmpResponse($this->multi, $request, $options, $this->logger); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof AmpResponse) { + $responses = [$responses]; + } elseif (!is_iterable($responses)) { + throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of AmpResponse objects, "%s" given.', __METHOD__, get_debug_type($responses))); + } + + return new ResponseStream(AmpResponse::stream($responses, $timeout)); + } + + public function reset() + { + $this->multi->dnsCache = []; + + foreach ($this->multi->pushedResponses as $authority => $pushedResponses) { + foreach ($pushedResponses as [$pushedUrl, $pushDeferred]) { + $pushDeferred->fail(new CancelledException()); + + if ($this->logger) { + $this->logger->debug(sprintf('Unused pushed response: "%s"', $pushedUrl)); + } + } + } + + $this->multi->pushedResponses = []; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/AsyncDecoratorTrait.php b/sites/all/libraries/vendor/symfony/http-client/AsyncDecoratorTrait.php new file mode 100644 index 0000000000..aff402d83c --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/AsyncDecoratorTrait.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Response\AsyncResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; + +/** + * Eases with processing responses while streaming them. + * + * @author Nicolas Grekas + */ +trait AsyncDecoratorTrait +{ + use DecoratorTrait; + + /** + * {@inheritdoc} + * + * @return AsyncResponse + */ + abstract public function request(string $method, string $url, array $options = []): ResponseInterface; + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof AsyncResponse) { + $responses = [$responses]; + } elseif (!is_iterable($responses)) { + throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of AsyncResponse objects, "%s" given.', __METHOD__, get_debug_type($responses))); + } + + return new ResponseStream(AsyncResponse::stream($responses, $timeout, static::class)); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/CHANGELOG.md b/sites/all/libraries/vendor/symfony/http-client/CHANGELOG.md new file mode 100644 index 0000000000..7c2fc2273b --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/CHANGELOG.md @@ -0,0 +1,54 @@ +CHANGELOG +========= + +5.4 +--- + + * Add `MockHttpClient::setResponseFactory()` method to be able to set response factory after client creating + +5.3 +--- + + * Implement `HttpClientInterface::withOptions()` from `symfony/contracts` v2.4 + * Add `DecoratorTrait` to ease writing simple decorators + +5.2.0 +----- + + * added `AsyncDecoratorTrait` to ease processing responses without breaking async + * added support for pausing responses with a new `pause_handler` callable exposed as an info item + * added `StreamableInterface` to ease turning responses into PHP streams + * added `MockResponse::getRequestMethod()` and `getRequestUrl()` to allow inspecting which request has been sent + * added `EventSourceHttpClient` a Server-Sent events stream implementing the [EventSource specification](https://www.w3.org/TR/eventsource/#eventsource) + * added option "extra.curl" to allow setting additional curl options in `CurlHttpClient` + * added `RetryableHttpClient` to automatically retry failed HTTP requests. + * added `extra.trace_content` option to `TraceableHttpClient` to prevent it from keeping the content in memory + +5.1.0 +----- + + * added `NoPrivateNetworkHttpClient` decorator + * added `AmpHttpClient`, a portable HTTP/2 implementation based on Amp + * added `LoggerAwareInterface` to `ScopingHttpClient` and `TraceableHttpClient` + * made `HttpClient::create()` return an `AmpHttpClient` when `amphp/http-client` is found but curl is not or too old + +4.4.0 +----- + + * added `canceled` to `ResponseInterface::getInfo()` + * added `HttpClient::createForBaseUri()` + * added `HttplugClient` with support for sync and async requests + * added `max_duration` option + * added support for NTLM authentication + * added `StreamWrapper` to cast any `ResponseInterface` instances to PHP streams. + * added `$response->toStream()` to cast responses to regular PHP streams + * made `Psr18Client` implement relevant PSR-17 factories and have streaming responses + * added `TraceableHttpClient`, `HttpClientDataCollector` and `HttpClientPass` to integrate with the web profiler + * allow enabling buffering conditionally with a Closure + * allow option "buffer" to be a stream resource + * allow arbitrary values for the "json" option + +4.3.0 +----- + + * added the component diff --git a/sites/all/libraries/vendor/symfony/http-client/CachingHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/CachingHttpClient.php new file mode 100644 index 0000000000..e1d7023d9a --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/CachingHttpClient.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\HttpCache\HttpCache; +use Symfony\Component\HttpKernel\HttpCache\StoreInterface; +use Symfony\Component\HttpKernel\HttpClientKernel; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Adds caching on top of an HTTP client. + * + * The implementation buffers responses in memory and doesn't stream directly from the network. + * You can disable/enable this layer by setting option "no_cache" under "extra" to true/false. + * By default, caching is enabled unless the "buffer" option is set to false. + * + * @author Nicolas Grekas + */ +class CachingHttpClient implements HttpClientInterface, ResetInterface +{ + use HttpClientTrait; + + private $client; + private $cache; + private $defaultOptions = self::OPTIONS_DEFAULTS; + + public function __construct(HttpClientInterface $client, StoreInterface $store, array $defaultOptions = []) + { + if (!class_exists(HttpClientKernel::class)) { + throw new \LogicException(sprintf('Using "%s" requires that the HttpKernel component version 4.3 or higher is installed, try running "composer require symfony/http-kernel:^5.4".', __CLASS__)); + } + + $this->client = $client; + $kernel = new HttpClientKernel($client); + $this->cache = new HttpCache($kernel, $store, null, $defaultOptions); + + unset($defaultOptions['debug']); + unset($defaultOptions['default_ttl']); + unset($defaultOptions['private_headers']); + unset($defaultOptions['allow_reload']); + unset($defaultOptions['allow_revalidate']); + unset($defaultOptions['stale_while_revalidate']); + unset($defaultOptions['stale_if_error']); + unset($defaultOptions['trace_level']); + unset($defaultOptions['trace_header']); + + if ($defaultOptions) { + [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions); + } + } + + /** + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + [$url, $options] = $this->prepareRequest($method, $url, $options, $this->defaultOptions, true); + $url = implode('', $url); + + if (!empty($options['body']) || !empty($options['extra']['no_cache']) || !\in_array($method, ['GET', 'HEAD', 'OPTIONS'])) { + return $this->client->request($method, $url, $options); + } + + $request = Request::create($url, $method); + $request->attributes->set('http_client_options', $options); + + foreach ($options['normalized_headers'] as $name => $values) { + if ('cookie' !== $name) { + foreach ($values as $value) { + $request->headers->set($name, substr($value, 2 + \strlen($name)), false); + } + + continue; + } + + foreach ($values as $cookies) { + foreach (explode('; ', substr($cookies, \strlen('Cookie: '))) as $cookie) { + if ('' !== $cookie) { + $cookie = explode('=', $cookie, 2); + $request->cookies->set($cookie[0], $cookie[1] ?? ''); + } + } + } + } + + $response = $this->cache->handle($request); + $response = new MockResponse($response->getContent(), [ + 'http_code' => $response->getStatusCode(), + 'response_headers' => $response->headers->allPreserveCase(), + ]); + + return MockResponse::fromRequest($method, $url, $options, $response); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof ResponseInterface) { + $responses = [$responses]; + } elseif (!is_iterable($responses)) { + throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of ResponseInterface objects, "%s" given.', __METHOD__, get_debug_type($responses))); + } + + $mockResponses = []; + $clientResponses = []; + + foreach ($responses as $response) { + if ($response instanceof MockResponse) { + $mockResponses[] = $response; + } else { + $clientResponses[] = $response; + } + } + + if (!$mockResponses) { + return $this->client->stream($clientResponses, $timeout); + } + + if (!$clientResponses) { + return new ResponseStream(MockResponse::stream($mockResponses, $timeout)); + } + + return new ResponseStream((function () use ($mockResponses, $clientResponses, $timeout) { + yield from MockResponse::stream($mockResponses, $timeout); + yield $this->client->stream($clientResponses, $timeout); + })()); + } + + public function reset() + { + if ($this->client instanceof ResetInterface) { + $this->client->reset(); + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Chunk/DataChunk.php b/sites/all/libraries/vendor/symfony/http-client/Chunk/DataChunk.php new file mode 100644 index 0000000000..37ca848541 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Chunk/DataChunk.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +use Symfony\Contracts\HttpClient\ChunkInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class DataChunk implements ChunkInterface +{ + private $offset = 0; + private $content = ''; + + public function __construct(int $offset = 0, string $content = '') + { + $this->offset = $offset; + $this->content = $content; + } + + /** + * {@inheritdoc} + */ + public function isTimeout(): bool + { + return false; + } + + /** + * {@inheritdoc} + */ + public function isFirst(): bool + { + return false; + } + + /** + * {@inheritdoc} + */ + public function isLast(): bool + { + return false; + } + + /** + * {@inheritdoc} + */ + public function getInformationalStatus(): ?array + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getContent(): string + { + return $this->content; + } + + /** + * {@inheritdoc} + */ + public function getOffset(): int + { + return $this->offset; + } + + /** + * {@inheritdoc} + */ + public function getError(): ?string + { + return null; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Chunk/ErrorChunk.php b/sites/all/libraries/vendor/symfony/http-client/Chunk/ErrorChunk.php new file mode 100644 index 0000000000..a19f433620 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Chunk/ErrorChunk.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +use Symfony\Component\HttpClient\Exception\TimeoutException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Contracts\HttpClient\ChunkInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class ErrorChunk implements ChunkInterface +{ + private $didThrow = false; + private $offset; + private $errorMessage; + private $error; + + /** + * @param \Throwable|string $error + */ + public function __construct(int $offset, $error) + { + $this->offset = $offset; + + if (\is_string($error)) { + $this->errorMessage = $error; + } else { + $this->error = $error; + $this->errorMessage = $error->getMessage(); + } + } + + /** + * {@inheritdoc} + */ + public function isTimeout(): bool + { + $this->didThrow = true; + + if (null !== $this->error) { + throw new TransportException($this->errorMessage, 0, $this->error); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function isFirst(): bool + { + $this->didThrow = true; + throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage); + } + + /** + * {@inheritdoc} + */ + public function isLast(): bool + { + $this->didThrow = true; + throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage); + } + + /** + * {@inheritdoc} + */ + public function getInformationalStatus(): ?array + { + $this->didThrow = true; + throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage); + } + + /** + * {@inheritdoc} + */ + public function getContent(): string + { + $this->didThrow = true; + throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage); + } + + /** + * {@inheritdoc} + */ + public function getOffset(): int + { + return $this->offset; + } + + /** + * {@inheritdoc} + */ + public function getError(): ?string + { + return $this->errorMessage; + } + + /** + * @return bool Whether the wrapped error has been thrown or not + */ + public function didThrow(bool $didThrow = null): bool + { + if (null !== $didThrow && $this->didThrow !== $didThrow) { + return !$this->didThrow = $didThrow; + } + + return $this->didThrow; + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + if (!$this->didThrow) { + $this->didThrow = true; + throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage); + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Chunk/FirstChunk.php b/sites/all/libraries/vendor/symfony/http-client/Chunk/FirstChunk.php new file mode 100644 index 0000000000..d891ca856d --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Chunk/FirstChunk.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class FirstChunk extends DataChunk +{ + /** + * {@inheritdoc} + */ + public function isFirst(): bool + { + return true; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Chunk/InformationalChunk.php b/sites/all/libraries/vendor/symfony/http-client/Chunk/InformationalChunk.php new file mode 100644 index 0000000000..c4452f15a0 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Chunk/InformationalChunk.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class InformationalChunk extends DataChunk +{ + private $status; + + public function __construct(int $statusCode, array $headers) + { + $this->status = [$statusCode, $headers]; + } + + /** + * {@inheritdoc} + */ + public function getInformationalStatus(): ?array + { + return $this->status; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Chunk/LastChunk.php b/sites/all/libraries/vendor/symfony/http-client/Chunk/LastChunk.php new file mode 100644 index 0000000000..84095d3925 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Chunk/LastChunk.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class LastChunk extends DataChunk +{ + /** + * {@inheritdoc} + */ + public function isLast(): bool + { + return true; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Chunk/ServerSentEvent.php b/sites/all/libraries/vendor/symfony/http-client/Chunk/ServerSentEvent.php new file mode 100644 index 0000000000..f7ff4b9631 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Chunk/ServerSentEvent.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +use Symfony\Contracts\HttpClient\ChunkInterface; + +/** + * @author Antoine Bluchet + * @author Nicolas Grekas + */ +final class ServerSentEvent extends DataChunk implements ChunkInterface +{ + private $data = ''; + private $id = ''; + private $type = 'message'; + private $retry = 0; + + public function __construct(string $content) + { + parent::__construct(-1, $content); + + // remove BOM + if (0 === strpos($content, "\xEF\xBB\xBF")) { + $content = substr($content, 3); + } + + foreach (preg_split("/(?:\r\n|[\r\n])/", $content) as $line) { + if (0 === $i = strpos($line, ':')) { + continue; + } + + $i = false === $i ? \strlen($line) : $i; + $field = substr($line, 0, $i); + $i += 1 + (' ' === ($line[1 + $i] ?? '')); + + switch ($field) { + case 'id': $this->id = substr($line, $i); break; + case 'event': $this->type = substr($line, $i); break; + case 'data': $this->data .= ('' === $this->data ? '' : "\n").substr($line, $i); break; + case 'retry': + $retry = substr($line, $i); + + if ('' !== $retry && \strlen($retry) === strspn($retry, '0123456789')) { + $this->retry = $retry / 1000.0; + } + break; + } + } + } + + public function getId(): string + { + return $this->id; + } + + public function getType(): string + { + return $this->type; + } + + public function getData(): string + { + return $this->data; + } + + public function getRetry(): float + { + return $this->retry; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/CurlHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/CurlHttpClient.php new file mode 100644 index 0000000000..3807244dc6 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/CurlHttpClient.php @@ -0,0 +1,551 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\CurlClientState; +use Symfony\Component\HttpClient\Internal\PushedResponse; +use Symfony\Component\HttpClient\Response\CurlResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * A performant implementation of the HttpClientInterface contracts based on the curl extension. + * + * This provides fully concurrent HTTP requests, with transparent + * HTTP/2 push when a curl version that supports it is installed. + * + * @author Nicolas Grekas + */ +final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface +{ + use HttpClientTrait; + + private $defaultOptions = self::OPTIONS_DEFAULTS + [ + 'auth_ntlm' => null, // array|string - an array containing the username as first value, and optionally the + // password as the second one; or string like username:password - enabling NTLM auth + 'extra' => [ + 'curl' => [], // A list of extra curl options indexed by their corresponding CURLOPT_* + ], + ]; + private static $emptyDefaults = self::OPTIONS_DEFAULTS + ['auth_ntlm' => null]; + + /** + * @var LoggerInterface|null + */ + private $logger; + + /** + * An internal object to share state between the client and its responses. + * + * @var CurlClientState + */ + private $multi; + + /** + * @param array $defaultOptions Default request's options + * @param int $maxHostConnections The maximum number of connections to a single host + * @param int $maxPendingPushes The maximum number of pushed responses to accept in the queue + * + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + */ + public function __construct(array $defaultOptions = [], int $maxHostConnections = 6, int $maxPendingPushes = 50) + { + if (!\extension_loaded('curl')) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\CurlHttpClient" as the "curl" extension is not installed.'); + } + + $this->defaultOptions['buffer'] = $this->defaultOptions['buffer'] ?? \Closure::fromCallable([__CLASS__, 'shouldBuffer']); + + if ($defaultOptions) { + [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions); + } + + $this->multi = new CurlClientState($maxHostConnections, $maxPendingPushes); + } + + public function setLogger(LoggerInterface $logger): void + { + $this->logger = $this->multi->logger = $logger; + } + + /** + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + * + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions); + $scheme = $url['scheme']; + $authority = $url['authority']; + $host = parse_url($authority, \PHP_URL_HOST); + $proxy = $options['proxy'] + ?? ('https:' === $url['scheme'] ? $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? null : null) + // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities + ?? $_SERVER['http_proxy'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null; + $url = implode('', $url); + + if (!isset($options['normalized_headers']['user-agent'])) { + $options['headers'][] = 'User-Agent: Symfony HttpClient/Curl'; + } + + $curlopts = [ + \CURLOPT_URL => $url, + \CURLOPT_TCP_NODELAY => true, + \CURLOPT_PROTOCOLS => \CURLPROTO_HTTP | \CURLPROTO_HTTPS, + \CURLOPT_REDIR_PROTOCOLS => \CURLPROTO_HTTP | \CURLPROTO_HTTPS, + \CURLOPT_FOLLOWLOCATION => true, + \CURLOPT_MAXREDIRS => 0 < $options['max_redirects'] ? $options['max_redirects'] : 0, + \CURLOPT_COOKIEFILE => '', // Keep track of cookies during redirects + \CURLOPT_TIMEOUT => 0, + \CURLOPT_PROXY => $proxy, + \CURLOPT_NOPROXY => $options['no_proxy'] ?? $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? '', + \CURLOPT_SSL_VERIFYPEER => $options['verify_peer'], + \CURLOPT_SSL_VERIFYHOST => $options['verify_host'] ? 2 : 0, + \CURLOPT_CAINFO => $options['cafile'], + \CURLOPT_CAPATH => $options['capath'], + \CURLOPT_SSL_CIPHER_LIST => $options['ciphers'], + \CURLOPT_SSLCERT => $options['local_cert'], + \CURLOPT_SSLKEY => $options['local_pk'], + \CURLOPT_KEYPASSWD => $options['passphrase'], + \CURLOPT_CERTINFO => $options['capture_peer_cert_chain'], + ]; + + if (1.0 === (float) $options['http_version']) { + $curlopts[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0; + } elseif (1.1 === (float) $options['http_version']) { + $curlopts[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1; + } elseif (\defined('CURL_VERSION_HTTP2') && (\CURL_VERSION_HTTP2 & CurlClientState::$curlVersion['features']) && ('https:' === $scheme || 2.0 === (float) $options['http_version'])) { + $curlopts[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0; + } + + if (isset($options['auth_ntlm'])) { + $curlopts[\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM; + $curlopts[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1; + + if (\is_array($options['auth_ntlm'])) { + $count = \count($options['auth_ntlm']); + if ($count <= 0 || $count > 2) { + throw new InvalidArgumentException(sprintf('Option "auth_ntlm" must contain 1 or 2 elements, %d given.', $count)); + } + + $options['auth_ntlm'] = implode(':', $options['auth_ntlm']); + } + + if (!\is_string($options['auth_ntlm'])) { + throw new InvalidArgumentException(sprintf('Option "auth_ntlm" must be a string or an array, "%s" given.', get_debug_type($options['auth_ntlm']))); + } + + $curlopts[\CURLOPT_USERPWD] = $options['auth_ntlm']; + } + + if (!\ZEND_THREAD_SAFE) { + $curlopts[\CURLOPT_DNS_USE_GLOBAL_CACHE] = false; + } + + if (\defined('CURLOPT_HEADEROPT') && \defined('CURLHEADER_SEPARATE')) { + $curlopts[\CURLOPT_HEADEROPT] = \CURLHEADER_SEPARATE; + } + + // curl's resolve feature varies by host:port but ours varies by host only, let's handle this with our own DNS map + if (isset($this->multi->dnsCache->hostnames[$host])) { + $options['resolve'] += [$host => $this->multi->dnsCache->hostnames[$host]]; + } + + if ($options['resolve'] || $this->multi->dnsCache->evictions) { + // First reset any old DNS cache entries then add the new ones + $resolve = $this->multi->dnsCache->evictions; + $this->multi->dnsCache->evictions = []; + $port = parse_url($authority, \PHP_URL_PORT) ?: ('http:' === $scheme ? 80 : 443); + + if ($resolve && 0x072A00 > CurlClientState::$curlVersion['version_number']) { + // DNS cache removals require curl 7.42 or higher + $this->multi->reset(); + } + + foreach ($options['resolve'] as $host => $ip) { + $resolve[] = null === $ip ? "-$host:$port" : "$host:$port:$ip"; + $this->multi->dnsCache->hostnames[$host] = $ip; + $this->multi->dnsCache->removals["-$host:$port"] = "-$host:$port"; + } + + $curlopts[\CURLOPT_RESOLVE] = $resolve; + } + + if ('POST' === $method) { + // Use CURLOPT_POST to have browser-like POST-to-GET redirects for 301, 302 and 303 + $curlopts[\CURLOPT_POST] = true; + } elseif ('HEAD' === $method) { + $curlopts[\CURLOPT_NOBODY] = true; + } else { + $curlopts[\CURLOPT_CUSTOMREQUEST] = $method; + } + + if ('\\' !== \DIRECTORY_SEPARATOR && $options['timeout'] < 1) { + $curlopts[\CURLOPT_NOSIGNAL] = true; + } + + if (\extension_loaded('zlib') && !isset($options['normalized_headers']['accept-encoding'])) { + $options['headers'][] = 'Accept-Encoding: gzip'; // Expose only one encoding, some servers mess up when more are provided + } + + foreach ($options['headers'] as $header) { + if (':' === $header[-2] && \strlen($header) - 2 === strpos($header, ': ')) { + // curl requires a special syntax to send empty headers + $curlopts[\CURLOPT_HTTPHEADER][] = substr_replace($header, ';', -2); + } else { + $curlopts[\CURLOPT_HTTPHEADER][] = $header; + } + } + + // Prevent curl from sending its default Accept and Expect headers + foreach (['accept', 'expect'] as $header) { + if (!isset($options['normalized_headers'][$header][0])) { + $curlopts[\CURLOPT_HTTPHEADER][] = $header.':'; + } + } + + if (!\is_string($body = $options['body'])) { + if (\is_resource($body)) { + $curlopts[\CURLOPT_INFILE] = $body; + } else { + $eof = false; + $buffer = ''; + $curlopts[\CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use ($body, &$buffer, &$eof) { + return self::readRequestBody($length, $body, $buffer, $eof); + }; + } + + if (isset($options['normalized_headers']['content-length'][0])) { + $curlopts[\CURLOPT_INFILESIZE] = substr($options['normalized_headers']['content-length'][0], \strlen('Content-Length: ')); + } elseif (!isset($options['normalized_headers']['transfer-encoding'])) { + $curlopts[\CURLOPT_HTTPHEADER][] = 'Transfer-Encoding: chunked'; // Enable chunked request bodies + } + + if ('POST' !== $method) { + $curlopts[\CURLOPT_UPLOAD] = true; + + if (!isset($options['normalized_headers']['content-type'])) { + $curlopts[\CURLOPT_HTTPHEADER][] = 'Content-Type: application/x-www-form-urlencoded'; + } + } + } elseif ('' !== $body || 'POST' === $method) { + $curlopts[\CURLOPT_POSTFIELDS] = $body; + } + + if ($options['peer_fingerprint']) { + if (!isset($options['peer_fingerprint']['pin-sha256'])) { + throw new TransportException(__CLASS__.' supports only "pin-sha256" fingerprints.'); + } + + $curlopts[\CURLOPT_PINNEDPUBLICKEY] = 'sha256//'.implode(';sha256//', $options['peer_fingerprint']['pin-sha256']); + } + + if ($options['bindto']) { + if (file_exists($options['bindto'])) { + $curlopts[\CURLOPT_UNIX_SOCKET_PATH] = $options['bindto']; + } elseif (!str_starts_with($options['bindto'], 'if!') && preg_match('/^(.*):(\d+)$/', $options['bindto'], $matches)) { + $curlopts[\CURLOPT_INTERFACE] = $matches[1]; + $curlopts[\CURLOPT_LOCALPORT] = $matches[2]; + } else { + $curlopts[\CURLOPT_INTERFACE] = $options['bindto']; + } + } + + if (0 < $options['max_duration']) { + $curlopts[\CURLOPT_TIMEOUT_MS] = 1000 * $options['max_duration']; + } + + if (!empty($options['extra']['curl']) && \is_array($options['extra']['curl'])) { + $this->validateExtraCurlOptions($options['extra']['curl']); + $curlopts += $options['extra']['curl']; + } + + if ($pushedResponse = $this->multi->pushedResponses[$url] ?? null) { + unset($this->multi->pushedResponses[$url]); + + if (self::acceptPushForRequest($method, $options, $pushedResponse)) { + $this->logger && $this->logger->debug(sprintf('Accepting pushed response: "%s %s"', $method, $url)); + + // Reinitialize the pushed response with request's options + $ch = $pushedResponse->handle; + $pushedResponse = $pushedResponse->response; + $pushedResponse->__construct($this->multi, $url, $options, $this->logger); + } else { + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response: "%s"', $url)); + $pushedResponse = null; + } + } + + if (!$pushedResponse) { + $ch = curl_init(); + $this->logger && $this->logger->info(sprintf('Request: "%s %s"', $method, $url)); + $curlopts += [\CURLOPT_SHARE => $this->multi->share]; + } + + foreach ($curlopts as $opt => $value) { + if (null !== $value && !curl_setopt($ch, $opt, $value) && \CURLOPT_CERTINFO !== $opt && (!\defined('CURLOPT_HEADEROPT') || \CURLOPT_HEADEROPT !== $opt)) { + $constantName = $this->findConstantName($opt); + throw new TransportException(sprintf('Curl option "%s" is not supported.', $constantName ?? $opt)); + } + } + + return $pushedResponse ?? new CurlResponse($this->multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $host), CurlClientState::$curlVersion['version_number']); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof CurlResponse) { + $responses = [$responses]; + } elseif (!is_iterable($responses)) { + throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of CurlResponse objects, "%s" given.', __METHOD__, get_debug_type($responses))); + } + + if (\is_resource($this->multi->handle) || $this->multi->handle instanceof \CurlMultiHandle) { + $active = 0; + while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)) { + } + } + + return new ResponseStream(CurlResponse::stream($responses, $timeout)); + } + + public function reset() + { + $this->multi->reset(); + } + + /** + * Accepts pushed responses only if their headers related to authentication match the request. + */ + private static function acceptPushForRequest(string $method, array $options, PushedResponse $pushedResponse): bool + { + if ('' !== $options['body'] || $method !== $pushedResponse->requestHeaders[':method'][0]) { + return false; + } + + foreach (['proxy', 'no_proxy', 'bindto', 'local_cert', 'local_pk'] as $k) { + if ($options[$k] !== $pushedResponse->parentOptions[$k]) { + return false; + } + } + + foreach (['authorization', 'cookie', 'range', 'proxy-authorization'] as $k) { + $normalizedHeaders = $options['normalized_headers'][$k] ?? []; + foreach ($normalizedHeaders as $i => $v) { + $normalizedHeaders[$i] = substr($v, \strlen($k) + 2); + } + + if (($pushedResponse->requestHeaders[$k] ?? []) !== $normalizedHeaders) { + return false; + } + } + + return true; + } + + /** + * Wraps the request's body callback to allow it to return strings longer than curl requested. + */ + private static function readRequestBody(int $length, \Closure $body, string &$buffer, bool &$eof): string + { + if (!$eof && \strlen($buffer) < $length) { + if (!\is_string($data = $body($length))) { + throw new TransportException(sprintf('The return value of the "body" option callback must be a string, "%s" returned.', get_debug_type($data))); + } + + $buffer .= $data; + $eof = '' === $data; + } + + $data = substr($buffer, 0, $length); + $buffer = substr($buffer, $length); + + return $data; + } + + /** + * Resolves relative URLs on redirects and deals with authentication headers. + * + * Work around CVE-2018-1000007: Authorization and Cookie headers should not follow redirects - fixed in Curl 7.64 + */ + private static function createRedirectResolver(array $options, string $host): \Closure + { + $redirectHeaders = []; + if (0 < $options['max_redirects']) { + $redirectHeaders['host'] = $host; + $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['headers'], static function ($h) { + return 0 !== stripos($h, 'Host:'); + }); + + if (isset($options['normalized_headers']['authorization'][0]) || isset($options['normalized_headers']['cookie'][0])) { + $redirectHeaders['no_auth'] = array_filter($options['headers'], static function ($h) { + return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); + }); + } + } + + return static function ($ch, string $location, bool $noContent) use (&$redirectHeaders) { + try { + $location = self::parseUrl($location); + } catch (InvalidArgumentException $e) { + return null; + } + + if ($noContent && $redirectHeaders) { + $filterContentHeaders = static function ($h) { + return 0 !== stripos($h, 'Content-Length:') && 0 !== stripos($h, 'Content-Type:') && 0 !== stripos($h, 'Transfer-Encoding:'); + }; + $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], $filterContentHeaders); + $redirectHeaders['with_auth'] = array_filter($redirectHeaders['with_auth'], $filterContentHeaders); + } + + if ($redirectHeaders && $host = parse_url('http:'.$location['authority'], \PHP_URL_HOST)) { + $requestHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth']; + curl_setopt($ch, \CURLOPT_HTTPHEADER, $requestHeaders); + } elseif ($noContent && $redirectHeaders) { + curl_setopt($ch, \CURLOPT_HTTPHEADER, $redirectHeaders['with_auth']); + } + + $url = self::parseUrl(curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL)); + $url = self::resolveUrl($location, $url); + + curl_setopt($ch, \CURLOPT_PROXY, $options['proxy'] + ?? ('https:' === $url['scheme'] ? $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? null : null) + // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities + ?? $_SERVER['http_proxy'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null + ); + + return implode('', $url); + }; + } + + private function findConstantName(int $opt): ?string + { + $constants = array_filter(get_defined_constants(), static function ($v, $k) use ($opt) { + return $v === $opt && 'C' === $k[0] && (str_starts_with($k, 'CURLOPT_') || str_starts_with($k, 'CURLINFO_')); + }, \ARRAY_FILTER_USE_BOTH); + + return key($constants); + } + + /** + * Prevents overriding options that are set internally throughout the request. + */ + private function validateExtraCurlOptions(array $options): void + { + $curloptsToConfig = [ + // options used in CurlHttpClient + \CURLOPT_HTTPAUTH => 'auth_ntlm', + \CURLOPT_USERPWD => 'auth_ntlm', + \CURLOPT_RESOLVE => 'resolve', + \CURLOPT_NOSIGNAL => 'timeout', + \CURLOPT_HTTPHEADER => 'headers', + \CURLOPT_INFILE => 'body', + \CURLOPT_READFUNCTION => 'body', + \CURLOPT_INFILESIZE => 'body', + \CURLOPT_POSTFIELDS => 'body', + \CURLOPT_UPLOAD => 'body', + \CURLOPT_INTERFACE => 'bindto', + \CURLOPT_TIMEOUT_MS => 'max_duration', + \CURLOPT_TIMEOUT => 'max_duration', + \CURLOPT_MAXREDIRS => 'max_redirects', + \CURLOPT_PROXY => 'proxy', + \CURLOPT_NOPROXY => 'no_proxy', + \CURLOPT_SSL_VERIFYPEER => 'verify_peer', + \CURLOPT_SSL_VERIFYHOST => 'verify_host', + \CURLOPT_CAINFO => 'cafile', + \CURLOPT_CAPATH => 'capath', + \CURLOPT_SSL_CIPHER_LIST => 'ciphers', + \CURLOPT_SSLCERT => 'local_cert', + \CURLOPT_SSLKEY => 'local_pk', + \CURLOPT_KEYPASSWD => 'passphrase', + \CURLOPT_CERTINFO => 'capture_peer_cert_chain', + \CURLOPT_USERAGENT => 'normalized_headers', + \CURLOPT_REFERER => 'headers', + // options used in CurlResponse + \CURLOPT_NOPROGRESS => 'on_progress', + \CURLOPT_PROGRESSFUNCTION => 'on_progress', + ]; + + if (\defined('CURLOPT_UNIX_SOCKET_PATH')) { + $curloptsToConfig[\CURLOPT_UNIX_SOCKET_PATH] = 'bindto'; + } + + if (\defined('CURLOPT_PINNEDPUBLICKEY')) { + $curloptsToConfig[\CURLOPT_PINNEDPUBLICKEY] = 'peer_fingerprint'; + } + + $curloptsToCheck = [ + \CURLOPT_PRIVATE, + \CURLOPT_HEADERFUNCTION, + \CURLOPT_WRITEFUNCTION, + \CURLOPT_VERBOSE, + \CURLOPT_STDERR, + \CURLOPT_RETURNTRANSFER, + \CURLOPT_URL, + \CURLOPT_FOLLOWLOCATION, + \CURLOPT_HEADER, + \CURLOPT_CONNECTTIMEOUT, + \CURLOPT_CONNECTTIMEOUT_MS, + \CURLOPT_HTTP_VERSION, + \CURLOPT_PORT, + \CURLOPT_DNS_USE_GLOBAL_CACHE, + \CURLOPT_PROTOCOLS, + \CURLOPT_REDIR_PROTOCOLS, + \CURLOPT_COOKIEFILE, + \CURLINFO_REDIRECT_COUNT, + ]; + + if (\defined('CURLOPT_HTTP09_ALLOWED')) { + $curloptsToCheck[] = \CURLOPT_HTTP09_ALLOWED; + } + + if (\defined('CURLOPT_HEADEROPT')) { + $curloptsToCheck[] = \CURLOPT_HEADEROPT; + } + + $methodOpts = [ + \CURLOPT_POST, + \CURLOPT_PUT, + \CURLOPT_CUSTOMREQUEST, + \CURLOPT_HTTPGET, + \CURLOPT_NOBODY, + ]; + + foreach ($options as $opt => $optValue) { + if (isset($curloptsToConfig[$opt])) { + $constName = $this->findConstantName($opt) ?? $opt; + throw new InvalidArgumentException(sprintf('Cannot set "%s" with "extra.curl", use option "%s" instead.', $constName, $curloptsToConfig[$opt])); + } + + if (\in_array($opt, $methodOpts)) { + throw new InvalidArgumentException('The HTTP method cannot be overridden using "extra.curl".'); + } + + if (\in_array($opt, $curloptsToCheck)) { + $constName = $this->findConstantName($opt) ?? $opt; + throw new InvalidArgumentException(sprintf('Cannot set "%s" with "extra.curl".', $constName)); + } + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/DataCollector/HttpClientDataCollector.php b/sites/all/libraries/vendor/symfony/http-client/DataCollector/HttpClientDataCollector.php new file mode 100644 index 0000000000..db8bbbdd69 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/DataCollector/HttpClientDataCollector.php @@ -0,0 +1,170 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\DataCollector; + +use Symfony\Component\HttpClient\TraceableHttpClient; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; +use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; +use Symfony\Component\VarDumper\Caster\ImgStub; + +/** + * @author Jérémy Romey + */ +final class HttpClientDataCollector extends DataCollector implements LateDataCollectorInterface +{ + /** + * @var TraceableHttpClient[] + */ + private $clients = []; + + public function registerClient(string $name, TraceableHttpClient $client) + { + $this->clients[$name] = $client; + } + + /** + * {@inheritdoc} + */ + public function collect(Request $request, Response $response, \Throwable $exception = null) + { + $this->reset(); + + foreach ($this->clients as $name => $client) { + [$errorCount, $traces] = $this->collectOnClient($client); + + $this->data['clients'][$name] = [ + 'traces' => $traces, + 'error_count' => $errorCount, + ]; + + $this->data['request_count'] += \count($traces); + $this->data['error_count'] += $errorCount; + } + } + + public function lateCollect() + { + foreach ($this->clients as $client) { + $client->reset(); + } + } + + public function getClients(): array + { + return $this->data['clients'] ?? []; + } + + public function getRequestCount(): int + { + return $this->data['request_count'] ?? 0; + } + + public function getErrorCount(): int + { + return $this->data['error_count'] ?? 0; + } + + /** + * {@inheritdoc} + */ + public function getName(): string + { + return 'http_client'; + } + + public function reset() + { + $this->data = [ + 'clients' => [], + 'request_count' => 0, + 'error_count' => 0, + ]; + } + + private function collectOnClient(TraceableHttpClient $client): array + { + $traces = $client->getTracedRequests(); + $errorCount = 0; + $baseInfo = [ + 'response_headers' => 1, + 'retry_count' => 1, + 'redirect_count' => 1, + 'redirect_url' => 1, + 'user_data' => 1, + 'error' => 1, + 'url' => 1, + ]; + + foreach ($traces as $i => $trace) { + if (400 <= ($trace['info']['http_code'] ?? 0)) { + ++$errorCount; + } + + $info = $trace['info']; + $traces[$i]['http_code'] = $info['http_code'] ?? 0; + + unset($info['filetime'], $info['http_code'], $info['ssl_verify_result'], $info['content_type']); + + if (($info['http_method'] ?? null) === $trace['method']) { + unset($info['http_method']); + } + + if (($info['url'] ?? null) === $trace['url']) { + unset($info['url']); + } + + foreach ($info as $k => $v) { + if (!$v || (is_numeric($v) && 0 > $v)) { + unset($info[$k]); + } + } + + if (\is_string($content = $trace['content'])) { + $contentType = 'application/octet-stream'; + + foreach ($info['response_headers'] ?? [] as $h) { + if (0 === stripos($h, 'content-type: ')) { + $contentType = substr($h, \strlen('content-type: ')); + break; + } + } + + if (0 === strpos($contentType, 'image/') && class_exists(ImgStub::class)) { + $content = new ImgStub($content, $contentType, ''); + } else { + $content = [$content]; + } + + $content = ['response_content' => $content]; + } elseif (\is_array($content)) { + $content = ['response_json' => $content]; + } else { + $content = []; + } + + if (isset($info['retry_count'])) { + $content['retries'] = $info['previous_info']; + unset($info['previous_info']); + } + + $debugInfo = array_diff_key($info, $baseInfo); + $info = ['info' => $debugInfo] + array_diff_key($info, $debugInfo) + $content; + unset($traces[$i]['info']); // break PHP reference used by TraceableHttpClient + $traces[$i]['info'] = $this->cloneVar($info); + $traces[$i]['options'] = $this->cloneVar($trace['options']); + } + + return [$errorCount, $traces]; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/DecoratorTrait.php b/sites/all/libraries/vendor/symfony/http-client/DecoratorTrait.php new file mode 100644 index 0000000000..790fc32a59 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/DecoratorTrait.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Eases with writing decorators. + * + * @author Nicolas Grekas + */ +trait DecoratorTrait +{ + private $client; + + public function __construct(HttpClientInterface $client = null) + { + $this->client = $client ?? HttpClient::create(); + } + + /** + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + return $this->client->request($method, $url, $options); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + return $this->client->stream($responses, $timeout); + } + + /** + * {@inheritdoc} + */ + public function withOptions(array $options): self + { + $clone = clone $this; + $clone->client = $this->client->withOptions($options); + + return $clone; + } + + public function reset() + { + if ($this->client instanceof ResetInterface) { + $this->client->reset(); + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/DependencyInjection/HttpClientPass.php b/sites/all/libraries/vendor/symfony/http-client/DependencyInjection/HttpClientPass.php new file mode 100644 index 0000000000..73f8865134 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/DependencyInjection/HttpClientPass.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpClient\TraceableHttpClient; + +final class HttpClientPass implements CompilerPassInterface +{ + private $clientTag; + + public function __construct(string $clientTag = 'http_client.client') + { + if (0 < \func_num_args()) { + trigger_deprecation('symfony/http-client', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); + } + + $this->clientTag = $clientTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('data_collector.http_client')) { + return; + } + + foreach ($container->findTaggedServiceIds($this->clientTag) as $id => $tags) { + $container->register('.debug.'.$id, TraceableHttpClient::class) + ->setArguments([new Reference('.debug.'.$id.'.inner'), new Reference('debug.stopwatch', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]) + ->addTag('kernel.reset', ['method' => 'reset']) + ->setDecoratedService($id); + $container->getDefinition('data_collector.http_client') + ->addMethodCall('registerClient', [$id, new Reference('.debug.'.$id)]); + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/EventSourceHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/EventSourceHttpClient.php new file mode 100644 index 0000000000..60e4e821d1 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/EventSourceHttpClient.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Chunk\ServerSentEvent; +use Symfony\Component\HttpClient\Exception\EventSourceException; +use Symfony\Component\HttpClient\Response\AsyncContext; +use Symfony\Component\HttpClient\Response\AsyncResponse; +use Symfony\Contracts\HttpClient\ChunkInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * @author Antoine Bluchet + * @author Nicolas Grekas + */ +final class EventSourceHttpClient implements HttpClientInterface, ResetInterface +{ + use AsyncDecoratorTrait, HttpClientTrait { + AsyncDecoratorTrait::withOptions insteadof HttpClientTrait; + } + + private $reconnectionTime; + + public function __construct(HttpClientInterface $client = null, float $reconnectionTime = 10.0) + { + $this->client = $client ?? HttpClient::create(); + $this->reconnectionTime = $reconnectionTime; + } + + public function connect(string $url, array $options = []): ResponseInterface + { + return $this->request('GET', $url, self::mergeDefaultOptions($options, [ + 'buffer' => false, + 'headers' => [ + 'Accept' => 'text/event-stream', + 'Cache-Control' => 'no-cache', + ], + ], true)); + } + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + $state = new class() { + public $buffer = null; + public $lastEventId = null; + public $reconnectionTime; + public $lastError = null; + }; + $state->reconnectionTime = $this->reconnectionTime; + + if ($accept = self::normalizeHeaders($options['headers'] ?? [])['accept'] ?? []) { + $state->buffer = \in_array($accept, [['Accept: text/event-stream'], ['accept: text/event-stream']], true) ? '' : null; + + if (null !== $state->buffer) { + $options['extra']['trace_content'] = false; + } + } + + return new AsyncResponse($this->client, $method, $url, $options, static function (ChunkInterface $chunk, AsyncContext $context) use ($state, $method, $url, $options) { + if (null !== $state->buffer) { + $context->setInfo('reconnection_time', $state->reconnectionTime); + $isTimeout = false; + } + $lastError = $state->lastError; + $state->lastError = null; + + try { + $isTimeout = $chunk->isTimeout(); + + if (null !== $chunk->getInformationalStatus() || $context->getInfo('canceled')) { + yield $chunk; + + return; + } + } catch (TransportExceptionInterface $e) { + $state->lastError = $lastError ?? microtime(true); + + if (null === $state->buffer || ($isTimeout && microtime(true) - $state->lastError < $state->reconnectionTime)) { + yield $chunk; + } else { + $options['headers']['Last-Event-ID'] = $state->lastEventId; + $state->buffer = ''; + $state->lastError = microtime(true); + $context->getResponse()->cancel(); + $context->replaceRequest($method, $url, $options); + if ($isTimeout) { + yield $chunk; + } else { + $context->pause($state->reconnectionTime); + } + } + + return; + } + + if ($chunk->isFirst()) { + if (preg_match('/^text\/event-stream(;|$)/i', $context->getHeaders()['content-type'][0] ?? '')) { + $state->buffer = ''; + } elseif (null !== $lastError || (null !== $state->buffer && 200 === $context->getStatusCode())) { + throw new EventSourceException(sprintf('Response content-type is "%s" while "text/event-stream" was expected for "%s".', $context->getHeaders()['content-type'][0] ?? '', $context->getInfo('url'))); + } else { + $context->passthru(); + } + + if (null === $lastError) { + yield $chunk; + } + + return; + } + + $rx = '/((?:\r\n|[\r\n]){2,})/'; + $content = $state->buffer.$chunk->getContent(); + + if ($chunk->isLast()) { + $rx = substr_replace($rx, '|$', -2, 0); + } + $events = preg_split($rx, $content, -1, \PREG_SPLIT_DELIM_CAPTURE); + $state->buffer = array_pop($events); + + for ($i = 0; isset($events[$i]); $i += 2) { + $event = new ServerSentEvent($events[$i].$events[1 + $i]); + + if ('' !== $event->getId()) { + $context->setInfo('last_event_id', $state->lastEventId = $event->getId()); + } + + if ($event->getRetry()) { + $context->setInfo('reconnection_time', $state->reconnectionTime = $event->getRetry()); + } + + yield $event; + } + + if (preg_match('/^(?::[^\r\n]*+(?:\r\n|[\r\n]))+$/m', $state->buffer)) { + $content = $state->buffer; + $state->buffer = ''; + + yield $context->createChunk($content); + } + + if ($chunk->isLast()) { + yield $chunk; + } + }); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Exception/ClientException.php b/sites/all/libraries/vendor/symfony/http-client/Exception/ClientException.php new file mode 100644 index 0000000000..4264534c01 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Exception/ClientException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; + +/** + * Represents a 4xx response. + * + * @author Nicolas Grekas + */ +final class ClientException extends \RuntimeException implements ClientExceptionInterface +{ + use HttpExceptionTrait; +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Exception/EventSourceException.php b/sites/all/libraries/vendor/symfony/http-client/Exception/EventSourceException.php new file mode 100644 index 0000000000..30ab7957c5 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Exception/EventSourceException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; + +/** + * @author Nicolas Grekas + */ +final class EventSourceException extends \RuntimeException implements DecodingExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Exception/HttpExceptionTrait.php b/sites/all/libraries/vendor/symfony/http-client/Exception/HttpExceptionTrait.php new file mode 100644 index 0000000000..8cbaa1cd10 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Exception/HttpExceptionTrait.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +trait HttpExceptionTrait +{ + private $response; + + public function __construct(ResponseInterface $response) + { + $this->response = $response; + $code = $response->getInfo('http_code'); + $url = $response->getInfo('url'); + $message = sprintf('HTTP %d returned for "%s".', $code, $url); + + $httpCodeFound = false; + $isJson = false; + foreach (array_reverse($response->getInfo('response_headers')) as $h) { + if (str_starts_with($h, 'HTTP/')) { + if ($httpCodeFound) { + break; + } + + $message = sprintf('%s returned for "%s".', $h, $url); + $httpCodeFound = true; + } + + if (0 === stripos($h, 'content-type:')) { + if (preg_match('/\bjson\b/i', $h)) { + $isJson = true; + } + + if ($httpCodeFound) { + break; + } + } + } + + // Try to guess a better error message using common API error formats + // The MIME type isn't explicitly checked because some formats inherit from others + // Ex: JSON:API follows RFC 7807 semantics, Hydra can be used in any JSON-LD-compatible format + if ($isJson && $body = json_decode($response->getContent(false), true)) { + if (isset($body['hydra:title']) || isset($body['hydra:description'])) { + // see http://www.hydra-cg.com/spec/latest/core/#description-of-http-status-codes-and-errors + $separator = isset($body['hydra:title'], $body['hydra:description']) ? "\n\n" : ''; + $message = ($body['hydra:title'] ?? '').$separator.($body['hydra:description'] ?? ''); + } elseif ((isset($body['title']) || isset($body['detail'])) + && (\is_scalar($body['title'] ?? '') && \is_scalar($body['detail'] ?? ''))) { + // see RFC 7807 and https://jsonapi.org/format/#error-objects + $separator = isset($body['title'], $body['detail']) ? "\n\n" : ''; + $message = ($body['title'] ?? '').$separator.($body['detail'] ?? ''); + } + } + + parent::__construct($message, $code); + } + + public function getResponse(): ResponseInterface + { + return $this->response; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Exception/InvalidArgumentException.php b/sites/all/libraries/vendor/symfony/http-client/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..6c2fae76fc --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * @author Nicolas Grekas + */ +final class InvalidArgumentException extends \InvalidArgumentException implements TransportExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Exception/JsonException.php b/sites/all/libraries/vendor/symfony/http-client/Exception/JsonException.php new file mode 100644 index 0000000000..54502e6269 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Exception/JsonException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; + +/** + * Thrown by responses' toArray() method when their content cannot be JSON-decoded. + * + * @author Nicolas Grekas + */ +final class JsonException extends \JsonException implements DecodingExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Exception/RedirectionException.php b/sites/all/libraries/vendor/symfony/http-client/Exception/RedirectionException.php new file mode 100644 index 0000000000..5b936702ca --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Exception/RedirectionException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; + +/** + * Represents a 3xx response. + * + * @author Nicolas Grekas + */ +final class RedirectionException extends \RuntimeException implements RedirectionExceptionInterface +{ + use HttpExceptionTrait; +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Exception/ServerException.php b/sites/all/libraries/vendor/symfony/http-client/Exception/ServerException.php new file mode 100644 index 0000000000..c6f827310c --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Exception/ServerException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; + +/** + * Represents a 5xx response. + * + * @author Nicolas Grekas + */ +final class ServerException extends \RuntimeException implements ServerExceptionInterface +{ + use HttpExceptionTrait; +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Exception/TimeoutException.php b/sites/all/libraries/vendor/symfony/http-client/Exception/TimeoutException.php new file mode 100644 index 0000000000..a9155cc8f6 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Exception/TimeoutException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\TimeoutExceptionInterface; + +/** + * @author Nicolas Grekas + */ +final class TimeoutException extends TransportException implements TimeoutExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Exception/TransportException.php b/sites/all/libraries/vendor/symfony/http-client/Exception/TransportException.php new file mode 100644 index 0000000000..a3a80c6dc6 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Exception/TransportException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * @author Nicolas Grekas + */ +class TransportException extends \RuntimeException implements TransportExceptionInterface +{ +} diff --git a/sites/all/libraries/vendor/symfony/http-client/HttpClient.php b/sites/all/libraries/vendor/symfony/http-client/HttpClient.php new file mode 100644 index 0000000000..30fe339a37 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/HttpClient.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Amp\Http\Client\Connection\ConnectionLimitingPool; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * A factory to instantiate the best possible HTTP client for the runtime. + * + * @author Nicolas Grekas + */ +final class HttpClient +{ + /** + * @param array $defaultOptions Default request's options + * @param int $maxHostConnections The maximum number of connections to a single host + * @param int $maxPendingPushes The maximum number of pushed responses to accept in the queue + * + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + */ + public static function create(array $defaultOptions = [], int $maxHostConnections = 6, int $maxPendingPushes = 50): HttpClientInterface + { + if ($amp = class_exists(ConnectionLimitingPool::class)) { + if (!\extension_loaded('curl')) { + return new AmpHttpClient($defaultOptions, null, $maxHostConnections, $maxPendingPushes); + } + + // Skip curl when HTTP/2 push is unsupported or buggy, see https://bugs.php.net/77535 + if (\PHP_VERSION_ID < 70217 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304) || !\defined('CURLMOPT_PUSHFUNCTION')) { + return new AmpHttpClient($defaultOptions, null, $maxHostConnections, $maxPendingPushes); + } + + static $curlVersion = null; + $curlVersion = $curlVersion ?? curl_version(); + + // HTTP/2 push crashes before curl 7.61 + if (0x073D00 > $curlVersion['version_number'] || !(\CURL_VERSION_HTTP2 & $curlVersion['features'])) { + return new AmpHttpClient($defaultOptions, null, $maxHostConnections, $maxPendingPushes); + } + } + + if (\extension_loaded('curl')) { + if ('\\' !== \DIRECTORY_SEPARATOR || isset($defaultOptions['cafile']) || isset($defaultOptions['capath']) || \ini_get('curl.cainfo') || \ini_get('openssl.cafile') || \ini_get('openssl.capath')) { + return new CurlHttpClient($defaultOptions, $maxHostConnections, $maxPendingPushes); + } + + @trigger_error('Configure the "curl.cainfo", "openssl.cafile" or "openssl.capath" php.ini setting to enable the CurlHttpClient', \E_USER_WARNING); + } + + if ($amp) { + return new AmpHttpClient($defaultOptions, null, $maxHostConnections, $maxPendingPushes); + } + + @trigger_error((\extension_loaded('curl') ? 'Upgrade' : 'Install').' the curl extension or run "composer require amphp/http-client" to perform async HTTP operations, including full HTTP/2 support', \E_USER_NOTICE); + + return new NativeHttpClient($defaultOptions, $maxHostConnections); + } + + /** + * Creates a client that adds options (e.g. authentication headers) only when the request URL matches the provided base URI. + */ + public static function createForBaseUri(string $baseUri, array $defaultOptions = [], int $maxHostConnections = 6, int $maxPendingPushes = 50): HttpClientInterface + { + $client = self::create([], $maxHostConnections, $maxPendingPushes); + + return ScopingHttpClient::forBaseUri($client, $baseUri, $defaultOptions); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/HttpClientTrait.php b/sites/all/libraries/vendor/symfony/http-client/HttpClientTrait.php new file mode 100644 index 0000000000..57ffc51352 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/HttpClientTrait.php @@ -0,0 +1,686 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Exception\TransportException; + +/** + * Provides the common logic from writing HttpClientInterface implementations. + * + * All private methods are static to prevent implementers from creating memory leaks via circular references. + * + * @author Nicolas Grekas + */ +trait HttpClientTrait +{ + private static $CHUNK_SIZE = 16372; + + /** + * {@inheritdoc} + */ + public function withOptions(array $options): self + { + $clone = clone $this; + $clone->defaultOptions = self::mergeDefaultOptions($options, $this->defaultOptions); + + return $clone; + } + + /** + * Validates and normalizes method, URL and options, and merges them with defaults. + * + * @throws InvalidArgumentException When a not-supported option is found + */ + private static function prepareRequest(?string $method, ?string $url, array $options, array $defaultOptions = [], bool $allowExtraOptions = false): array + { + if (null !== $method) { + if (\strlen($method) !== strspn($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')) { + throw new InvalidArgumentException(sprintf('Invalid HTTP method "%s", only uppercase letters are accepted.', $method)); + } + if (!$method) { + throw new InvalidArgumentException('The HTTP method cannot be empty.'); + } + } + + $options = self::mergeDefaultOptions($options, $defaultOptions, $allowExtraOptions); + + $buffer = $options['buffer'] ?? true; + + if ($buffer instanceof \Closure) { + $options['buffer'] = static function (array $headers) use ($buffer) { + if (!\is_bool($buffer = $buffer($headers))) { + if (!\is_array($bufferInfo = @stream_get_meta_data($buffer))) { + throw new \LogicException(sprintf('The closure passed as option "buffer" must return bool or stream resource, got "%s".', get_debug_type($buffer))); + } + + if (false === strpbrk($bufferInfo['mode'], 'acew+')) { + throw new \LogicException(sprintf('The stream returned by the closure passed as option "buffer" must be writeable, got mode "%s".', $bufferInfo['mode'])); + } + } + + return $buffer; + }; + } elseif (!\is_bool($buffer)) { + if (!\is_array($bufferInfo = @stream_get_meta_data($buffer))) { + throw new InvalidArgumentException(sprintf('Option "buffer" must be bool, stream resource or Closure, "%s" given.', get_debug_type($buffer))); + } + + if (false === strpbrk($bufferInfo['mode'], 'acew+')) { + throw new InvalidArgumentException(sprintf('The stream in option "buffer" must be writeable, mode "%s" given.', $bufferInfo['mode'])); + } + } + + if (isset($options['json'])) { + if (isset($options['body']) && '' !== $options['body']) { + throw new InvalidArgumentException('Define either the "json" or the "body" option, setting both is not supported.'); + } + $options['body'] = self::jsonEncode($options['json']); + unset($options['json']); + + if (!isset($options['normalized_headers']['content-type'])) { + $options['normalized_headers']['content-type'] = ['Content-Type: application/json']; + } + } + + if (!isset($options['normalized_headers']['accept'])) { + $options['normalized_headers']['accept'] = ['Accept: */*']; + } + + if (isset($options['body'])) { + $options['body'] = self::normalizeBody($options['body']); + + if (\is_string($options['body']) + && (string) \strlen($options['body']) !== substr($h = $options['normalized_headers']['content-length'][0] ?? '', 16) + && ('' !== $h || '' !== $options['body']) + ) { + if ('chunked' === substr($options['normalized_headers']['transfer-encoding'][0] ?? '', \strlen('Transfer-Encoding: '))) { + unset($options['normalized_headers']['transfer-encoding']); + $options['body'] = self::dechunk($options['body']); + } + + $options['normalized_headers']['content-length'] = [substr_replace($h ?: 'Content-Length: ', \strlen($options['body']), 16)]; + } + } + + if (isset($options['peer_fingerprint'])) { + $options['peer_fingerprint'] = self::normalizePeerFingerprint($options['peer_fingerprint']); + } + + // Validate on_progress + if (isset($options['on_progress']) && !\is_callable($onProgress = $options['on_progress'])) { + throw new InvalidArgumentException(sprintf('Option "on_progress" must be callable, "%s" given.', get_debug_type($onProgress))); + } + + if (\is_array($options['auth_basic'] ?? null)) { + $count = \count($options['auth_basic']); + if ($count <= 0 || $count > 2) { + throw new InvalidArgumentException(sprintf('Option "auth_basic" must contain 1 or 2 elements, "%s" given.', $count)); + } + + $options['auth_basic'] = implode(':', $options['auth_basic']); + } + + if (!\is_string($options['auth_basic'] ?? '')) { + throw new InvalidArgumentException(sprintf('Option "auth_basic" must be string or an array, "%s" given.', get_debug_type($options['auth_basic']))); + } + + if (isset($options['auth_bearer'])) { + if (!\is_string($options['auth_bearer'])) { + throw new InvalidArgumentException(sprintf('Option "auth_bearer" must be a string, "%s" given.', get_debug_type($options['auth_bearer']))); + } + if (preg_match('{[^\x21-\x7E]}', $options['auth_bearer'])) { + throw new InvalidArgumentException('Invalid character found in option "auth_bearer": '.json_encode($options['auth_bearer']).'.'); + } + } + + if (isset($options['auth_basic'], $options['auth_bearer'])) { + throw new InvalidArgumentException('Define either the "auth_basic" or the "auth_bearer" option, setting both is not supported.'); + } + + if (null !== $url) { + // Merge auth with headers + if (($options['auth_basic'] ?? false) && !($options['normalized_headers']['authorization'] ?? false)) { + $options['normalized_headers']['authorization'] = ['Authorization: Basic '.base64_encode($options['auth_basic'])]; + } + // Merge bearer with headers + if (($options['auth_bearer'] ?? false) && !($options['normalized_headers']['authorization'] ?? false)) { + $options['normalized_headers']['authorization'] = ['Authorization: Bearer '.$options['auth_bearer']]; + } + + unset($options['auth_basic'], $options['auth_bearer']); + + // Parse base URI + if (\is_string($options['base_uri'])) { + $options['base_uri'] = self::parseUrl($options['base_uri']); + } + + // Validate and resolve URL + $url = self::parseUrl($url, $options['query']); + $url = self::resolveUrl($url, $options['base_uri'], $defaultOptions['query'] ?? []); + } + + // Finalize normalization of options + $options['http_version'] = (string) ($options['http_version'] ?? '') ?: null; + if (0 > $options['timeout'] = (float) ($options['timeout'] ?? \ini_get('default_socket_timeout'))) { + $options['timeout'] = 172800.0; // 2 days + } + + $options['max_duration'] = isset($options['max_duration']) ? (float) $options['max_duration'] : 0; + $options['headers'] = array_merge(...array_values($options['normalized_headers'])); + + return [$url, $options]; + } + + /** + * @throws InvalidArgumentException When an invalid option is found + */ + private static function mergeDefaultOptions(array $options, array $defaultOptions, bool $allowExtraOptions = false): array + { + $options['normalized_headers'] = self::normalizeHeaders($options['headers'] ?? []); + + if ($defaultOptions['headers'] ?? false) { + $options['normalized_headers'] += self::normalizeHeaders($defaultOptions['headers']); + } + + $options['headers'] = array_merge(...array_values($options['normalized_headers']) ?: [[]]); + + if ($resolve = $options['resolve'] ?? false) { + $options['resolve'] = []; + foreach ($resolve as $k => $v) { + $options['resolve'][substr(self::parseUrl('http://'.$k)['authority'], 2)] = (string) $v; + } + } + + // Option "query" is never inherited from defaults + $options['query'] = $options['query'] ?? []; + + $options += $defaultOptions; + + if (isset(self::$emptyDefaults)) { + foreach (self::$emptyDefaults as $k => $v) { + if (!isset($options[$k])) { + $options[$k] = $v; + } + } + } + + if (isset($defaultOptions['extra'])) { + $options['extra'] += $defaultOptions['extra']; + } + + if ($resolve = $defaultOptions['resolve'] ?? false) { + foreach ($resolve as $k => $v) { + $options['resolve'] += [substr(self::parseUrl('http://'.$k)['authority'], 2) => (string) $v]; + } + } + + if ($allowExtraOptions || !$defaultOptions) { + return $options; + } + + // Look for unsupported options + foreach ($options as $name => $v) { + if (\array_key_exists($name, $defaultOptions) || 'normalized_headers' === $name) { + continue; + } + + if ('auth_ntlm' === $name) { + if (!\extension_loaded('curl')) { + $msg = 'try installing the "curl" extension to use "%s" instead.'; + } else { + $msg = 'try using "%s" instead.'; + } + + throw new InvalidArgumentException(sprintf('Option "auth_ntlm" is not supported by "%s", '.$msg, __CLASS__, CurlHttpClient::class)); + } + + $alternatives = []; + + foreach ($defaultOptions as $k => $v) { + if (levenshtein($name, $k) <= \strlen($name) / 3 || str_contains($k, $name)) { + $alternatives[] = $k; + } + } + + throw new InvalidArgumentException(sprintf('Unsupported option "%s" passed to "%s", did you mean "%s"?', $name, __CLASS__, implode('", "', $alternatives ?: array_keys($defaultOptions)))); + } + + return $options; + } + + /** + * @return string[][] + * + * @throws InvalidArgumentException When an invalid header is found + */ + private static function normalizeHeaders(array $headers): array + { + $normalizedHeaders = []; + + foreach ($headers as $name => $values) { + if (\is_object($values) && method_exists($values, '__toString')) { + $values = (string) $values; + } + + if (\is_int($name)) { + if (!\is_string($values)) { + throw new InvalidArgumentException(sprintf('Invalid value for header "%s": expected string, "%s" given.', $name, get_debug_type($values))); + } + [$name, $values] = explode(':', $values, 2); + $values = [ltrim($values)]; + } elseif (!is_iterable($values)) { + if (\is_object($values)) { + throw new InvalidArgumentException(sprintf('Invalid value for header "%s": expected string, "%s" given.', $name, get_debug_type($values))); + } + + $values = (array) $values; + } + + $lcName = strtolower($name); + $normalizedHeaders[$lcName] = []; + + foreach ($values as $value) { + $normalizedHeaders[$lcName][] = $value = $name.': '.$value; + + if (\strlen($value) !== strcspn($value, "\r\n\0")) { + throw new InvalidArgumentException(sprintf('Invalid header: CR/LF/NUL found in "%s".', $value)); + } + } + } + + return $normalizedHeaders; + } + + /** + * @param array|string|resource|\Traversable|\Closure $body + * + * @return string|resource|\Closure + * + * @throws InvalidArgumentException When an invalid body is passed + */ + private static function normalizeBody($body) + { + if (\is_array($body)) { + array_walk_recursive($body, $caster = static function (&$v) use (&$caster) { + if (\is_object($v)) { + if ($vars = get_object_vars($v)) { + array_walk_recursive($vars, $caster); + $v = $vars; + } elseif (method_exists($v, '__toString')) { + $v = (string) $v; + } + } + }); + + return http_build_query($body, '', '&'); + } + + if (\is_string($body)) { + return $body; + } + + $generatorToCallable = static function (\Generator $body): \Closure { + return static function () use ($body) { + while ($body->valid()) { + $chunk = $body->current(); + $body->next(); + + if ('' !== $chunk) { + return $chunk; + } + } + + return ''; + }; + }; + + if ($body instanceof \Generator) { + return $generatorToCallable($body); + } + + if ($body instanceof \Traversable) { + return $generatorToCallable((static function ($body) { yield from $body; })($body)); + } + + if ($body instanceof \Closure) { + $r = new \ReflectionFunction($body); + $body = $r->getClosure(); + + if ($r->isGenerator()) { + $body = $body(self::$CHUNK_SIZE); + + return $generatorToCallable($body); + } + + return $body; + } + + if (!\is_array(@stream_get_meta_data($body))) { + throw new InvalidArgumentException(sprintf('Option "body" must be string, stream resource, iterable or callable, "%s" given.', get_debug_type($body))); + } + + return $body; + } + + private static function dechunk(string $body): string + { + $h = fopen('php://temp', 'w+'); + stream_filter_append($h, 'dechunk', \STREAM_FILTER_WRITE); + fwrite($h, $body); + $body = stream_get_contents($h, -1, 0); + rewind($h); + ftruncate($h, 0); + + if (fwrite($h, '-') && '' !== stream_get_contents($h, -1, 0)) { + throw new TransportException('Request body has broken chunked encoding.'); + } + + return $body; + } + + /** + * @param string|string[] $fingerprint + * + * @throws InvalidArgumentException When an invalid fingerprint is passed + */ + private static function normalizePeerFingerprint($fingerprint): array + { + if (\is_string($fingerprint)) { + switch (\strlen($fingerprint = str_replace(':', '', $fingerprint))) { + case 32: $fingerprint = ['md5' => $fingerprint]; break; + case 40: $fingerprint = ['sha1' => $fingerprint]; break; + case 44: $fingerprint = ['pin-sha256' => [$fingerprint]]; break; + case 64: $fingerprint = ['sha256' => $fingerprint]; break; + default: throw new InvalidArgumentException(sprintf('Cannot auto-detect fingerprint algorithm for "%s".', $fingerprint)); + } + } elseif (\is_array($fingerprint)) { + foreach ($fingerprint as $algo => $hash) { + $fingerprint[$algo] = 'pin-sha256' === $algo ? (array) $hash : str_replace(':', '', $hash); + } + } else { + throw new InvalidArgumentException(sprintf('Option "peer_fingerprint" must be string or array, "%s" given.', get_debug_type($fingerprint))); + } + + return $fingerprint; + } + + /** + * @param mixed $value + * + * @throws InvalidArgumentException When the value cannot be json-encoded + */ + private static function jsonEncode($value, int $flags = null, int $maxDepth = 512): string + { + $flags = $flags ?? (\JSON_HEX_TAG | \JSON_HEX_APOS | \JSON_HEX_AMP | \JSON_HEX_QUOT | \JSON_PRESERVE_ZERO_FRACTION); + + try { + $value = json_encode($value, $flags | (\PHP_VERSION_ID >= 70300 ? \JSON_THROW_ON_ERROR : 0), $maxDepth); + } catch (\JsonException $e) { + throw new InvalidArgumentException('Invalid value for "json" option: '.$e->getMessage()); + } + + if (\PHP_VERSION_ID < 70300 && \JSON_ERROR_NONE !== json_last_error() && (false === $value || !($flags & \JSON_PARTIAL_OUTPUT_ON_ERROR))) { + throw new InvalidArgumentException('Invalid value for "json" option: '.json_last_error_msg()); + } + + return $value; + } + + /** + * Resolves a URL against a base URI. + * + * @see https://tools.ietf.org/html/rfc3986#section-5.2.2 + * + * @throws InvalidArgumentException When an invalid URL is passed + */ + private static function resolveUrl(array $url, ?array $base, array $queryDefaults = []): array + { + if (null !== $base && '' === ($base['scheme'] ?? '').($base['authority'] ?? '')) { + throw new InvalidArgumentException(sprintf('Invalid "base_uri" option: host or scheme is missing in "%s".', implode('', $base))); + } + + if (null === $url['scheme'] && (null === $base || null === $base['scheme'])) { + throw new InvalidArgumentException(sprintf('Invalid URL: scheme is missing in "%s". Did you forget to add "http(s)://"?', implode('', $base ?? $url))); + } + + if (null === $base && '' === $url['scheme'].$url['authority']) { + throw new InvalidArgumentException(sprintf('Invalid URL: no "base_uri" option was provided and host or scheme is missing in "%s".', implode('', $url))); + } + + if (null !== $url['scheme']) { + $url['path'] = self::removeDotSegments($url['path'] ?? ''); + } else { + if (null !== $url['authority']) { + $url['path'] = self::removeDotSegments($url['path'] ?? ''); + } else { + if (null === $url['path']) { + $url['path'] = $base['path']; + $url['query'] = $url['query'] ?? $base['query']; + } else { + if ('/' !== $url['path'][0]) { + if (null === $base['path']) { + $url['path'] = '/'.$url['path']; + } else { + $segments = explode('/', $base['path']); + array_splice($segments, -1, 1, [$url['path']]); + $url['path'] = implode('/', $segments); + } + } + + $url['path'] = self::removeDotSegments($url['path']); + } + + $url['authority'] = $base['authority']; + + if ($queryDefaults) { + $url['query'] = '?'.self::mergeQueryString(substr($url['query'] ?? '', 1), $queryDefaults, false); + } + } + + $url['scheme'] = $base['scheme']; + } + + if ('' === ($url['path'] ?? '')) { + $url['path'] = '/'; + } + + if ('?' === ($url['query'] ?? '')) { + $url['query'] = null; + } + + return $url; + } + + /** + * Parses a URL and fixes its encoding if needed. + * + * @throws InvalidArgumentException When an invalid URL is passed + */ + private static function parseUrl(string $url, array $query = [], array $allowedSchemes = ['http' => 80, 'https' => 443]): array + { + if (false === $parts = parse_url($url)) { + throw new InvalidArgumentException(sprintf('Malformed URL "%s".', $url)); + } + + if ($query) { + $parts['query'] = self::mergeQueryString($parts['query'] ?? null, $query, true); + } + + $port = $parts['port'] ?? 0; + + if (null !== $scheme = $parts['scheme'] ?? null) { + if (!isset($allowedSchemes[$scheme = strtolower($scheme)])) { + throw new InvalidArgumentException(sprintf('Unsupported scheme in "%s".', $url)); + } + + $port = $allowedSchemes[$scheme] === $port ? 0 : $port; + $scheme .= ':'; + } + + if (null !== $host = $parts['host'] ?? null) { + if (!\defined('INTL_IDNA_VARIANT_UTS46') && preg_match('/[\x80-\xFF]/', $host)) { + throw new InvalidArgumentException(sprintf('Unsupported IDN "%s", try enabling the "intl" PHP extension or running "composer require symfony/polyfill-intl-idn".', $host)); + } + + $host = \defined('INTL_IDNA_VARIANT_UTS46') ? idn_to_ascii($host, \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46) ?: strtolower($host) : strtolower($host); + $host .= $port ? ':'.$port : ''; + } + + foreach (['user', 'pass', 'path', 'query', 'fragment'] as $part) { + if (!isset($parts[$part])) { + continue; + } + + if (str_contains($parts[$part], '%')) { + // https://tools.ietf.org/html/rfc3986#section-2.3 + $parts[$part] = preg_replace_callback('/%(?:2[DE]|3[0-9]|[46][1-9A-F]|5F|[57][0-9A]|7E)++/i', function ($m) { return rawurldecode($m[0]); }, $parts[$part]); + } + + // https://tools.ietf.org/html/rfc3986#section-3.3 + $parts[$part] = preg_replace_callback("#[^-A-Za-z0-9._~!$&/'()*+,;=:@%]++#", function ($m) { return rawurlencode($m[0]); }, $parts[$part]); + } + + return [ + 'scheme' => $scheme, + 'authority' => null !== $host ? '//'.(isset($parts['user']) ? $parts['user'].(isset($parts['pass']) ? ':'.$parts['pass'] : '').'@' : '').$host : null, + 'path' => isset($parts['path'][0]) ? $parts['path'] : null, + 'query' => isset($parts['query']) ? '?'.$parts['query'] : null, + 'fragment' => isset($parts['fragment']) ? '#'.$parts['fragment'] : null, + ]; + } + + /** + * Removes dot-segments from a path. + * + * @see https://tools.ietf.org/html/rfc3986#section-5.2.4 + */ + private static function removeDotSegments(string $path) + { + $result = ''; + + while (!\in_array($path, ['', '.', '..'], true)) { + if ('.' === $path[0] && (str_starts_with($path, $p = '../') || str_starts_with($path, $p = './'))) { + $path = substr($path, \strlen($p)); + } elseif ('/.' === $path || str_starts_with($path, '/./')) { + $path = substr_replace($path, '/', 0, 3); + } elseif ('/..' === $path || str_starts_with($path, '/../')) { + $i = strrpos($result, '/'); + $result = $i ? substr($result, 0, $i) : ''; + $path = substr_replace($path, '/', 0, 4); + } else { + $i = strpos($path, '/', 1) ?: \strlen($path); + $result .= substr($path, 0, $i); + $path = substr($path, $i); + } + } + + return $result; + } + + /** + * Merges and encodes a query array with a query string. + * + * @throws InvalidArgumentException When an invalid query-string value is passed + */ + private static function mergeQueryString(?string $queryString, array $queryArray, bool $replace): ?string + { + if (!$queryArray) { + return $queryString; + } + + $query = []; + + if (null !== $queryString) { + foreach (explode('&', $queryString) as $v) { + if ('' !== $v) { + $k = urldecode(explode('=', $v, 2)[0]); + $query[$k] = (isset($query[$k]) ? $query[$k].'&' : '').$v; + } + } + } + + if ($replace) { + foreach ($queryArray as $k => $v) { + if (null === $v) { + unset($query[$k]); + } + } + } + + $queryString = http_build_query($queryArray, '', '&', \PHP_QUERY_RFC3986); + $queryArray = []; + + if ($queryString) { + foreach (explode('&', $queryString) as $v) { + $queryArray[rawurldecode(explode('=', $v, 2)[0])] = $v; + } + } + + return implode('&', $replace ? array_replace($query, $queryArray) : ($query + $queryArray)); + } + + /** + * Loads proxy configuration from the same environment variables as curl when no proxy is explicitly set. + */ + private static function getProxy(?string $proxy, array $url, ?string $noProxy): ?array + { + if (null === $proxy) { + // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities + $proxy = $_SERVER['http_proxy'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null; + + if ('https:' === $url['scheme']) { + $proxy = $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? $proxy; + } + } + + if (null === $proxy) { + return null; + } + + $proxy = (parse_url($proxy) ?: []) + ['scheme' => 'http']; + + if (!isset($proxy['host'])) { + throw new TransportException('Invalid HTTP proxy: host is missing.'); + } + + if ('http' === $proxy['scheme']) { + $proxyUrl = 'tcp://'.$proxy['host'].':'.($proxy['port'] ?? '80'); + } elseif ('https' === $proxy['scheme']) { + $proxyUrl = 'ssl://'.$proxy['host'].':'.($proxy['port'] ?? '443'); + } else { + throw new TransportException(sprintf('Unsupported proxy scheme "%s": "http" or "https" expected.', $proxy['scheme'])); + } + + $noProxy = $noProxy ?? $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? ''; + $noProxy = $noProxy ? preg_split('/[\s,]+/', $noProxy) : []; + + return [ + 'url' => $proxyUrl, + 'auth' => isset($proxy['user']) ? 'Basic '.base64_encode(rawurldecode($proxy['user']).':'.rawurldecode($proxy['pass'] ?? '')) : null, + 'no_proxy' => $noProxy, + ]; + } + + private static function shouldBuffer(array $headers): bool + { + if (null === $contentType = $headers['content-type'][0] ?? null) { + return false; + } + + if (false !== $i = strpos($contentType, ';')) { + $contentType = substr($contentType, 0, $i); + } + + return $contentType && preg_match('#^(?:text/|application/(?:.+\+)?(?:json|xml)$)#i', $contentType); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/HttpOptions.php b/sites/all/libraries/vendor/symfony/http-client/HttpOptions.php new file mode 100644 index 0000000000..da55f9965f --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/HttpOptions.php @@ -0,0 +1,331 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * A helper providing autocompletion for available options. + * + * @see HttpClientInterface for a description of each options. + * + * @author Nicolas Grekas + */ +class HttpOptions +{ + private $options = []; + + public function toArray(): array + { + return $this->options; + } + + /** + * @return $this + */ + public function setAuthBasic(string $user, string $password = '') + { + $this->options['auth_basic'] = $user; + + if ('' !== $password) { + $this->options['auth_basic'] .= ':'.$password; + } + + return $this; + } + + /** + * @return $this + */ + public function setAuthBearer(string $token) + { + $this->options['auth_bearer'] = $token; + + return $this; + } + + /** + * @return $this + */ + public function setQuery(array $query) + { + $this->options['query'] = $query; + + return $this; + } + + /** + * @return $this + */ + public function setHeaders(iterable $headers) + { + $this->options['headers'] = $headers; + + return $this; + } + + /** + * @param array|string|resource|\Traversable|\Closure $body + * + * @return $this + */ + public function setBody($body) + { + $this->options['body'] = $body; + + return $this; + } + + /** + * @param mixed $json + * + * @return $this + */ + public function setJson($json) + { + $this->options['json'] = $json; + + return $this; + } + + /** + * @return $this + */ + public function setUserData($data) + { + $this->options['user_data'] = $data; + + return $this; + } + + /** + * @return $this + */ + public function setMaxRedirects(int $max) + { + $this->options['max_redirects'] = $max; + + return $this; + } + + /** + * @return $this + */ + public function setHttpVersion(string $version) + { + $this->options['http_version'] = $version; + + return $this; + } + + /** + * @return $this + */ + public function setBaseUri(string $uri) + { + $this->options['base_uri'] = $uri; + + return $this; + } + + /** + * @return $this + */ + public function buffer(bool $buffer) + { + $this->options['buffer'] = $buffer; + + return $this; + } + + /** + * @return $this + */ + public function setOnProgress(callable $callback) + { + $this->options['on_progress'] = $callback; + + return $this; + } + + /** + * @return $this + */ + public function resolve(array $hostIps) + { + $this->options['resolve'] = $hostIps; + + return $this; + } + + /** + * @return $this + */ + public function setProxy(string $proxy) + { + $this->options['proxy'] = $proxy; + + return $this; + } + + /** + * @return $this + */ + public function setNoProxy(string $noProxy) + { + $this->options['no_proxy'] = $noProxy; + + return $this; + } + + /** + * @return $this + */ + public function setTimeout(float $timeout) + { + $this->options['timeout'] = $timeout; + + return $this; + } + + /** + * @return $this + */ + public function setMaxDuration(float $maxDuration) + { + $this->options['max_duration'] = $maxDuration; + + return $this; + } + + /** + * @return $this + */ + public function bindTo(string $bindto) + { + $this->options['bindto'] = $bindto; + + return $this; + } + + /** + * @return $this + */ + public function verifyPeer(bool $verify) + { + $this->options['verify_peer'] = $verify; + + return $this; + } + + /** + * @return $this + */ + public function verifyHost(bool $verify) + { + $this->options['verify_host'] = $verify; + + return $this; + } + + /** + * @return $this + */ + public function setCaFile(string $cafile) + { + $this->options['cafile'] = $cafile; + + return $this; + } + + /** + * @return $this + */ + public function setCaPath(string $capath) + { + $this->options['capath'] = $capath; + + return $this; + } + + /** + * @return $this + */ + public function setLocalCert(string $cert) + { + $this->options['local_cert'] = $cert; + + return $this; + } + + /** + * @return $this + */ + public function setLocalPk(string $pk) + { + $this->options['local_pk'] = $pk; + + return $this; + } + + /** + * @return $this + */ + public function setPassphrase(string $passphrase) + { + $this->options['passphrase'] = $passphrase; + + return $this; + } + + /** + * @return $this + */ + public function setCiphers(string $ciphers) + { + $this->options['ciphers'] = $ciphers; + + return $this; + } + + /** + * @param string|array $fingerprint + * + * @return $this + */ + public function setPeerFingerprint($fingerprint) + { + $this->options['peer_fingerprint'] = $fingerprint; + + return $this; + } + + /** + * @return $this + */ + public function capturePeerCertChain(bool $capture) + { + $this->options['capture_peer_cert_chain'] = $capture; + + return $this; + } + + /** + * @return $this + */ + public function setExtra(string $name, $value) + { + $this->options['extra'][$name] = $value; + + return $this; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/HttplugClient.php b/sites/all/libraries/vendor/symfony/http-client/HttplugClient.php new file mode 100644 index 0000000000..ec3b01d999 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/HttplugClient.php @@ -0,0 +1,271 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use GuzzleHttp\Promise\Promise as GuzzlePromise; +use GuzzleHttp\Promise\RejectedPromise; +use GuzzleHttp\Promise\Utils; +use Http\Client\Exception\NetworkException; +use Http\Client\Exception\RequestException; +use Http\Client\HttpAsyncClient; +use Http\Client\HttpClient as HttplugInterface; +use Http\Discovery\Exception\NotFoundException; +use Http\Discovery\Psr17FactoryDiscovery; +use Http\Message\RequestFactory; +use Http\Message\StreamFactory; +use Http\Message\UriFactory; +use Http\Promise\Promise; +use Nyholm\Psr7\Factory\Psr17Factory; +use Nyholm\Psr7\Request; +use Nyholm\Psr7\Uri; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UriFactoryInterface; +use Psr\Http\Message\UriInterface; +use Symfony\Component\HttpClient\Internal\HttplugWaitLoop; +use Symfony\Component\HttpClient\Response\HttplugPromise; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\Service\ResetInterface; + +if (!interface_exists(HttplugInterface::class)) { + throw new \LogicException('You cannot use "Symfony\Component\HttpClient\HttplugClient" as the "php-http/httplug" package is not installed. Try running "composer require php-http/httplug".'); +} + +if (!interface_exists(RequestFactory::class)) { + throw new \LogicException('You cannot use "Symfony\Component\HttpClient\HttplugClient" as the "php-http/message-factory" package is not installed. Try running "composer require nyholm/psr7".'); +} + +/** + * An adapter to turn a Symfony HttpClientInterface into an Httplug client. + * + * Run "composer require nyholm/psr7" to install an efficient implementation of response + * and stream factories with flex-provided autowiring aliases. + * + * @author Nicolas Grekas + */ +final class HttplugClient implements HttplugInterface, HttpAsyncClient, RequestFactory, StreamFactory, UriFactory, ResetInterface +{ + private $client; + private $responseFactory; + private $streamFactory; + + /** + * @var \SplObjectStorage|null + */ + private $promisePool; + + private $waitLoop; + + public function __construct(HttpClientInterface $client = null, ResponseFactoryInterface $responseFactory = null, StreamFactoryInterface $streamFactory = null) + { + $this->client = $client ?? HttpClient::create(); + $this->responseFactory = $responseFactory; + $this->streamFactory = $streamFactory ?? ($responseFactory instanceof StreamFactoryInterface ? $responseFactory : null); + $this->promisePool = class_exists(Utils::class) ? new \SplObjectStorage() : null; + + if (null === $this->responseFactory || null === $this->streamFactory) { + if (!class_exists(Psr17Factory::class) && !class_exists(Psr17FactoryDiscovery::class)) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".'); + } + + try { + $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null; + $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory(); + $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory(); + } catch (NotFoundException $e) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been found. Try running "composer require nyholm/psr7".', 0, $e); + } + } + + $this->waitLoop = new HttplugWaitLoop($this->client, $this->promisePool, $this->responseFactory, $this->streamFactory); + } + + /** + * {@inheritdoc} + */ + public function sendRequest(RequestInterface $request): Psr7ResponseInterface + { + try { + return $this->waitLoop->createPsr7Response($this->sendPsr7Request($request)); + } catch (TransportExceptionInterface $e) { + throw new NetworkException($e->getMessage(), $request, $e); + } + } + + /** + * {@inheritdoc} + * + * @return HttplugPromise + */ + public function sendAsyncRequest(RequestInterface $request): Promise + { + if (!$promisePool = $this->promisePool) { + throw new \LogicException(sprintf('You cannot use "%s()" as the "guzzlehttp/promises" package is not installed. Try running "composer require guzzlehttp/promises".', __METHOD__)); + } + + try { + $response = $this->sendPsr7Request($request, true); + } catch (NetworkException $e) { + return new HttplugPromise(new RejectedPromise($e)); + } + + $waitLoop = $this->waitLoop; + + $promise = new GuzzlePromise(static function () use ($response, $waitLoop) { + $waitLoop->wait($response); + }, static function () use ($response, $promisePool) { + $response->cancel(); + unset($promisePool[$response]); + }); + + $promisePool[$response] = [$request, $promise]; + + return new HttplugPromise($promise); + } + + /** + * Resolves pending promises that complete before the timeouts are reached. + * + * When $maxDuration is null and $idleTimeout is reached, promises are rejected. + * + * @return int The number of remaining pending promises + */ + public function wait(float $maxDuration = null, float $idleTimeout = null): int + { + return $this->waitLoop->wait(null, $maxDuration, $idleTimeout); + } + + /** + * {@inheritdoc} + */ + public function createRequest($method, $uri, array $headers = [], $body = null, $protocolVersion = '1.1'): RequestInterface + { + if ($this->responseFactory instanceof RequestFactoryInterface) { + $request = $this->responseFactory->createRequest($method, $uri); + } elseif (class_exists(Request::class)) { + $request = new Request($method, $uri); + } elseif (class_exists(Psr17FactoryDiscovery::class)) { + $request = Psr17FactoryDiscovery::findRequestFactory()->createRequest($method, $uri); + } else { + throw new \LogicException(sprintf('You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".', __METHOD__)); + } + + $request = $request + ->withProtocolVersion($protocolVersion) + ->withBody($this->createStream($body)) + ; + + foreach ($headers as $name => $value) { + $request = $request->withAddedHeader($name, $value); + } + + return $request; + } + + /** + * {@inheritdoc} + */ + public function createStream($body = null): StreamInterface + { + if ($body instanceof StreamInterface) { + return $body; + } + + if (\is_string($body ?? '')) { + $stream = $this->streamFactory->createStream($body ?? ''); + } elseif (\is_resource($body)) { + $stream = $this->streamFactory->createStreamFromResource($body); + } else { + throw new \InvalidArgumentException(sprintf('"%s()" expects string, resource or StreamInterface, "%s" given.', __METHOD__, get_debug_type($body))); + } + + if ($stream->isSeekable()) { + $stream->seek(0); + } + + return $stream; + } + + /** + * {@inheritdoc} + */ + public function createUri($uri): UriInterface + { + if ($uri instanceof UriInterface) { + return $uri; + } + + if ($this->responseFactory instanceof UriFactoryInterface) { + return $this->responseFactory->createUri($uri); + } + + if (class_exists(Uri::class)) { + return new Uri($uri); + } + + if (class_exists(Psr17FactoryDiscovery::class)) { + return Psr17FactoryDiscovery::findUrlFactory()->createUri($uri); + } + + throw new \LogicException(sprintf('You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".', __METHOD__)); + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + $this->wait(); + } + + public function reset() + { + if ($this->client instanceof ResetInterface) { + $this->client->reset(); + } + } + + private function sendPsr7Request(RequestInterface $request, bool $buffer = null): ResponseInterface + { + try { + $body = $request->getBody(); + + if ($body->isSeekable()) { + $body->seek(0); + } + + return $this->client->request($request->getMethod(), (string) $request->getUri(), [ + 'headers' => $request->getHeaders(), + 'body' => $body->getContents(), + 'http_version' => '1.0' === $request->getProtocolVersion() ? '1.0' : null, + 'buffer' => $buffer, + ]); + } catch (\InvalidArgumentException $e) { + throw new RequestException($e->getMessage(), $request, $e); + } catch (TransportExceptionInterface $e) { + throw new NetworkException($e->getMessage(), $request, $e); + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/AmpBody.php b/sites/all/libraries/vendor/symfony/http-client/Internal/AmpBody.php new file mode 100644 index 0000000000..b99742b13b --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/AmpBody.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +use Amp\ByteStream\InputStream; +use Amp\ByteStream\ResourceInputStream; +use Amp\Http\Client\RequestBody; +use Amp\Promise; +use Amp\Success; +use Symfony\Component\HttpClient\Exception\TransportException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class AmpBody implements RequestBody, InputStream +{ + private $body; + private $info; + private $onProgress; + private $offset = 0; + private $length = -1; + private $uploaded; + + public function __construct($body, &$info, \Closure $onProgress) + { + $this->body = $body; + $this->info = &$info; + $this->onProgress = $onProgress; + + if (\is_resource($body)) { + $this->offset = ftell($body); + $this->length = fstat($body)['size']; + $this->body = new ResourceInputStream($body); + } elseif (\is_string($body)) { + $this->length = \strlen($body); + } + } + + public function createBodyStream(): InputStream + { + if (null !== $this->uploaded) { + $this->uploaded = null; + + if (\is_string($this->body)) { + $this->offset = 0; + } elseif ($this->body instanceof ResourceInputStream) { + fseek($this->body->getResource(), $this->offset); + } + } + + return $this; + } + + public function getHeaders(): Promise + { + return new Success([]); + } + + public function getBodyLength(): Promise + { + return new Success($this->length - $this->offset); + } + + public function read(): Promise + { + $this->info['size_upload'] += $this->uploaded; + $this->uploaded = 0; + ($this->onProgress)(); + + $chunk = $this->doRead(); + $chunk->onResolve(function ($e, $data) { + if (null !== $data) { + $this->uploaded = \strlen($data); + } else { + $this->info['upload_content_length'] = $this->info['size_upload']; + } + }); + + return $chunk; + } + + public static function rewind(RequestBody $body): RequestBody + { + if (!$body instanceof self) { + return $body; + } + + $body->uploaded = null; + + if ($body->body instanceof ResourceInputStream) { + fseek($body->body->getResource(), $body->offset); + + return new $body($body->body, $body->info, $body->onProgress); + } + + if (\is_string($body->body)) { + $body->offset = 0; + } + + return $body; + } + + private function doRead(): Promise + { + if ($this->body instanceof ResourceInputStream) { + return $this->body->read(); + } + + if (null === $this->offset || !$this->length) { + return new Success(); + } + + if (\is_string($this->body)) { + $this->offset = null; + + return new Success($this->body); + } + + if ('' === $data = ($this->body)(16372)) { + $this->offset = null; + + return new Success(); + } + + if (!\is_string($data)) { + throw new TransportException(sprintf('Return value of the "body" option callback must be string, "%s" returned.', get_debug_type($data))); + } + + return new Success($data); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/AmpClientState.php b/sites/all/libraries/vendor/symfony/http-client/Internal/AmpClientState.php new file mode 100644 index 0000000000..3061f0802d --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/AmpClientState.php @@ -0,0 +1,217 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +use Amp\CancellationToken; +use Amp\Deferred; +use Amp\Http\Client\Connection\ConnectionLimitingPool; +use Amp\Http\Client\Connection\DefaultConnectionFactory; +use Amp\Http\Client\InterceptedHttpClient; +use Amp\Http\Client\Interceptor\RetryRequests; +use Amp\Http\Client\PooledHttpClient; +use Amp\Http\Client\Request; +use Amp\Http\Client\Response; +use Amp\Http\Tunnel\Http1TunnelConnector; +use Amp\Http\Tunnel\Https1TunnelConnector; +use Amp\Promise; +use Amp\Socket\Certificate; +use Amp\Socket\ClientTlsContext; +use Amp\Socket\ConnectContext; +use Amp\Socket\Connector; +use Amp\Socket\DnsConnector; +use Amp\Socket\SocketAddress; +use Amp\Success; +use Psr\Log\LoggerInterface; + +/** + * Internal representation of the Amp client's state. + * + * @author Nicolas Grekas + * + * @internal + */ +final class AmpClientState extends ClientState +{ + public $dnsCache = []; + public $responseCount = 0; + public $pushedResponses = []; + + private $clients = []; + private $clientConfigurator; + private $maxHostConnections; + private $maxPendingPushes; + private $logger; + + public function __construct(?callable $clientConfigurator, int $maxHostConnections, int $maxPendingPushes, ?LoggerInterface &$logger) + { + $this->clientConfigurator = $clientConfigurator ?? static function (PooledHttpClient $client) { + return new InterceptedHttpClient($client, new RetryRequests(2)); + }; + $this->maxHostConnections = $maxHostConnections; + $this->maxPendingPushes = $maxPendingPushes; + $this->logger = &$logger; + } + + /** + * @return Promise + */ + public function request(array $options, Request $request, CancellationToken $cancellation, array &$info, \Closure $onProgress, &$handle): Promise + { + if ($options['proxy']) { + if ($request->hasHeader('proxy-authorization')) { + $options['proxy']['auth'] = $request->getHeader('proxy-authorization'); + } + + // Matching "no_proxy" should follow the behavior of curl + $host = $request->getUri()->getHost(); + foreach ($options['proxy']['no_proxy'] as $rule) { + $dotRule = '.'.ltrim($rule, '.'); + + if ('*' === $rule || $host === $rule || substr($host, -\strlen($dotRule)) === $dotRule) { + $options['proxy'] = null; + break; + } + } + } + + $request = clone $request; + + if ($request->hasHeader('proxy-authorization')) { + $request->removeHeader('proxy-authorization'); + } + + if ($options['capture_peer_cert_chain']) { + $info['peer_certificate_chain'] = []; + } + + $request->addEventListener(new AmpListener($info, $options['peer_fingerprint']['pin-sha256'] ?? [], $onProgress, $handle)); + $request->setPushHandler(function ($request, $response) use ($options): Promise { + return $this->handlePush($request, $response, $options); + }); + + ($request->hasHeader('content-length') ? new Success((int) $request->getHeader('content-length')) : $request->getBody()->getBodyLength()) + ->onResolve(static function ($e, $bodySize) use (&$info) { + if (null !== $bodySize && 0 <= $bodySize) { + $info['upload_content_length'] = ((1 + $info['upload_content_length']) ?? 1) - 1 + $bodySize; + } + }); + + [$client, $connector] = $this->getClient($options); + $response = $client->request($request, $cancellation); + $response->onResolve(static function ($e) use ($connector, &$handle) { + if (null === $e) { + $handle = $connector->handle; + } + }); + + return $response; + } + + private function getClient(array $options): array + { + $options = [ + 'bindto' => $options['bindto'] ?: '0', + 'verify_peer' => $options['verify_peer'], + 'capath' => $options['capath'], + 'cafile' => $options['cafile'], + 'local_cert' => $options['local_cert'], + 'local_pk' => $options['local_pk'], + 'ciphers' => $options['ciphers'], + 'capture_peer_cert_chain' => $options['capture_peer_cert_chain'] || $options['peer_fingerprint'], + 'proxy' => $options['proxy'], + ]; + + $key = md5(serialize($options)); + + if (isset($this->clients[$key])) { + return $this->clients[$key]; + } + + $context = new ClientTlsContext(''); + $options['verify_peer'] || $context = $context->withoutPeerVerification(); + $options['cafile'] && $context = $context->withCaFile($options['cafile']); + $options['capath'] && $context = $context->withCaPath($options['capath']); + $options['local_cert'] && $context = $context->withCertificate(new Certificate($options['local_cert'], $options['local_pk'])); + $options['ciphers'] && $context = $context->withCiphers($options['ciphers']); + $options['capture_peer_cert_chain'] && $context = $context->withPeerCapturing(); + + $connector = $handleConnector = new class() implements Connector { + public $connector; + public $uri; + public $handle; + + public function connect(string $uri, ConnectContext $context = null, CancellationToken $token = null): Promise + { + $result = $this->connector->connect($this->uri ?? $uri, $context, $token); + $result->onResolve(function ($e, $socket) { + $this->handle = null !== $socket ? $socket->getResource() : false; + }); + + return $result; + } + }; + $connector->connector = new DnsConnector(new AmpResolver($this->dnsCache)); + + $context = (new ConnectContext()) + ->withTcpNoDelay() + ->withTlsContext($context); + + if ($options['bindto']) { + if (file_exists($options['bindto'])) { + $connector->uri = 'unix://'.$options['bindto']; + } else { + $context = $context->withBindTo($options['bindto']); + } + } + + if ($options['proxy']) { + $proxyUrl = parse_url($options['proxy']['url']); + $proxySocket = new SocketAddress($proxyUrl['host'], $proxyUrl['port']); + $proxyHeaders = $options['proxy']['auth'] ? ['Proxy-Authorization' => $options['proxy']['auth']] : []; + + if ('ssl' === $proxyUrl['scheme']) { + $connector = new Https1TunnelConnector($proxySocket, $context->getTlsContext(), $proxyHeaders, $connector); + } else { + $connector = new Http1TunnelConnector($proxySocket, $proxyHeaders, $connector); + } + } + + $maxHostConnections = 0 < $this->maxHostConnections ? $this->maxHostConnections : \PHP_INT_MAX; + $pool = new DefaultConnectionFactory($connector, $context); + $pool = ConnectionLimitingPool::byAuthority($maxHostConnections, $pool); + + return $this->clients[$key] = [($this->clientConfigurator)(new PooledHttpClient($pool)), $handleConnector]; + } + + private function handlePush(Request $request, Promise $response, array $options): Promise + { + $deferred = new Deferred(); + $authority = $request->getUri()->getAuthority(); + + if ($this->maxPendingPushes <= \count($this->pushedResponses[$authority] ?? [])) { + $fifoUrl = key($this->pushedResponses[$authority]); + unset($this->pushedResponses[$authority][$fifoUrl]); + $this->logger && $this->logger->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); + } + + $url = (string) $request->getUri(); + $this->logger && $this->logger->debug(sprintf('Queueing pushed response: "%s"', $url)); + $this->pushedResponses[$authority][] = [$url, $deferred, $request, $response, [ + 'proxy' => $options['proxy'], + 'bindto' => $options['bindto'], + 'local_cert' => $options['local_cert'], + 'local_pk' => $options['local_pk'], + ]]; + + return $deferred->promise(); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/AmpListener.php b/sites/all/libraries/vendor/symfony/http-client/Internal/AmpListener.php new file mode 100644 index 0000000000..cb3235bca3 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/AmpListener.php @@ -0,0 +1,183 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +use Amp\Http\Client\Connection\Stream; +use Amp\Http\Client\EventListener; +use Amp\Http\Client\Request; +use Amp\Promise; +use Amp\Success; +use Symfony\Component\HttpClient\Exception\TransportException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class AmpListener implements EventListener +{ + private $info; + private $pinSha256; + private $onProgress; + private $handle; + + public function __construct(array &$info, array $pinSha256, \Closure $onProgress, &$handle) + { + $info += [ + 'connect_time' => 0.0, + 'pretransfer_time' => 0.0, + 'starttransfer_time' => 0.0, + 'total_time' => 0.0, + 'namelookup_time' => 0.0, + 'primary_ip' => '', + 'primary_port' => 0, + ]; + + $this->info = &$info; + $this->pinSha256 = $pinSha256; + $this->onProgress = $onProgress; + $this->handle = &$handle; + } + + public function startRequest(Request $request): Promise + { + $this->info['start_time'] = $this->info['start_time'] ?? microtime(true); + ($this->onProgress)(); + + return new Success(); + } + + public function startDnsResolution(Request $request): Promise + { + ($this->onProgress)(); + + return new Success(); + } + + public function startConnectionCreation(Request $request): Promise + { + ($this->onProgress)(); + + return new Success(); + } + + public function startTlsNegotiation(Request $request): Promise + { + ($this->onProgress)(); + + return new Success(); + } + + public function startSendingRequest(Request $request, Stream $stream): Promise + { + $host = $stream->getRemoteAddress()->getHost(); + + if (false !== strpos($host, ':')) { + $host = '['.$host.']'; + } + + $this->info['primary_ip'] = $host; + $this->info['primary_port'] = $stream->getRemoteAddress()->getPort(); + $this->info['pretransfer_time'] = microtime(true) - $this->info['start_time']; + $this->info['debug'] .= sprintf("* Connected to %s (%s) port %d\n", $request->getUri()->getHost(), $host, $this->info['primary_port']); + + if ((isset($this->info['peer_certificate_chain']) || $this->pinSha256) && null !== $tlsInfo = $stream->getTlsInfo()) { + foreach ($tlsInfo->getPeerCertificates() as $cert) { + $this->info['peer_certificate_chain'][] = openssl_x509_read($cert->toPem()); + } + + if ($this->pinSha256) { + $pin = openssl_pkey_get_public($this->info['peer_certificate_chain'][0]); + $pin = openssl_pkey_get_details($pin)['key']; + $pin = \array_slice(explode("\n", $pin), 1, -2); + $pin = base64_decode(implode('', $pin)); + $pin = base64_encode(hash('sha256', $pin, true)); + + if (!\in_array($pin, $this->pinSha256, true)) { + throw new TransportException(sprintf('SSL public key does not match pinned public key for "%s".', $this->info['url'])); + } + } + } + ($this->onProgress)(); + + $uri = $request->getUri(); + $requestUri = $uri->getPath() ?: '/'; + + if ('' !== $query = $uri->getQuery()) { + $requestUri .= '?'.$query; + } + + if ('CONNECT' === $method = $request->getMethod()) { + $requestUri = $uri->getHost().': '.($uri->getPort() ?? ('https' === $uri->getScheme() ? 443 : 80)); + } + + $this->info['debug'] .= sprintf("> %s %s HTTP/%s \r\n", $method, $requestUri, $request->getProtocolVersions()[0]); + + foreach ($request->getRawHeaders() as [$name, $value]) { + $this->info['debug'] .= $name.': '.$value."\r\n"; + } + $this->info['debug'] .= "\r\n"; + + return new Success(); + } + + public function completeSendingRequest(Request $request, Stream $stream): Promise + { + ($this->onProgress)(); + + return new Success(); + } + + public function startReceivingResponse(Request $request, Stream $stream): Promise + { + $this->info['starttransfer_time'] = microtime(true) - $this->info['start_time']; + ($this->onProgress)(); + + return new Success(); + } + + public function completeReceivingResponse(Request $request, Stream $stream): Promise + { + $this->handle = null; + ($this->onProgress)(); + + return new Success(); + } + + public function completeDnsResolution(Request $request): Promise + { + $this->info['namelookup_time'] = microtime(true) - $this->info['start_time']; + ($this->onProgress)(); + + return new Success(); + } + + public function completeConnectionCreation(Request $request): Promise + { + $this->info['connect_time'] = microtime(true) - $this->info['start_time']; + ($this->onProgress)(); + + return new Success(); + } + + public function completeTlsNegotiation(Request $request): Promise + { + ($this->onProgress)(); + + return new Success(); + } + + public function abort(Request $request, \Throwable $cause): Promise + { + return new Success(); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/AmpResolver.php b/sites/all/libraries/vendor/symfony/http-client/Internal/AmpResolver.php new file mode 100644 index 0000000000..d31476a583 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/AmpResolver.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +use Amp\Dns; +use Amp\Dns\Record; +use Amp\Promise; +use Amp\Success; + +/** + * Handles local overrides for the DNS resolver. + * + * @author Nicolas Grekas + * + * @internal + */ +class AmpResolver implements Dns\Resolver +{ + private $dnsMap; + + public function __construct(array &$dnsMap) + { + $this->dnsMap = &$dnsMap; + } + + public function resolve(string $name, int $typeRestriction = null): Promise + { + if (!isset($this->dnsMap[$name]) || !\in_array($typeRestriction, [Record::A, null], true)) { + return Dns\resolver()->resolve($name, $typeRestriction); + } + + return new Success([new Record($this->dnsMap[$name], Record::A, null)]); + } + + public function query(string $name, int $type): Promise + { + if (!isset($this->dnsMap[$name]) || Record::A !== $type) { + return Dns\resolver()->query($name, $type); + } + + return new Success([new Record($this->dnsMap[$name], Record::A, null)]); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/Canary.php b/sites/all/libraries/vendor/symfony/http-client/Internal/Canary.php new file mode 100644 index 0000000000..3d14b5fd1a --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/Canary.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class Canary +{ + private $canceller; + + public function __construct(\Closure $canceller) + { + $this->canceller = $canceller; + } + + public function cancel() + { + if (($canceller = $this->canceller) instanceof \Closure) { + $this->canceller = null; + $canceller(); + } + } + + public function __destruct() + { + $this->cancel(); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/ClientState.php b/sites/all/libraries/vendor/symfony/http-client/Internal/ClientState.php new file mode 100644 index 0000000000..52fe3c8c05 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/ClientState.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +/** + * Internal representation of the client state. + * + * @author Alexander M. Turek + * + * @internal + */ +class ClientState +{ + public $handlesActivity = []; + public $openHandles = []; + public $lastTimeout; +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/CurlClientState.php b/sites/all/libraries/vendor/symfony/http-client/Internal/CurlClientState.php new file mode 100644 index 0000000000..7d51c15cac --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/CurlClientState.php @@ -0,0 +1,148 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Response\CurlResponse; + +/** + * Internal representation of the cURL client's state. + * + * @author Alexander M. Turek + * + * @internal + */ +final class CurlClientState extends ClientState +{ + /** @var \CurlMultiHandle|resource|null */ + public $handle; + /** @var \CurlShareHandle|resource|null */ + public $share; + /** @var PushedResponse[] */ + public $pushedResponses = []; + /** @var DnsCache */ + public $dnsCache; + /** @var float[] */ + public $pauseExpiries = []; + public $execCounter = \PHP_INT_MIN; + /** @var LoggerInterface|null */ + public $logger; + + public static $curlVersion; + + public function __construct(int $maxHostConnections, int $maxPendingPushes) + { + self::$curlVersion = self::$curlVersion ?? curl_version(); + + $this->handle = curl_multi_init(); + $this->dnsCache = new DnsCache(); + $this->reset(); + + // Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order + if (\defined('CURLPIPE_MULTIPLEX')) { + curl_multi_setopt($this->handle, \CURLMOPT_PIPELINING, \CURLPIPE_MULTIPLEX); + } + if (\defined('CURLMOPT_MAX_HOST_CONNECTIONS')) { + $maxHostConnections = curl_multi_setopt($this->handle, \CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : \PHP_INT_MAX) ? 0 : $maxHostConnections; + } + if (\defined('CURLMOPT_MAXCONNECTS') && 0 < $maxHostConnections) { + curl_multi_setopt($this->handle, \CURLMOPT_MAXCONNECTS, $maxHostConnections); + } + + // Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/77535 + if (0 >= $maxPendingPushes || \PHP_VERSION_ID < 70217 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304)) { + return; + } + + // HTTP/2 push crashes before curl 7.61 + if (!\defined('CURLMOPT_PUSHFUNCTION') || 0x073D00 > self::$curlVersion['version_number'] || !(\CURL_VERSION_HTTP2 & self::$curlVersion['features'])) { + return; + } + + // Clone to prevent a circular reference + $multi = clone $this; + $multi->handle = null; + $multi->share = null; + $multi->pushedResponses = &$this->pushedResponses; + $multi->logger = &$this->logger; + $multi->handlesActivity = &$this->handlesActivity; + $multi->openHandles = &$this->openHandles; + + curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes) { + return $multi->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes); + }); + } + + public function reset() + { + foreach ($this->pushedResponses as $url => $response) { + $this->logger && $this->logger->debug(sprintf('Unused pushed response: "%s"', $url)); + curl_multi_remove_handle($this->handle, $response->handle); + curl_close($response->handle); + } + + $this->pushedResponses = []; + $this->dnsCache->evictions = $this->dnsCache->evictions ?: $this->dnsCache->removals; + $this->dnsCache->removals = $this->dnsCache->hostnames = []; + + $this->share = curl_share_init(); + + curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_DNS); + curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_SSL_SESSION); + + if (\defined('CURL_LOCK_DATA_CONNECT') && \PHP_VERSION_ID >= 80000) { + curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_CONNECT); + } + } + + private function handlePush($parent, $pushed, array $requestHeaders, int $maxPendingPushes): int + { + $headers = []; + $origin = curl_getinfo($parent, \CURLINFO_EFFECTIVE_URL); + + foreach ($requestHeaders as $h) { + if (false !== $i = strpos($h, ':', 1)) { + $headers[substr($h, 0, $i)][] = substr($h, 1 + $i); + } + } + + if (!isset($headers[':method']) || !isset($headers[':scheme']) || !isset($headers[':authority']) || !isset($headers[':path'])) { + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); + + return \CURL_PUSH_DENY; + } + + $url = $headers[':scheme'][0].'://'.$headers[':authority'][0]; + + // curl before 7.65 doesn't validate the pushed ":authority" header, + // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host, + // ignoring domains mentioned as alt-name in the certificate for now (same as curl). + if (!str_starts_with($origin, $url.'/')) { + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); + + return \CURL_PUSH_DENY; + } + + if ($maxPendingPushes <= \count($this->pushedResponses)) { + $fifoUrl = key($this->pushedResponses); + unset($this->pushedResponses[$fifoUrl]); + $this->logger && $this->logger->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl)); + } + + $url .= $headers[':path'][0]; + $this->logger && $this->logger->debug(sprintf('Queueing pushed response: "%s"', $url)); + + $this->pushedResponses[$url] = new PushedResponse(new CurlResponse($this, $pushed), $headers, $this->openHandles[(int) $parent][1] ?? [], $pushed); + + return \CURL_PUSH_OK; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/DnsCache.php b/sites/all/libraries/vendor/symfony/http-client/Internal/DnsCache.php new file mode 100644 index 0000000000..bd23f77f8a --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/DnsCache.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +/** + * Cache for resolved DNS queries. + * + * @author Alexander M. Turek + * + * @internal + */ +final class DnsCache +{ + /** + * Resolved hostnames (hostname => IP address). + * + * @var string[] + */ + public $hostnames = []; + + /** + * @var string[] + */ + public $removals = []; + + /** + * @var string[] + */ + public $evictions = []; +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/HttplugWaitLoop.php b/sites/all/libraries/vendor/symfony/http-client/Internal/HttplugWaitLoop.php new file mode 100644 index 0000000000..9f5658f560 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/HttplugWaitLoop.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +use Http\Client\Exception\NetworkException; +use Http\Promise\Promise; +use Psr\Http\Message\RequestInterface as Psr7RequestInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Symfony\Component\HttpClient\Response\StreamableInterface; +use Symfony\Component\HttpClient\Response\StreamWrapper; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class HttplugWaitLoop +{ + private $client; + private $promisePool; + private $responseFactory; + private $streamFactory; + + /** + * @param \SplObjectStorage|null $promisePool + */ + public function __construct(HttpClientInterface $client, ?\SplObjectStorage $promisePool, ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory) + { + $this->client = $client; + $this->promisePool = $promisePool; + $this->responseFactory = $responseFactory; + $this->streamFactory = $streamFactory; + } + + public function wait(?ResponseInterface $pendingResponse, float $maxDuration = null, float $idleTimeout = null): int + { + if (!$this->promisePool) { + return 0; + } + + $guzzleQueue = \GuzzleHttp\Promise\Utils::queue(); + + if (0.0 === $remainingDuration = $maxDuration) { + $idleTimeout = 0.0; + } elseif (null !== $maxDuration) { + $startTime = microtime(true); + $idleTimeout = max(0.0, min($maxDuration / 5, $idleTimeout ?? $maxDuration)); + } + + do { + foreach ($this->client->stream($this->promisePool, $idleTimeout) as $response => $chunk) { + try { + if (null !== $maxDuration && $chunk->isTimeout()) { + goto check_duration; + } + + if ($chunk->isFirst()) { + // Deactivate throwing on 3/4/5xx + $response->getStatusCode(); + } + + if (!$chunk->isLast()) { + goto check_duration; + } + + if ([, $promise] = $this->promisePool[$response] ?? null) { + unset($this->promisePool[$response]); + $promise->resolve($this->createPsr7Response($response, true)); + } + } catch (\Exception $e) { + if ([$request, $promise] = $this->promisePool[$response] ?? null) { + unset($this->promisePool[$response]); + + if ($e instanceof TransportExceptionInterface) { + $e = new NetworkException($e->getMessage(), $request, $e); + } + + $promise->reject($e); + } + } + + $guzzleQueue->run(); + + if ($pendingResponse === $response) { + return $this->promisePool->count(); + } + + check_duration: + if (null !== $maxDuration && $idleTimeout && $idleTimeout > $remainingDuration = max(0.0, $maxDuration - microtime(true) + $startTime)) { + $idleTimeout = $remainingDuration / 5; + break; + } + } + + if (!$count = $this->promisePool->count()) { + return 0; + } + } while (null === $maxDuration || 0 < $remainingDuration); + + return $count; + } + + public function createPsr7Response(ResponseInterface $response, bool $buffer = false): Psr7ResponseInterface + { + $psrResponse = $this->responseFactory->createResponse($response->getStatusCode()); + + foreach ($response->getHeaders(false) as $name => $values) { + foreach ($values as $value) { + $psrResponse = $psrResponse->withAddedHeader($name, $value); + } + } + + if ($response instanceof StreamableInterface) { + $body = $this->streamFactory->createStreamFromResource($response->toStream(false)); + } elseif (!$buffer) { + $body = $this->streamFactory->createStreamFromResource(StreamWrapper::createResource($response, $this->client)); + } else { + $body = $this->streamFactory->createStream($response->getContent(false)); + } + + if ($body->isSeekable()) { + $body->seek(0); + } + + return $psrResponse->withBody($body); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/NativeClientState.php b/sites/all/libraries/vendor/symfony/http-client/Internal/NativeClientState.php new file mode 100644 index 0000000000..20b2727f59 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/NativeClientState.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +/** + * Internal representation of the native client's state. + * + * @author Alexander M. Turek + * + * @internal + */ +final class NativeClientState extends ClientState +{ + /** @var int */ + public $id; + /** @var int */ + public $maxHostConnections = \PHP_INT_MAX; + /** @var int */ + public $responseCount = 0; + /** @var string[] */ + public $dnsCache = []; + /** @var bool */ + public $sleep = false; + /** @var int[] */ + public $hosts = []; + + public function __construct() + { + $this->id = random_int(\PHP_INT_MIN, \PHP_INT_MAX); + } + + public function reset() + { + $this->responseCount = 0; + $this->dnsCache = []; + $this->hosts = []; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Internal/PushedResponse.php b/sites/all/libraries/vendor/symfony/http-client/Internal/PushedResponse.php new file mode 100644 index 0000000000..08fca60dcb --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Internal/PushedResponse.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Internal; + +use Symfony\Component\HttpClient\Response\CurlResponse; + +/** + * A pushed response with its request headers. + * + * @author Alexander M. Turek + * + * @internal + */ +final class PushedResponse +{ + public $response; + + /** @var string[] */ + public $requestHeaders; + + public $parentOptions = []; + + public $handle; + + public function __construct(CurlResponse $response, array $requestHeaders, array $parentOptions, $handle) + { + $this->response = $response; + $this->requestHeaders = $requestHeaders; + $this->parentOptions = $parentOptions; + $this->handle = $handle; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/LICENSE b/sites/all/libraries/vendor/symfony/http-client/LICENSE new file mode 100644 index 0000000000..74cdc2dbf6 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +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/sites/all/libraries/vendor/symfony/http-client/MockHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/MockHttpClient.php new file mode 100644 index 0000000000..fecba0ee56 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/MockHttpClient.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * A test-friendly HttpClient that doesn't make actual HTTP requests. + * + * @author Nicolas Grekas + */ +class MockHttpClient implements HttpClientInterface, ResetInterface +{ + use HttpClientTrait; + + private $responseFactory; + private $requestsCount = 0; + private $defaultOptions = []; + + /** + * @param callable|callable[]|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory + */ + public function __construct($responseFactory = null, ?string $baseUri = 'https://example.com') + { + $this->setResponseFactory($responseFactory); + $this->defaultOptions['base_uri'] = $baseUri; + } + + /** + * @param callable|callable[]|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory + */ + public function setResponseFactory($responseFactory): void + { + if ($responseFactory instanceof ResponseInterface) { + $responseFactory = [$responseFactory]; + } + + if (!$responseFactory instanceof \Iterator && null !== $responseFactory && !\is_callable($responseFactory)) { + $responseFactory = (static function () use ($responseFactory) { + yield from $responseFactory; + })(); + } + + $this->responseFactory = $responseFactory; + } + + /** + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + [$url, $options] = $this->prepareRequest($method, $url, $options, $this->defaultOptions, true); + $url = implode('', $url); + + if (null === $this->responseFactory) { + $response = new MockResponse(); + } elseif (\is_callable($this->responseFactory)) { + $response = ($this->responseFactory)($method, $url, $options); + } elseif (!$this->responseFactory->valid()) { + throw new TransportException('The response factory iterator passed to MockHttpClient is empty.'); + } else { + $responseFactory = $this->responseFactory->current(); + $response = \is_callable($responseFactory) ? $responseFactory($method, $url, $options) : $responseFactory; + $this->responseFactory->next(); + } + ++$this->requestsCount; + + if (!$response instanceof ResponseInterface) { + throw new TransportException(sprintf('The response factory passed to MockHttpClient must return/yield an instance of ResponseInterface, "%s" given.', \is_object($response) ? \get_class($response) : \gettype($response))); + } + + return MockResponse::fromRequest($method, $url, $options, $response); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof ResponseInterface) { + $responses = [$responses]; + } elseif (!is_iterable($responses)) { + throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of MockResponse objects, "%s" given.', __METHOD__, get_debug_type($responses))); + } + + return new ResponseStream(MockResponse::stream($responses, $timeout)); + } + + public function getRequestsCount(): int + { + return $this->requestsCount; + } + + /** + * {@inheritdoc} + */ + public function withOptions(array $options): self + { + $clone = clone $this; + $clone->defaultOptions = self::mergeDefaultOptions($options, $this->defaultOptions, true); + + return $clone; + } + + public function reset() + { + $this->requestsCount = 0; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/NativeHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/NativeHttpClient.php new file mode 100644 index 0000000000..63fcc1ca91 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/NativeHttpClient.php @@ -0,0 +1,468 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\NativeClientState; +use Symfony\Component\HttpClient\Response\NativeResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * A portable implementation of the HttpClientInterface contracts based on PHP stream wrappers. + * + * PHP stream wrappers are able to fetch response bodies concurrently, + * but each request is opened synchronously. + * + * @author Nicolas Grekas + */ +final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface +{ + use HttpClientTrait; + use LoggerAwareTrait; + + private $defaultOptions = self::OPTIONS_DEFAULTS; + private static $emptyDefaults = self::OPTIONS_DEFAULTS; + + /** @var NativeClientState */ + private $multi; + + /** + * @param array $defaultOptions Default request's options + * @param int $maxHostConnections The maximum number of connections to open + * + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + */ + public function __construct(array $defaultOptions = [], int $maxHostConnections = 6) + { + $this->defaultOptions['buffer'] = $this->defaultOptions['buffer'] ?? \Closure::fromCallable([__CLASS__, 'shouldBuffer']); + + if ($defaultOptions) { + [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions); + } + + $this->multi = new NativeClientState(); + $this->multi->maxHostConnections = 0 < $maxHostConnections ? $maxHostConnections : \PHP_INT_MAX; + } + + /** + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + * + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions); + + if ($options['bindto']) { + if (file_exists($options['bindto'])) { + throw new TransportException(__CLASS__.' cannot bind to local Unix sockets, use e.g. CurlHttpClient instead.'); + } + if (str_starts_with($options['bindto'], 'if!')) { + throw new TransportException(__CLASS__.' cannot bind to network interfaces, use e.g. CurlHttpClient instead.'); + } + if (str_starts_with($options['bindto'], 'host!')) { + $options['bindto'] = substr($options['bindto'], 5); + } + } + + $hasContentLength = isset($options['normalized_headers']['content-length']); + $hasBody = '' !== $options['body'] || 'POST' === $method || $hasContentLength; + + $options['body'] = self::getBodyAsString($options['body']); + + if ('chunked' === substr($options['normalized_headers']['transfer-encoding'][0] ?? '', \strlen('Transfer-Encoding: '))) { + unset($options['normalized_headers']['transfer-encoding']); + $options['headers'] = array_merge(...array_values($options['normalized_headers'])); + $options['body'] = self::dechunk($options['body']); + } + if ('' === $options['body'] && $hasBody && !$hasContentLength) { + $options['headers'][] = 'Content-Length: 0'; + } + if ($hasBody && !isset($options['normalized_headers']['content-type'])) { + $options['headers'][] = 'Content-Type: application/x-www-form-urlencoded'; + } + + if (\extension_loaded('zlib') && !isset($options['normalized_headers']['accept-encoding'])) { + // gzip is the most widely available algo, no need to deal with deflate + $options['headers'][] = 'Accept-Encoding: gzip'; + } + + if ($options['peer_fingerprint']) { + if (isset($options['peer_fingerprint']['pin-sha256']) && 1 === \count($options['peer_fingerprint'])) { + throw new TransportException(__CLASS__.' cannot verify "pin-sha256" fingerprints, please provide a "sha256" one.'); + } + + unset($options['peer_fingerprint']['pin-sha256']); + } + + $info = [ + 'response_headers' => [], + 'url' => $url, + 'error' => null, + 'canceled' => false, + 'http_method' => $method, + 'http_code' => 0, + 'redirect_count' => 0, + 'start_time' => 0.0, + 'connect_time' => 0.0, + 'redirect_time' => 0.0, + 'pretransfer_time' => 0.0, + 'starttransfer_time' => 0.0, + 'total_time' => 0.0, + 'namelookup_time' => 0.0, + 'size_upload' => 0, + 'size_download' => 0, + 'size_body' => \strlen($options['body']), + 'primary_ip' => '', + 'primary_port' => 'http:' === $url['scheme'] ? 80 : 443, + 'debug' => \extension_loaded('curl') ? '' : "* Enable the curl extension for better performance\n", + ]; + + if ($onProgress = $options['on_progress']) { + // Memoize the last progress to ease calling the callback periodically when no network transfer happens + $lastProgress = [0, 0]; + $maxDuration = 0 < $options['max_duration'] ? $options['max_duration'] : \INF; + $onProgress = static function (...$progress) use ($onProgress, &$lastProgress, &$info, $maxDuration) { + if ($info['total_time'] >= $maxDuration) { + throw new TransportException(sprintf('Max duration was reached for "%s".', implode('', $info['url']))); + } + + $progressInfo = $info; + $progressInfo['url'] = implode('', $info['url']); + unset($progressInfo['size_body']); + + if ($progress && -1 === $progress[0]) { + // Response completed + $lastProgress[0] = max($lastProgress); + } else { + $lastProgress = $progress ?: $lastProgress; + } + + $onProgress($lastProgress[0], $lastProgress[1], $progressInfo); + }; + } elseif (0 < $options['max_duration']) { + $maxDuration = $options['max_duration']; + $onProgress = static function () use (&$info, $maxDuration): void { + if ($info['total_time'] >= $maxDuration) { + throw new TransportException(sprintf('Max duration was reached for "%s".', implode('', $info['url']))); + } + }; + } + + // Always register a notification callback to compute live stats about the response + $notification = static function (int $code, int $severity, ?string $msg, int $msgCode, int $dlNow, int $dlSize) use ($onProgress, &$info) { + $info['total_time'] = microtime(true) - $info['start_time']; + + if (\STREAM_NOTIFY_PROGRESS === $code) { + $info['starttransfer_time'] = $info['starttransfer_time'] ?: $info['total_time']; + $info['size_upload'] += $dlNow ? 0 : $info['size_body']; + $info['size_download'] = $dlNow; + } elseif (\STREAM_NOTIFY_CONNECT === $code) { + $info['connect_time'] = $info['total_time']; + $info['debug'] .= $info['request_header']; + unset($info['request_header']); + } else { + return; + } + + if ($onProgress) { + $onProgress($dlNow, $dlSize); + } + }; + + if ($options['resolve']) { + $this->multi->dnsCache = $options['resolve'] + $this->multi->dnsCache; + } + + $this->logger && $this->logger->info(sprintf('Request: "%s %s"', $method, implode('', $url))); + + if (!isset($options['normalized_headers']['user-agent'])) { + $options['headers'][] = 'User-Agent: Symfony HttpClient/Native'; + } + + if (0 < $options['max_duration']) { + $options['timeout'] = min($options['max_duration'], $options['timeout']); + } + + $bindto = $options['bindto']; + if (!$bindto && (70322 === \PHP_VERSION_ID || 70410 === \PHP_VERSION_ID)) { + $bindto = '0:0'; + } + + $context = [ + 'http' => [ + 'protocol_version' => min($options['http_version'] ?: '1.1', '1.1'), + 'method' => $method, + 'content' => $options['body'], + 'ignore_errors' => true, + 'curl_verify_ssl_peer' => $options['verify_peer'], + 'curl_verify_ssl_host' => $options['verify_host'], + 'auto_decode' => false, // Disable dechunk filter, it's incompatible with stream_select() + 'timeout' => $options['timeout'], + 'follow_location' => false, // We follow redirects ourselves - the native logic is too limited + ], + 'ssl' => array_filter([ + 'verify_peer' => $options['verify_peer'], + 'verify_peer_name' => $options['verify_host'], + 'cafile' => $options['cafile'], + 'capath' => $options['capath'], + 'local_cert' => $options['local_cert'], + 'local_pk' => $options['local_pk'], + 'passphrase' => $options['passphrase'], + 'ciphers' => $options['ciphers'], + 'peer_fingerprint' => $options['peer_fingerprint'], + 'capture_peer_cert_chain' => $options['capture_peer_cert_chain'], + 'allow_self_signed' => (bool) $options['peer_fingerprint'], + 'SNI_enabled' => true, + 'disable_compression' => true, + ], static function ($v) { return null !== $v; }), + 'socket' => [ + 'bindto' => $bindto, + 'tcp_nodelay' => true, + ], + ]; + + $context = stream_context_create($context, ['notification' => $notification]); + + $resolver = static function ($multi) use ($context, $options, $url, &$info, $onProgress) { + [$host, $port] = self::parseHostPort($url, $info); + + if (!isset($options['normalized_headers']['host'])) { + $options['headers'][] = 'Host: '.$host.$port; + } + + $proxy = self::getProxy($options['proxy'], $url, $options['no_proxy']); + + if (!self::configureHeadersAndProxy($context, $host, $options['headers'], $proxy, 'https:' === $url['scheme'])) { + $ip = self::dnsResolve($host, $multi, $info, $onProgress); + $url['authority'] = substr_replace($url['authority'], $ip, -\strlen($host) - \strlen($port), \strlen($host)); + } + + return [self::createRedirectResolver($options, $host, $proxy, $info, $onProgress), implode('', $url)]; + }; + + return new NativeResponse($this->multi, $context, implode('', $url), $options, $info, $resolver, $onProgress, $this->logger); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof NativeResponse) { + $responses = [$responses]; + } elseif (!is_iterable($responses)) { + throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of NativeResponse objects, "%s" given.', __METHOD__, get_debug_type($responses))); + } + + return new ResponseStream(NativeResponse::stream($responses, $timeout)); + } + + public function reset() + { + $this->multi->reset(); + } + + private static function getBodyAsString($body): string + { + if (\is_resource($body)) { + return stream_get_contents($body); + } + + if (!$body instanceof \Closure) { + return $body; + } + + $result = ''; + + while ('' !== $data = $body(self::$CHUNK_SIZE)) { + if (!\is_string($data)) { + throw new TransportException(sprintf('Return value of the "body" option callback must be string, "%s" returned.', get_debug_type($data))); + } + + $result .= $data; + } + + return $result; + } + + /** + * Extracts the host and the port from the URL. + */ + private static function parseHostPort(array $url, array &$info): array + { + if ($port = parse_url($url['authority'], \PHP_URL_PORT) ?: '') { + $info['primary_port'] = $port; + $port = ':'.$port; + } else { + $info['primary_port'] = 'http:' === $url['scheme'] ? 80 : 443; + } + + return [parse_url($url['authority'], \PHP_URL_HOST), $port]; + } + + /** + * Resolves the IP of the host using the local DNS cache if possible. + */ + private static function dnsResolve($host, NativeClientState $multi, array &$info, ?\Closure $onProgress): string + { + if (null === $ip = $multi->dnsCache[$host] ?? null) { + $info['debug'] .= "* Hostname was NOT found in DNS cache\n"; + $now = microtime(true); + + if (!$ip = gethostbynamel($host)) { + throw new TransportException(sprintf('Could not resolve host "%s".', $host)); + } + + $info['namelookup_time'] = microtime(true) - ($info['start_time'] ?: $now); + $multi->dnsCache[$host] = $ip = $ip[0]; + $info['debug'] .= "* Added {$host}:0:{$ip} to DNS cache\n"; + } else { + $info['debug'] .= "* Hostname was found in DNS cache\n"; + } + + $info['primary_ip'] = $ip; + + if ($onProgress) { + // Notify DNS resolution + $onProgress(); + } + + return $ip; + } + + /** + * Handles redirects - the native logic is too buggy to be used. + */ + private static function createRedirectResolver(array $options, string $host, ?array $proxy, array &$info, ?\Closure $onProgress): \Closure + { + $redirectHeaders = []; + if (0 < $maxRedirects = $options['max_redirects']) { + $redirectHeaders = ['host' => $host]; + $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['headers'], static function ($h) { + return 0 !== stripos($h, 'Host:'); + }); + + if (isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) { + $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) { + return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); + }); + } + } + + return static function (NativeClientState $multi, ?string $location, $context) use (&$redirectHeaders, $proxy, &$info, $maxRedirects, $onProgress): ?string { + if (null === $location || $info['http_code'] < 300 || 400 <= $info['http_code']) { + $info['redirect_url'] = null; + + return null; + } + + try { + $url = self::parseUrl($location); + } catch (InvalidArgumentException $e) { + $info['redirect_url'] = null; + + return null; + } + + $url = self::resolveUrl($url, $info['url']); + $info['redirect_url'] = implode('', $url); + + if ($info['redirect_count'] >= $maxRedirects) { + return null; + } + + $info['url'] = $url; + ++$info['redirect_count']; + $info['redirect_time'] = microtime(true) - $info['start_time']; + + // Do like curl and browsers: turn POST to GET on 301, 302 and 303 + if (\in_array($info['http_code'], [301, 302, 303], true)) { + $options = stream_context_get_options($context)['http']; + + if ('POST' === $options['method'] || 303 === $info['http_code']) { + $info['http_method'] = $options['method'] = 'HEAD' === $options['method'] ? 'HEAD' : 'GET'; + $options['content'] = ''; + $filterContentHeaders = static function ($h) { + return 0 !== stripos($h, 'Content-Length:') && 0 !== stripos($h, 'Content-Type:') && 0 !== stripos($h, 'Transfer-Encoding:'); + }; + $options['header'] = array_filter($options['header'], $filterContentHeaders); + $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], $filterContentHeaders); + $redirectHeaders['with_auth'] = array_filter($redirectHeaders['with_auth'], $filterContentHeaders); + + stream_context_set_option($context, ['http' => $options]); + } + } + + [$host, $port] = self::parseHostPort($url, $info); + + if (false !== (parse_url($location, \PHP_URL_HOST) ?? false)) { + // Authorization and Cookie headers MUST NOT follow except for the initial host name + $requestHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth']; + $requestHeaders[] = 'Host: '.$host.$port; + $dnsResolve = !self::configureHeadersAndProxy($context, $host, $requestHeaders, $proxy, 'https:' === $url['scheme']); + } else { + $dnsResolve = isset(stream_context_get_options($context)['ssl']['peer_name']); + } + + if ($dnsResolve) { + $ip = self::dnsResolve($host, $multi, $info, $onProgress); + $url['authority'] = substr_replace($url['authority'], $ip, -\strlen($host) - \strlen($port), \strlen($host)); + } + + return implode('', $url); + }; + } + + private static function configureHeadersAndProxy($context, string $host, array $requestHeaders, ?array $proxy, bool $isSsl): bool + { + if (null === $proxy) { + stream_context_set_option($context, 'http', 'header', $requestHeaders); + stream_context_set_option($context, 'ssl', 'peer_name', $host); + + return false; + } + + // Matching "no_proxy" should follow the behavior of curl + + foreach ($proxy['no_proxy'] as $rule) { + $dotRule = '.'.ltrim($rule, '.'); + + if ('*' === $rule || $host === $rule || str_ends_with($host, $dotRule)) { + stream_context_set_option($context, 'http', 'proxy', null); + stream_context_set_option($context, 'http', 'request_fulluri', false); + stream_context_set_option($context, 'http', 'header', $requestHeaders); + stream_context_set_option($context, 'ssl', 'peer_name', $host); + + return false; + } + } + + if (null !== $proxy['auth']) { + $requestHeaders[] = 'Proxy-Authorization: '.$proxy['auth']; + } + + stream_context_set_option($context, 'http', 'proxy', $proxy['url']); + stream_context_set_option($context, 'http', 'request_fulluri', !$isSsl); + stream_context_set_option($context, 'http', 'header', $requestHeaders); + stream_context_set_option($context, 'ssl', 'peer_name', null); + + return true; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/NoPrivateNetworkHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/NoPrivateNetworkHttpClient.php new file mode 100644 index 0000000000..911cce9da4 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/NoPrivateNetworkHttpClient.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpFoundation\IpUtils; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Decorator that blocks requests to private networks by default. + * + * @author Hallison Boaventura + */ +final class NoPrivateNetworkHttpClient implements HttpClientInterface, LoggerAwareInterface, ResetInterface +{ + use HttpClientTrait; + + private const PRIVATE_SUBNETS = [ + '127.0.0.0/8', + '10.0.0.0/8', + '192.168.0.0/16', + '172.16.0.0/12', + '169.254.0.0/16', + '0.0.0.0/8', + '240.0.0.0/4', + '::1/128', + 'fc00::/7', + 'fe80::/10', + '::ffff:0:0/96', + '::/128', + ]; + + private $client; + private $subnets; + + /** + * @param string|array|null $subnets String or array of subnets using CIDR notation that will be used by IpUtils. + * If null is passed, the standard private subnets will be used. + */ + public function __construct(HttpClientInterface $client, $subnets = null) + { + if (!(\is_array($subnets) || \is_string($subnets) || null === $subnets)) { + throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be of the type array, string or null. "%s" given.', __METHOD__, get_debug_type($subnets))); + } + + if (!class_exists(IpUtils::class)) { + throw new \LogicException(sprintf('You cannot use "%s" if the HttpFoundation component is not installed. Try running "composer require symfony/http-foundation".', __CLASS__)); + } + + $this->client = $client; + $this->subnets = $subnets; + } + + /** + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + $onProgress = $options['on_progress'] ?? null; + if (null !== $onProgress && !\is_callable($onProgress)) { + throw new InvalidArgumentException(sprintf('Option "on_progress" must be callable, "%s" given.', get_debug_type($onProgress))); + } + + $subnets = $this->subnets; + $lastPrimaryIp = ''; + + $options['on_progress'] = function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets, &$lastPrimaryIp): void { + if ($info['primary_ip'] !== $lastPrimaryIp) { + if ($info['primary_ip'] && IpUtils::checkIp($info['primary_ip'], $subnets ?? self::PRIVATE_SUBNETS)) { + throw new TransportException(sprintf('IP "%s" is blocked for "%s".', $info['primary_ip'], $info['url'])); + } + + $lastPrimaryIp = $info['primary_ip']; + } + + null !== $onProgress && $onProgress($dlNow, $dlSize, $info); + }; + + return $this->client->request($method, $url, $options); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + return $this->client->stream($responses, $timeout); + } + + /** + * {@inheritdoc} + */ + public function setLogger(LoggerInterface $logger): void + { + if ($this->client instanceof LoggerAwareInterface) { + $this->client->setLogger($logger); + } + } + + /** + * {@inheritdoc} + */ + public function withOptions(array $options): self + { + $clone = clone $this; + $clone->client = $this->client->withOptions($options); + + return $clone; + } + + public function reset() + { + if ($this->client instanceof ResetInterface) { + $this->client->reset(); + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Psr18Client.php b/sites/all/libraries/vendor/symfony/http-client/Psr18Client.php new file mode 100644 index 0000000000..c62df84ecd --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Psr18Client.php @@ -0,0 +1,243 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Http\Discovery\Exception\NotFoundException; +use Http\Discovery\Psr17FactoryDiscovery; +use Nyholm\Psr7\Factory\Psr17Factory; +use Nyholm\Psr7\Request; +use Nyholm\Psr7\Uri; +use Psr\Http\Client\ClientInterface; +use Psr\Http\Client\NetworkExceptionInterface; +use Psr\Http\Client\RequestExceptionInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UriFactoryInterface; +use Psr\Http\Message\UriInterface; +use Symfony\Component\HttpClient\Response\StreamableInterface; +use Symfony\Component\HttpClient\Response\StreamWrapper; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\Service\ResetInterface; + +if (!interface_exists(RequestFactoryInterface::class)) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\Psr18Client" as the "psr/http-factory" package is not installed. Try running "composer require nyholm/psr7".'); +} + +if (!interface_exists(ClientInterface::class)) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\Psr18Client" as the "psr/http-client" package is not installed. Try running "composer require psr/http-client".'); +} + +/** + * An adapter to turn a Symfony HttpClientInterface into a PSR-18 ClientInterface. + * + * Run "composer require psr/http-client" to install the base ClientInterface. Run + * "composer require nyholm/psr7" to install an efficient implementation of response + * and stream factories with flex-provided autowiring aliases. + * + * @author Nicolas Grekas + */ +final class Psr18Client implements ClientInterface, RequestFactoryInterface, StreamFactoryInterface, UriFactoryInterface, ResetInterface +{ + private $client; + private $responseFactory; + private $streamFactory; + + public function __construct(HttpClientInterface $client = null, ResponseFactoryInterface $responseFactory = null, StreamFactoryInterface $streamFactory = null) + { + $this->client = $client ?? HttpClient::create(); + $this->responseFactory = $responseFactory; + $this->streamFactory = $streamFactory ?? ($responseFactory instanceof StreamFactoryInterface ? $responseFactory : null); + + if (null !== $this->responseFactory && null !== $this->streamFactory) { + return; + } + + if (!class_exists(Psr17Factory::class) && !class_exists(Psr17FactoryDiscovery::class)) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\Psr18Client" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".'); + } + + try { + $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null; + $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory(); + $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory(); + } catch (NotFoundException $e) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been found. Try running "composer require nyholm/psr7".', 0, $e); + } + } + + /** + * {@inheritdoc} + */ + public function sendRequest(RequestInterface $request): ResponseInterface + { + try { + $body = $request->getBody(); + + if ($body->isSeekable()) { + $body->seek(0); + } + + $response = $this->client->request($request->getMethod(), (string) $request->getUri(), [ + 'headers' => $request->getHeaders(), + 'body' => $body->getContents(), + 'http_version' => '1.0' === $request->getProtocolVersion() ? '1.0' : null, + ]); + + $psrResponse = $this->responseFactory->createResponse($response->getStatusCode()); + + foreach ($response->getHeaders(false) as $name => $values) { + foreach ($values as $value) { + try { + $psrResponse = $psrResponse->withAddedHeader($name, $value); + } catch (\InvalidArgumentException $e) { + // ignore invalid header + } + } + } + + $body = $response instanceof StreamableInterface ? $response->toStream(false) : StreamWrapper::createResource($response, $this->client); + $body = $this->streamFactory->createStreamFromResource($body); + + if ($body->isSeekable()) { + $body->seek(0); + } + + return $psrResponse->withBody($body); + } catch (TransportExceptionInterface $e) { + if ($e instanceof \InvalidArgumentException) { + throw new Psr18RequestException($e, $request); + } + + throw new Psr18NetworkException($e, $request); + } + } + + /** + * {@inheritdoc} + */ + public function createRequest(string $method, $uri): RequestInterface + { + if ($this->responseFactory instanceof RequestFactoryInterface) { + return $this->responseFactory->createRequest($method, $uri); + } + + if (class_exists(Request::class)) { + return new Request($method, $uri); + } + + if (class_exists(Psr17FactoryDiscovery::class)) { + return Psr17FactoryDiscovery::findRequestFactory()->createRequest($method, $uri); + } + + throw new \LogicException(sprintf('You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function createStream(string $content = ''): StreamInterface + { + $stream = $this->streamFactory->createStream($content); + + if ($stream->isSeekable()) { + $stream->seek(0); + } + + return $stream; + } + + /** + * {@inheritdoc} + */ + public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface + { + return $this->streamFactory->createStreamFromFile($filename, $mode); + } + + /** + * {@inheritdoc} + */ + public function createStreamFromResource($resource): StreamInterface + { + return $this->streamFactory->createStreamFromResource($resource); + } + + /** + * {@inheritdoc} + */ + public function createUri(string $uri = ''): UriInterface + { + if ($this->responseFactory instanceof UriFactoryInterface) { + return $this->responseFactory->createUri($uri); + } + + if (class_exists(Uri::class)) { + return new Uri($uri); + } + + if (class_exists(Psr17FactoryDiscovery::class)) { + return Psr17FactoryDiscovery::findUrlFactory()->createUri($uri); + } + + throw new \LogicException(sprintf('You cannot use "%s()" as the "nyholm/psr7" package is not installed. Try running "composer require nyholm/psr7".', __METHOD__)); + } + + public function reset() + { + if ($this->client instanceof ResetInterface) { + $this->client->reset(); + } + } +} + +/** + * @internal + */ +class Psr18NetworkException extends \RuntimeException implements NetworkExceptionInterface +{ + private $request; + + public function __construct(TransportExceptionInterface $e, RequestInterface $request) + { + parent::__construct($e->getMessage(), 0, $e); + $this->request = $request; + } + + public function getRequest(): RequestInterface + { + return $this->request; + } +} + +/** + * @internal + */ +class Psr18RequestException extends \InvalidArgumentException implements RequestExceptionInterface +{ + private $request; + + public function __construct(TransportExceptionInterface $e, RequestInterface $request) + { + parent::__construct($e->getMessage(), 0, $e); + $this->request = $request; + } + + public function getRequest(): RequestInterface + { + return $this->request; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/README.md b/sites/all/libraries/vendor/symfony/http-client/README.md new file mode 100644 index 0000000000..0c55ccc118 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/README.md @@ -0,0 +1,27 @@ +HttpClient component +==================== + +The HttpClient component provides powerful methods to fetch HTTP resources synchronously or asynchronously. + +Sponsor +------- + +The Httpclient component for Symfony 5.4/6.0 is [backed][1] by [Klaxoon][2]. + +Klaxoon is a platform that empowers organizations to run effective and +productive workshops easily in a hybrid environment. Anytime, Anywhere. + +Help Symfony by [sponsoring][3] its development! + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/http_client.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://klaxoon.com +[3]: https://symfony.com/sponsor diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/AmpResponse.php b/sites/all/libraries/vendor/symfony/http-client/Response/AmpResponse.php new file mode 100644 index 0000000000..6d0ce6e33e --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/AmpResponse.php @@ -0,0 +1,461 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Amp\ByteStream\StreamException; +use Amp\CancellationTokenSource; +use Amp\Coroutine; +use Amp\Deferred; +use Amp\Http\Client\HttpException; +use Amp\Http\Client\Request; +use Amp\Http\Client\Response; +use Amp\Loop; +use Amp\Promise; +use Amp\Success; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Chunk\InformationalChunk; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\HttpClientTrait; +use Symfony\Component\HttpClient\Internal\AmpBody; +use Symfony\Component\HttpClient\Internal\AmpClientState; +use Symfony\Component\HttpClient\Internal\Canary; +use Symfony\Component\HttpClient\Internal\ClientState; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class AmpResponse implements ResponseInterface, StreamableInterface +{ + use CommonResponseTrait; + use TransportResponseTrait; + + private static $nextId = 'a'; + + private $multi; + private $options; + private $canceller; + private $onProgress; + + private static $delay; + + /** + * @internal + */ + public function __construct(AmpClientState $multi, Request $request, array $options, ?LoggerInterface $logger) + { + $this->multi = $multi; + $this->options = &$options; + $this->logger = $logger; + $this->timeout = $options['timeout']; + $this->shouldBuffer = $options['buffer']; + + if ($this->inflate = \extension_loaded('zlib') && !$request->hasHeader('accept-encoding')) { + $request->setHeader('Accept-Encoding', 'gzip'); + } + + $this->initializer = static function (self $response) { + return null !== $response->options; + }; + + $info = &$this->info; + $headers = &$this->headers; + $canceller = $this->canceller = new CancellationTokenSource(); + $handle = &$this->handle; + + $info['url'] = (string) $request->getUri(); + $info['http_method'] = $request->getMethod(); + $info['start_time'] = null; + $info['redirect_url'] = null; + $info['redirect_time'] = 0.0; + $info['redirect_count'] = 0; + $info['size_upload'] = 0.0; + $info['size_download'] = 0.0; + $info['upload_content_length'] = -1.0; + $info['download_content_length'] = -1.0; + $info['user_data'] = $options['user_data']; + $info['max_duration'] = $options['max_duration']; + $info['debug'] = ''; + + $onProgress = $options['on_progress'] ?? static function () {}; + $onProgress = $this->onProgress = static function () use (&$info, $onProgress) { + $info['total_time'] = microtime(true) - $info['start_time']; + $onProgress((int) $info['size_download'], ((int) (1 + $info['download_content_length']) ?: 1) - 1, (array) $info); + }; + + $pauseDeferred = new Deferred(); + $pause = new Success(); + + $throttleWatcher = null; + + $this->id = $id = self::$nextId++; + Loop::defer(static function () use ($request, $multi, &$id, &$info, &$headers, $canceller, &$options, $onProgress, &$handle, $logger, &$pause) { + return new Coroutine(self::generateResponse($request, $multi, $id, $info, $headers, $canceller, $options, $onProgress, $handle, $logger, $pause)); + }); + + $info['pause_handler'] = static function (float $duration) use (&$throttleWatcher, &$pauseDeferred, &$pause) { + if (null !== $throttleWatcher) { + Loop::cancel($throttleWatcher); + } + + $pause = $pauseDeferred->promise(); + + if ($duration <= 0) { + $deferred = $pauseDeferred; + $pauseDeferred = new Deferred(); + $deferred->resolve(); + } else { + $throttleWatcher = Loop::delay(ceil(1000 * $duration), static function () use (&$pauseDeferred) { + $deferred = $pauseDeferred; + $pauseDeferred = new Deferred(); + $deferred->resolve(); + }); + } + }; + + $multi->lastTimeout = null; + $multi->openHandles[$id] = $id; + ++$multi->responseCount; + + $this->canary = new Canary(static function () use ($canceller, $multi, $id) { + $canceller->cancel(); + unset($multi->openHandles[$id], $multi->handlesActivity[$id]); + }); + } + + /** + * {@inheritdoc} + */ + public function getInfo(string $type = null) + { + return null !== $type ? $this->info[$type] ?? null : $this->info; + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + try { + $this->doDestruct(); + } finally { + // Clear the DNS cache when all requests completed + if (0 >= --$this->multi->responseCount) { + $this->multi->responseCount = 0; + $this->multi->dnsCache = []; + } + } + } + + /** + * {@inheritdoc} + */ + private static function schedule(self $response, array &$runningResponses): void + { + if (isset($runningResponses[0])) { + $runningResponses[0][1][$response->id] = $response; + } else { + $runningResponses[0] = [$response->multi, [$response->id => $response]]; + } + + if (!isset($response->multi->openHandles[$response->id])) { + $response->multi->handlesActivity[$response->id][] = null; + $response->multi->handlesActivity[$response->id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null; + } + } + + /** + * {@inheritdoc} + * + * @param AmpClientState $multi + */ + private static function perform(ClientState $multi, array &$responses = null): void + { + if ($responses) { + foreach ($responses as $response) { + try { + if ($response->info['start_time']) { + $response->info['total_time'] = microtime(true) - $response->info['start_time']; + ($response->onProgress)(); + } + } catch (\Throwable $e) { + $multi->handlesActivity[$response->id][] = null; + $multi->handlesActivity[$response->id][] = $e; + } + } + } + } + + /** + * {@inheritdoc} + * + * @param AmpClientState $multi + */ + private static function select(ClientState $multi, float $timeout): int + { + $timeout += microtime(true); + self::$delay = Loop::defer(static function () use ($timeout) { + if (0 < $timeout -= microtime(true)) { + self::$delay = Loop::delay(ceil(1000 * $timeout), [Loop::class, 'stop']); + } else { + Loop::stop(); + } + }); + + Loop::run(); + + return null === self::$delay ? 1 : 0; + } + + private static function generateResponse(Request $request, AmpClientState $multi, string $id, array &$info, array &$headers, CancellationTokenSource $canceller, array &$options, \Closure $onProgress, &$handle, ?LoggerInterface $logger, Promise &$pause) + { + $request->setInformationalResponseHandler(static function (Response $response) use ($multi, $id, &$info, &$headers) { + self::addResponseHeaders($response, $info, $headers); + $multi->handlesActivity[$id][] = new InformationalChunk($response->getStatus(), $response->getHeaders()); + self::stopLoop(); + }); + + try { + /* @var Response $response */ + if (null === $response = yield from self::getPushedResponse($request, $multi, $info, $headers, $options, $logger)) { + $logger && $logger->info(sprintf('Request: "%s %s"', $info['http_method'], $info['url'])); + + $response = yield from self::followRedirects($request, $multi, $info, $headers, $canceller, $options, $onProgress, $handle, $logger, $pause); + } + + $options = null; + + $multi->handlesActivity[$id][] = new FirstChunk(); + + if ('HEAD' === $response->getRequest()->getMethod() || \in_array($info['http_code'], [204, 304], true)) { + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = null; + self::stopLoop(); + + return; + } + + if ($response->hasHeader('content-length')) { + $info['download_content_length'] = (float) $response->getHeader('content-length'); + } + + $body = $response->getBody(); + + while (true) { + self::stopLoop(); + + yield $pause; + + if (null === $data = yield $body->read()) { + break; + } + + $info['size_download'] += \strlen($data); + $multi->handlesActivity[$id][] = $data; + } + + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = null; + } catch (\Throwable $e) { + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = $e; + } finally { + $info['download_content_length'] = $info['size_download']; + } + + self::stopLoop(); + } + + private static function followRedirects(Request $originRequest, AmpClientState $multi, array &$info, array &$headers, CancellationTokenSource $canceller, array $options, \Closure $onProgress, &$handle, ?LoggerInterface $logger, Promise &$pause) + { + yield $pause; + + $originRequest->setBody(new AmpBody($options['body'], $info, $onProgress)); + $response = yield $multi->request($options, $originRequest, $canceller->getToken(), $info, $onProgress, $handle); + $previousUrl = null; + + while (true) { + self::addResponseHeaders($response, $info, $headers); + $status = $response->getStatus(); + + if (!\in_array($status, [301, 302, 303, 307, 308], true) || null === $location = $response->getHeader('location')) { + return $response; + } + + $urlResolver = new class() { + use HttpClientTrait { + parseUrl as public; + resolveUrl as public; + } + }; + + try { + $previousUrl = $previousUrl ?? $urlResolver::parseUrl($info['url']); + $location = $urlResolver::parseUrl($location); + $location = $urlResolver::resolveUrl($location, $previousUrl); + $info['redirect_url'] = implode('', $location); + } catch (InvalidArgumentException $e) { + return $response; + } + + if (0 >= $options['max_redirects'] || $info['redirect_count'] >= $options['max_redirects']) { + return $response; + } + + $logger && $logger->info(sprintf('Redirecting: "%s %s"', $status, $info['url'])); + + try { + // Discard body of redirects + while (null !== yield $response->getBody()->read()) { + } + } catch (HttpException|StreamException $e) { + // Ignore streaming errors on previous responses + } + + ++$info['redirect_count']; + $info['url'] = $info['redirect_url']; + $info['redirect_url'] = null; + $previousUrl = $location; + + $request = new Request($info['url'], $info['http_method']); + $request->setProtocolVersions($originRequest->getProtocolVersions()); + $request->setTcpConnectTimeout($originRequest->getTcpConnectTimeout()); + $request->setTlsHandshakeTimeout($originRequest->getTlsHandshakeTimeout()); + $request->setTransferTimeout($originRequest->getTransferTimeout()); + + if (\in_array($status, [301, 302, 303], true)) { + $originRequest->removeHeader('transfer-encoding'); + $originRequest->removeHeader('content-length'); + $originRequest->removeHeader('content-type'); + + // Do like curl and browsers: turn POST to GET on 301, 302 and 303 + if ('POST' === $response->getRequest()->getMethod() || 303 === $status) { + $info['http_method'] = 'HEAD' === $response->getRequest()->getMethod() ? 'HEAD' : 'GET'; + $request->setMethod($info['http_method']); + } + } else { + $request->setBody(AmpBody::rewind($response->getRequest()->getBody())); + } + + foreach ($originRequest->getRawHeaders() as [$name, $value]) { + $request->setHeader($name, $value); + } + + if ($request->getUri()->getAuthority() !== $originRequest->getUri()->getAuthority()) { + $request->removeHeader('authorization'); + $request->removeHeader('cookie'); + $request->removeHeader('host'); + } + + yield $pause; + + $response = yield $multi->request($options, $request, $canceller->getToken(), $info, $onProgress, $handle); + $info['redirect_time'] = microtime(true) - $info['start_time']; + } + } + + private static function addResponseHeaders(Response $response, array &$info, array &$headers): void + { + $info['http_code'] = $response->getStatus(); + + if ($headers) { + $info['debug'] .= "< \r\n"; + $headers = []; + } + + $h = sprintf('HTTP/%s %s %s', $response->getProtocolVersion(), $response->getStatus(), $response->getReason()); + $info['debug'] .= "< {$h}\r\n"; + $info['response_headers'][] = $h; + + foreach ($response->getRawHeaders() as [$name, $value]) { + $headers[strtolower($name)][] = $value; + $h = $name.': '.$value; + $info['debug'] .= "< {$h}\r\n"; + $info['response_headers'][] = $h; + } + + $info['debug'] .= "< \r\n"; + } + + /** + * Accepts pushed responses only if their headers related to authentication match the request. + */ + private static function getPushedResponse(Request $request, AmpClientState $multi, array &$info, array &$headers, array $options, ?LoggerInterface $logger) + { + if ('' !== $options['body']) { + return null; + } + + $authority = $request->getUri()->getAuthority(); + + foreach ($multi->pushedResponses[$authority] ?? [] as $i => [$pushedUrl, $pushDeferred, $pushedRequest, $pushedResponse, $parentOptions]) { + if ($info['url'] !== $pushedUrl || $info['http_method'] !== $pushedRequest->getMethod()) { + continue; + } + + foreach ($parentOptions as $k => $v) { + if ($options[$k] !== $v) { + continue 2; + } + } + + foreach (['authorization', 'cookie', 'range', 'proxy-authorization'] as $k) { + if ($pushedRequest->getHeaderArray($k) !== $request->getHeaderArray($k)) { + continue 2; + } + } + + $response = yield $pushedResponse; + + foreach ($response->getHeaderArray('vary') as $vary) { + foreach (preg_split('/\s*+,\s*+/', $vary) as $v) { + if ('*' === $v || ($pushedRequest->getHeaderArray($v) !== $request->getHeaderArray($v) && 'accept-encoding' !== strtolower($v))) { + $logger && $logger->debug(sprintf('Skipping pushed response: "%s"', $info['url'])); + continue 3; + } + } + } + + $pushDeferred->resolve(); + $logger && $logger->debug(sprintf('Accepting pushed response: "%s %s"', $info['http_method'], $info['url'])); + self::addResponseHeaders($response, $info, $headers); + unset($multi->pushedResponses[$authority][$i]); + + if (!$multi->pushedResponses[$authority]) { + unset($multi->pushedResponses[$authority]); + } + + return $response; + } + } + + private static function stopLoop(): void + { + if (null !== self::$delay) { + Loop::cancel(self::$delay); + self::$delay = null; + } + + Loop::defer([Loop::class, 'stop']); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/AsyncContext.php b/sites/all/libraries/vendor/symfony/http-client/Response/AsyncContext.php new file mode 100644 index 0000000000..646458e13c --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/AsyncContext.php @@ -0,0 +1,195 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Chunk\DataChunk; +use Symfony\Component\HttpClient\Chunk\LastChunk; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Contracts\HttpClient\ChunkInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * A DTO to work with AsyncResponse. + * + * @author Nicolas Grekas + */ +final class AsyncContext +{ + private $passthru; + private $client; + private $response; + private $info = []; + private $content; + private $offset; + + public function __construct(&$passthru, HttpClientInterface $client, ResponseInterface &$response, array &$info, $content, int $offset) + { + $this->passthru = &$passthru; + $this->client = $client; + $this->response = &$response; + $this->info = &$info; + $this->content = $content; + $this->offset = $offset; + } + + /** + * Returns the HTTP status without consuming the response. + */ + public function getStatusCode(): int + { + return $this->response->getInfo('http_code'); + } + + /** + * Returns the headers without consuming the response. + */ + public function getHeaders(): array + { + $headers = []; + + foreach ($this->response->getInfo('response_headers') as $h) { + if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? ([123456789]\d\d)(?: |$)#', $h, $m)) { + $headers = []; + } elseif (2 === \count($m = explode(':', $h, 2))) { + $headers[strtolower($m[0])][] = ltrim($m[1]); + } + } + + return $headers; + } + + /** + * @return resource|null The PHP stream resource where the content is buffered, if it is + */ + public function getContent() + { + return $this->content; + } + + /** + * Creates a new chunk of content. + */ + public function createChunk(string $data): ChunkInterface + { + return new DataChunk($this->offset, $data); + } + + /** + * Pauses the request for the given number of seconds. + */ + public function pause(float $duration): void + { + if (\is_callable($pause = $this->response->getInfo('pause_handler'))) { + $pause($duration); + } elseif (0 < $duration) { + usleep(1E6 * $duration); + } + } + + /** + * Cancels the request and returns the last chunk to yield. + */ + public function cancel(): ChunkInterface + { + $this->info['canceled'] = true; + $this->info['error'] = 'Response has been canceled.'; + $this->response->cancel(); + + return new LastChunk(); + } + + /** + * Returns the current info of the response. + */ + public function getInfo(string $type = null) + { + if (null !== $type) { + return $this->info[$type] ?? $this->response->getInfo($type); + } + + return $this->info + $this->response->getInfo(); + } + + /** + * Attaches an info to the response. + * + * @return $this + */ + public function setInfo(string $type, $value): self + { + if ('canceled' === $type && $value !== $this->info['canceled']) { + throw new \LogicException('You cannot set the "canceled" info directly.'); + } + + if (null === $value) { + unset($this->info[$type]); + } else { + $this->info[$type] = $value; + } + + return $this; + } + + /** + * Returns the currently processed response. + */ + public function getResponse(): ResponseInterface + { + return $this->response; + } + + /** + * Replaces the currently processed response by doing a new request. + */ + public function replaceRequest(string $method, string $url, array $options = []): ResponseInterface + { + $this->info['previous_info'][] = $info = $this->response->getInfo(); + if (null !== $onProgress = $options['on_progress'] ?? null) { + $thisInfo = &$this->info; + $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use (&$thisInfo, $onProgress) { + $onProgress($dlNow, $dlSize, $thisInfo + $info); + }; + } + if (0 < ($info['max_duration'] ?? 0) && 0 < ($info['total_time'] ?? 0)) { + if (0 >= $options['max_duration'] = $info['max_duration'] - $info['total_time']) { + throw new TransportException(sprintf('Max duration was reached for "%s".', $info['url'])); + } + } + + return $this->response = $this->client->request($method, $url, ['buffer' => false] + $options); + } + + /** + * Replaces the currently processed response by another one. + */ + public function replaceResponse(ResponseInterface $response): ResponseInterface + { + $this->info['previous_info'][] = $this->response->getInfo(); + + return $this->response = $response; + } + + /** + * Replaces or removes the chunk filter iterator. + * + * @param ?callable(ChunkInterface, self): ?\Iterator $passthru + */ + public function passthru(callable $passthru = null): void + { + $this->passthru = $passthru ?? static function ($chunk, $context) { + $context->passthru = null; + + yield $chunk; + }; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/AsyncResponse.php b/sites/all/libraries/vendor/symfony/http-client/Response/AsyncResponse.php new file mode 100644 index 0000000000..80c9f7da37 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/AsyncResponse.php @@ -0,0 +1,478 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Chunk\LastChunk; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Contracts\HttpClient\ChunkInterface; +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * Provides a single extension point to process a response's content stream. + * + * @author Nicolas Grekas + */ +final class AsyncResponse implements ResponseInterface, StreamableInterface +{ + use CommonResponseTrait; + + private const FIRST_CHUNK_YIELDED = 1; + private const LAST_CHUNK_YIELDED = 2; + + private $client; + private $response; + private $info = ['canceled' => false]; + private $passthru; + private $stream; + private $yieldedState; + + /** + * @param ?callable(ChunkInterface, AsyncContext): ?\Iterator $passthru + */ + public function __construct(HttpClientInterface $client, string $method, string $url, array $options, callable $passthru = null) + { + $this->client = $client; + $this->shouldBuffer = $options['buffer'] ?? true; + + if (null !== $onProgress = $options['on_progress'] ?? null) { + $thisInfo = &$this->info; + $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use (&$thisInfo, $onProgress) { + $onProgress($dlNow, $dlSize, $thisInfo + $info); + }; + } + $this->response = $client->request($method, $url, ['buffer' => false] + $options); + $this->passthru = $passthru; + $this->initializer = static function (self $response, float $timeout = null) { + if (null === $response->shouldBuffer) { + return false; + } + + while (true) { + foreach (self::stream([$response], $timeout) as $chunk) { + if ($chunk->isTimeout() && $response->passthru) { + foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, new TransportException($chunk->getError()))) as $chunk) { + if ($chunk->isFirst()) { + return false; + } + } + + continue 2; + } + + if ($chunk->isFirst()) { + return false; + } + } + + return false; + } + }; + if (\array_key_exists('user_data', $options)) { + $this->info['user_data'] = $options['user_data']; + } + if (\array_key_exists('max_duration', $options)) { + $this->info['max_duration'] = $options['max_duration']; + } + } + + public function getStatusCode(): int + { + if ($this->initializer) { + self::initialize($this); + } + + return $this->response->getStatusCode(); + } + + public function getHeaders(bool $throw = true): array + { + if ($this->initializer) { + self::initialize($this); + } + + $headers = $this->response->getHeaders(false); + + if ($throw) { + $this->checkStatusCode(); + } + + return $headers; + } + + public function getInfo(string $type = null) + { + if (null !== $type) { + return $this->info[$type] ?? $this->response->getInfo($type); + } + + return $this->info + $this->response->getInfo(); + } + + /** + * {@inheritdoc} + */ + public function toStream(bool $throw = true) + { + if ($throw) { + // Ensure headers arrived + $this->getHeaders(true); + } + + $handle = function () { + $stream = $this->response instanceof StreamableInterface ? $this->response->toStream(false) : StreamWrapper::createResource($this->response); + + return stream_get_meta_data($stream)['wrapper_data']->stream_cast(\STREAM_CAST_FOR_SELECT); + }; + + $stream = StreamWrapper::createResource($this); + stream_get_meta_data($stream)['wrapper_data'] + ->bindHandles($handle, $this->content); + + return $stream; + } + + /** + * {@inheritdoc} + */ + public function cancel(): void + { + if ($this->info['canceled']) { + return; + } + + $this->info['canceled'] = true; + $this->info['error'] = 'Response has been canceled.'; + $this->close(); + $client = $this->client; + $this->client = null; + + if (!$this->passthru) { + return; + } + + try { + foreach (self::passthru($client, $this, new LastChunk()) as $chunk) { + // no-op + } + + $this->passthru = null; + } catch (ExceptionInterface $e) { + // ignore any errors when canceling + } + } + + public function __destruct() + { + $httpException = null; + + if ($this->initializer && null === $this->getInfo('error')) { + try { + self::initialize($this, -0.0); + $this->getHeaders(true); + } catch (HttpExceptionInterface $httpException) { + // no-op + } + } + + if ($this->passthru && null === $this->getInfo('error')) { + $this->info['canceled'] = true; + + try { + foreach (self::passthru($this->client, $this, new LastChunk()) as $chunk) { + // no-op + } + } catch (ExceptionInterface $e) { + // ignore any errors when destructing + } + } + + if (null !== $httpException) { + throw $httpException; + } + } + + /** + * @internal + */ + public static function stream(iterable $responses, float $timeout = null, string $class = null): \Generator + { + while ($responses) { + $wrappedResponses = []; + $asyncMap = new \SplObjectStorage(); + $client = null; + + foreach ($responses as $r) { + if (!$r instanceof self) { + throw new \TypeError(sprintf('"%s::stream()" expects parameter 1 to be an iterable of AsyncResponse objects, "%s" given.', $class ?? static::class, get_debug_type($r))); + } + + if (null !== $e = $r->info['error'] ?? null) { + yield $r => $chunk = new ErrorChunk($r->offset, new TransportException($e)); + $chunk->didThrow() ?: $chunk->getContent(); + continue; + } + + if (null === $client) { + $client = $r->client; + } elseif ($r->client !== $client) { + throw new TransportException('Cannot stream AsyncResponse objects with many clients.'); + } + + $asyncMap[$r->response] = $r; + $wrappedResponses[] = $r->response; + + if ($r->stream) { + yield from self::passthruStream($response = $r->response, $r, new FirstChunk(), $asyncMap); + + if (!isset($asyncMap[$response])) { + array_pop($wrappedResponses); + } + + if ($r->response !== $response && !isset($asyncMap[$r->response])) { + $asyncMap[$r->response] = $r; + $wrappedResponses[] = $r->response; + } + } + } + + if (!$client || !$wrappedResponses) { + return; + } + + foreach ($client->stream($wrappedResponses, $timeout) as $response => $chunk) { + $r = $asyncMap[$response]; + + if (null === $chunk->getError()) { + if ($chunk->isFirst()) { + // Ensure no exception is thrown on destruct for the wrapped response + $r->response->getStatusCode(); + } elseif (0 === $r->offset && null === $r->content && $chunk->isLast()) { + $r->content = fopen('php://memory', 'w+'); + } + } + + if (!$r->passthru) { + if (null !== $chunk->getError() || $chunk->isLast()) { + unset($asyncMap[$response]); + } elseif (null !== $r->content && '' !== ($content = $chunk->getContent()) && \strlen($content) !== fwrite($r->content, $content)) { + $chunk = new ErrorChunk($r->offset, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($content)))); + $r->info['error'] = $chunk->getError(); + $r->response->cancel(); + } + + yield $r => $chunk; + continue; + } + + if (null !== $chunk->getError()) { + // no-op + } elseif ($chunk->isFirst()) { + $r->yieldedState = self::FIRST_CHUNK_YIELDED; + } elseif (self::FIRST_CHUNK_YIELDED !== $r->yieldedState && null === $chunk->getInformationalStatus()) { + throw new \LogicException(sprintf('Instance of "%s" is already consumed and cannot be managed by "%s". A decorated client should not call any of the response\'s methods in its "request()" method.', get_debug_type($response), $class ?? static::class)); + } + + foreach (self::passthru($r->client, $r, $chunk, $asyncMap) as $chunk) { + yield $r => $chunk; + } + + if ($r->response !== $response && isset($asyncMap[$response])) { + break; + } + } + + if (null === $chunk->getError() && $chunk->isLast()) { + $r->yieldedState = self::LAST_CHUNK_YIELDED; + } + if (null === $chunk->getError() && self::LAST_CHUNK_YIELDED !== $r->yieldedState && $r->response === $response && null !== $r->client) { + throw new \LogicException('A chunk passthru must yield an "isLast()" chunk before ending a stream.'); + } + + $responses = []; + foreach ($asyncMap as $response) { + $r = $asyncMap[$response]; + + if (null !== $r->client) { + $responses[] = $asyncMap[$response]; + } + } + } + } + + /** + * @param \SplObjectStorage|null $asyncMap + */ + private static function passthru(HttpClientInterface $client, self $r, ChunkInterface $chunk, \SplObjectStorage $asyncMap = null): \Generator + { + $r->stream = null; + $response = $r->response; + $context = new AsyncContext($r->passthru, $client, $r->response, $r->info, $r->content, $r->offset); + if (null === $stream = ($r->passthru)($chunk, $context)) { + if ($r->response === $response && (null !== $chunk->getError() || $chunk->isLast())) { + throw new \LogicException('A chunk passthru cannot swallow the last chunk.'); + } + + return; + } + + if (!$stream instanceof \Iterator) { + throw new \LogicException(sprintf('A chunk passthru must return an "Iterator", "%s" returned.', get_debug_type($stream))); + } + $r->stream = $stream; + + yield from self::passthruStream($response, $r, null, $asyncMap); + } + + /** + * @param \SplObjectStorage|null $asyncMap + */ + private static function passthruStream(ResponseInterface $response, self $r, ?ChunkInterface $chunk, ?\SplObjectStorage $asyncMap): \Generator + { + while (true) { + try { + if (null !== $chunk && $r->stream) { + $r->stream->next(); + } + + if (!$r->stream || !$r->stream->valid() || !$r->stream) { + $r->stream = null; + break; + } + } catch (\Throwable $e) { + unset($asyncMap[$response]); + $r->stream = null; + $r->info['error'] = $e->getMessage(); + $r->response->cancel(); + + yield $r => $chunk = new ErrorChunk($r->offset, $e); + $chunk->didThrow() ?: $chunk->getContent(); + break; + } + + $chunk = $r->stream->current(); + + if (!$chunk instanceof ChunkInterface) { + throw new \LogicException(sprintf('A chunk passthru must yield instances of "%s", "%s" yielded.', ChunkInterface::class, get_debug_type($chunk))); + } + + if (null !== $chunk->getError()) { + // no-op + } elseif ($chunk->isFirst()) { + $e = $r->openBuffer(); + + yield $r => $chunk; + + if ($r->initializer && null === $r->getInfo('error')) { + // Ensure the HTTP status code is always checked + $r->getHeaders(true); + } + + if (null === $e) { + continue; + } + + $r->response->cancel(); + $chunk = new ErrorChunk($r->offset, $e); + } elseif ('' !== $content = $chunk->getContent()) { + if (null !== $r->shouldBuffer) { + throw new \LogicException('A chunk passthru must yield an "isFirst()" chunk before any content chunk.'); + } + + if (null !== $r->content && \strlen($content) !== fwrite($r->content, $content)) { + $chunk = new ErrorChunk($r->offset, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($content)))); + $r->info['error'] = $chunk->getError(); + $r->response->cancel(); + } + } + + if (null !== $chunk->getError() || $chunk->isLast()) { + $stream = $r->stream; + $r->stream = null; + unset($asyncMap[$response]); + } + + if (null === $chunk->getError()) { + $r->offset += \strlen($content); + + yield $r => $chunk; + + if (!$chunk->isLast()) { + continue; + } + + $stream->next(); + + if ($stream->valid()) { + throw new \LogicException('A chunk passthru cannot yield after an "isLast()" chunk.'); + } + + $r->passthru = null; + } else { + if ($chunk instanceof ErrorChunk) { + $chunk->didThrow(false); + } else { + try { + $chunk = new ErrorChunk($chunk->getOffset(), !$chunk->isTimeout() ?: $chunk->getError()); + } catch (TransportExceptionInterface $e) { + $chunk = new ErrorChunk($chunk->getOffset(), $e); + } + } + + yield $r => $chunk; + $chunk->didThrow() ?: $chunk->getContent(); + } + + break; + } + } + + private function openBuffer(): ?\Throwable + { + if (null === $shouldBuffer = $this->shouldBuffer) { + throw new \LogicException('A chunk passthru cannot yield more than one "isFirst()" chunk.'); + } + + $e = $this->shouldBuffer = null; + + if ($shouldBuffer instanceof \Closure) { + try { + $shouldBuffer = $shouldBuffer($this->getHeaders(false)); + + if (null !== $e = $this->response->getInfo('error')) { + throw new TransportException($e); + } + } catch (\Throwable $e) { + $this->info['error'] = $e->getMessage(); + $this->response->cancel(); + } + } + + if (true === $shouldBuffer) { + $this->content = fopen('php://temp', 'w+'); + } elseif (\is_resource($shouldBuffer)) { + $this->content = $shouldBuffer; + } + + return $e; + } + + private function close(): void + { + $this->response->cancel(); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/CommonResponseTrait.php b/sites/all/libraries/vendor/symfony/http-client/Response/CommonResponseTrait.php new file mode 100644 index 0000000000..11a8d6ca79 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/CommonResponseTrait.php @@ -0,0 +1,185 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Exception\ClientException; +use Symfony\Component\HttpClient\Exception\JsonException; +use Symfony\Component\HttpClient\Exception\RedirectionException; +use Symfony\Component\HttpClient\Exception\ServerException; +use Symfony\Component\HttpClient\Exception\TransportException; + +/** + * Implements common logic for response classes. + * + * @author Nicolas Grekas + * + * @internal + */ +trait CommonResponseTrait +{ + /** + * @var callable|null A callback that tells whether we're waiting for response headers + */ + private $initializer; + private $shouldBuffer; + private $content; + private $offset = 0; + private $jsonData; + + /** + * {@inheritdoc} + */ + public function getContent(bool $throw = true): string + { + if ($this->initializer) { + self::initialize($this); + } + + if ($throw) { + $this->checkStatusCode(); + } + + if (null === $this->content) { + $content = null; + + foreach (self::stream([$this]) as $chunk) { + if (!$chunk->isLast()) { + $content .= $chunk->getContent(); + } + } + + if (null !== $content) { + return $content; + } + + if (null === $this->content) { + throw new TransportException('Cannot get the content of the response twice: buffering is disabled.'); + } + } else { + foreach (self::stream([$this]) as $chunk) { + // Chunks are buffered in $this->content already + } + } + + rewind($this->content); + + return stream_get_contents($this->content); + } + + /** + * {@inheritdoc} + */ + public function toArray(bool $throw = true): array + { + if ('' === $content = $this->getContent($throw)) { + throw new JsonException('Response body is empty.'); + } + + if (null !== $this->jsonData) { + return $this->jsonData; + } + + try { + $content = json_decode($content, true, 512, \JSON_BIGINT_AS_STRING | (\PHP_VERSION_ID >= 70300 ? \JSON_THROW_ON_ERROR : 0)); + } catch (\JsonException $e) { + throw new JsonException($e->getMessage().sprintf(' for "%s".', $this->getInfo('url')), $e->getCode()); + } + + if (\PHP_VERSION_ID < 70300 && \JSON_ERROR_NONE !== json_last_error()) { + throw new JsonException(json_last_error_msg().sprintf(' for "%s".', $this->getInfo('url')), json_last_error()); + } + + if (!\is_array($content)) { + throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned for "%s".', get_debug_type($content), $this->getInfo('url'))); + } + + if (null !== $this->content) { + // Option "buffer" is true + return $this->jsonData = $content; + } + + return $content; + } + + /** + * {@inheritdoc} + */ + public function toStream(bool $throw = true) + { + if ($throw) { + // Ensure headers arrived + $this->getHeaders($throw); + } + + $stream = StreamWrapper::createResource($this); + stream_get_meta_data($stream)['wrapper_data'] + ->bindHandles($this->handle, $this->content); + + return $stream; + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + /** + * Closes the response and all its network handles. + */ + abstract protected function close(): void; + + private static function initialize(self $response): void + { + if (null !== $response->getInfo('error')) { + throw new TransportException($response->getInfo('error')); + } + + try { + if (($response->initializer)($response, -0.0)) { + foreach (self::stream([$response], -0.0) as $chunk) { + if ($chunk->isFirst()) { + break; + } + } + } + } catch (\Throwable $e) { + // Persist timeouts thrown during initialization + $response->info['error'] = $e->getMessage(); + $response->close(); + throw $e; + } + + $response->initializer = null; + } + + private function checkStatusCode() + { + $code = $this->getInfo('http_code'); + + if (500 <= $code) { + throw new ServerException($this); + } + + if (400 <= $code) { + throw new ClientException($this); + } + + if (300 <= $code) { + throw new RedirectionException($this); + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/CurlResponse.php b/sites/all/libraries/vendor/symfony/http-client/Response/CurlResponse.php new file mode 100644 index 0000000000..b03a49a946 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/CurlResponse.php @@ -0,0 +1,474 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Chunk\InformationalChunk; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\Canary; +use Symfony\Component\HttpClient\Internal\ClientState; +use Symfony\Component\HttpClient\Internal\CurlClientState; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class CurlResponse implements ResponseInterface, StreamableInterface +{ + use CommonResponseTrait { + getContent as private doGetContent; + } + use TransportResponseTrait; + + private static $performing = false; + private $multi; + private $debugBuffer; + + /** + * @param \CurlHandle|resource|string $ch + * + * @internal + */ + public function __construct(CurlClientState $multi, $ch, array $options = null, LoggerInterface $logger = null, string $method = 'GET', callable $resolveRedirect = null, int $curlVersion = null) + { + $this->multi = $multi; + + if (\is_resource($ch) || $ch instanceof \CurlHandle) { + $this->handle = $ch; + $this->debugBuffer = fopen('php://temp', 'w+'); + if (0x074000 === $curlVersion) { + fwrite($this->debugBuffer, 'Due to a bug in curl 7.64.0, the debug log is disabled; use another version to work around the issue.'); + } else { + curl_setopt($ch, \CURLOPT_VERBOSE, true); + curl_setopt($ch, \CURLOPT_STDERR, $this->debugBuffer); + } + } else { + $this->info['url'] = $ch; + $ch = $this->handle; + } + + $this->id = $id = (int) $ch; + $this->logger = $logger; + $this->shouldBuffer = $options['buffer'] ?? true; + $this->timeout = $options['timeout'] ?? null; + $this->info['http_method'] = $method; + $this->info['user_data'] = $options['user_data'] ?? null; + $this->info['max_duration'] = $options['max_duration'] ?? null; + $this->info['start_time'] = $this->info['start_time'] ?? microtime(true); + $info = &$this->info; + $headers = &$this->headers; + $debugBuffer = $this->debugBuffer; + + if (!$info['response_headers']) { + // Used to keep track of what we're waiting for + curl_setopt($ch, \CURLOPT_PRIVATE, \in_array($method, ['GET', 'HEAD', 'OPTIONS', 'TRACE'], true) && 1.0 < (float) ($options['http_version'] ?? 1.1) ? 'H2' : 'H0'); // H = headers + retry counter + } + + curl_setopt($ch, \CURLOPT_HEADERFUNCTION, static function ($ch, string $data) use (&$info, &$headers, $options, $multi, $id, &$location, $resolveRedirect, $logger): int { + if (0 !== substr_compare($data, "\r\n", -2)) { + return 0; + } + + $len = 0; + + foreach (explode("\r\n", substr($data, 0, -2)) as $data) { + $len += 2 + self::parseHeaderLine($ch, $data, $info, $headers, $options, $multi, $id, $location, $resolveRedirect, $logger); + } + + return $len; + }); + + if (null === $options) { + // Pushed response: buffer until requested + curl_setopt($ch, \CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int { + $multi->handlesActivity[$id][] = $data; + curl_pause($ch, \CURLPAUSE_RECV); + + return \strlen($data); + }); + + return; + } + + $execCounter = $multi->execCounter; + $this->info['pause_handler'] = static function (float $duration) use ($ch, $multi, $execCounter) { + if (0 < $duration) { + if ($execCounter === $multi->execCounter) { + $multi->execCounter = !\is_float($execCounter) ? 1 + $execCounter : \PHP_INT_MIN; + curl_multi_remove_handle($multi->handle, $ch); + } + + $lastExpiry = end($multi->pauseExpiries); + $multi->pauseExpiries[(int) $ch] = $duration += microtime(true); + if (false !== $lastExpiry && $lastExpiry > $duration) { + asort($multi->pauseExpiries); + } + curl_pause($ch, \CURLPAUSE_ALL); + } else { + unset($multi->pauseExpiries[(int) $ch]); + curl_pause($ch, \CURLPAUSE_CONT); + curl_multi_add_handle($multi->handle, $ch); + } + }; + + $this->inflate = !isset($options['normalized_headers']['accept-encoding']); + curl_pause($ch, \CURLPAUSE_CONT); + + if ($onProgress = $options['on_progress']) { + $url = isset($info['url']) ? ['url' => $info['url']] : []; + curl_setopt($ch, \CURLOPT_NOPROGRESS, false); + curl_setopt($ch, \CURLOPT_PROGRESSFUNCTION, static function ($ch, $dlSize, $dlNow) use ($onProgress, &$info, $url, $multi, $debugBuffer) { + try { + rewind($debugBuffer); + $debug = ['debug' => stream_get_contents($debugBuffer)]; + $onProgress($dlNow, $dlSize, $url + curl_getinfo($ch) + $info + $debug); + } catch (\Throwable $e) { + $multi->handlesActivity[(int) $ch][] = null; + $multi->handlesActivity[(int) $ch][] = $e; + + return 1; // Abort the request + } + + return null; + }); + } + + curl_setopt($ch, \CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int { + if ('H' === (curl_getinfo($ch, \CURLINFO_PRIVATE)[0] ?? null)) { + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = new TransportException(sprintf('Unsupported protocol for "%s"', curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL))); + + return 0; + } + + curl_setopt($ch, \CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int { + $multi->handlesActivity[$id][] = $data; + + return \strlen($data); + }); + + $multi->handlesActivity[$id][] = $data; + + return \strlen($data); + }); + + $this->initializer = static function (self $response) { + $waitFor = curl_getinfo($ch = $response->handle, \CURLINFO_PRIVATE); + + return 'H' === $waitFor[0]; + }; + + // Schedule the request in a non-blocking way + $multi->lastTimeout = null; + $multi->openHandles[$id] = [$ch, $options]; + curl_multi_add_handle($multi->handle, $ch); + + $this->canary = new Canary(static function () use ($ch, $multi, $id) { + unset($multi->pauseExpiries[$id], $multi->openHandles[$id], $multi->handlesActivity[$id]); + curl_setopt($ch, \CURLOPT_PRIVATE, '_0'); + + if (self::$performing) { + return; + } + + curl_multi_remove_handle($multi->handle, $ch); + curl_setopt_array($ch, [ + \CURLOPT_NOPROGRESS => true, + \CURLOPT_PROGRESSFUNCTION => null, + \CURLOPT_HEADERFUNCTION => null, + \CURLOPT_WRITEFUNCTION => null, + \CURLOPT_READFUNCTION => null, + \CURLOPT_INFILE => null, + ]); + + if (!$multi->openHandles) { + // Schedule DNS cache eviction for the next request + $multi->dnsCache->evictions = $multi->dnsCache->evictions ?: $multi->dnsCache->removals; + $multi->dnsCache->removals = $multi->dnsCache->hostnames = []; + } + }); + } + + /** + * {@inheritdoc} + */ + public function getInfo(string $type = null) + { + if (!$info = $this->finalInfo) { + $info = array_merge($this->info, curl_getinfo($this->handle)); + $info['url'] = $this->info['url'] ?? $info['url']; + $info['redirect_url'] = $this->info['redirect_url'] ?? null; + + // workaround curl not subtracting the time offset for pushed responses + if (isset($this->info['url']) && $info['start_time'] / 1000 < $info['total_time']) { + $info['total_time'] -= $info['starttransfer_time'] ?: $info['total_time']; + $info['starttransfer_time'] = 0.0; + } + + rewind($this->debugBuffer); + $info['debug'] = stream_get_contents($this->debugBuffer); + $waitFor = curl_getinfo($this->handle, \CURLINFO_PRIVATE); + + if ('H' !== $waitFor[0] && 'C' !== $waitFor[0]) { + curl_setopt($this->handle, \CURLOPT_VERBOSE, false); + rewind($this->debugBuffer); + ftruncate($this->debugBuffer, 0); + $this->finalInfo = $info; + } + } + + return null !== $type ? $info[$type] ?? null : $info; + } + + /** + * {@inheritdoc} + */ + public function getContent(bool $throw = true): string + { + $performing = self::$performing; + self::$performing = $performing || '_0' === curl_getinfo($this->handle, \CURLINFO_PRIVATE); + + try { + return $this->doGetContent($throw); + } finally { + self::$performing = $performing; + } + } + + public function __destruct() + { + try { + if (null === $this->timeout) { + return; // Unused pushed response + } + + $this->doDestruct(); + } finally { + if (\is_resource($this->handle) || $this->handle instanceof \CurlHandle) { + curl_setopt($this->handle, \CURLOPT_VERBOSE, false); + } + } + } + + /** + * {@inheritdoc} + */ + private static function schedule(self $response, array &$runningResponses): void + { + if (isset($runningResponses[$i = (int) $response->multi->handle])) { + $runningResponses[$i][1][$response->id] = $response; + } else { + $runningResponses[$i] = [$response->multi, [$response->id => $response]]; + } + + if ('_0' === curl_getinfo($ch = $response->handle, \CURLINFO_PRIVATE)) { + // Response already completed + $response->multi->handlesActivity[$response->id][] = null; + $response->multi->handlesActivity[$response->id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null; + } + } + + /** + * {@inheritdoc} + * + * @param CurlClientState $multi + */ + private static function perform(ClientState $multi, array &$responses = null): void + { + if (self::$performing) { + if ($responses) { + $response = current($responses); + $multi->handlesActivity[(int) $response->handle][] = null; + $multi->handlesActivity[(int) $response->handle][] = new TransportException(sprintf('Userland callback cannot use the client nor the response while processing "%s".', curl_getinfo($response->handle, \CURLINFO_EFFECTIVE_URL))); + } + + return; + } + + try { + self::$performing = true; + ++$multi->execCounter; + $active = 0; + while (\CURLM_CALL_MULTI_PERFORM === ($err = curl_multi_exec($multi->handle, $active))) { + } + + if (\CURLM_OK !== $err) { + throw new TransportException(curl_multi_strerror($err)); + } + + while ($info = curl_multi_info_read($multi->handle)) { + if (\CURLMSG_DONE !== $info['msg']) { + continue; + } + $result = $info['result']; + $id = (int) $ch = $info['handle']; + $waitFor = @curl_getinfo($ch, \CURLINFO_PRIVATE) ?: '_0'; + + if (\in_array($result, [\CURLE_SEND_ERROR, \CURLE_RECV_ERROR, /* CURLE_HTTP2 */ 16, /* CURLE_HTTP2_STREAM */ 92], true) && $waitFor[1] && 'C' !== $waitFor[0]) { + curl_multi_remove_handle($multi->handle, $ch); + $waitFor[1] = (string) ((int) $waitFor[1] - 1); // decrement the retry counter + curl_setopt($ch, \CURLOPT_PRIVATE, $waitFor); + curl_setopt($ch, \CURLOPT_FORBID_REUSE, true); + + if (0 === curl_multi_add_handle($multi->handle, $ch)) { + continue; + } + } + + if (\CURLE_RECV_ERROR === $result && 'H' === $waitFor[0] && 400 <= ($responses[(int) $ch]->info['http_code'] ?? 0)) { + $multi->handlesActivity[$id][] = new FirstChunk(); + } + + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = \in_array($result, [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || '_0' === $waitFor || curl_getinfo($ch, \CURLINFO_SIZE_DOWNLOAD) === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) ? null : new TransportException(ucfirst(curl_error($ch) ?: curl_strerror($result)).sprintf(' for "%s".', curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL))); + } + } finally { + self::$performing = false; + } + } + + /** + * {@inheritdoc} + * + * @param CurlClientState $multi + */ + private static function select(ClientState $multi, float $timeout): int + { + if (\PHP_VERSION_ID < 70211) { + // workaround https://bugs.php.net/76480 + $timeout = min($timeout, 0.01); + } + + if ($multi->pauseExpiries) { + $now = microtime(true); + + foreach ($multi->pauseExpiries as $id => $pauseExpiry) { + if ($now < $pauseExpiry) { + $timeout = min($timeout, $pauseExpiry - $now); + break; + } + + unset($multi->pauseExpiries[$id]); + curl_pause($multi->openHandles[$id][0], \CURLPAUSE_CONT); + curl_multi_add_handle($multi->handle, $multi->openHandles[$id][0]); + } + } + + if (0 !== $selected = curl_multi_select($multi->handle, $timeout)) { + return $selected; + } + + if ($multi->pauseExpiries && 0 < $timeout -= microtime(true) - $now) { + usleep((int) (1E6 * $timeout)); + } + + return 0; + } + + /** + * Parses header lines as curl yields them to us. + */ + private static function parseHeaderLine($ch, string $data, array &$info, array &$headers, ?array $options, CurlClientState $multi, int $id, ?string &$location, ?callable $resolveRedirect, ?LoggerInterface $logger): int + { + $waitFor = @curl_getinfo($ch, \CURLINFO_PRIVATE) ?: '_0'; + + if ('H' !== $waitFor[0]) { + return \strlen($data); // Ignore HTTP trailers + } + + if ('' !== $data) { + // Regular header line: add it to the list + self::addResponseHeaders([$data], $info, $headers); + + if (!str_starts_with($data, 'HTTP/')) { + if (0 === stripos($data, 'Location:')) { + $location = trim(substr($data, 9)); + } + + return \strlen($data); + } + + if (\function_exists('openssl_x509_read') && $certinfo = curl_getinfo($ch, \CURLINFO_CERTINFO)) { + $info['peer_certificate_chain'] = array_map('openssl_x509_read', array_column($certinfo, 'Cert')); + } + + if (300 <= $info['http_code'] && $info['http_code'] < 400) { + if (curl_getinfo($ch, \CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) { + curl_setopt($ch, \CURLOPT_FOLLOWLOCATION, false); + } elseif (303 === $info['http_code'] || ('POST' === $info['http_method'] && \in_array($info['http_code'], [301, 302], true))) { + curl_setopt($ch, \CURLOPT_POSTFIELDS, ''); + } + } + + return \strlen($data); + } + + // End of headers: handle informational responses, redirects, etc. + + if (200 > $statusCode = curl_getinfo($ch, \CURLINFO_RESPONSE_CODE)) { + $multi->handlesActivity[$id][] = new InformationalChunk($statusCode, $headers); + $location = null; + + return \strlen($data); + } + + $info['redirect_url'] = null; + + if (300 <= $statusCode && $statusCode < 400 && null !== $location) { + if ($noContent = 303 === $statusCode || ('POST' === $info['http_method'] && \in_array($statusCode, [301, 302], true))) { + $info['http_method'] = 'HEAD' === $info['http_method'] ? 'HEAD' : 'GET'; + curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, $info['http_method']); + } + + if (null === $info['redirect_url'] = $resolveRedirect($ch, $location, $noContent)) { + $options['max_redirects'] = curl_getinfo($ch, \CURLINFO_REDIRECT_COUNT); + curl_setopt($ch, \CURLOPT_FOLLOWLOCATION, false); + curl_setopt($ch, \CURLOPT_MAXREDIRS, $options['max_redirects']); + } else { + $url = parse_url($location ?? ':'); + + if (isset($url['host']) && null !== $ip = $multi->dnsCache->hostnames[$url['host'] = strtolower($url['host'])] ?? null) { + // Populate DNS cache for redirects if needed + $port = $url['port'] ?? ('http' === ($url['scheme'] ?? parse_url(curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL), \PHP_URL_SCHEME)) ? 80 : 443); + curl_setopt($ch, \CURLOPT_RESOLVE, ["{$url['host']}:$port:$ip"]); + $multi->dnsCache->removals["-{$url['host']}:$port"] = "-{$url['host']}:$port"; + } + } + } + + if (401 === $statusCode && isset($options['auth_ntlm']) && 0 === strncasecmp($headers['www-authenticate'][0] ?? '', 'NTLM ', 5)) { + // Continue with NTLM auth + } elseif ($statusCode < 300 || 400 <= $statusCode || null === $location || curl_getinfo($ch, \CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) { + // Headers and redirects completed, time to get the response's content + $multi->handlesActivity[$id][] = new FirstChunk(); + + if ('HEAD' === $info['http_method'] || \in_array($statusCode, [204, 304], true)) { + $waitFor = '_0'; // no content expected + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = null; + } else { + $waitFor[0] = 'C'; // C = content + } + + curl_setopt($ch, \CURLOPT_PRIVATE, $waitFor); + } elseif (null !== $info['redirect_url'] && $logger) { + $logger->info(sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url'])); + } + + $location = null; + + return \strlen($data); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/HttplugPromise.php b/sites/all/libraries/vendor/symfony/http-client/Response/HttplugPromise.php new file mode 100644 index 0000000000..2efacca763 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/HttplugPromise.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use GuzzleHttp\Promise\Create; +use GuzzleHttp\Promise\PromiseInterface as GuzzlePromiseInterface; +use Http\Promise\Promise as HttplugPromiseInterface; +use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface; + +/** + * @author Tobias Nyholm + * + * @internal + */ +final class HttplugPromise implements HttplugPromiseInterface +{ + private $promise; + + public function __construct(GuzzlePromiseInterface $promise) + { + $this->promise = $promise; + } + + public function then(callable $onFulfilled = null, callable $onRejected = null): self + { + return new self($this->promise->then( + $this->wrapThenCallback($onFulfilled), + $this->wrapThenCallback($onRejected) + )); + } + + public function cancel(): void + { + $this->promise->cancel(); + } + + /** + * {@inheritdoc} + */ + public function getState(): string + { + return $this->promise->getState(); + } + + /** + * {@inheritdoc} + * + * @return Psr7ResponseInterface|mixed + */ + public function wait($unwrap = true) + { + $result = $this->promise->wait($unwrap); + + while ($result instanceof HttplugPromiseInterface || $result instanceof GuzzlePromiseInterface) { + $result = $result->wait($unwrap); + } + + return $result; + } + + private function wrapThenCallback(?callable $callback): ?callable + { + if (null === $callback) { + return null; + } + + return static function ($value) use ($callback) { + return Create::promiseFor($callback($value)); + }; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/MockResponse.php b/sites/all/libraries/vendor/symfony/http-client/Response/MockResponse.php new file mode 100644 index 0000000000..6420aa05de --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/MockResponse.php @@ -0,0 +1,339 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\ClientState; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * A test-friendly response. + * + * @author Nicolas Grekas + */ +class MockResponse implements ResponseInterface, StreamableInterface +{ + use CommonResponseTrait; + use TransportResponseTrait { + doDestruct as public __destruct; + } + + private $body; + private $requestOptions = []; + private $requestUrl; + private $requestMethod; + + private static $mainMulti; + private static $idSequence = 0; + + /** + * @param string|string[]|iterable $body The response body as a string or an iterable of strings, + * yielding an empty string simulates an idle timeout, + * throwing an exception yields an ErrorChunk + * + * @see ResponseInterface::getInfo() for possible info, e.g. "response_headers" + */ + public function __construct($body = '', array $info = []) + { + $this->body = is_iterable($body) ? $body : (string) $body; + $this->info = $info + ['http_code' => 200] + $this->info; + + if (!isset($info['response_headers'])) { + return; + } + + $responseHeaders = []; + + foreach ($info['response_headers'] as $k => $v) { + foreach ((array) $v as $v) { + $responseHeaders[] = (\is_string($k) ? $k.': ' : '').$v; + } + } + + $this->info['response_headers'] = []; + self::addResponseHeaders($responseHeaders, $this->info, $this->headers); + } + + /** + * Returns the options used when doing the request. + */ + public function getRequestOptions(): array + { + return $this->requestOptions; + } + + /** + * Returns the URL used when doing the request. + */ + public function getRequestUrl(): string + { + return $this->requestUrl; + } + + /** + * Returns the method used when doing the request. + */ + public function getRequestMethod(): string + { + return $this->requestMethod; + } + + /** + * {@inheritdoc} + */ + public function getInfo(string $type = null) + { + return null !== $type ? $this->info[$type] ?? null : $this->info; + } + + /** + * {@inheritdoc} + */ + public function cancel(): void + { + $this->info['canceled'] = true; + $this->info['error'] = 'Response has been canceled.'; + try { + $this->body = null; + } catch (TransportException $e) { + // ignore errors when canceling + } + } + + /** + * {@inheritdoc} + */ + protected function close(): void + { + $this->inflate = null; + $this->body = []; + } + + /** + * @internal + */ + public static function fromRequest(string $method, string $url, array $options, ResponseInterface $mock): self + { + $response = new self([]); + $response->requestOptions = $options; + $response->id = ++self::$idSequence; + $response->shouldBuffer = $options['buffer'] ?? true; + $response->initializer = static function (self $response) { + return \is_array($response->body[0] ?? null); + }; + + $response->info['redirect_count'] = 0; + $response->info['redirect_url'] = null; + $response->info['start_time'] = microtime(true); + $response->info['http_method'] = $method; + $response->info['http_code'] = 0; + $response->info['user_data'] = $options['user_data'] ?? null; + $response->info['max_duration'] = $options['max_duration'] ?? null; + $response->info['url'] = $url; + + if ($mock instanceof self) { + $mock->requestOptions = $response->requestOptions; + $mock->requestMethod = $method; + $mock->requestUrl = $url; + } + + self::writeRequest($response, $options, $mock); + $response->body[] = [$options, $mock]; + + return $response; + } + + /** + * {@inheritdoc} + */ + protected static function schedule(self $response, array &$runningResponses): void + { + if (!$response->id) { + throw new InvalidArgumentException('MockResponse instances must be issued by MockHttpClient before processing.'); + } + + $multi = self::$mainMulti ?? self::$mainMulti = new ClientState(); + + if (!isset($runningResponses[0])) { + $runningResponses[0] = [$multi, []]; + } + + $runningResponses[0][1][$response->id] = $response; + } + + /** + * {@inheritdoc} + */ + protected static function perform(ClientState $multi, array &$responses): void + { + foreach ($responses as $response) { + $id = $response->id; + + if (null === $response->body) { + // Canceled response + $response->body = []; + } elseif ([] === $response->body) { + // Error chunk + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null; + } elseif (null === $chunk = array_shift($response->body)) { + // Last chunk + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = array_shift($response->body); + } elseif (\is_array($chunk)) { + // First chunk + try { + $offset = 0; + $chunk[1]->getStatusCode(); + $chunk[1]->getHeaders(false); + self::readResponse($response, $chunk[0], $chunk[1], $offset); + $multi->handlesActivity[$id][] = new FirstChunk(); + $buffer = $response->requestOptions['buffer'] ?? null; + + if ($buffer instanceof \Closure && $response->content = $buffer($response->headers) ?: null) { + $response->content = \is_resource($response->content) ? $response->content : fopen('php://temp', 'w+'); + } + } catch (\Throwable $e) { + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = $e; + } + } elseif ($chunk instanceof \Throwable) { + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = $chunk; + } else { + // Data or timeout chunk + $multi->handlesActivity[$id][] = $chunk; + } + } + } + + /** + * {@inheritdoc} + */ + protected static function select(ClientState $multi, float $timeout): int + { + return 42; + } + + /** + * Simulates sending the request. + */ + private static function writeRequest(self $response, array $options, ResponseInterface $mock) + { + $onProgress = $options['on_progress'] ?? static function () {}; + $response->info += $mock->getInfo() ?: []; + + // simulate "size_upload" if it is set + if (isset($response->info['size_upload'])) { + $response->info['size_upload'] = 0.0; + } + + // simulate "total_time" if it is not set + if (!isset($response->info['total_time'])) { + $response->info['total_time'] = microtime(true) - $response->info['start_time']; + } + + // "notify" DNS resolution + $onProgress(0, 0, $response->info); + + // consume the request body + if (\is_resource($body = $options['body'] ?? '')) { + $data = stream_get_contents($body); + if (isset($response->info['size_upload'])) { + $response->info['size_upload'] += \strlen($data); + } + } elseif ($body instanceof \Closure) { + while ('' !== $data = $body(16372)) { + if (!\is_string($data)) { + throw new TransportException(sprintf('Return value of the "body" option callback must be string, "%s" returned.', get_debug_type($data))); + } + + // "notify" upload progress + if (isset($response->info['size_upload'])) { + $response->info['size_upload'] += \strlen($data); + } + + $onProgress(0, 0, $response->info); + } + } + } + + /** + * Simulates reading the response. + */ + private static function readResponse(self $response, array $options, ResponseInterface $mock, int &$offset) + { + $onProgress = $options['on_progress'] ?? static function () {}; + + // populate info related to headers + $info = $mock->getInfo() ?: []; + $response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode() ?: 200; + $response->addResponseHeaders($info['response_headers'] ?? [], $response->info, $response->headers); + $dlSize = isset($response->headers['content-encoding']) || 'HEAD' === $response->info['http_method'] || \in_array($response->info['http_code'], [204, 304], true) ? 0 : (int) ($response->headers['content-length'][0] ?? 0); + + $response->info = [ + 'start_time' => $response->info['start_time'], + 'user_data' => $response->info['user_data'], + 'max_duration' => $response->info['max_duration'], + 'http_code' => $response->info['http_code'], + ] + $info + $response->info; + + if (null !== $response->info['error']) { + throw new TransportException($response->info['error']); + } + + if (!isset($response->info['total_time'])) { + $response->info['total_time'] = microtime(true) - $response->info['start_time']; + } + + // "notify" headers arrival + $onProgress(0, $dlSize, $response->info); + + // cast response body to activity list + $body = $mock instanceof self ? $mock->body : $mock->getContent(false); + + if (!\is_string($body)) { + try { + foreach ($body as $chunk) { + if ('' === $chunk = (string) $chunk) { + // simulate an idle timeout + $response->body[] = new ErrorChunk($offset, sprintf('Idle timeout reached for "%s".', $response->info['url'])); + } else { + $response->body[] = $chunk; + $offset += \strlen($chunk); + // "notify" download progress + $onProgress($offset, $dlSize, $response->info); + } + } + } catch (\Throwable $e) { + $response->body[] = $e; + } + } elseif ('' !== $body) { + $response->body[] = $body; + $offset = \strlen($body); + } + + if (!isset($response->info['total_time'])) { + $response->info['total_time'] = microtime(true) - $response->info['start_time']; + } + + // "notify" completion + $onProgress($offset, $dlSize, $response->info); + + if ($dlSize && $offset !== $dlSize) { + throw new TransportException(sprintf('Transfer closed with %d bytes remaining to read.', $dlSize - $offset)); + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/NativeResponse.php b/sites/all/libraries/vendor/symfony/http-client/Response/NativeResponse.php new file mode 100644 index 0000000000..c00e946f63 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/NativeResponse.php @@ -0,0 +1,376 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\Canary; +use Symfony\Component\HttpClient\Internal\ClientState; +use Symfony\Component\HttpClient\Internal\NativeClientState; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class NativeResponse implements ResponseInterface, StreamableInterface +{ + use CommonResponseTrait; + use TransportResponseTrait; + + private $context; + private $url; + private $resolver; + private $onProgress; + private $remaining; + private $buffer; + private $multi; + private $pauseExpiry = 0; + + /** + * @internal + */ + public function __construct(NativeClientState $multi, $context, string $url, array $options, array &$info, callable $resolver, ?callable $onProgress, ?LoggerInterface $logger) + { + $this->multi = $multi; + $this->id = $id = (int) $context; + $this->context = $context; + $this->url = $url; + $this->logger = $logger; + $this->timeout = $options['timeout']; + $this->info = &$info; + $this->resolver = $resolver; + $this->onProgress = $onProgress; + $this->inflate = !isset($options['normalized_headers']['accept-encoding']); + $this->shouldBuffer = $options['buffer'] ?? true; + + // Temporary resource to dechunk the response stream + $this->buffer = fopen('php://temp', 'w+'); + + $info['user_data'] = $options['user_data']; + $info['max_duration'] = $options['max_duration']; + ++$multi->responseCount; + + $this->initializer = static function (self $response) { + return null === $response->remaining; + }; + + $pauseExpiry = &$this->pauseExpiry; + $info['pause_handler'] = static function (float $duration) use (&$pauseExpiry) { + $pauseExpiry = 0 < $duration ? microtime(true) + $duration : 0; + }; + + $this->canary = new Canary(static function () use ($multi, $id) { + if (null !== ($host = $multi->openHandles[$id][6] ?? null) && 0 >= --$multi->hosts[$host]) { + unset($multi->hosts[$host]); + } + unset($multi->openHandles[$id], $multi->handlesActivity[$id]); + }); + } + + /** + * {@inheritdoc} + */ + public function getInfo(string $type = null) + { + if (!$info = $this->finalInfo) { + $info = $this->info; + $info['url'] = implode('', $info['url']); + unset($info['size_body'], $info['request_header']); + + if (null === $this->buffer) { + $this->finalInfo = $info; + } + } + + return null !== $type ? $info[$type] ?? null : $info; + } + + public function __destruct() + { + try { + $this->doDestruct(); + } finally { + // Clear the DNS cache when all requests completed + if (0 >= --$this->multi->responseCount) { + $this->multi->responseCount = 0; + $this->multi->dnsCache = []; + } + } + } + + private function open(): void + { + $url = $this->url; + + set_error_handler(function ($type, $msg) use (&$url) { + if (\E_NOTICE !== $type || 'fopen(): Content-type not specified assuming application/x-www-form-urlencoded' !== $msg) { + throw new TransportException($msg); + } + + $this->logger && $this->logger->info(sprintf('%s for "%s".', $msg, $url ?? $this->url)); + }); + + try { + $this->info['start_time'] = microtime(true); + + [$resolver, $url] = ($this->resolver)($this->multi); + + while (true) { + $context = stream_context_get_options($this->context); + + if ($proxy = $context['http']['proxy'] ?? null) { + $this->info['debug'] .= "* Establish HTTP proxy tunnel to {$proxy}\n"; + $this->info['request_header'] = $url; + } else { + $this->info['debug'] .= "* Trying {$this->info['primary_ip']}...\n"; + $this->info['request_header'] = $this->info['url']['path'].$this->info['url']['query']; + } + + $this->info['request_header'] = sprintf("> %s %s HTTP/%s \r\n", $context['http']['method'], $this->info['request_header'], $context['http']['protocol_version']); + $this->info['request_header'] .= implode("\r\n", $context['http']['header'])."\r\n\r\n"; + + if (\array_key_exists('peer_name', $context['ssl']) && null === $context['ssl']['peer_name']) { + unset($context['ssl']['peer_name']); + $this->context = stream_context_create([], ['options' => $context] + stream_context_get_params($this->context)); + } + + // Send request and follow redirects when needed + $this->handle = $h = fopen($url, 'r', false, $this->context); + self::addResponseHeaders(stream_get_meta_data($h)['wrapper_data'], $this->info, $this->headers, $this->info['debug']); + $url = $resolver($this->multi, $this->headers['location'][0] ?? null, $this->context); + + if (null === $url) { + break; + } + + $this->logger && $this->logger->info(sprintf('Redirecting: "%s %s"', $this->info['http_code'], $url ?? $this->url)); + } + } catch (\Throwable $e) { + $this->close(); + $this->multi->handlesActivity[$this->id][] = null; + $this->multi->handlesActivity[$this->id][] = $e; + + return; + } finally { + $this->info['pretransfer_time'] = $this->info['total_time'] = microtime(true) - $this->info['start_time']; + restore_error_handler(); + } + + if (isset($context['ssl']['capture_peer_cert_chain']) && isset(($context = stream_context_get_options($this->context))['ssl']['peer_certificate_chain'])) { + $this->info['peer_certificate_chain'] = $context['ssl']['peer_certificate_chain']; + } + + stream_set_blocking($h, false); + $this->context = $this->resolver = null; + + // Create dechunk buffers + if (isset($this->headers['content-length'])) { + $this->remaining = (int) $this->headers['content-length'][0]; + } elseif ('chunked' === ($this->headers['transfer-encoding'][0] ?? null)) { + stream_filter_append($this->buffer, 'dechunk', \STREAM_FILTER_WRITE); + $this->remaining = -1; + } else { + $this->remaining = -2; + } + + $this->multi->handlesActivity[$this->id] = [new FirstChunk()]; + + if ('HEAD' === $context['http']['method'] || \in_array($this->info['http_code'], [204, 304], true)) { + $this->multi->handlesActivity[$this->id][] = null; + $this->multi->handlesActivity[$this->id][] = null; + + return; + } + + $host = parse_url($this->info['redirect_url'] ?? $this->url, \PHP_URL_HOST); + $this->multi->lastTimeout = null; + $this->multi->openHandles[$this->id] = [&$this->pauseExpiry, $h, $this->buffer, $this->onProgress, &$this->remaining, &$this->info, $host]; + $this->multi->hosts[$host] = 1 + ($this->multi->hosts[$host] ?? 0); + } + + /** + * {@inheritdoc} + */ + private function close(): void + { + $this->canary->cancel(); + $this->handle = $this->buffer = $this->inflate = $this->onProgress = null; + } + + /** + * {@inheritdoc} + */ + private static function schedule(self $response, array &$runningResponses): void + { + if (!isset($runningResponses[$i = $response->multi->id])) { + $runningResponses[$i] = [$response->multi, []]; + } + + $runningResponses[$i][1][$response->id] = $response; + + if (null === $response->buffer) { + // Response already completed + $response->multi->handlesActivity[$response->id][] = null; + $response->multi->handlesActivity[$response->id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null; + } + } + + /** + * {@inheritdoc} + * + * @param NativeClientState $multi + */ + private static function perform(ClientState $multi, array &$responses = null): void + { + foreach ($multi->openHandles as $i => [$pauseExpiry, $h, $buffer, $onProgress]) { + if ($pauseExpiry) { + if (microtime(true) < $pauseExpiry) { + continue; + } + + $multi->openHandles[$i][0] = 0; + } + + $hasActivity = false; + $remaining = &$multi->openHandles[$i][4]; + $info = &$multi->openHandles[$i][5]; + $e = null; + + // Read incoming buffer and write it to the dechunk one + try { + if ($remaining && '' !== $data = (string) fread($h, 0 > $remaining ? 16372 : $remaining)) { + fwrite($buffer, $data); + $hasActivity = true; + $multi->sleep = false; + + if (-1 !== $remaining) { + $remaining -= \strlen($data); + } + } + } catch (\Throwable $e) { + $hasActivity = $onProgress = false; + } + + if (!$hasActivity) { + if ($onProgress) { + try { + // Notify the progress callback so that it can e.g. cancel + // the request if the stream is inactive for too long + $info['total_time'] = microtime(true) - $info['start_time']; + $onProgress(); + } catch (\Throwable $e) { + // no-op + } + } + } elseif ('' !== $data = stream_get_contents($buffer, -1, 0)) { + rewind($buffer); + ftruncate($buffer, 0); + + if (null === $e) { + $multi->handlesActivity[$i][] = $data; + } + } + + if (null !== $e || !$remaining || feof($h)) { + // Stream completed + $info['total_time'] = microtime(true) - $info['start_time']; + $info['starttransfer_time'] = $info['starttransfer_time'] ?: $info['total_time']; + + if ($onProgress) { + try { + $onProgress(-1); + } catch (\Throwable $e) { + // no-op + } + } + + if (null === $e) { + if (0 < $remaining) { + $e = new TransportException(sprintf('Transfer closed with %s bytes remaining to read.', $remaining)); + } elseif (-1 === $remaining && fwrite($buffer, '-') && '' !== stream_get_contents($buffer, -1, 0)) { + $e = new TransportException('Transfer closed with outstanding data remaining from chunked response.'); + } + } + + $multi->handlesActivity[$i][] = null; + $multi->handlesActivity[$i][] = $e; + if (null !== ($host = $multi->openHandles[$i][6] ?? null) && 0 >= --$multi->hosts[$host]) { + unset($multi->hosts[$host]); + } + unset($multi->openHandles[$i]); + $multi->sleep = false; + } + } + + if (null === $responses) { + return; + } + + $maxHosts = $multi->maxHostConnections; + + foreach ($responses as $i => $response) { + if (null !== $response->remaining || null === $response->buffer) { + continue; + } + + if ($response->pauseExpiry && microtime(true) < $response->pauseExpiry) { + // Create empty open handles to tell we still have pending requests + $multi->openHandles[$i] = [\INF, null, null, null]; + } elseif ($maxHosts && $maxHosts > ($multi->hosts[parse_url($response->url, \PHP_URL_HOST)] ?? 0)) { + // Open the next pending request - this is a blocking operation so we do only one of them + $response->open(); + $multi->sleep = false; + self::perform($multi); + $maxHosts = 0; + } + } + } + + /** + * {@inheritdoc} + * + * @param NativeClientState $multi + */ + private static function select(ClientState $multi, float $timeout): int + { + if (!$multi->sleep = !$multi->sleep) { + return -1; + } + + $_ = $handles = []; + $now = null; + + foreach ($multi->openHandles as [$pauseExpiry, $h]) { + if (null === $h) { + continue; + } + + if ($pauseExpiry && ($now ?? $now = microtime(true)) < $pauseExpiry) { + $timeout = min($timeout, $pauseExpiry - $now); + continue; + } + + $handles[] = $h; + } + + if (!$handles) { + usleep((int) (1E6 * $timeout)); + + return 0; + } + + return stream_select($handles, $_, $_, (int) $timeout, (int) (1E6 * ($timeout - (int) $timeout))); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/ResponseStream.php b/sites/all/libraries/vendor/symfony/http-client/Response/ResponseStream.php new file mode 100644 index 0000000000..f86d2d4077 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/ResponseStream.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Contracts\HttpClient\ChunkInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; + +/** + * @author Nicolas Grekas + */ +final class ResponseStream implements ResponseStreamInterface +{ + private $generator; + + public function __construct(\Generator $generator) + { + $this->generator = $generator; + } + + public function key(): ResponseInterface + { + return $this->generator->key(); + } + + public function current(): ChunkInterface + { + return $this->generator->current(); + } + + public function next(): void + { + $this->generator->next(); + } + + public function rewind(): void + { + $this->generator->rewind(); + } + + public function valid(): bool + { + return $this->generator->valid(); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/StreamWrapper.php b/sites/all/libraries/vendor/symfony/http-client/Response/StreamWrapper.php new file mode 100644 index 0000000000..50a7c36623 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/StreamWrapper.php @@ -0,0 +1,313 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * Allows turning ResponseInterface instances to PHP streams. + * + * @author Nicolas Grekas + */ +class StreamWrapper +{ + /** @var resource|null */ + public $context; + + /** @var HttpClientInterface */ + private $client; + + /** @var ResponseInterface */ + private $response; + + /** @var resource|string|null */ + private $content; + + /** @var resource|null */ + private $handle; + + private $blocking = true; + private $timeout; + private $eof = false; + private $offset = 0; + + /** + * Creates a PHP stream resource from a ResponseInterface. + * + * @return resource + */ + public static function createResource(ResponseInterface $response, HttpClientInterface $client = null) + { + if ($response instanceof StreamableInterface) { + $stack = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 2); + + if ($response !== ($stack[1]['object'] ?? null)) { + return $response->toStream(false); + } + } + + if (null === $client && !method_exists($response, 'stream')) { + throw new \InvalidArgumentException(sprintf('Providing a client to "%s()" is required when the response doesn\'t have any "stream()" method.', __CLASS__)); + } + + static $registered = false; + + if (!$registered = $registered || stream_wrapper_register(strtr(__CLASS__, '\\', '-'), __CLASS__)) { + throw new \RuntimeException(error_get_last()['message'] ?? 'Registering the "symfony" stream wrapper failed.'); + } + + $context = [ + 'client' => $client ?? $response, + 'response' => $response, + ]; + + return fopen(strtr(__CLASS__, '\\', '-').'://'.$response->getInfo('url'), 'r', false, stream_context_create(['symfony' => $context])); + } + + public function getResponse(): ResponseInterface + { + return $this->response; + } + + /** + * @param resource|callable|null $handle The resource handle that should be monitored when + * stream_select() is used on the created stream + * @param resource|null $content The seekable resource where the response body is buffered + */ + public function bindHandles(&$handle, &$content): void + { + $this->handle = &$handle; + $this->content = &$content; + $this->offset = null; + } + + public function stream_open(string $path, string $mode, int $options): bool + { + if ('r' !== $mode) { + if ($options & \STREAM_REPORT_ERRORS) { + trigger_error(sprintf('Invalid mode "%s": only "r" is supported.', $mode), \E_USER_WARNING); + } + + return false; + } + + $context = stream_context_get_options($this->context)['symfony'] ?? null; + $this->client = $context['client'] ?? null; + $this->response = $context['response'] ?? null; + $this->context = null; + + if (null !== $this->client && null !== $this->response) { + return true; + } + + if ($options & \STREAM_REPORT_ERRORS) { + trigger_error('Missing options "client" or "response" in "symfony" stream context.', \E_USER_WARNING); + } + + return false; + } + + public function stream_read(int $count) + { + if (\is_resource($this->content)) { + // Empty the internal activity list + foreach ($this->client->stream([$this->response], 0) as $chunk) { + try { + if (!$chunk->isTimeout() && $chunk->isFirst()) { + $this->response->getStatusCode(); // ignore 3/4/5xx + } + } catch (ExceptionInterface $e) { + trigger_error($e->getMessage(), \E_USER_WARNING); + + return false; + } + } + + if (0 !== fseek($this->content, $this->offset ?? 0)) { + return false; + } + + if ('' !== $data = fread($this->content, $count)) { + fseek($this->content, 0, \SEEK_END); + $this->offset += \strlen($data); + + return $data; + } + } + + if (\is_string($this->content)) { + if (\strlen($this->content) <= $count) { + $data = $this->content; + $this->content = null; + } else { + $data = substr($this->content, 0, $count); + $this->content = substr($this->content, $count); + } + $this->offset += \strlen($data); + + return $data; + } + + foreach ($this->client->stream([$this->response], $this->blocking ? $this->timeout : 0) as $chunk) { + try { + $this->eof = true; + $this->eof = !$chunk->isTimeout(); + + if (!$this->eof && !$this->blocking) { + return ''; + } + + $this->eof = $chunk->isLast(); + + if ($chunk->isFirst()) { + $this->response->getStatusCode(); // ignore 3/4/5xx + } + + if ('' !== $data = $chunk->getContent()) { + if (\strlen($data) > $count) { + if (null === $this->content) { + $this->content = substr($data, $count); + } + $data = substr($data, 0, $count); + } + $this->offset += \strlen($data); + + return $data; + } + } catch (ExceptionInterface $e) { + trigger_error($e->getMessage(), \E_USER_WARNING); + + return false; + } + } + + return ''; + } + + public function stream_set_option(int $option, int $arg1, ?int $arg2): bool + { + if (\STREAM_OPTION_BLOCKING === $option) { + $this->blocking = (bool) $arg1; + } elseif (\STREAM_OPTION_READ_TIMEOUT === $option) { + $this->timeout = $arg1 + $arg2 / 1e6; + } else { + return false; + } + + return true; + } + + public function stream_tell(): int + { + return $this->offset ?? 0; + } + + public function stream_eof(): bool + { + return $this->eof && !\is_string($this->content); + } + + public function stream_seek(int $offset, int $whence = \SEEK_SET): bool + { + if (null === $this->content && null === $this->offset) { + $this->response->getStatusCode(); + $this->offset = 0; + } + + if (!\is_resource($this->content) || 0 !== fseek($this->content, 0, \SEEK_END)) { + return false; + } + + $size = ftell($this->content); + + if (\SEEK_CUR === $whence) { + $offset += $this->offset ?? 0; + } + + if (\SEEK_END === $whence || $size < $offset) { + foreach ($this->client->stream([$this->response]) as $chunk) { + try { + if ($chunk->isFirst()) { + $this->response->getStatusCode(); // ignore 3/4/5xx + } + + // Chunks are buffered in $this->content already + $size += \strlen($chunk->getContent()); + + if (\SEEK_END !== $whence && $offset <= $size) { + break; + } + } catch (ExceptionInterface $e) { + trigger_error($e->getMessage(), \E_USER_WARNING); + + return false; + } + } + + if (\SEEK_END === $whence) { + $offset += $size; + } + } + + if (0 <= $offset && $offset <= $size) { + $this->eof = false; + $this->offset = $offset; + + return true; + } + + return false; + } + + public function stream_cast(int $castAs) + { + if (\STREAM_CAST_FOR_SELECT === $castAs) { + $this->response->getHeaders(false); + + return (\is_callable($this->handle) ? ($this->handle)() : $this->handle) ?? false; + } + + return false; + } + + public function stream_stat(): array + { + try { + $headers = $this->response->getHeaders(false); + } catch (ExceptionInterface $e) { + trigger_error($e->getMessage(), \E_USER_WARNING); + $headers = []; + } + + return [ + 'dev' => 0, + 'ino' => 0, + 'mode' => 33060, + 'nlink' => 0, + 'uid' => 0, + 'gid' => 0, + 'rdev' => 0, + 'size' => (int) ($headers['content-length'][0] ?? -1), + 'atime' => 0, + 'mtime' => strtotime($headers['last-modified'][0] ?? '') ?: 0, + 'ctime' => 0, + 'blksize' => 0, + 'blocks' => 0, + ]; + } + + private function __construct() + { + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/StreamableInterface.php b/sites/all/libraries/vendor/symfony/http-client/Response/StreamableInterface.php new file mode 100644 index 0000000000..eb1f9335c7 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/StreamableInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * @author Nicolas Grekas + */ +interface StreamableInterface +{ + /** + * Casts the response to a PHP stream resource. + * + * @return resource + * + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function toStream(bool $throw = true); +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/TraceableResponse.php b/sites/all/libraries/vendor/symfony/http-client/Response/TraceableResponse.php new file mode 100644 index 0000000000..d656c0a5f9 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/TraceableResponse.php @@ -0,0 +1,219 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Exception\ClientException; +use Symfony\Component\HttpClient\Exception\RedirectionException; +use Symfony\Component\HttpClient\Exception\ServerException; +use Symfony\Component\HttpClient\TraceableHttpClient; +use Symfony\Component\Stopwatch\StopwatchEvent; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class TraceableResponse implements ResponseInterface, StreamableInterface +{ + private $client; + private $response; + private $content; + private $event; + + public function __construct(HttpClientInterface $client, ResponseInterface $response, &$content, StopwatchEvent $event = null) + { + $this->client = $client; + $this->response = $response; + $this->content = &$content; + $this->event = $event; + } + + public function __sleep(): array + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + try { + $this->response->__destruct(); + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->stop(); + } + } + } + + public function getStatusCode(): int + { + try { + return $this->response->getStatusCode(); + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->lap(); + } + } + } + + public function getHeaders(bool $throw = true): array + { + try { + return $this->response->getHeaders($throw); + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->lap(); + } + } + } + + public function getContent(bool $throw = true): string + { + try { + if (false === $this->content) { + return $this->response->getContent($throw); + } + + return $this->content = $this->response->getContent(false); + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->stop(); + } + if ($throw) { + $this->checkStatusCode($this->response->getStatusCode()); + } + } + } + + public function toArray(bool $throw = true): array + { + try { + if (false === $this->content) { + return $this->response->toArray($throw); + } + + return $this->content = $this->response->toArray(false); + } finally { + if ($this->event && $this->event->isStarted()) { + $this->event->stop(); + } + if ($throw) { + $this->checkStatusCode($this->response->getStatusCode()); + } + } + } + + public function cancel(): void + { + $this->response->cancel(); + + if ($this->event && $this->event->isStarted()) { + $this->event->stop(); + } + } + + public function getInfo(string $type = null) + { + return $this->response->getInfo($type); + } + + /** + * Casts the response to a PHP stream resource. + * + * @return resource + * + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function toStream(bool $throw = true) + { + if ($throw) { + // Ensure headers arrived + $this->response->getHeaders(true); + } + + if ($this->response instanceof StreamableInterface) { + return $this->response->toStream(false); + } + + return StreamWrapper::createResource($this->response, $this->client); + } + + /** + * @internal + */ + public static function stream(HttpClientInterface $client, iterable $responses, ?float $timeout): \Generator + { + $wrappedResponses = []; + $traceableMap = new \SplObjectStorage(); + + foreach ($responses as $r) { + if (!$r instanceof self) { + throw new \TypeError(sprintf('"%s::stream()" expects parameter 1 to be an iterable of TraceableResponse objects, "%s" given.', TraceableHttpClient::class, get_debug_type($r))); + } + + $traceableMap[$r->response] = $r; + $wrappedResponses[] = $r->response; + if ($r->event && !$r->event->isStarted()) { + $r->event->start(); + } + } + + foreach ($client->stream($wrappedResponses, $timeout) as $r => $chunk) { + if ($traceableMap[$r]->event && $traceableMap[$r]->event->isStarted()) { + try { + if ($chunk->isTimeout() || !$chunk->isLast()) { + $traceableMap[$r]->event->lap(); + } else { + $traceableMap[$r]->event->stop(); + } + } catch (TransportExceptionInterface $e) { + $traceableMap[$r]->event->stop(); + if ($chunk instanceof ErrorChunk) { + $chunk->didThrow(false); + } else { + $chunk = new ErrorChunk($chunk->getOffset(), $e); + } + } + } + yield $traceableMap[$r] => $chunk; + } + } + + private function checkStatusCode(int $code) + { + if (500 <= $code) { + throw new ServerException($this); + } + + if (400 <= $code) { + throw new ClientException($this); + } + + if (300 <= $code) { + throw new RedirectionException($this); + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Response/TransportResponseTrait.php b/sites/all/libraries/vendor/symfony/http-client/Response/TransportResponseTrait.php new file mode 100644 index 0000000000..566d61e176 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Response/TransportResponseTrait.php @@ -0,0 +1,312 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Chunk\DataChunk; +use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Chunk\LastChunk; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\ClientState; + +/** + * Implements common logic for transport-level response classes. + * + * @author Nicolas Grekas + * + * @internal + */ +trait TransportResponseTrait +{ + private $canary; + private $headers = []; + private $info = [ + 'response_headers' => [], + 'http_code' => 0, + 'error' => null, + 'canceled' => false, + ]; + + /** @var object|resource */ + private $handle; + private $id; + private $timeout = 0; + private $inflate; + private $finalInfo; + private $logger; + + /** + * {@inheritdoc} + */ + public function getStatusCode(): int + { + if ($this->initializer) { + self::initialize($this); + } + + return $this->info['http_code']; + } + + /** + * {@inheritdoc} + */ + public function getHeaders(bool $throw = true): array + { + if ($this->initializer) { + self::initialize($this); + } + + if ($throw) { + $this->checkStatusCode(); + } + + return $this->headers; + } + + /** + * {@inheritdoc} + */ + public function cancel(): void + { + $this->info['canceled'] = true; + $this->info['error'] = 'Response has been canceled.'; + $this->close(); + } + + /** + * Closes the response and all its network handles. + */ + protected function close(): void + { + $this->canary->cancel(); + $this->inflate = null; + } + + /** + * Adds pending responses to the activity list. + */ + abstract protected static function schedule(self $response, array &$runningResponses): void; + + /** + * Performs all pending non-blocking operations. + */ + abstract protected static function perform(ClientState $multi, array &$responses): void; + + /** + * Waits for network activity. + */ + abstract protected static function select(ClientState $multi, float $timeout): int; + + private static function addResponseHeaders(array $responseHeaders, array &$info, array &$headers, string &$debug = ''): void + { + foreach ($responseHeaders as $h) { + if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? (\d\d\d)(?: |$)#', $h, $m)) { + if ($headers) { + $debug .= "< \r\n"; + $headers = []; + } + $info['http_code'] = (int) $m[1]; + } elseif (2 === \count($m = explode(':', $h, 2))) { + $headers[strtolower($m[0])][] = ltrim($m[1]); + } + + $debug .= "< {$h}\r\n"; + $info['response_headers'][] = $h; + } + + $debug .= "< \r\n"; + } + + /** + * Ensures the request is always sent and that the response code was checked. + */ + private function doDestruct() + { + $this->shouldBuffer = true; + + if ($this->initializer && null === $this->info['error']) { + self::initialize($this); + $this->checkStatusCode(); + } + } + + /** + * Implements an event loop based on a buffer activity queue. + * + * @param iterable $responses + * + * @internal + */ + public static function stream(iterable $responses, float $timeout = null): \Generator + { + $runningResponses = []; + + foreach ($responses as $response) { + self::schedule($response, $runningResponses); + } + + $lastActivity = microtime(true); + $elapsedTimeout = 0; + + if ($fromLastTimeout = 0.0 === $timeout && '-0' === (string) $timeout) { + $timeout = null; + } elseif ($fromLastTimeout = 0 > $timeout) { + $timeout = -$timeout; + } + + while (true) { + $hasActivity = false; + $timeoutMax = 0; + $timeoutMin = $timeout ?? \INF; + + /** @var ClientState $multi */ + foreach ($runningResponses as $i => [$multi]) { + $responses = &$runningResponses[$i][1]; + self::perform($multi, $responses); + + foreach ($responses as $j => $response) { + $timeoutMax = $timeout ?? max($timeoutMax, $response->timeout); + $timeoutMin = min($timeoutMin, $response->timeout, 1); + $chunk = false; + + if ($fromLastTimeout && null !== $multi->lastTimeout) { + $elapsedTimeout = microtime(true) - $multi->lastTimeout; + } + + if (isset($multi->handlesActivity[$j])) { + $multi->lastTimeout = null; + } elseif (!isset($multi->openHandles[$j])) { + unset($responses[$j]); + continue; + } elseif ($elapsedTimeout >= $timeoutMax) { + $multi->handlesActivity[$j] = [new ErrorChunk($response->offset, sprintf('Idle timeout reached for "%s".', $response->getInfo('url')))]; + $multi->lastTimeout ?? $multi->lastTimeout = $lastActivity; + } else { + continue; + } + + while ($multi->handlesActivity[$j] ?? false) { + $hasActivity = true; + $elapsedTimeout = 0; + + if (\is_string($chunk = array_shift($multi->handlesActivity[$j]))) { + if (null !== $response->inflate && false === $chunk = @inflate_add($response->inflate, $chunk)) { + $multi->handlesActivity[$j] = [null, new TransportException(sprintf('Error while processing content unencoding for "%s".', $response->getInfo('url')))]; + continue; + } + + if ('' !== $chunk && null !== $response->content && \strlen($chunk) !== fwrite($response->content, $chunk)) { + $multi->handlesActivity[$j] = [null, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($chunk)))]; + continue; + } + + $chunkLen = \strlen($chunk); + $chunk = new DataChunk($response->offset, $chunk); + $response->offset += $chunkLen; + } elseif (null === $chunk) { + $e = $multi->handlesActivity[$j][0]; + unset($responses[$j], $multi->handlesActivity[$j]); + $response->close(); + + if (null !== $e) { + $response->info['error'] = $e->getMessage(); + + if ($e instanceof \Error) { + throw $e; + } + + $chunk = new ErrorChunk($response->offset, $e); + } else { + if (0 === $response->offset && null === $response->content) { + $response->content = fopen('php://memory', 'w+'); + } + + $chunk = new LastChunk($response->offset); + } + } elseif ($chunk instanceof ErrorChunk) { + unset($responses[$j]); + $elapsedTimeout = $timeoutMax; + } elseif ($chunk instanceof FirstChunk) { + if ($response->logger) { + $info = $response->getInfo(); + $response->logger->info(sprintf('Response: "%s %s"', $info['http_code'], $info['url'])); + } + + $response->inflate = \extension_loaded('zlib') && $response->inflate && 'gzip' === ($response->headers['content-encoding'][0] ?? null) ? inflate_init(\ZLIB_ENCODING_GZIP) : null; + + if ($response->shouldBuffer instanceof \Closure) { + try { + $response->shouldBuffer = ($response->shouldBuffer)($response->headers); + + if (null !== $response->info['error']) { + throw new TransportException($response->info['error']); + } + } catch (\Throwable $e) { + $response->close(); + $multi->handlesActivity[$j] = [null, $e]; + } + } + + if (true === $response->shouldBuffer) { + $response->content = fopen('php://temp', 'w+'); + } elseif (\is_resource($response->shouldBuffer)) { + $response->content = $response->shouldBuffer; + } + $response->shouldBuffer = null; + + yield $response => $chunk; + + if ($response->initializer && null === $response->info['error']) { + // Ensure the HTTP status code is always checked + $response->getHeaders(true); + } + + continue; + } + + yield $response => $chunk; + } + + unset($multi->handlesActivity[$j]); + + if ($chunk instanceof ErrorChunk && !$chunk->didThrow()) { + // Ensure transport exceptions are always thrown + $chunk->getContent(); + } + } + + if (!$responses) { + unset($runningResponses[$i]); + } + + // Prevent memory leaks + $multi->handlesActivity = $multi->handlesActivity ?: []; + $multi->openHandles = $multi->openHandles ?: []; + } + + if (!$runningResponses) { + break; + } + + if ($hasActivity) { + $lastActivity = microtime(true); + continue; + } + + if (-1 === self::select($multi, min($timeoutMin, $timeoutMax - $elapsedTimeout))) { + usleep(min(500, 1E6 * $timeoutMin)); + } + + $elapsedTimeout = microtime(true) - $lastActivity; + } + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Retry/GenericRetryStrategy.php b/sites/all/libraries/vendor/symfony/http-client/Retry/GenericRetryStrategy.php new file mode 100644 index 0000000000..ebe10a2186 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Retry/GenericRetryStrategy.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Retry; + +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Response\AsyncContext; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * Decides to retry the request when HTTP status codes belong to the given list of codes. + * + * @author Jérémy Derussé + */ +class GenericRetryStrategy implements RetryStrategyInterface +{ + public const IDEMPOTENT_METHODS = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']; + public const DEFAULT_RETRY_STATUS_CODES = [ + 0 => self::IDEMPOTENT_METHODS, // for transport exceptions + 423, + 425, + 429, + 500 => self::IDEMPOTENT_METHODS, + 502, + 503, + 504 => self::IDEMPOTENT_METHODS, + 507 => self::IDEMPOTENT_METHODS, + 510 => self::IDEMPOTENT_METHODS, + ]; + + private $statusCodes; + private $delayMs; + private $multiplier; + private $maxDelayMs; + private $jitter; + + /** + * @param array $statusCodes List of HTTP status codes that trigger a retry + * @param int $delayMs Amount of time to delay (or the initial value when multiplier is used) + * @param float $multiplier Multiplier to apply to the delay each time a retry occurs + * @param int $maxDelayMs Maximum delay to allow (0 means no maximum) + * @param float $jitter Probability of randomness int delay (0 = none, 1 = 100% random) + */ + public function __construct(array $statusCodes = self::DEFAULT_RETRY_STATUS_CODES, int $delayMs = 1000, float $multiplier = 2.0, int $maxDelayMs = 0, float $jitter = 0.1) + { + $this->statusCodes = $statusCodes; + + if ($delayMs < 0) { + throw new InvalidArgumentException(sprintf('Delay must be greater than or equal to zero: "%s" given.', $delayMs)); + } + $this->delayMs = $delayMs; + + if ($multiplier < 1) { + throw new InvalidArgumentException(sprintf('Multiplier must be greater than or equal to one: "%s" given.', $multiplier)); + } + $this->multiplier = $multiplier; + + if ($maxDelayMs < 0) { + throw new InvalidArgumentException(sprintf('Max delay must be greater than or equal to zero: "%s" given.', $maxDelayMs)); + } + $this->maxDelayMs = $maxDelayMs; + + if ($jitter < 0 || $jitter > 1) { + throw new InvalidArgumentException(sprintf('Jitter must be between 0 and 1: "%s" given.', $jitter)); + } + $this->jitter = $jitter; + } + + public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool + { + $statusCode = $context->getStatusCode(); + if (\in_array($statusCode, $this->statusCodes, true)) { + return true; + } + if (isset($this->statusCodes[$statusCode]) && \is_array($this->statusCodes[$statusCode])) { + return \in_array($context->getInfo('http_method'), $this->statusCodes[$statusCode], true); + } + if (null === $exception) { + return false; + } + + if (\in_array(0, $this->statusCodes, true)) { + return true; + } + if (isset($this->statusCodes[0]) && \is_array($this->statusCodes[0])) { + return \in_array($context->getInfo('http_method'), $this->statusCodes[0], true); + } + + return false; + } + + public function getDelay(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): int + { + $delay = $this->delayMs * $this->multiplier ** $context->getInfo('retry_count'); + + if ($this->jitter > 0) { + $randomness = $delay * $this->jitter; + $delay = $delay + random_int(-$randomness, +$randomness); + } + + if ($delay > $this->maxDelayMs && 0 !== $this->maxDelayMs) { + return $this->maxDelayMs; + } + + return (int) $delay; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Retry/RetryStrategyInterface.php b/sites/all/libraries/vendor/symfony/http-client/Retry/RetryStrategyInterface.php new file mode 100644 index 0000000000..25764336ea --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Retry/RetryStrategyInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Retry; + +use Symfony\Component\HttpClient\Response\AsyncContext; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * @author Jérémy Derussé + * @author Nicolas Grekas + */ +interface RetryStrategyInterface +{ + /** + * Returns whether the request should be retried. + * + * @param ?string $responseContent Null is passed when the body did not arrive yet + * + * @return bool|null Returns null to signal that the body is required to take a decision + */ + public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool; + + /** + * Returns the time to wait in milliseconds. + */ + public function getDelay(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): int; +} diff --git a/sites/all/libraries/vendor/symfony/http-client/RetryableHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/RetryableHttpClient.php new file mode 100644 index 0000000000..bec13784b1 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/RetryableHttpClient.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Symfony\Component\HttpClient\Response\AsyncContext; +use Symfony\Component\HttpClient\Response\AsyncResponse; +use Symfony\Component\HttpClient\Retry\GenericRetryStrategy; +use Symfony\Component\HttpClient\Retry\RetryStrategyInterface; +use Symfony\Contracts\HttpClient\ChunkInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Automatically retries failing HTTP requests. + * + * @author Jérémy Derussé + */ +class RetryableHttpClient implements HttpClientInterface, ResetInterface +{ + use AsyncDecoratorTrait; + + private $strategy; + private $maxRetries; + private $logger; + + /** + * @param int $maxRetries The maximum number of times to retry + */ + public function __construct(HttpClientInterface $client, RetryStrategyInterface $strategy = null, int $maxRetries = 3, LoggerInterface $logger = null) + { + $this->client = $client; + $this->strategy = $strategy ?? new GenericRetryStrategy(); + $this->maxRetries = $maxRetries; + $this->logger = $logger ?? new NullLogger(); + } + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + if ($this->maxRetries <= 0) { + return new AsyncResponse($this->client, $method, $url, $options); + } + + $retryCount = 0; + $content = ''; + $firstChunk = null; + + return new AsyncResponse($this->client, $method, $url, $options, function (ChunkInterface $chunk, AsyncContext $context) use ($method, $url, $options, &$retryCount, &$content, &$firstChunk) { + $exception = null; + try { + if ($context->getInfo('canceled') || $chunk->isTimeout() || null !== $chunk->getInformationalStatus()) { + yield $chunk; + + return; + } + } catch (TransportExceptionInterface $exception) { + // catch TransportExceptionInterface to send it to the strategy + } + if (null !== $exception) { + // always retry request that fail to resolve DNS + if ('' !== $context->getInfo('primary_ip')) { + $shouldRetry = $this->strategy->shouldRetry($context, null, $exception); + if (null === $shouldRetry) { + throw new \LogicException(sprintf('The "%s::shouldRetry()" method must not return null when called with an exception.', \get_class($this->strategy))); + } + + if (false === $shouldRetry) { + yield from $this->passthru($context, $firstChunk, $content, $chunk); + + return; + } + } + } elseif ($chunk->isFirst()) { + if (false === $shouldRetry = $this->strategy->shouldRetry($context, null, null)) { + yield from $this->passthru($context, $firstChunk, $content, $chunk); + + return; + } + + // Body is needed to decide + if (null === $shouldRetry) { + $firstChunk = $chunk; + $content = ''; + + return; + } + } else { + if (!$chunk->isLast()) { + $content .= $chunk->getContent(); + + return; + } + + if (null === $shouldRetry = $this->strategy->shouldRetry($context, $content, null)) { + throw new \LogicException(sprintf('The "%s::shouldRetry()" method must not return null when called with a body.', \get_class($this->strategy))); + } + + if (false === $shouldRetry) { + yield from $this->passthru($context, $firstChunk, $content, $chunk); + + return; + } + } + + $context->getResponse()->cancel(); + + $delay = $this->getDelayFromHeader($context->getHeaders()) ?? $this->strategy->getDelay($context, !$exception && $chunk->isLast() ? $content : null, $exception); + ++$retryCount; + $content = ''; + $firstChunk = null; + + $this->logger->info('Try #{count} after {delay}ms'.($exception ? ': '.$exception->getMessage() : ', status code: '.$context->getStatusCode()), [ + 'count' => $retryCount, + 'delay' => $delay, + ]); + + $context->setInfo('retry_count', $retryCount); + $context->replaceRequest($method, $url, $options); + $context->pause($delay / 1000); + + if ($retryCount >= $this->maxRetries) { + $context->passthru(); + } + }); + } + + private function getDelayFromHeader(array $headers): ?int + { + if (null !== $after = $headers['retry-after'][0] ?? null) { + if (is_numeric($after)) { + return (int) ($after * 1000); + } + + if (false !== $time = strtotime($after)) { + return max(0, $time - time()) * 1000; + } + } + + return null; + } + + private function passthru(AsyncContext $context, ?ChunkInterface $firstChunk, string &$content, ChunkInterface $lastChunk): \Generator + { + $context->passthru(); + + if (null !== $firstChunk) { + yield $firstChunk; + } + + if ('' !== $content) { + $chunk = $context->createChunk($content); + $content = ''; + + yield $chunk; + } + + yield $lastChunk; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/ScopingHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/ScopingHttpClient.php new file mode 100644 index 0000000000..85fa26acd8 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/ScopingHttpClient.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Auto-configure the default options based on the requested URL. + * + * @author Anthony Martin + */ +class ScopingHttpClient implements HttpClientInterface, ResetInterface, LoggerAwareInterface +{ + use HttpClientTrait; + + private $client; + private $defaultOptionsByRegexp; + private $defaultRegexp; + + public function __construct(HttpClientInterface $client, array $defaultOptionsByRegexp, string $defaultRegexp = null) + { + $this->client = $client; + $this->defaultOptionsByRegexp = $defaultOptionsByRegexp; + $this->defaultRegexp = $defaultRegexp; + + if (null !== $defaultRegexp && !isset($defaultOptionsByRegexp[$defaultRegexp])) { + throw new InvalidArgumentException(sprintf('No options are mapped to the provided "%s" default regexp.', $defaultRegexp)); + } + } + + public static function forBaseUri(HttpClientInterface $client, string $baseUri, array $defaultOptions = [], string $regexp = null): self + { + if (null === $regexp) { + $regexp = preg_quote(implode('', self::resolveUrl(self::parseUrl('.'), self::parseUrl($baseUri)))); + } + + $defaultOptions['base_uri'] = $baseUri; + + return new self($client, [$regexp => $defaultOptions], $regexp); + } + + /** + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + $e = null; + $url = self::parseUrl($url, $options['query'] ?? []); + + if (\is_string($options['base_uri'] ?? null)) { + $options['base_uri'] = self::parseUrl($options['base_uri']); + } + + try { + $url = implode('', self::resolveUrl($url, $options['base_uri'] ?? null)); + } catch (InvalidArgumentException $e) { + if (null === $this->defaultRegexp) { + throw $e; + } + + $defaultOptions = $this->defaultOptionsByRegexp[$this->defaultRegexp]; + $options = self::mergeDefaultOptions($options, $defaultOptions, true); + if (\is_string($options['base_uri'] ?? null)) { + $options['base_uri'] = self::parseUrl($options['base_uri']); + } + $url = implode('', self::resolveUrl($url, $options['base_uri'] ?? null, $defaultOptions['query'] ?? [])); + } + + foreach ($this->defaultOptionsByRegexp as $regexp => $defaultOptions) { + if (preg_match("{{$regexp}}A", $url)) { + if (null === $e || $regexp !== $this->defaultRegexp) { + $options = self::mergeDefaultOptions($options, $defaultOptions, true); + } + break; + } + } + + return $this->client->request($method, $url, $options); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + return $this->client->stream($responses, $timeout); + } + + public function reset() + { + if ($this->client instanceof ResetInterface) { + $this->client->reset(); + } + } + + /** + * {@inheritdoc} + */ + public function setLogger(LoggerInterface $logger): void + { + if ($this->client instanceof LoggerAwareInterface) { + $this->client->setLogger($logger); + } + } + + /** + * {@inheritdoc} + */ + public function withOptions(array $options): self + { + $clone = clone $this; + $clone->client = $this->client->withOptions($options); + + return $clone; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/AmpHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/AmpHttpClientTest.php new file mode 100644 index 0000000000..e17b45a0ce --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/AmpHttpClientTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Symfony\Component\HttpClient\AmpHttpClient; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class AmpHttpClientTest extends HttpClientTestCase +{ + protected function getHttpClient(string $testCase): HttpClientInterface + { + return new AmpHttpClient(['verify_peer' => false, 'verify_host' => false, 'timeout' => 5]); + } + + public function testProxy() + { + $this->markTestSkipped('A real proxy server would be needed.'); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/AsyncDecoratorTraitTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/AsyncDecoratorTraitTest.php new file mode 100644 index 0000000000..199d2cf5d0 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/AsyncDecoratorTraitTest.php @@ -0,0 +1,367 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Symfony\Component\HttpClient\AsyncDecoratorTrait; +use Symfony\Component\HttpClient\DecoratorTrait; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\HttpClient\Response\AsyncContext; +use Symfony\Component\HttpClient\Response\AsyncResponse; +use Symfony\Contracts\HttpClient\ChunkInterface; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +class AsyncDecoratorTraitTest extends NativeHttpClientTest +{ + protected function getHttpClient(string $testCase, \Closure $chunkFilter = null, HttpClientInterface $decoratedClient = null): HttpClientInterface + { + if ('testHandleIsRemovedOnException' === $testCase) { + $this->markTestSkipped("AsyncDecoratorTrait doesn't cache handles"); + } + + if ('testTimeoutOnDestruct' === $testCase) { + return HttpClient::create(); + } + + $chunkFilter = $chunkFilter ?? static function (ChunkInterface $chunk, AsyncContext $context) { yield $chunk; }; + + return new class($decoratedClient ?? parent::getHttpClient($testCase), $chunkFilter) implements HttpClientInterface { + use AsyncDecoratorTrait; + + private $chunkFilter; + + public function __construct(HttpClientInterface $client, \Closure $chunkFilter = null) + { + $this->chunkFilter = $chunkFilter; + $this->client = $client; + } + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + return new AsyncResponse($this->client, $method, $url, $options, $this->chunkFilter); + } + }; + } + + public function testTimeoutOnDestruct() + { + if (HttpClient::create() instanceof NativeHttpClient) { + $this->markTestSkipped('NativeHttpClient doesn\'t support opening concurrent requests.'); + } + + HttpClientTestCase::testTimeoutOnDestruct(); + } + + public function testRetry404() + { + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) { + $this->assertTrue($chunk->isFirst()); + $this->assertSame(404, $context->getStatusCode()); + $context->getResponse()->cancel(); + $context->replaceRequest('GET', 'http://localhost:8057/'); + $context->passthru(); + }); + + $response = $client->request('GET', 'http://localhost:8057/404'); + + foreach ($client->stream($response) as $chunk) { + } + $this->assertTrue($chunk->isLast()); + $this->assertSame(200, $response->getStatusCode()); + } + + public function testRetry404WithThrow() + { + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) { + $this->assertTrue($chunk->isFirst()); + $this->assertSame(404, $context->getStatusCode()); + $context->getResponse()->cancel(); + $context->replaceRequest('GET', 'http://localhost:8057/404'); + $context->passthru(); + }); + + $response = $client->request('GET', 'http://localhost:8057/404'); + + $this->expectException(ClientExceptionInterface::class); + $response->getContent(true); + } + + public function testRetryTransportError() + { + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) { + try { + if ($chunk->isFirst()) { + $this->assertSame(200, $context->getStatusCode()); + } + } catch (TransportExceptionInterface $e) { + $context->getResponse()->cancel(); + $context->replaceRequest('GET', 'http://localhost:8057/'); + $context->passthru(); + } + }); + + $response = $client->request('GET', 'http://localhost:8057/chunked-broken'); + + $this->assertSame(200, $response->getStatusCode()); + } + + public function testJsonTransclusion() + { + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) { + if ('' === $content = $chunk->getContent()) { + yield $chunk; + + return; + } + + $this->assertSame('{"documents":[{"id":"\/json\/1"},{"id":"\/json\/2"},{"id":"\/json\/3"}]}', $content); + + $steps = preg_split('{\{"id":"\\\/json\\\/(\d)"\}}', $content, -1, \PREG_SPLIT_DELIM_CAPTURE); + $steps[7] = $context->getResponse(); + $steps[1] = $context->replaceRequest('GET', 'http://localhost:8057/json/1'); + $steps[3] = $context->replaceRequest('GET', 'http://localhost:8057/json/2'); + $steps[5] = $context->replaceRequest('GET', 'http://localhost:8057/json/3'); + + yield $context->createChunk(array_shift($steps)); + + $context->replaceResponse(array_shift($steps)); + $context->passthru(static function (ChunkInterface $chunk, AsyncContext $context) use (&$steps) { + if ($chunk->isFirst()) { + return; + } + + if ($steps && $chunk->isLast()) { + $chunk = $context->createChunk(array_shift($steps)); + $context->replaceResponse(array_shift($steps)); + } + + yield $chunk; + }); + }); + + $response = $client->request('GET', 'http://localhost:8057/json'); + + $this->assertSame('{"documents":[{"title":"\/json\/1"},{"title":"\/json\/2"},{"title":"\/json\/3"}]}', $response->getContent()); + } + + public function testPreflightRequest() + { + $client = new class(parent::getHttpClient(__FUNCTION__)) implements HttpClientInterface { + use AsyncDecoratorTrait; + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + $chunkFilter = static function (ChunkInterface $chunk, AsyncContext $context) use ($method, $url, $options) { + $context->replaceRequest($method, $url, $options); + $context->passthru(); + }; + + return new AsyncResponse($this->client, 'GET', 'http://localhost:8057', $options, $chunkFilter); + } + }; + + $response = $client->request('GET', 'http://localhost:8057/json'); + + $this->assertSame('{"documents":[{"id":"\/json\/1"},{"id":"\/json\/2"},{"id":"\/json\/3"}]}', $response->getContent()); + $this->assertSame('http://localhost:8057/', $response->getInfo('previous_info')[0]['url']); + } + + public function testProcessingHappensOnce() + { + $lastChunks = 0; + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) use (&$lastChunks) { + $lastChunks += $chunk->isLast(); + + yield $chunk; + }); + + $response = $client->request('GET', 'http://localhost:8057/'); + + foreach ($client->stream($response) as $chunk) { + } + $this->assertTrue($chunk->isLast()); + $this->assertSame(1, $lastChunks); + + $chunk = null; + foreach ($client->stream($response) as $chunk) { + } + $this->assertTrue($chunk->isLast()); + $this->assertSame(1, $lastChunks); + } + + public function testLastChunkIsYieldOnHttpExceptionAtDestructTime() + { + $lastChunk = null; + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) use (&$lastChunk) { + $lastChunk = $chunk; + + yield $chunk; + }); + + try { + $client->request('GET', 'http://localhost:8057/404'); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + } + + $this->assertTrue($lastChunk->isLast()); + } + + public function testBufferPurePassthru() + { + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) { + $context->passthru(); + + yield $chunk; + }); + + $response = $client->request('GET', 'http://localhost:8057/'); + + $this->assertStringContainsString('SERVER_PROTOCOL', $response->getContent()); + $this->assertStringContainsString('HTTP_HOST', $response->getContent()); + } + + public function testRetryTimeout() + { + $cpt = 0; + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) use (&$cpt) { + try { + $this->assertTrue($chunk->isTimeout()); + yield $chunk; + } catch (TransportExceptionInterface $e) { + if ($cpt++ < 3) { + $context->getResponse()->cancel(); + $context->replaceRequest('GET', 'http://localhost:8057/timeout-header', ['timeout' => 0.1]); + } else { + $context->passthru(); + $context->getResponse()->cancel(); + $context->replaceRequest('GET', 'http://localhost:8057/timeout-header', ['timeout' => 10]); + } + } + }); + + $response = $client->request('GET', 'http://localhost:8057/timeout-header', ['timeout' => 0.1]); + + $this->assertSame(200, $response->getStatusCode()); + } + + public function testRecurciveStream() + { + $client = new class(parent::getHttpClient(__FUNCTION__)) implements HttpClientInterface { + use AsyncDecoratorTrait; + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + return new AsyncResponse($this->client, $method, $url, $options); + } + }; + + $response = $client->request('GET', 'http://localhost:8057/json'); + $content = ''; + foreach ($client->stream($response) as $chunk) { + $content .= $chunk->getContent(); + foreach ($client->stream($response) as $chunk) { + $content .= $chunk->getContent(); + } + } + + $this->assertSame('{"documents":[{"id":"\/json\/1"},{"id":"\/json\/2"},{"id":"\/json\/3"}]}', $content); + } + + public function testInfoPassToDecorator() + { + $lastInfo = null; + $options = ['on_progress' => function (int $dlNow, int $dlSize, array $info) use (&$lastInfo) { + $lastInfo = $info; + }]; + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) use ($options) { + $context->setInfo('foo', 'test'); + $context->getResponse()->cancel(); + $context->replaceRequest('GET', 'http://localhost:8057/', $options); + $context->passthru(); + }); + + $client->request('GET', 'http://localhost:8057')->getContent(); + $this->assertArrayHasKey('foo', $lastInfo); + $this->assertSame('test', $lastInfo['foo']); + $this->assertArrayHasKey('previous_info', $lastInfo); + } + + public function testMultipleYieldInInitializer() + { + $first = null; + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) use (&$first) { + if ($chunk->isFirst()) { + $first = $chunk; + + return; + } + $context->passthru(); + yield $first; + yield $context->createChunk('injectedFoo'); + yield $chunk; + }); + + $response = $client->request('GET', 'http://localhost:8057/404', ['timeout' => 0.1]); + + $this->assertSame(404, $response->getStatusCode()); + $this->assertStringContainsString('injectedFoo', $response->getContent(false)); + } + + public function testConsumingDecoratedClient() + { + $client = $this->getHttpClient(__FUNCTION__, null, new class(parent::getHttpClient(__FUNCTION__)) implements HttpClientInterface { + use DecoratorTrait; + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + $response = $this->client->request($method, $url, $options); + $response->getStatusCode(); // should be avoided and breaks compatibility with AsyncDecoratorTrait + + return $response; + } + }); + + $response = $client->request('GET', 'http://localhost:8057/'); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Instance of "Symfony\Component\HttpClient\Response\NativeResponse" is already consumed and cannot be managed by "Symfony\Component\HttpClient\Response\AsyncResponse". A decorated client should not call any of the response\'s methods in its "request()" method.'); + $response->getStatusCode(); + } + + public function testMaxDuration() + { + $sawFirst = false; + $client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) use (&$sawFirst) { + try { + if (!$chunk->isFirst() || !$sawFirst) { + $sawFirst = $sawFirst || $chunk->isFirst(); + yield $chunk; + } + } catch (TransportExceptionInterface $e) { + $context->getResponse()->cancel(); + $context->replaceRequest('GET', 'http://localhost:8057/timeout-body', ['timeout' => 0.4]); + } + }); + + $response = $client->request('GET', 'http://localhost:8057/timeout-body', ['max_duration' => 0.75, 'timeout' => 0.4]); + + $this->assertSame(0.75, $response->getInfo('max_duration')); + + $this->expectException(TransportException::class); + $this->expectExceptionMessage('Max duration was reached for "http://localhost:8057/timeout-body".'); + $response->getContent(); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/CachingHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/CachingHttpClientTest.php new file mode 100644 index 0000000000..ad07f86451 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/CachingHttpClientTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\CachingHttpClient; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpKernel\HttpCache\Store; +use Symfony\Contracts\HttpClient\ResponseInterface; + +class CachingHttpClientTest extends TestCase +{ + public function testRequestHeaders() + { + $options = [ + 'headers' => [ + 'Application-Name' => 'test1234', + 'Test-Name-Header' => 'test12345', + ], + ]; + + $mockClient = new MockHttpClient(); + $store = new Store(sys_get_temp_dir().'/sf_http_cache'); + $client = new CachingHttpClient($mockClient, $store, $options); + + $response = $client->request('GET', 'http://example.com/foo-bar'); + + rmdir(sys_get_temp_dir().'/sf_http_cache'); + self::assertInstanceOf(MockResponse::class, $response); + self::assertSame($response->getRequestOptions()['normalized_headers']['application-name'][0], 'Application-Name: test1234'); + self::assertSame($response->getRequestOptions()['normalized_headers']['test-name-header'][0], 'Test-Name-Header: test12345'); + } + + public function testDoesNotEvaluateResponseBody() + { + $body = file_get_contents(__DIR__.'/Fixtures/assertion_failure.php'); + $response = $this->runRequest(new MockResponse($body, ['response_headers' => ['X-Body-Eval' => true]])); + $headers = $response->getHeaders(); + + $this->assertSame($body, $response->getContent()); + $this->assertArrayNotHasKey('x-body-eval', $headers); + } + + public function testDoesNotIncludeFile() + { + $file = __DIR__.'/Fixtures/assertion_failure.php'; + + $response = $this->runRequest(new MockResponse( + 'test', ['response_headers' => [ + 'X-Body-Eval' => true, + 'X-Body-File' => $file, + ]] + )); + $headers = $response->getHeaders(); + + $this->assertSame('test', $response->getContent()); + $this->assertArrayNotHasKey('x-body-eval', $headers); + $this->assertArrayNotHasKey('x-body-file', $headers); + } + + public function testDoesNotReadFile() + { + $file = __DIR__.'/Fixtures/assertion_failure.php'; + + $response = $this->runRequest(new MockResponse( + 'test', ['response_headers' => [ + 'X-Body-File' => $file, + ]] + )); + $headers = $response->getHeaders(); + + $this->assertSame('test', $response->getContent()); + $this->assertArrayNotHasKey('x-body-file', $headers); + } + + public function testRemovesXContentDigest() + { + $response = $this->runRequest(new MockResponse( + 'test', [ + 'response_headers' => [ + 'X-Content-Digest' => 'some-hash', + ], + ])); + $headers = $response->getHeaders(); + + $this->assertArrayNotHasKey('x-content-digest', $headers); + } + + private function runRequest(MockResponse $mockResponse): ResponseInterface + { + $mockClient = new MockHttpClient($mockResponse); + + $store = new Store(sys_get_temp_dir().'/sf_http_cache'); + $client = new CachingHttpClient($mockClient, $store); + + $response = $client->request('GET', 'http://test'); + + return $response; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/Chunk/ServerSentEventTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/Chunk/ServerSentEventTest.php new file mode 100644 index 0000000000..1c0d6834a7 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/Chunk/ServerSentEventTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests\Chunk; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Chunk\ServerSentEvent; + +/** + * @author Antoine Bluchet + */ +class ServerSentEventTest extends TestCase +{ + public function testParse() + { + $rawData = <<assertSame("test\ntest", $sse->getData()); + $this->assertSame('12', $sse->getId()); + $this->assertSame('testEvent', $sse->getType()); + } + + public function testParseValid() + { + $rawData = <<assertSame('', $sse->getData()); + $this->assertSame('', $sse->getId()); + $this->assertSame('testEvent', $sse->getType()); + } + + public function testParseRetry() + { + $rawData = <<assertSame('', $sse->getData()); + $this->assertSame('', $sse->getId()); + $this->assertSame('message', $sse->getType()); + $this->assertSame(0.012, $sse->getRetry()); + } + + public function testParseNewLine() + { + $rawData = << +data +data: +data: +data: +data: +STR; + $sse = new ServerSentEvent($rawData); + $this->assertSame("\n\n \n\n\n", $sse->getData()); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/CurlHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/CurlHttpClientTest.php new file mode 100644 index 0000000000..284a243496 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/CurlHttpClientTest.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Symfony\Component\HttpClient\CurlHttpClient; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @requires extension curl + */ +class CurlHttpClientTest extends HttpClientTestCase +{ + protected function getHttpClient(string $testCase): HttpClientInterface + { + if (false !== strpos($testCase, 'Push')) { + if (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304) { + $this->markTestSkipped('PHP 7.3.0 to 7.3.3 don\'t support HTTP/2 PUSH'); + } + + if (!\defined('CURLMOPT_PUSHFUNCTION') || 0x073D00 > ($v = curl_version())['version_number'] || !(\CURL_VERSION_HTTP2 & $v['features'])) { + $this->markTestSkipped('curl <7.61 is used or it is not compiled with support for HTTP/2 PUSH'); + } + } + + return new CurlHttpClient(['verify_peer' => false, 'verify_host' => false]); + } + + public function testBindToPort() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', ['bindto' => '127.0.0.1:9876']); + $response->getStatusCode(); + + $r = new \ReflectionProperty($response, 'handle'); + $r->setAccessible(true); + + $curlInfo = curl_getinfo($r->getValue($response)); + + self::assertSame('127.0.0.1', $curlInfo['local_ip']); + self::assertSame(9876, $curlInfo['local_port']); + } + + public function testTimeoutIsNotAFatalError() + { + if ('\\' === \DIRECTORY_SEPARATOR) { + $this->markTestSkipped('Too transient on Windows'); + } + + parent::testTimeoutIsNotAFatalError(); + } + + public function testHandleIsReinitOnReset() + { + $httpClient = $this->getHttpClient(__FUNCTION__); + + $r = new \ReflectionProperty($httpClient, 'multi'); + $r->setAccessible(true); + $clientState = $r->getValue($httpClient); + $initialShareId = $clientState->share; + $httpClient->reset(); + self::assertNotSame($initialShareId, $clientState->share); + } + + public function testProcessAfterReset() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://127.0.0.1:8057/json'); + + $client->reset(); + + $this->assertSame(['application/json'], $response->getHeaders()['content-type']); + } + + public function testOverridingRefererUsingCurlOptions() + { + $httpClient = $this->getHttpClient(__FUNCTION__); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot set "CURLOPT_REFERER" with "extra.curl", use option "headers" instead.'); + + $httpClient->request('GET', 'http://localhost:8057/', [ + 'extra' => [ + 'curl' => [ + \CURLOPT_REFERER => 'Banana', + ], + ], + ]); + } + + public function testOverridingHttpMethodUsingCurlOptions() + { + $httpClient = $this->getHttpClient(__FUNCTION__); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The HTTP method cannot be overridden using "extra.curl".'); + + $httpClient->request('POST', 'http://localhost:8057/', [ + 'extra' => [ + 'curl' => [ + \CURLOPT_HTTPGET => true, + ], + ], + ]); + } + + public function testOverridingInternalAttributesUsingCurlOptions() + { + $httpClient = $this->getHttpClient(__FUNCTION__); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot set "CURLOPT_PRIVATE" with "extra.curl".'); + + $httpClient->request('POST', 'http://localhost:8057/', [ + 'extra' => [ + 'curl' => [ + \CURLOPT_PRIVATE => 'overriden private', + ], + ], + ]); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/DataCollector/HttpClientDataCollectorTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/DataCollector/HttpClientDataCollectorTest.php new file mode 100755 index 0000000000..76bbbe7c57 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/DataCollector/HttpClientDataCollectorTest.php @@ -0,0 +1,180 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests\DataCollector; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\DataCollector\HttpClientDataCollector; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Component\HttpClient\TraceableHttpClient; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\HttpClient\Test\TestHttpServer; + +class HttpClientDataCollectorTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + TestHttpServer::start(); + } + + public function testItCollectsRequestCount() + { + $httpClient1 = $this->httpClientThatHasTracedRequests([ + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/', + ], + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/301', + ], + ]); + $httpClient2 = $this->httpClientThatHasTracedRequests([ + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/404', + ], + ]); + $httpClient3 = $this->httpClientThatHasTracedRequests([]); + $sut = new HttpClientDataCollector(); + $sut->registerClient('http_client1', $httpClient1); + $sut->registerClient('http_client2', $httpClient2); + $sut->registerClient('http_client3', $httpClient3); + $this->assertEquals(0, $sut->getRequestCount()); + $sut->collect(new Request(), new Response()); + $this->assertEquals(3, $sut->getRequestCount()); + } + + public function testItCollectsErrorCount() + { + $httpClient1 = $this->httpClientThatHasTracedRequests([ + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/', + ], + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/301', + ], + ]); + $httpClient2 = $this->httpClientThatHasTracedRequests([ + [ + 'method' => 'GET', + 'url' => '/404', + 'options' => ['base_uri' => 'http://localhost:8057/'], + ], + ]); + $httpClient3 = $this->httpClientThatHasTracedRequests([]); + $sut = new HttpClientDataCollector(); + $sut->registerClient('http_client1', $httpClient1); + $sut->registerClient('http_client2', $httpClient2); + $sut->registerClient('http_client3', $httpClient3); + $this->assertEquals(0, $sut->getErrorCount()); + $sut->collect(new Request(), new Response()); + $this->assertEquals(1, $sut->getErrorCount()); + } + + public function testItCollectsErrorCountByClient() + { + $httpClient1 = $this->httpClientThatHasTracedRequests([ + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/', + ], + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/301', + ], + ]); + $httpClient2 = $this->httpClientThatHasTracedRequests([ + [ + 'method' => 'GET', + 'url' => '/404', + 'options' => ['base_uri' => 'http://localhost:8057/'], + ], + ]); + $httpClient3 = $this->httpClientThatHasTracedRequests([]); + $sut = new HttpClientDataCollector(); + $sut->registerClient('http_client1', $httpClient1); + $sut->registerClient('http_client2', $httpClient2); + $sut->registerClient('http_client3', $httpClient3); + $this->assertEquals([], $sut->getClients()); + $sut->collect(new Request(), new Response()); + $collectedData = $sut->getClients(); + $this->assertEquals(0, $collectedData['http_client1']['error_count']); + $this->assertEquals(1, $collectedData['http_client2']['error_count']); + $this->assertEquals(0, $collectedData['http_client3']['error_count']); + } + + public function testItCollectsTracesByClient() + { + $httpClient1 = $this->httpClientThatHasTracedRequests([ + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/', + ], + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/301', + ], + ]); + $httpClient2 = $this->httpClientThatHasTracedRequests([ + [ + 'method' => 'GET', + 'url' => '/404', + 'options' => ['base_uri' => 'http://localhost:8057/'], + ], + ]); + $httpClient3 = $this->httpClientThatHasTracedRequests([]); + $sut = new HttpClientDataCollector(); + $sut->registerClient('http_client1', $httpClient1); + $sut->registerClient('http_client2', $httpClient2); + $sut->registerClient('http_client3', $httpClient3); + $this->assertEquals([], $sut->getClients()); + $sut->collect(new Request(), new Response()); + $collectedData = $sut->getClients(); + $this->assertCount(2, $collectedData['http_client1']['traces']); + $this->assertCount(1, $collectedData['http_client2']['traces']); + $this->assertCount(0, $collectedData['http_client3']['traces']); + } + + public function testItIsEmptyAfterReset() + { + $httpClient1 = $this->httpClientThatHasTracedRequests([ + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/', + ], + ]); + $sut = new HttpClientDataCollector(); + $sut->registerClient('http_client1', $httpClient1); + $sut->collect(new Request(), new Response()); + $collectedData = $sut->getClients(); + $this->assertCount(1, $collectedData['http_client1']['traces']); + $sut->reset(); + $this->assertEquals([], $sut->getClients()); + $this->assertEquals(0, $sut->getErrorCount()); + $this->assertEquals(0, $sut->getRequestCount()); + } + + private function httpClientThatHasTracedRequests($tracedRequests): TraceableHttpClient + { + $httpClient = new TraceableHttpClient(new NativeHttpClient()); + + foreach ($tracedRequests as $request) { + $response = $httpClient->request($request['method'], $request['url'], $request['options'] ?? []); + $response->getContent(false); // disables exceptions from destructors + } + + return $httpClient; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/DependencyInjection/HttpClientPassTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/DependencyInjection/HttpClientPassTest.php new file mode 100755 index 0000000000..eb04f88226 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/DependencyInjection/HttpClientPassTest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpClient\DataCollector\HttpClientDataCollector; +use Symfony\Component\HttpClient\DependencyInjection\HttpClientPass; +use Symfony\Component\HttpClient\TraceableHttpClient; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class HttpClientPassTest extends TestCase +{ + public function testItRequiresDataCollector() + { + $container = $this->buildContainerBuilder('http_client'); + $sut = new HttpClientPass(); + $sut->process($container); + + $this->assertFalse($container->hasDefinition('.debug.http_client')); + } + + public function testItDecoratesHttpClientWithTraceableHttpClient() + { + $container = $this->buildContainerBuilder('foo'); + $container->register('data_collector.http_client', HttpClientDataCollector::class); + $sut = new HttpClientPass(); + $sut->process($container); + $this->assertTrue($container->hasDefinition('.debug.foo')); + $this->assertSame(TraceableHttpClient::class, $container->getDefinition('.debug.foo')->getClass()); + $this->assertSame(['foo', null, 0], $container->getDefinition('.debug.foo')->getDecoratedService()); + } + + public function testItRegistersDebugHttpClientToCollector() + { + $container = $this->buildContainerBuilder('foo_client'); + $container->register('data_collector.http_client', HttpClientDataCollector::class); + $sut = new HttpClientPass(); + $sut->process($container); + $this->assertEquals( + [['registerClient', ['foo_client', new Reference('.debug.foo_client')]]], + $container->getDefinition('data_collector.http_client')->getMethodCalls() + ); + } + + private function buildContainerBuilder(string $clientId = 'http_client'): ContainerBuilder + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.debug', true); + + $container->register($clientId, HttpClientInterface::class)->addTag('http_client.client')->setArgument(0, []); + + return $container; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/EventSourceHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/EventSourceHttpClientTest.php new file mode 100644 index 0000000000..b738c15a18 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/EventSourceHttpClientTest.php @@ -0,0 +1,169 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Chunk\DataChunk; +use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Chunk\ServerSentEvent; +use Symfony\Component\HttpClient\EventSourceHttpClient; +use Symfony\Component\HttpClient\Exception\EventSourceException; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Antoine Bluchet + */ +class EventSourceHttpClientTest extends TestCase +{ + public function testGetServerSentEvents() + { + $data = << +data +data: +data +data: + +id: 60 +data +TXT; + + $chunk = new DataChunk(0, $data); + $response = new MockResponse('', ['canceled' => false, 'http_method' => 'GET', 'url' => 'http://localhost:8080/events', 'response_headers' => ['content-type: text/event-stream']]); + $responseStream = new ResponseStream((function () use ($response, $chunk) { + yield $response => new FirstChunk(); + yield $response => $chunk; + yield $response => new ErrorChunk(0, 'timeout'); + })()); + + $hasCorrectHeaders = function ($options) { + $this->assertSame(['Accept: text/event-stream', 'Cache-Control: no-cache'], $options['headers']); + + return true; + }; + + $httpClient = $this->createMock(HttpClientInterface::class); + $httpClient->method('request')->with('GET', 'http://localhost:8080/events', $this->callback($hasCorrectHeaders))->willReturn($response); + + $httpClient->method('stream')->willReturn($responseStream); + + $es = new EventSourceHttpClient($httpClient); + $res = $es->connect('http://localhost:8080/events'); + + $expected = [ + new FirstChunk(), + new ServerSentEvent("event: builderror\nid: 46\ndata: {\"foo\": \"bar\"}\n\n"), + new ServerSentEvent("event: reload\nid: 47\ndata: {}\n\n"), + new ServerSentEvent("event: reload\nid: 48\ndata: {}\n\n"), + new ServerSentEvent("data: test\ndata:test\nid: 49\nevent: testEvent\n\n\n"), + new ServerSentEvent("id: 50\ndata: \ndata\ndata: \ndata\ndata: \n\n"), + ]; + $i = 0; + + $this->expectExceptionMessage('Response has been canceled'); + while ($res) { + if ($i > 0) { + $res->cancel(); + } + foreach ($es->stream($res) as $chunk) { + if ($chunk->isTimeout()) { + continue; + } + + if ($chunk->isLast()) { + continue; + } + + $this->assertEquals($expected[$i++], $chunk); + } + } + } + + /** + * @dataProvider contentTypeProvider + */ + public function testContentType($contentType, $expected) + { + $chunk = new DataChunk(0, ''); + $response = new MockResponse('', ['canceled' => false, 'http_method' => 'GET', 'url' => 'http://localhost:8080/events', 'response_headers' => ['content-type: '.$contentType]]); + $responseStream = new ResponseStream((function () use ($response, $chunk) { + yield $response => new FirstChunk(); + yield $response => $chunk; + yield $response => new ErrorChunk(0, 'timeout'); + })()); + + $hasCorrectHeaders = function ($options) { + $this->assertSame(['Accept: text/event-stream', 'Cache-Control: no-cache'], $options['headers']); + + return true; + }; + + $httpClient = $this->createMock(HttpClientInterface::class); + $httpClient->method('request')->with('GET', 'http://localhost:8080/events', $this->callback($hasCorrectHeaders))->willReturn($response); + + $httpClient->method('stream')->willReturn($responseStream); + + $es = new EventSourceHttpClient($httpClient); + $res = $es->connect('http://localhost:8080/events'); + + if ($expected instanceof EventSourceException) { + $this->expectExceptionMessage($expected->getMessage()); + } + + foreach ($es->stream($res) as $chunk) { + if ($chunk->isTimeout()) { + continue; + } + + if ($chunk->isLast()) { + return; + } + } + } + + public function contentTypeProvider() + { + return [ + ['text/event-stream', true], + ['text/event-stream;charset=utf-8', true], + ['text/event-stream;charset=UTF-8', true], + ['Text/EVENT-STREAM;Charset="utf-8"', true], + ['text/event-stream; charset="utf-8"', true], + ['text/event-stream; charset=iso-8859-15', true], + ['text/html', new EventSourceException('Response content-type is "text/html" while "text/event-stream" was expected for "http://localhost:8080/events".')], + ['text/html; charset="utf-8"', new EventSourceException('Response content-type is "text/html; charset="utf-8"" while "text/event-stream" was expected for "http://localhost:8080/events".')], + ['text/event-streambla', new EventSourceException('Response content-type is "text/event-streambla" while "text/event-stream" was expected for "http://localhost:8080/events".')], + ]; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/Exception/HttpExceptionTraitTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/Exception/HttpExceptionTraitTest.php new file mode 100644 index 0000000000..f7b4ce59e9 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/Exception/HttpExceptionTraitTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests\Exception; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\HttpExceptionTrait; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Kévin Dunglas + */ +class HttpExceptionTraitTest extends TestCase +{ + public function provideParseError(): iterable + { + $errorWithoutMessage = 'HTTP/1.1 400 Bad Request returned for "http://example.com".'; + + $errorWithMessage = <<createMock(ResponseInterface::class); + $response + ->method('getInfo') + ->willReturnMap([ + ['http_code', 400], + ['url', 'http://example.com'], + ['response_headers', [ + 'HTTP/1.1 400 Bad Request', + 'Content-Type: '.$mimeType, + ]], + ]); + $response->method('getContent')->willReturn($json); + + $e = new TestException($response); + $this->assertSame(400, $e->getCode()); + $this->assertSame($expectedMessage, $e->getMessage()); + } +} + +class TestException extends \Exception +{ + use HttpExceptionTrait; +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/Fixtures/assertion_failure.php b/sites/all/libraries/vendor/symfony/http-client/Tests/Fixtures/assertion_failure.php new file mode 100644 index 0000000000..52f31b45a2 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/Fixtures/assertion_failure.php @@ -0,0 +1,3 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class HttpClientTest extends TestCase +{ + public function testCreateClient() + { + $this->assertInstanceOf(HttpClientInterface::class, HttpClient::create()); + $this->assertNotInstanceOf(NativeHttpClient::class, HttpClient::create()); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/HttpClientTestCase.php b/sites/all/libraries/vendor/symfony/http-client/Tests/HttpClientTestCase.php new file mode 100644 index 0000000000..9a1c177a53 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/HttpClientTestCase.php @@ -0,0 +1,458 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\SkippedTestSuiteError; +use Symfony\Component\HttpClient\Exception\ClientException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\ClientState; +use Symfony\Component\HttpClient\Response\StreamWrapper; +use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Process; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\Test\HttpClientTestCase as BaseHttpClientTestCase; + +/* +Tests for HTTP2 Push need a recent version of both PHP and curl. This docker command should run them: +docker run -it --rm -v $(pwd):/app -v /path/to/vulcain:/usr/local/bin/vulcain -w /app php:7.3-alpine ./phpunit src/Symfony/Component/HttpClient --filter Push +The vulcain binary can be found at https://github.com/symfony/binary-utils/releases/download/v0.1/vulcain_0.1.3_Linux_x86_64.tar.gz - see https://github.com/dunglas/vulcain for source +*/ + +abstract class HttpClientTestCase extends BaseHttpClientTestCase +{ + private static $vulcainStarted = false; + + public function testTimeoutOnDestruct() + { + if (!method_exists(parent::class, 'testTimeoutOnDestruct')) { + $this->markTestSkipped('BaseHttpClientTestCase doesn\'t have testTimeoutOnDestruct().'); + } + + parent::testTimeoutOnDestruct(); + } + + public function testAcceptHeader() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057'); + $requestHeaders = $response->toArray(); + + $this->assertSame('*/*', $requestHeaders['HTTP_ACCEPT']); + + $response = $client->request('GET', 'http://localhost:8057', [ + 'headers' => [ + 'Accept' => 'foo/bar', + ], + ]); + $requestHeaders = $response->toArray(); + + $this->assertSame('foo/bar', $requestHeaders['HTTP_ACCEPT']); + + $response = $client->request('GET', 'http://localhost:8057', [ + 'headers' => [ + 'Accept' => null, + ], + ]); + $requestHeaders = $response->toArray(); + + $this->assertArrayNotHasKey('HTTP_ACCEPT', $requestHeaders); + } + + public function testToStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057'); + $stream = $response->toStream(); + + $this->assertSame("{\n \"SER", fread($stream, 10)); + $this->assertSame('VER_PROTOCOL', fread($stream, 12)); + $this->assertFalse(feof($stream)); + $this->assertTrue(rewind($stream)); + + $this->assertIsArray(json_decode(fread($stream, 1024), true)); + $this->assertSame('', fread($stream, 1)); + $this->assertTrue(feof($stream)); + } + + public function testStreamCopyToStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057'); + $h = fopen('php://temp', 'w+'); + stream_copy_to_stream($response->toStream(), $h); + + $this->assertTrue(rewind($h)); + $this->assertSame("{\n \"SER", fread($h, 10)); + $this->assertSame('VER_PROTOCOL', fread($h, 12)); + $this->assertFalse(feof($h)); + } + + public function testToStream404() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/404'); + $stream = $response->toStream(false); + + $this->assertSame("{\n \"SER", fread($stream, 10)); + $this->assertSame('VER_PROTOCOL', fread($stream, 12)); + $this->assertSame($response, stream_get_meta_data($stream)['wrapper_data']->getResponse()); + $this->assertSame(404, $response->getStatusCode()); + + $response = $client->request('GET', 'http://localhost:8057/404'); + $this->expectException(ClientException::class); + $response->toStream(); + } + + public function testNonBlockingStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + $stream = $response->toStream(); + usleep(10000); + + $this->assertTrue(stream_set_blocking($stream, false)); + $this->assertSame('<1>', fread($stream, 8192)); + $this->assertFalse(feof($stream)); + + $this->assertTrue(stream_set_blocking($stream, true)); + $this->assertSame('<2>', fread($stream, 8192)); + $this->assertSame('', fread($stream, 8192)); + $this->assertTrue(feof($stream)); + } + + public function testSeekAsyncStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + $stream = $response->toStream(false); + + $this->assertSame(0, fseek($stream, 0, \SEEK_CUR)); + $this->assertSame('<1>', fread($stream, 8192)); + $this->assertFalse(feof($stream)); + $this->assertSame('<2>', stream_get_contents($stream)); + } + + public function testResponseStreamRewind() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/103'); + + $stream = $response->toStream(); + + $this->assertSame('Here the body', stream_get_contents($stream)); + rewind($stream); + $this->assertSame('Here the body', stream_get_contents($stream)); + } + + public function testStreamWrapperStreamRewind() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/103'); + + $stream = StreamWrapper::createResource($response); + + $this->assertSame('Here the body', stream_get_contents($stream)); + rewind($stream); + $this->assertSame('Here the body', stream_get_contents($stream)); + } + + public function testStreamWrapperWithClientStreamRewind() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/103'); + + $stream = StreamWrapper::createResource($response, $client); + + $this->assertSame('Here the body', stream_get_contents($stream)); + rewind($stream); + $this->assertSame('Here the body', stream_get_contents($stream)); + } + + public function testHttp2PushVulcain() + { + $client = $this->getHttpClient(__FUNCTION__); + self::startVulcain($client); + $logger = new TestLogger(); + $client->setLogger($logger); + + $responseAsArray = $client->request('GET', 'https://127.0.0.1:3000/json', [ + 'headers' => [ + 'Preload' => '/documents/*/id', + ], + ])->toArray(); + + foreach ($responseAsArray['documents'] as $document) { + $client->request('GET', 'https://127.0.0.1:3000'.$document['id'])->toArray(); + } + + $client->reset(); + + $expected = [ + 'Request: "GET https://127.0.0.1:3000/json"', + 'Queueing pushed response: "https://127.0.0.1:3000/json/1"', + 'Queueing pushed response: "https://127.0.0.1:3000/json/2"', + 'Queueing pushed response: "https://127.0.0.1:3000/json/3"', + 'Response: "200 https://127.0.0.1:3000/json"', + 'Accepting pushed response: "GET https://127.0.0.1:3000/json/1"', + 'Response: "200 https://127.0.0.1:3000/json/1"', + 'Accepting pushed response: "GET https://127.0.0.1:3000/json/2"', + 'Response: "200 https://127.0.0.1:3000/json/2"', + 'Accepting pushed response: "GET https://127.0.0.1:3000/json/3"', + 'Response: "200 https://127.0.0.1:3000/json/3"', + ]; + $this->assertSame($expected, $logger->logs); + } + + public function testPause() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/'); + + $time = microtime(true); + $response->getInfo('pause_handler')(0.5); + $this->assertSame(200, $response->getStatusCode()); + $this->assertTrue(0.5 <= microtime(true) - $time); + + $response = $client->request('GET', 'http://localhost:8057/'); + + $time = microtime(true); + $response->getInfo('pause_handler')(1); + + foreach ($client->stream($response, 0.5) as $chunk) { + $this->assertTrue($chunk->isTimeout()); + $response->cancel(); + } + $response = null; + $this->assertTrue(1.0 > microtime(true) - $time); + $this->assertTrue(0.5 <= microtime(true) - $time); + } + + public function testPauseReplace() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/'); + + $time = microtime(true); + $response->getInfo('pause_handler')(10); + $response->getInfo('pause_handler')(0.5); + $this->assertSame(200, $response->getStatusCode()); + $this->assertGreaterThanOrEqual(0.5, microtime(true) - $time); + $this->assertLessThanOrEqual(5, microtime(true) - $time); + } + + public function testPauseDuringBody() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + + $time = microtime(true); + $this->assertSame(200, $response->getStatusCode()); + $response->getInfo('pause_handler')(1); + $response->getContent(); + $this->assertGreaterThanOrEqual(1, microtime(true) - $time); + } + + public function testHttp2PushVulcainWithUnusedResponse() + { + $client = $this->getHttpClient(__FUNCTION__); + self::startVulcain($client); + $logger = new TestLogger(); + $client->setLogger($logger); + + $responseAsArray = $client->request('GET', 'https://127.0.0.1:3000/json', [ + 'headers' => [ + 'Preload' => '/documents/*/id', + ], + ])->toArray(); + + $i = 0; + foreach ($responseAsArray['documents'] as $document) { + $client->request('GET', 'https://127.0.0.1:3000'.$document['id'])->toArray(); + if (++$i >= 2) { + break; + } + } + + $client->reset(); + + $expected = [ + 'Request: "GET https://127.0.0.1:3000/json"', + 'Queueing pushed response: "https://127.0.0.1:3000/json/1"', + 'Queueing pushed response: "https://127.0.0.1:3000/json/2"', + 'Queueing pushed response: "https://127.0.0.1:3000/json/3"', + 'Response: "200 https://127.0.0.1:3000/json"', + 'Accepting pushed response: "GET https://127.0.0.1:3000/json/1"', + 'Response: "200 https://127.0.0.1:3000/json/1"', + 'Accepting pushed response: "GET https://127.0.0.1:3000/json/2"', + 'Response: "200 https://127.0.0.1:3000/json/2"', + 'Unused pushed response: "https://127.0.0.1:3000/json/3"', + ]; + $this->assertSame($expected, $logger->logs); + } + + public function testDnsFailure() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://bad.host.test/'); + + $this->expectException(TransportException::class); + $response->getStatusCode(); + } + + private static function startVulcain(HttpClientInterface $client) + { + if (self::$vulcainStarted) { + return; + } + + if ('\\' === \DIRECTORY_SEPARATOR) { + throw new SkippedTestSuiteError('Testing with the "vulcain" is not supported on Windows.'); + } + + if (['application/json'] !== $client->request('GET', 'http://127.0.0.1:8057/json')->getHeaders()['content-type']) { + throw new SkippedTestSuiteError('symfony/http-client-contracts >= 2.0.1 required'); + } + + $process = new Process(['vulcain'], null, [ + 'DEBUG' => 1, + 'UPSTREAM' => 'http://127.0.0.1:8057', + 'ADDR' => ':3000', + 'KEY_FILE' => __DIR__.'/Fixtures/tls/server.key', + 'CERT_FILE' => __DIR__.'/Fixtures/tls/server.crt', + ]); + $process->start(); + + register_shutdown_function([$process, 'stop']); + sleep('\\' === \DIRECTORY_SEPARATOR ? 10 : 1); + + if (!$process->isRunning()) { + if ('\\' !== \DIRECTORY_SEPARATOR && 127 === $process->getExitCode()) { + throw new SkippedTestSuiteError('vulcain binary is missing'); + } + + if ('\\' !== \DIRECTORY_SEPARATOR && 126 === $process->getExitCode()) { + throw new SkippedTestSuiteError('vulcain binary is not executable'); + } + + throw new SkippedTestSuiteError((new ProcessFailedException($process))->getMessage()); + } + + self::$vulcainStarted = true; + } + + public function testHandleIsRemovedOnException() + { + $client = $this->getHttpClient(__FUNCTION__); + + try { + $client->request('GET', 'http://localhost:8057/304'); + $this->fail(RedirectionExceptionInterface::class.' expected'); + } catch (RedirectionExceptionInterface $e) { + // The response content-type mustn't be json as that calls getContent + // @see src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php:58 + $this->assertStringNotContainsString('json', $e->getResponse()->getHeaders(false)['content-type'][0] ?? ''); + unset($e); + + $r = new \ReflectionProperty($client, 'multi'); + $r->setAccessible(true); + /** @var ClientState $clientState */ + $clientState = $r->getValue($client); + + $this->assertCount(0, $clientState->handlesActivity); + $this->assertCount(0, $clientState->openHandles); + } + } + + public function testDebugInfoOnDestruct() + { + $client = $this->getHttpClient(__FUNCTION__); + + $traceInfo = []; + $client->request('GET', 'http://localhost:8057', ['on_progress' => function (int $dlNow, int $dlSize, array $info) use (&$traceInfo) { + $traceInfo = $info; + }]); + + $this->assertNotEmpty($traceInfo['debug']); + } + + public function testFixContentLength() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => 'abc=def', + 'headers' => ['Content-Length: 4'], + ]); + + $body = $response->toArray(); + + $this->assertSame(['abc' => 'def', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testDropContentRelatedHeadersWhenFollowingRequestIsUsingGet() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/302', [ + 'body' => 'foo', + 'headers' => ['Content-Length: 3'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + } + + public function testNegativeTimeout() + { + $client = $this->getHttpClient(__FUNCTION__); + + $this->assertSame(200, $client->request('GET', 'http://localhost:8057', [ + 'timeout' => -1, + ])->getStatusCode()); + } + + public function testRedirectAfterPost() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/302/relative', [ + 'body' => '', + ]); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertStringContainsStringIgnoringCase("\r\nContent-Length: 0", $response->getInfo('debug')); + } + + public function testEmptyPut() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('PUT', 'http://localhost:8057/post', [ + 'headers' => ['Content-Length' => '0'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertStringContainsString("\r\nContent-Length: ", $response->getInfo('debug')); + } + + public function testNullBody() + { + $client = $this->getHttpClient(__FUNCTION__); + + $client->request('POST', 'http://localhost:8057/post', [ + 'body' => null, + ]); + + $this->expectNotToPerformAssertions(); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/HttpClientTraitTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/HttpClientTraitTest.php new file mode 100644 index 0000000000..b811626c0c --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/HttpClientTraitTest.php @@ -0,0 +1,277 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\HttpClientTrait; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class HttpClientTraitTest extends TestCase +{ + use HttpClientTrait; + + private const RFC3986_BASE = 'http://a/b/c/d;p?q'; + + /** + * @dataProvider providePrepareRequestUrl + */ + public function testPrepareRequestUrl(string $expected, string $url, array $query = []) + { + $defaults = [ + 'base_uri' => 'http://example.com?c=c', + 'query' => ['a' => 1, 'b' => 'b'], + ]; + [, $defaults] = self::prepareRequest(null, null, $defaults); + + [$url] = self::prepareRequest(null, $url, ['query' => $query], $defaults); + $this->assertSame($expected, implode('', $url)); + } + + public function providePrepareRequestUrl(): iterable + { + yield ['http://example.com/', 'http://example.com/']; + yield ['http://example.com/?a=1&b=b', '.']; + yield ['http://example.com/?a=2&b=b', '.?a=2']; + yield ['http://example.com/?a=3&b=b', '.', ['a' => 3]]; + yield ['http://example.com/?a=3&b=b', '.?a=0', ['a' => 3]]; + yield ['http://example.com/', 'http://example.com/', ['a' => null]]; + yield ['http://example.com/?b=', 'http://example.com/', ['b' => '']]; + yield ['http://example.com/?b=', 'http://example.com/', ['a' => null, 'b' => '']]; + } + + /** + * @dataProvider provideResolveUrl + */ + public function testResolveUrl(string $base, string $url, string $expected) + { + $this->assertSame($expected, implode('', self::resolveUrl(self::parseUrl($url), self::parseUrl($base)))); + } + + /** + * From https://github.com/guzzle/psr7/blob/master/tests/UriResoverTest.php. + */ + public function provideResolveUrl(): array + { + return [ + [self::RFC3986_BASE, 'http:h', 'http:h'], + [self::RFC3986_BASE, 'g', 'http://a/b/c/g'], + [self::RFC3986_BASE, './g', 'http://a/b/c/g'], + [self::RFC3986_BASE, 'g/', 'http://a/b/c/g/'], + [self::RFC3986_BASE, '/g', 'http://a/g'], + [self::RFC3986_BASE, '//g', 'http://g/'], + [self::RFC3986_BASE, '?y', 'http://a/b/c/d;p?y'], + [self::RFC3986_BASE, 'g?y', 'http://a/b/c/g?y'], + [self::RFC3986_BASE, '#s', 'http://a/b/c/d;p?q#s'], + [self::RFC3986_BASE, 'g#s', 'http://a/b/c/g#s'], + [self::RFC3986_BASE, 'g?y#s', 'http://a/b/c/g?y#s'], + [self::RFC3986_BASE, ';x', 'http://a/b/c/;x'], + [self::RFC3986_BASE, 'g;x', 'http://a/b/c/g;x'], + [self::RFC3986_BASE, 'g;x?y#s', 'http://a/b/c/g;x?y#s'], + [self::RFC3986_BASE, '', self::RFC3986_BASE], + [self::RFC3986_BASE, '.', 'http://a/b/c/'], + [self::RFC3986_BASE, './', 'http://a/b/c/'], + [self::RFC3986_BASE, '..', 'http://a/b/'], + [self::RFC3986_BASE, '../', 'http://a/b/'], + [self::RFC3986_BASE, '../g', 'http://a/b/g'], + [self::RFC3986_BASE, '../..', 'http://a/'], + [self::RFC3986_BASE, '../../', 'http://a/'], + [self::RFC3986_BASE, '../../g', 'http://a/g'], + [self::RFC3986_BASE, '../../../g', 'http://a/g'], + [self::RFC3986_BASE, '../../../../g', 'http://a/g'], + [self::RFC3986_BASE, '/./g', 'http://a/g'], + [self::RFC3986_BASE, '/../g', 'http://a/g'], + [self::RFC3986_BASE, 'g.', 'http://a/b/c/g.'], + [self::RFC3986_BASE, '.g', 'http://a/b/c/.g'], + [self::RFC3986_BASE, 'g..', 'http://a/b/c/g..'], + [self::RFC3986_BASE, '..g', 'http://a/b/c/..g'], + [self::RFC3986_BASE, './../g', 'http://a/b/g'], + [self::RFC3986_BASE, 'foo////g', 'http://a/b/c/foo////g'], + [self::RFC3986_BASE, './g/.', 'http://a/b/c/g/'], + [self::RFC3986_BASE, 'g/./h', 'http://a/b/c/g/h'], + [self::RFC3986_BASE, 'g/../h', 'http://a/b/c/h'], + [self::RFC3986_BASE, 'g;x=1/./y', 'http://a/b/c/g;x=1/y'], + [self::RFC3986_BASE, 'g;x=1/../y', 'http://a/b/c/y'], + // dot-segments in the query or fragment + [self::RFC3986_BASE, 'g?y/./x', 'http://a/b/c/g?y/./x'], + [self::RFC3986_BASE, 'g?y/../x', 'http://a/b/c/g?y/../x'], + [self::RFC3986_BASE, 'g#s/./x', 'http://a/b/c/g#s/./x'], + [self::RFC3986_BASE, 'g#s/../x', 'http://a/b/c/g#s/../x'], + [self::RFC3986_BASE, 'g#s/../x', 'http://a/b/c/g#s/../x'], + [self::RFC3986_BASE, '?y#s', 'http://a/b/c/d;p?y#s'], + // base with fragment + ['http://a/b/c?q#s', '?y', 'http://a/b/c?y'], + // base with user info + ['http://u@a/b/c/d;p?q', '.', 'http://u@a/b/c/'], + ['http://u:p@a/b/c/d;p?q', '.', 'http://u:p@a/b/c/'], + // path ending with slash or no slash at all + ['http://a/b/c/d/', 'e', 'http://a/b/c/d/e'], + ['http:no-slash', 'e', 'http:e'], + // falsey relative parts + [self::RFC3986_BASE, '//0', 'http://0/'], + [self::RFC3986_BASE, '0', 'http://a/b/c/0'], + [self::RFC3986_BASE, '?0', 'http://a/b/c/d;p?0'], + [self::RFC3986_BASE, '#0', 'http://a/b/c/d;p?q#0'], + ]; + } + + public function testResolveUrlWithoutScheme() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid URL: scheme is missing in "//localhost:8080". Did you forget to add "http(s)://"?'); + self::resolveUrl(self::parseUrl('localhost:8080'), null); + } + + public function testResolveBaseUrlWitoutScheme() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid URL: scheme is missing in "//localhost:8081". Did you forget to add "http(s)://"?'); + self::resolveUrl(self::parseUrl('/foo'), self::parseUrl('localhost:8081')); + } + + /** + * @dataProvider provideParseUrl + */ + public function testParseUrl(array $expected, string $url, array $query = []) + { + $expected = array_combine(['scheme', 'authority', 'path', 'query', 'fragment'], $expected); + + $this->assertSame($expected, self::parseUrl($url, $query)); + } + + public function provideParseUrl(): iterable + { + yield [['http:', '//example.com', null, null, null], 'http://Example.coM:80']; + yield [['https:', '//xn--dj-kia8a.example.com:8000', '/', null, null], 'https://DÉjà.Example.com:8000/']; + yield [[null, null, '/f%20o.o', '?a=b', '#c'], '/f o%2Eo?a=b#c']; + yield [[null, '//a:b@foo', '/bar', null, null], '//a:b@foo/bar']; + yield [['http:', null, null, null, null], 'http:']; + yield [['http:', null, 'bar', null, null], 'http:bar']; + yield [[null, null, 'bar', '?a=1&c=c', null], 'bar?a=a&b=b', ['b' => null, 'c' => 'c', 'a' => 1]]; + yield [[null, null, 'bar', '?a=b+c&b=b', null], 'bar?a=b+c', ['b' => 'b']]; + yield [[null, null, 'bar', '?a=b%2B%20c', null], 'bar?a=b+c', ['a' => 'b+ c']]; + yield [[null, null, 'bar', '?a%5Bb%5D=c', null], 'bar', ['a' => ['b' => 'c']]]; + yield [[null, null, 'bar', '?a%5Bb%5Bc%5D=d', null], 'bar?a[b[c]=d', []]; + yield [[null, null, 'bar', '?a%5Bb%5D%5Bc%5D=dd', null], 'bar?a[b][c]=d&e[f]=g', ['a' => ['b' => ['c' => 'dd']], 'e[f]' => null]]; + yield [[null, null, 'bar', '?a=b&a%5Bb%20c%5D=d&e%3Df=%E2%9C%93', null], 'bar?a=b', ['a' => ['b c' => 'd'], 'e=f' => '✓']]; + // IDNA 2008 compliance + yield [['https:', '//xn--fuball-cta.test', null, null, null], 'https://fußball.test']; + } + + /** + * @dataProvider provideRemoveDotSegments + */ + public function testRemoveDotSegments($expected, $url) + { + $this->assertSame($expected, self::removeDotSegments($url)); + } + + public function provideRemoveDotSegments() + { + yield ['', '']; + yield ['', '.']; + yield ['', '..']; + yield ['a', './a']; + yield ['a', '../a']; + yield ['/a/b', '/a/./b']; + yield ['/b/', '/a/../b/.']; + yield ['/a//b/', '/a///../b/.']; + yield ['/a/', '/a/b/..']; + yield ['/a///b', '/a///b']; + } + + public function testAuthBearerOption() + { + [, $options] = self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => 'foobar'], HttpClientInterface::OPTIONS_DEFAULTS); + $this->assertSame(['Accept: */*', 'Authorization: Bearer foobar'], $options['headers']); + $this->assertSame(['Authorization: Bearer foobar'], $options['normalized_headers']['authorization']); + } + + public function testInvalidAuthBearerOption() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Option "auth_bearer" must be a string, "stdClass" given.'); + self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => new \stdClass()], HttpClientInterface::OPTIONS_DEFAULTS); + } + + public function testInvalidAuthBearerValue() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid character found in option "auth_bearer": "a\nb".'); + self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => "a\nb"], HttpClientInterface::OPTIONS_DEFAULTS); + } + + public function testSetAuthBasicAndBearerOptions() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Define either the "auth_basic" or the "auth_bearer" option, setting both is not supported.'); + self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => 'foo', 'auth_basic' => 'foo:bar'], HttpClientInterface::OPTIONS_DEFAULTS); + } + + public function testSetJSONAndBodyOptions() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Define either the "json" or the "body" option, setting both is not supported'); + self::prepareRequest('POST', 'http://example.com', ['json' => ['foo' => 'bar'], 'body' => ''], HttpClientInterface::OPTIONS_DEFAULTS); + } + + public function providePrepareAuthBasic() + { + yield ['foo:bar', 'Zm9vOmJhcg==']; + yield [['foo', 'bar'], 'Zm9vOmJhcg==']; + yield ['foo', 'Zm9v']; + yield [['foo'], 'Zm9v']; + } + + /** + * @dataProvider providePrepareAuthBasic + */ + public function testPrepareAuthBasic($arg, $result) + { + [, $options] = $this->prepareRequest('POST', 'http://example.com', ['auth_basic' => $arg], HttpClientInterface::OPTIONS_DEFAULTS); + $this->assertSame('Authorization: Basic '.$result, $options['normalized_headers']['authorization'][0]); + } + + public function provideFingerprints() + { + foreach (['md5', 'sha1', 'sha256'] as $algo) { + $hash = hash($algo, $algo); + yield [$hash, [$algo => $hash]]; + } + + yield ['AAAA:BBBB:CCCC:DDDD:EEEE:FFFF:GGGG:HHHH:IIII:JJJJ:KKKK', ['pin-sha256' => ['AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKK']]]; + } + + /** + * @dataProvider provideFingerprints + */ + public function testNormalizePeerFingerprint($fingerprint, $expected) + { + self::assertSame($expected, $this->normalizePeerFingerprint($fingerprint)); + } + + public function testNormalizePeerFingerprintException() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Cannot auto-detect fingerprint algorithm for "foo".'); + $this->normalizePeerFingerprint('foo'); + } + + public function testNormalizePeerFingerprintTypeException() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Option "peer_fingerprint" must be string or array, "stdClass" given.'); + $fingerprint = new \stdClass(); + + $this->normalizePeerFingerprint($fingerprint); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/HttpOptionsTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/HttpOptionsTest.php new file mode 100644 index 0000000000..df5cb394df --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/HttpOptionsTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\HttpOptions; + +/** + * @author Kévin Dunglas + */ +class HttpOptionsTest extends TestCase +{ + public function provideSetAuthBasic(): iterable + { + yield ['user:password', 'user', 'password']; + yield ['user:password', 'user:password']; + yield ['user', 'user']; + yield ['user:0', 'user', '0']; + } + + /** + * @dataProvider provideSetAuthBasic + */ + public function testSetAuthBasic(string $expected, string $user, string $password = '') + { + $this->assertSame($expected, (new HttpOptions())->setAuthBasic($user, $password)->toArray()['auth_basic']); + } + + public function testSetAuthBearer() + { + $this->assertSame('foobar', (new HttpOptions())->setAuthBearer('foobar')->toArray()['auth_bearer']); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/HttplugClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/HttplugClientTest.php new file mode 100644 index 0000000000..1f48be5c57 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/HttplugClientTest.php @@ -0,0 +1,270 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use GuzzleHttp\Promise\FulfilledPromise as GuzzleFulfilledPromise; +use Http\Client\Exception\NetworkException; +use Http\Client\Exception\RequestException; +use Http\Promise\FulfilledPromise; +use Http\Promise\Promise; +use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ResponseInterface; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\HttplugClient; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Contracts\HttpClient\Test\TestHttpServer; + +class HttplugClientTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + TestHttpServer::start(); + } + + public function testSendRequest() + { + $client = new HttplugClient(new NativeHttpClient()); + + $response = $client->sendRequest($client->createRequest('GET', 'http://localhost:8057')); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('application/json', $response->getHeaderLine('content-type')); + + $body = json_decode((string) $response->getBody(), true); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + } + + public function testSendAsyncRequest() + { + $client = new HttplugClient(new NativeHttpClient()); + + $promise = $client->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057')); + $successCallableCalled = false; + $failureCallableCalled = false; + $promise->then(function (ResponseInterface $response) use (&$successCallableCalled) { + $successCallableCalled = true; + + return $response; + }, function (\Exception $exception) use (&$failureCallableCalled) { + $failureCallableCalled = true; + + throw $exception; + }); + + $this->assertEquals(Promise::PENDING, $promise->getState()); + + $response = $promise->wait(true); + $this->assertTrue($successCallableCalled, '$promise->then() was never called.'); + $this->assertFalse($failureCallableCalled, 'Failure callable should not be called when request is successful.'); + $this->assertEquals(Promise::FULFILLED, $promise->getState()); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('application/json', $response->getHeaderLine('content-type')); + + $body = json_decode((string) $response->getBody(), true); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + } + + public function testWait() + { + $client = new HttplugClient(new NativeHttpClient()); + + $successCallableCalled = false; + $failureCallableCalled = false; + $client->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057/timeout-body')) + ->then(function (ResponseInterface $response) use (&$successCallableCalled) { + $successCallableCalled = true; + + return $response; + }, function (\Exception $exception) use (&$failureCallableCalled) { + $failureCallableCalled = true; + + throw $exception; + }); + + $client->wait(0); + $this->assertFalse($successCallableCalled, '$promise->then() should not be called yet.'); + + $client->wait(); + $this->assertTrue($successCallableCalled, '$promise->then() should have been called.'); + $this->assertFalse($failureCallableCalled, 'Failure callable should not be called when request is successful.'); + } + + public function testPostRequest() + { + $client = new HttplugClient(new NativeHttpClient()); + + $request = $client->createRequest('POST', 'http://localhost:8057/post') + ->withBody($client->createStream('foo=0123456789')); + + $response = $client->sendRequest($request); + $body = json_decode((string) $response->getBody(), true); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testNetworkException() + { + $client = new HttplugClient(new NativeHttpClient()); + + $this->expectException(NetworkException::class); + $client->sendRequest($client->createRequest('GET', 'http://localhost:8058')); + } + + public function testAsyncNetworkException() + { + $client = new HttplugClient(new NativeHttpClient()); + + $promise = $client->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8058')); + $successCallableCalled = false; + $failureCallableCalled = false; + $promise->then(function (ResponseInterface $response) use (&$successCallableCalled) { + $successCallableCalled = true; + + return $response; + }, function (\Exception $exception) use (&$failureCallableCalled) { + $failureCallableCalled = true; + + throw $exception; + }); + + $promise->wait(false); + $this->assertFalse($successCallableCalled, 'Success callable should not be called when request fails.'); + $this->assertTrue($failureCallableCalled, 'Failure callable was never called.'); + $this->assertEquals(Promise::REJECTED, $promise->getState()); + + $this->expectException(NetworkException::class); + $promise->wait(true); + } + + public function testRequestException() + { + $client = new HttplugClient(new NativeHttpClient()); + + $this->expectException(RequestException::class); + $client->sendRequest($client->createRequest('BAD.METHOD', 'http://localhost:8057')); + } + + public function testRetry404() + { + $client = new HttplugClient(new NativeHttpClient()); + + $successCallableCalled = false; + $failureCallableCalled = false; + + $promise = $client + ->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057/404')) + ->then( + function (ResponseInterface $response) use (&$successCallableCalled, $client) { + $this->assertSame(404, $response->getStatusCode()); + $successCallableCalled = true; + + return $client->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057')); + }, + function (\Exception $exception) use (&$failureCallableCalled) { + $failureCallableCalled = true; + + throw $exception; + } + ) + ; + + $response = $promise->wait(true); + + $this->assertTrue($successCallableCalled); + $this->assertFalse($failureCallableCalled); + $this->assertSame(200, $response->getStatusCode()); + } + + public function testRetryNetworkError() + { + $client = new HttplugClient(new NativeHttpClient()); + + $successCallableCalled = false; + $failureCallableCalled = false; + + $promise = $client + ->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057/chunked-broken')) + ->then(function (ResponseInterface $response) use (&$successCallableCalled) { + $successCallableCalled = true; + + return $response; + }, function (\Exception $exception) use (&$failureCallableCalled, $client) { + $this->assertSame(NetworkException::class, \get_class($exception)); + $this->assertSame(TransportException::class, \get_class($exception->getPrevious())); + $failureCallableCalled = true; + + return $client->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057')); + }) + ; + + $response = $promise->wait(true); + + $this->assertFalse($successCallableCalled); + $this->assertTrue($failureCallableCalled); + $this->assertSame(200, $response->getStatusCode()); + } + + public function testRetryEarlierError() + { + $isFirstRequest = true; + $errorMessage = 'Error occurred before making the actual request.'; + + $client = new HttplugClient(new MockHttpClient(function () use (&$isFirstRequest, $errorMessage) { + if ($isFirstRequest) { + $isFirstRequest = false; + throw new TransportException($errorMessage); + } + + return new MockResponse('OK', ['http_code' => 200]); + })); + + $request = $client->createRequest('GET', 'http://test'); + + $successCallableCalled = false; + $failureCallableCalled = false; + + $promise = $client + ->sendAsyncRequest($request) + ->then( + function (ResponseInterface $response) use (&$successCallableCalled) { + $successCallableCalled = true; + + return $response; + }, + function (\Exception $exception) use ($errorMessage, &$failureCallableCalled, $client, $request) { + $this->assertSame(NetworkException::class, \get_class($exception)); + $this->assertSame($errorMessage, $exception->getMessage()); + $failureCallableCalled = true; + + // Ensure arbitrary levels of promises work. + return (new FulfilledPromise(null))->then(function () use ($client, $request) { + return (new GuzzleFulfilledPromise(null))->then(function () use ($client, $request) { + return $client->sendAsyncRequest($request); + }); + }); + } + ) + ; + + $response = $promise->wait(true); + + $this->assertFalse($successCallableCalled); + $this->assertTrue($failureCallableCalled); + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('OK', (string) $response->getBody()); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/MockHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/MockHttpClientTest.php new file mode 100644 index 0000000000..e06575cfc7 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/MockHttpClientTest.php @@ -0,0 +1,509 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Symfony\Component\HttpClient\Chunk\DataChunk; +use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\ChunkInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class MockHttpClientTest extends HttpClientTestCase +{ + /** + * @dataProvider mockingProvider + */ + public function testMocking($factory, array $expectedResponses) + { + $client = new MockHttpClient($factory); + $this->assertSame(0, $client->getRequestsCount()); + + $urls = ['/foo', '/bar']; + foreach ($urls as $i => $url) { + $response = $client->request('POST', $url, ['body' => 'payload']); + $this->assertEquals($expectedResponses[$i], $response->getContent()); + } + + $this->assertSame(2, $client->getRequestsCount()); + } + + public function mockingProvider(): iterable + { + yield 'callable' => [ + static function (string $method, string $url, array $options = []) { + return new MockResponse($method.': '.$url.' (body='.$options['body'].')'); + }, + [ + 'POST: https://example.com/foo (body=payload)', + 'POST: https://example.com/bar (body=payload)', + ], + ]; + + yield 'array of callable' => [ + [ + static function (string $method, string $url, array $options = []) { + return new MockResponse($method.': '.$url.' (body='.$options['body'].') [1]'); + }, + static function (string $method, string $url, array $options = []) { + return new MockResponse($method.': '.$url.' (body='.$options['body'].') [2]'); + }, + ], + [ + 'POST: https://example.com/foo (body=payload) [1]', + 'POST: https://example.com/bar (body=payload) [2]', + ], + ]; + + yield 'array of response objects' => [ + [ + new MockResponse('static response [1]'), + new MockResponse('static response [2]'), + ], + [ + 'static response [1]', + 'static response [2]', + ], + ]; + + yield 'iterator' => [ + new \ArrayIterator( + [ + new MockResponse('static response [1]'), + new MockResponse('static response [2]'), + ] + ), + [ + 'static response [1]', + 'static response [2]', + ], + ]; + + yield 'null' => [ + null, + [ + '', + '', + ], + ]; + } + + /** + * @dataProvider validResponseFactoryProvider + */ + public function testValidResponseFactory($responseFactory) + { + (new MockHttpClient($responseFactory))->request('GET', 'https://foo.bar'); + + $this->addToAssertionCount(1); + } + + public function validResponseFactoryProvider() + { + return [ + [static function (): MockResponse { return new MockResponse(); }], + [new MockResponse()], + [[new MockResponse()]], + [new \ArrayIterator([new MockResponse()])], + [null], + [(static function (): \Generator { yield new MockResponse(); })()], + ]; + } + + /** + * @dataProvider transportExceptionProvider + */ + public function testTransportExceptionThrowsIfPerformedMoreRequestsThanConfigured($factory) + { + $client = new MockHttpClient($factory); + + $client->request('POST', '/foo'); + $client->request('POST', '/foo'); + + $this->expectException(TransportException::class); + $client->request('POST', '/foo'); + } + + public function transportExceptionProvider(): iterable + { + yield 'array of callable' => [ + [ + static function (string $method, string $url, array $options = []) { + return new MockResponse(); + }, + static function (string $method, string $url, array $options = []) { + return new MockResponse(); + }, + ], + ]; + + yield 'array of response objects' => [ + [ + new MockResponse(), + new MockResponse(), + ], + ]; + + yield 'iterator' => [ + new \ArrayIterator( + [ + new MockResponse(), + new MockResponse(), + ] + ), + ]; + } + + /** + * @dataProvider invalidResponseFactoryProvider + */ + public function testInvalidResponseFactory($responseFactory, string $expectedExceptionMessage) + { + $this->expectException(TransportException::class); + $this->expectExceptionMessage($expectedExceptionMessage); + + (new MockHttpClient($responseFactory))->request('GET', 'https://foo.bar'); + } + + public function invalidResponseFactoryProvider() + { + return [ + [static function (): \Generator { yield new MockResponse(); }, 'The response factory passed to MockHttpClient must return/yield an instance of ResponseInterface, "Generator" given.'], + [static function (): array { return [new MockResponse()]; }, 'The response factory passed to MockHttpClient must return/yield an instance of ResponseInterface, "array" given.'], + [(static function (): \Generator { yield 'ccc'; })(), 'The response factory passed to MockHttpClient must return/yield an instance of ResponseInterface, "string" given.'], + ]; + } + + public function testZeroStatusCode() + { + $client = new MockHttpClient(new MockResponse('', ['response_headers' => ['HTTP/1.1 000 ']])); + $response = $client->request('GET', 'https://foo.bar'); + $this->assertSame(0, $response->getStatusCode()); + } + + public function testFixContentLength() + { + $client = new MockHttpClient(); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => 'abc=def', + 'headers' => ['Content-Length: 4'], + ]); + + $requestOptions = $response->getRequestOptions(); + $this->assertSame('Content-Length: 7', $requestOptions['headers'][0]); + $this->assertSame(['Content-Length: 7'], $requestOptions['normalized_headers']['content-length']); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => 'abc=def', + ]); + + $requestOptions = $response->getRequestOptions(); + $this->assertSame('Content-Length: 7', $requestOptions['headers'][1]); + $this->assertSame(['Content-Length: 7'], $requestOptions['normalized_headers']['content-length']); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => "8\r\nSymfony \r\n5\r\nis aw\r\n6\r\nesome!\r\n0\r\n\r\n", + 'headers' => ['Transfer-Encoding: chunked'], + ]); + + $requestOptions = $response->getRequestOptions(); + $this->assertSame(['Content-Length: 19'], $requestOptions['normalized_headers']['content-length']); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => '', + ]); + + $requestOptions = $response->getRequestOptions(); + $this->assertFalse(isset($requestOptions['normalized_headers']['content-length'])); + } + + public function testThrowExceptionInBodyGenerator() + { + $mockHttpClient = new MockHttpClient([ + new MockResponse((static function (): \Generator { + yield 'foo'; + throw new TransportException('foo ccc'); + })()), + new MockResponse((static function (): \Generator { + yield 'bar'; + throw new \RuntimeException('bar ccc'); + })()), + ]); + + try { + $mockHttpClient->request('GET', 'https://symfony.com', [])->getContent(); + $this->fail(); + } catch (TransportException $e) { + $this->assertEquals(new TransportException('foo ccc'), $e->getPrevious()); + $this->assertSame('foo ccc', $e->getMessage()); + } + + $chunks = []; + try { + foreach ($mockHttpClient->stream($mockHttpClient->request('GET', 'https://symfony.com', [])) as $chunk) { + $chunks[] = $chunk; + } + $this->fail(); + } catch (TransportException $e) { + $this->assertEquals(new \RuntimeException('bar ccc'), $e->getPrevious()); + $this->assertSame('bar ccc', $e->getMessage()); + } + + $this->assertCount(3, $chunks); + $this->assertEquals(new FirstChunk(0, ''), $chunks[0]); + $this->assertEquals(new DataChunk(0, 'bar'), $chunks[1]); + $this->assertInstanceOf(ErrorChunk::class, $chunks[2]); + $this->assertSame(3, $chunks[2]->getOffset()); + $this->assertSame('bar ccc', $chunks[2]->getError()); + } + + public function testMergeDefaultOptions() + { + $mockHttpClient = new MockHttpClient(null, 'https://example.com'); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid URL: scheme is missing'); + $mockHttpClient->request('GET', '/foo', ['base_uri' => null]); + } + + protected function getHttpClient(string $testCase): HttpClientInterface + { + $responses = []; + + $headers = [ + 'Host: localhost:8057', + 'Content-Type: application/json', + ]; + + $body = '{ + "SERVER_PROTOCOL": "HTTP/1.1", + "SERVER_NAME": "127.0.0.1", + "REQUEST_URI": "/", + "REQUEST_METHOD": "GET", + "HTTP_ACCEPT": "*/*", + "HTTP_FOO": "baR", + "HTTP_HOST": "localhost:8057" +}'; + + $client = new NativeHttpClient(); + + switch ($testCase) { + default: + return new MockHttpClient(function (string $method, string $url, array $options) use ($client) { + try { + // force the request to be completed so that we don't test side effects of the transport + $response = $client->request($method, $url, ['buffer' => false] + $options); + $content = $response->getContent(false); + + return new MockResponse($content, $response->getInfo()); + } catch (\Throwable $e) { + $this->fail($e->getMessage()); + } + }); + + case 'testUnsupportedOption': + $this->markTestSkipped('MockHttpClient accepts any options by default'); + break; + + case 'testChunkedEncoding': + $this->markTestSkipped("MockHttpClient doesn't dechunk"); + break; + + case 'testGzipBroken': + $this->markTestSkipped("MockHttpClient doesn't unzip"); + break; + + case 'testTimeoutWithActiveConcurrentStream': + $this->markTestSkipped('Real transport required'); + break; + + case 'testTimeoutOnInitialize': + case 'testTimeoutOnDestruct': + $this->markTestSkipped('Real transport required'); + break; + + case 'testDestruct': + $this->markTestSkipped("MockHttpClient doesn't timeout on destruct"); + break; + + case 'testHandleIsRemovedOnException': + $this->markTestSkipped("MockHttpClient doesn't cache handles"); + break; + + case 'testPause': + case 'testPauseReplace': + case 'testPauseDuringBody': + $this->markTestSkipped("MockHttpClient doesn't support pauses by default"); + break; + + case 'testDnsFailure': + $this->markTestSkipped("MockHttpClient doesn't use a DNS"); + break; + + case 'testGetRequest': + array_unshift($headers, 'HTTP/1.1 200 OK'); + $responses[] = new MockResponse($body, ['response_headers' => $headers]); + + $headers = [ + 'Host: localhost:8057', + 'Content-Length: 1000', + 'Content-Type: application/json', + ]; + + $responses[] = new MockResponse($body, ['response_headers' => $headers]); + break; + + case 'testDnsError': + $responses[] = $mockResponse = new MockResponse('', ['error' => 'DNS error']); + $responses[] = $mockResponse; + break; + + case 'testToStream': + case 'testBadRequestBody': + case 'testOnProgressCancel': + case 'testOnProgressError': + case 'testReentrantBufferCallback': + case 'testThrowingBufferCallback': + case 'testInfoOnCanceledResponse': + case 'testChangeResponseFactory': + $responses[] = new MockResponse($body, ['response_headers' => $headers]); + break; + + case 'testTimeoutOnAccess': + $responses[] = new MockResponse('', ['error' => 'Timeout']); + break; + + case 'testAcceptHeader': + $responses[] = new MockResponse($body, ['response_headers' => $headers]); + $responses[] = new MockResponse(str_replace('*/*', 'foo/bar', $body), ['response_headers' => $headers]); + $responses[] = new MockResponse(str_replace('"HTTP_ACCEPT": "*/*",', '', $body), ['response_headers' => $headers]); + break; + + case 'testResolve': + $responses[] = new MockResponse($body, ['response_headers' => $headers]); + $responses[] = new MockResponse($body, ['response_headers' => $headers]); + $responses[] = new MockResponse((function () { yield ''; })(), ['response_headers' => $headers]); + break; + + case 'testTimeoutOnStream': + case 'testUncheckedTimeoutThrows': + case 'testTimeoutIsNotAFatalError': + $body = ['<1>', '', '<2>']; + $responses[] = new MockResponse($body, ['response_headers' => $headers]); + break; + + case 'testInformationalResponseStream': + $client = $this->createMock(HttpClientInterface::class); + $response = new MockResponse('Here the body', ['response_headers' => [ + 'HTTP/1.1 103 ', + 'Link: ; rel=preload; as=style', + 'HTTP/1.1 200 ', + 'Date: foo', + 'Content-Length: 13', + ]]); + $client->method('request')->willReturn($response); + $client->method('stream')->willReturn(new ResponseStream((function () use ($response) { + $chunk = $this->createMock(ChunkInterface::class); + $chunk->method('getInformationalStatus') + ->willReturn([103, ['link' => ['; rel=preload; as=style', '; rel=preload; as=script']]]); + + yield $response => $chunk; + + $chunk = $this->createMock(ChunkInterface::class); + $chunk->method('isFirst')->willReturn(true); + + yield $response => $chunk; + + $chunk = $this->createMock(ChunkInterface::class); + $chunk->method('getContent')->willReturn('Here the body'); + + yield $response => $chunk; + + $chunk = $this->createMock(ChunkInterface::class); + $chunk->method('isLast')->willReturn(true); + + yield $response => $chunk; + })())); + + return $client; + + case 'testNonBlockingStream': + case 'testSeekAsyncStream': + $responses[] = new MockResponse((function () { yield '<1>'; yield ''; yield '<2>'; })(), ['response_headers' => $headers]); + break; + + case 'testMaxDuration': + $responses[] = new MockResponse('', ['error' => 'Max duration was reached.']); + break; + } + + return new MockHttpClient($responses); + } + + public function testHttp2PushVulcain() + { + $this->markTestSkipped('MockHttpClient doesn\'t support HTTP/2 PUSH.'); + } + + public function testHttp2PushVulcainWithUnusedResponse() + { + $this->markTestSkipped('MockHttpClient doesn\'t support HTTP/2 PUSH.'); + } + + public function testChangeResponseFactory() + { + /* @var MockHttpClient $client */ + $client = $this->getHttpClient(__METHOD__); + $expectedBody = '{"foo": "bar"}'; + $client->setResponseFactory(new MockResponse($expectedBody)); + + $response = $client->request('GET', 'http://localhost:8057'); + + $this->assertSame($expectedBody, $response->getContent()); + } + + public function testStringableBodyParam() + { + $client = new MockHttpClient(); + + $param = new class() { + public function __toString() + { + return 'bar'; + } + }; + + $response = $client->request('GET', 'https://example.com', [ + 'body' => ['foo' => $param], + ]); + + $this->assertSame('foo=bar', $response->getRequestOptions()['body']); + } + + public function testResetsRequestCount() + { + $client = new MockHttpClient([new MockResponse()]); + $this->assertSame(0, $client->getRequestsCount()); + + $client->request('POST', '/url', ['body' => 'payload']); + + $this->assertSame(1, $client->getRequestsCount()); + $client->reset(); + $this->assertSame(0, $client->getRequestsCount()); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/NativeHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/NativeHttpClientTest.php new file mode 100644 index 0000000000..3250b50137 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/NativeHttpClientTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class NativeHttpClientTest extends HttpClientTestCase +{ + protected function getHttpClient(string $testCase): HttpClientInterface + { + return new NativeHttpClient(); + } + + public function testInformationalResponseStream() + { + $this->markTestSkipped('NativeHttpClient doesn\'t support informational status codes.'); + } + + public function testTimeoutOnInitialize() + { + $this->markTestSkipped('NativeHttpClient doesn\'t support opening concurrent requests.'); + } + + public function testTimeoutOnDestruct() + { + $this->markTestSkipped('NativeHttpClient doesn\'t support opening concurrent requests.'); + } + + public function testHttp2PushVulcain() + { + $this->markTestSkipped('NativeHttpClient doesn\'t support HTTP/2.'); + } + + public function testHttp2PushVulcainWithUnusedResponse() + { + $this->markTestSkipped('NativeHttpClient doesn\'t support HTTP/2.'); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/NoPrivateNetworkHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/NoPrivateNetworkHttpClientTest.php new file mode 100755 index 0000000000..aabfe38c01 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/NoPrivateNetworkHttpClientTest.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\NoPrivateNetworkHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +class NoPrivateNetworkHttpClientTest extends TestCase +{ + public function getExcludeData(): array + { + return [ + // private + ['0.0.0.1', null, true], + ['169.254.0.1', null, true], + ['127.0.0.1', null, true], + ['240.0.0.1', null, true], + ['10.0.0.1', null, true], + ['172.16.0.1', null, true], + ['192.168.0.1', null, true], + ['::1', null, true], + ['::ffff:0:1', null, true], + ['fe80::1', null, true], + ['fc00::1', null, true], + ['fd00::1', null, true], + ['10.0.0.1', '10.0.0.0/24', true], + ['10.0.0.1', '10.0.0.1', true], + ['fc00::1', 'fc00::1/120', true], + ['fc00::1', 'fc00::1', true], + + ['172.16.0.1', ['10.0.0.0/8', '192.168.0.0/16'], false], + ['fc00::1', ['fe80::/10', '::ffff:0:0/96'], false], + + // public + ['104.26.14.6', null, false], + ['104.26.14.6', '104.26.14.0/24', true], + ['2606:4700:20::681a:e06', null, false], + ['2606:4700:20::681a:e06', '2606:4700:20::/43', true], + + // no ipv4/ipv6 at all + ['2606:4700:20::681a:e06', '::/0', true], + ['104.26.14.6', '0.0.0.0/0', true], + + // weird scenarios (e.g.: when trying to match ipv4 address on ipv6 subnet) + ['10.0.0.1', 'fc00::/7', false], + ['fc00::1', '10.0.0.0/8', false], + ]; + } + + /** + * @dataProvider getExcludeData + */ + public function testExclude(string $ipAddr, $subnets, bool $mustThrow) + { + $content = 'foo'; + $url = sprintf('http://%s/', 0 < substr_count($ipAddr, ':') ? sprintf('[%s]', $ipAddr) : $ipAddr); + + if ($mustThrow) { + $this->expectException(TransportException::class); + $this->expectExceptionMessage(sprintf('IP "%s" is blocked for "%s".', $ipAddr, $url)); + } + + $previousHttpClient = $this->getHttpClientMock($url, $ipAddr, $content); + $client = new NoPrivateNetworkHttpClient($previousHttpClient, $subnets); + $response = $client->request('GET', $url); + + if (!$mustThrow) { + $this->assertEquals($content, $response->getContent()); + $this->assertEquals(200, $response->getStatusCode()); + } + } + + public function testCustomOnProgressCallback() + { + $ipAddr = '104.26.14.6'; + $url = sprintf('http://%s/', $ipAddr); + $content = 'foo'; + + $executionCount = 0; + $customCallback = function (int $dlNow, int $dlSize, array $info) use (&$executionCount): void { + ++$executionCount; + }; + + $previousHttpClient = $this->getHttpClientMock($url, $ipAddr, $content); + $client = new NoPrivateNetworkHttpClient($previousHttpClient); + $response = $client->request('GET', $url, ['on_progress' => $customCallback]); + + $this->assertEquals(1, $executionCount); + $this->assertEquals($content, $response->getContent()); + $this->assertEquals(200, $response->getStatusCode()); + } + + public function testNonCallableOnProgressCallback() + { + $ipAddr = '104.26.14.6'; + $url = sprintf('http://%s/', $ipAddr); + $content = 'bar'; + $customCallback = sprintf('cb_%s', microtime(true)); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Option "on_progress" must be callable, "string" given.'); + + $client = new NoPrivateNetworkHttpClient(new MockHttpClient()); + $client->request('GET', $url, ['on_progress' => $customCallback]); + } + + public function testConstructor() + { + $this->expectException(\TypeError::class); + $this->expectExceptionMessage('Argument 2 passed to "Symfony\Component\HttpClient\NoPrivateNetworkHttpClient::__construct()" must be of the type array, string or null. "int" given.'); + + new NoPrivateNetworkHttpClient(new MockHttpClient(), 3); + } + + private function getHttpClientMock(string $url, string $ipAddr, string $content) + { + $previousHttpClient = $this + ->getMockBuilder(HttpClientInterface::class) + ->getMock(); + + $previousHttpClient + ->expects($this->once()) + ->method('request') + ->with( + 'GET', + $url, + $this->callback(function ($options) { + $this->assertArrayHasKey('on_progress', $options); + $onProgress = $options['on_progress']; + $this->assertIsCallable($onProgress); + + return true; + }) + ) + ->willReturnCallback(function ($method, $url, $options) use ($ipAddr, $content): ResponseInterface { + $info = [ + 'primary_ip' => $ipAddr, + 'url' => $url, + ]; + + $onProgress = $options['on_progress']; + $onProgress(0, 0, $info); + + return MockResponse::fromRequest($method, $url, [], new MockResponse($content)); + }); + + return $previousHttpClient; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/Psr18ClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/Psr18ClientTest.php new file mode 100644 index 0000000000..366d555ae0 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/Psr18ClientTest.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Nyholm\Psr7\Factory\Psr17Factory; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Component\HttpClient\Psr18Client; +use Symfony\Component\HttpClient\Psr18NetworkException; +use Symfony\Component\HttpClient\Psr18RequestException; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Contracts\HttpClient\Test\TestHttpServer; + +class Psr18ClientTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + TestHttpServer::start(); + } + + public function testSendRequest() + { + $factory = new Psr17Factory(); + $client = new Psr18Client(new NativeHttpClient(), $factory, $factory); + + $response = $client->sendRequest($factory->createRequest('GET', 'http://localhost:8057')); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('application/json', $response->getHeaderLine('content-type')); + + $body = json_decode((string) $response->getBody(), true); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + } + + public function testPostRequest() + { + $factory = new Psr17Factory(); + $client = new Psr18Client(new NativeHttpClient(), $factory, $factory); + + $request = $factory->createRequest('POST', 'http://localhost:8057/post') + ->withBody($factory->createStream('foo=0123456789')); + + $response = $client->sendRequest($request); + $body = json_decode((string) $response->getBody(), true); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testNetworkException() + { + $factory = new Psr17Factory(); + $client = new Psr18Client(new NativeHttpClient(), $factory, $factory); + + $this->expectException(Psr18NetworkException::class); + $client->sendRequest($factory->createRequest('GET', 'http://localhost:8058')); + } + + public function testRequestException() + { + $factory = new Psr17Factory(); + $client = new Psr18Client(new NativeHttpClient(), $factory, $factory); + + $this->expectException(Psr18RequestException::class); + $client->sendRequest($factory->createRequest('BAD.METHOD', 'http://localhost:8057')); + } + + public function test404() + { + $factory = new Psr17Factory(); + $client = new Psr18Client(new NativeHttpClient()); + + $response = $client->sendRequest($factory->createRequest('GET', 'http://localhost:8057/404')); + $this->assertSame(404, $response->getStatusCode()); + } + + public function testInvalidHeaderResponse() + { + $responseHeaders = [ + // space in header name not allowed in RFC 7230 + ' X-XSS-Protection' => '0', + 'Cache-Control' => 'no-cache', + ]; + $response = new MockResponse('body', ['response_headers' => $responseHeaders]); + $this->assertArrayHasKey(' x-xss-protection', $response->getHeaders()); + + $client = new Psr18Client(new MockHttpClient($response)); + $request = $client->createRequest('POST', 'http://localhost:8057/post') + ->withBody($client->createStream('foo=0123456789')); + + $resultResponse = $client->sendRequest($request); + $this->assertCount(1, $resultResponse->getHeaders()); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/Response/HttplugPromiseTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/Response/HttplugPromiseTest.php new file mode 100644 index 0000000000..d781d4925b --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/Response/HttplugPromiseTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests\Response; + +use GuzzleHttp\Promise\Promise; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Response\HttplugPromise; + +class HttplugPromiseTest extends TestCase +{ + public function testComplexNesting() + { + $mkPromise = function ($result): HttplugPromise { + $guzzlePromise = new Promise(function () use (&$guzzlePromise, $result) { + $guzzlePromise->resolve($result); + }); + + return new HttplugPromise($guzzlePromise); + }; + + $promise1 = $mkPromise('result'); + $promise2 = $promise1->then($mkPromise); + $promise3 = $promise2->then(function ($result) { return $result; }); + + $this->assertSame('result', $promise3->wait()); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/Response/MockResponseTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/Response/MockResponseTest.php new file mode 100644 index 0000000000..d6839fbcfe --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/Response/MockResponseTest.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests\Response; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\JsonException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Response\MockResponse; + +/** + * Test methods from Symfony\Component\HttpClient\Response\*ResponseTrait. + */ +class MockResponseTest extends TestCase +{ + public function testTotalTimeShouldBeSimulatedWhenNotProvided() + { + $response = new MockResponse('body'); + $response = MockResponse::fromRequest('GET', 'https://example.com/file.txt', [], $response); + + $this->assertNotNull($response->getInfo('total_time')); + $this->assertGreaterThan(0.0, $response->getInfo('total_time')); + } + + public function testTotalTimeShouldNotBeSimulatedWhenProvided() + { + $totalTime = 4.2; + $response = new MockResponse('body', ['total_time' => $totalTime]); + $response = MockResponse::fromRequest('GET', 'https://example.com/file.txt', [], $response); + + $this->assertEquals($totalTime, $response->getInfo('total_time')); + } + + public function testToArray() + { + $data = ['color' => 'orange', 'size' => 42]; + $response = new MockResponse(json_encode($data)); + $response = MockResponse::fromRequest('GET', 'https://example.com/file.json', [], $response); + + $this->assertSame($data, $response->toArray()); + } + + /** + * @dataProvider toArrayErrors + */ + public function testToArrayError($content, $responseHeaders, $message) + { + $this->expectException(JsonException::class); + $this->expectExceptionMessage($message); + + $response = new MockResponse($content, ['response_headers' => $responseHeaders]); + $response = MockResponse::fromRequest('GET', 'https://example.com/file.json', [], $response); + $response->toArray(); + } + + public function testUrlHttpMethodMockResponse() + { + $responseMock = new MockResponse(json_encode(['foo' => 'bar'])); + $url = 'https://example.com/some-endpoint'; + $response = MockResponse::fromRequest('GET', $url, [], $responseMock); + + $this->assertSame('GET', $response->getInfo('http_method')); + $this->assertSame('GET', $responseMock->getRequestMethod()); + + $this->assertSame($url, $response->getInfo('url')); + $this->assertSame($url, $responseMock->getRequestUrl()); + } + + public function toArrayErrors() + { + yield [ + 'content' => '', + 'responseHeaders' => [], + 'message' => 'Response body is empty.', + ]; + + yield [ + 'content' => 'not json', + 'responseHeaders' => [], + 'message' => 'Syntax error for "https://example.com/file.json".', + ]; + + yield [ + 'content' => '[1,2}', + 'responseHeaders' => [], + 'message' => 'State mismatch (invalid or malformed JSON) for "https://example.com/file.json".', + ]; + + yield [ + 'content' => '"not an array"', + 'responseHeaders' => [], + 'message' => 'JSON content was expected to decode to an array, "string" returned for "https://example.com/file.json".', + ]; + + yield [ + 'content' => '8', + 'responseHeaders' => [], + 'message' => 'JSON content was expected to decode to an array, "int" returned for "https://example.com/file.json".', + ]; + } + + public function testErrorIsTakenIntoAccountInInitialization() + { + $this->expectException(TransportException::class); + $this->expectExceptionMessage('ccc error'); + + MockResponse::fromRequest('GET', 'https://symfony.com', [], new MockResponse('', [ + 'error' => 'ccc error', + ]))->getStatusCode(); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/Retry/GenericRetryStrategyTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/Retry/GenericRetryStrategyTest.php new file mode 100644 index 0000000000..98b6578f0b --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/Retry/GenericRetryStrategyTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests\Retry; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\AsyncContext; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\Retry\GenericRetryStrategy; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +class GenericRetryStrategyTest extends TestCase +{ + /** + * @dataProvider provideRetryable + */ + public function testShouldRetry(string $method, int $code, ?TransportExceptionInterface $exception) + { + $strategy = new GenericRetryStrategy(); + + self::assertTrue($strategy->shouldRetry($this->getContext(0, $method, 'http://example.com/', $code), null, $exception)); + } + + /** + * @dataProvider provideNotRetryable + */ + public function testShouldNotRetry(string $method, int $code, ?TransportExceptionInterface $exception) + { + $strategy = new GenericRetryStrategy(); + + self::assertFalse($strategy->shouldRetry($this->getContext(0, $method, 'http://example.com/', $code), null, $exception)); + } + + public function provideRetryable(): iterable + { + yield ['GET', 200, new TransportException()]; + yield ['GET', 500, null]; + yield ['POST', 429, null]; + } + + public function provideNotRetryable(): iterable + { + yield ['POST', 200, null]; + yield ['POST', 200, new TransportException()]; + yield ['POST', 500, null]; + } + + /** + * @dataProvider provideDelay + */ + public function testGetDelay(int $delay, int $multiplier, int $maxDelay, int $previousRetries, int $expectedDelay) + { + $strategy = new GenericRetryStrategy([], $delay, $multiplier, $maxDelay, 0); + + self::assertSame($expectedDelay, $strategy->getDelay($this->getContext($previousRetries, 'GET', 'http://example.com/', 200), null, null)); + } + + public function provideDelay(): iterable + { + // delay, multiplier, maxDelay, retries, expectedDelay + yield [1000, 1, 5000, 0, 1000]; + yield [1000, 1, 5000, 1, 1000]; + yield [1000, 1, 5000, 2, 1000]; + + yield [1000, 2, 10000, 0, 1000]; + yield [1000, 2, 10000, 1, 2000]; + yield [1000, 2, 10000, 2, 4000]; + yield [1000, 2, 10000, 3, 8000]; + yield [1000, 2, 10000, 4, 10000]; // max hit + yield [1000, 2, 0, 4, 16000]; // no max + + yield [1000, 3, 10000, 0, 1000]; + yield [1000, 3, 10000, 1, 3000]; + yield [1000, 3, 10000, 2, 9000]; + + yield [1000, 1, 500, 0, 500]; // max hit immediately + + // never a delay + yield [0, 2, 10000, 0, 0]; + yield [0, 2, 10000, 1, 0]; + } + + public function testJitter() + { + $strategy = new GenericRetryStrategy([], 1000, 1, 0, 1); + $min = 2000; + $max = 0; + for ($i = 0; $i < 50; ++$i) { + $delay = $strategy->getDelay($this->getContext(0, 'GET', 'http://example.com/', 200), null, null); + $min = min($min, $delay); + $max = max($max, $delay); + } + $this->assertGreaterThanOrEqual(1000, $max - $min); + $this->assertGreaterThanOrEqual(1000, $max); + $this->assertLessThanOrEqual(1000, $min); + } + + private function getContext($retryCount, $method, $url, $statusCode): AsyncContext + { + $passthru = null; + $info = [ + 'retry_count' => $retryCount, + 'http_method' => $method, + 'url' => $url, + 'http_code' => $statusCode, + ]; + $response = new MockResponse('', $info); + + return new AsyncContext($passthru, new MockHttpClient(), $response, $info, null, 0); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/RetryableHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/RetryableHttpClientTest.php new file mode 100644 index 0000000000..cf2af1560c --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/RetryableHttpClientTest.php @@ -0,0 +1,247 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\ServerException; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Component\HttpClient\Response\AsyncContext; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\Retry\GenericRetryStrategy; +use Symfony\Component\HttpClient\RetryableHttpClient; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +class RetryableHttpClientTest extends TestCase +{ + public function testRetryOnError() + { + $client = new RetryableHttpClient( + new MockHttpClient([ + new MockResponse('', ['http_code' => 500]), + new MockResponse('', ['http_code' => 200]), + ]), + new GenericRetryStrategy([500], 0), + 1 + ); + + $response = $client->request('GET', 'http://example.com/foo-bar'); + + self::assertSame(200, $response->getStatusCode()); + } + + public function testRetryRespectStrategy() + { + $client = new RetryableHttpClient( + new MockHttpClient([ + new MockResponse('', ['http_code' => 500]), + new MockResponse('', ['http_code' => 500]), + new MockResponse('', ['http_code' => 200]), + ]), + new GenericRetryStrategy([500], 0), + 1 + ); + + $response = $client->request('GET', 'http://example.com/foo-bar'); + + $this->expectException(ServerException::class); + $response->getHeaders(); + } + + public function testRetryWithBody() + { + $client = new RetryableHttpClient( + new MockHttpClient([ + new MockResponse('abc', ['http_code' => 500]), + new MockResponse('def', ['http_code' => 200]), + ]), + new class(GenericRetryStrategy::DEFAULT_RETRY_STATUS_CODES, 0) extends GenericRetryStrategy { + public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool + { + return 500 === $context->getStatusCode() && null === $responseContent ? null : 200 !== $context->getStatusCode(); + } + }, + 2 + ); + + $response = $client->request('GET', 'http://example.com/foo-bar'); + + self::assertSame(200, $response->getStatusCode()); + self::assertSame('def', $response->getContent()); + } + + public function testRetryWithBodyKeepContent() + { + $client = new RetryableHttpClient( + new MockHttpClient([ + new MockResponse('my bad', ['http_code' => 400]), + ]), + new class([400], 0) extends GenericRetryStrategy { + public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool + { + if (null === $responseContent) { + return null; + } + + return 'my bad' !== $responseContent; + } + }, + 1 + ); + + $response = $client->request('GET', 'http://example.com/foo-bar'); + + self::assertSame(400, $response->getStatusCode()); + self::assertSame('my bad', $response->getContent(false)); + } + + public function testRetryWithBodyInvalid() + { + $client = new RetryableHttpClient( + new MockHttpClient([ + new MockResponse('', ['http_code' => 500]), + new MockResponse('', ['http_code' => 200]), + ]), + new class(GenericRetryStrategy::DEFAULT_RETRY_STATUS_CODES, 0) extends GenericRetryStrategy { + public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool + { + return null; + } + }, + 1 + ); + + $response = $client->request('GET', 'http://example.com/foo-bar'); + + $this->expectExceptionMessageMatches('/must not return null when called with a body/'); + $response->getHeaders(); + } + + public function testStreamNoRetry() + { + $client = new RetryableHttpClient( + new MockHttpClient([ + new MockResponse('', ['http_code' => 500]), + ]), + new GenericRetryStrategy([500], 0), + 0 + ); + + $response = $client->request('GET', 'http://example.com/foo-bar'); + + foreach ($client->stream($response) as $chunk) { + if ($chunk->isFirst()) { + self::assertSame(500, $response->getStatusCode()); + } + } + } + + public function testRetryWithDnsIssue() + { + $client = new RetryableHttpClient( + new NativeHttpClient(), + new class(GenericRetryStrategy::DEFAULT_RETRY_STATUS_CODES, 0) extends GenericRetryStrategy { + public function shouldRetry(AsyncContext $context, ?string $responseContent, ?TransportExceptionInterface $exception): ?bool + { + $this->fail('should not be called'); + } + }, + 2, + $logger = new TestLogger() + ); + + $response = $client->request('GET', 'http://does.not.exists/foo-bar'); + + try { + $response->getHeaders(); + } catch (TransportExceptionInterface $e) { + $this->assertSame('Could not resolve host "does.not.exists".', $e->getMessage()); + } + $this->assertCount(2, $logger->logs); + $this->assertSame('Try #{count} after {delay}ms: Could not resolve host "does.not.exists".', $logger->logs[0]); + } + + public function testCancelOnTimeout() + { + $client = HttpClient::create(); + + if ($client instanceof NativeHttpClient) { + $this->markTestSkipped('NativeHttpClient cannot timeout before receiving headers'); + } + + $client = new RetryableHttpClient($client); + + $response = $client->request('GET', 'https://example.com/'); + + foreach ($client->stream($response, 0) as $chunk) { + $this->assertTrue($chunk->isTimeout()); + $response->cancel(); + } + } + + public function testRetryWithDelay() + { + $retryAfter = '0.46'; + + $client = new RetryableHttpClient( + new MockHttpClient([ + new MockResponse('', [ + 'http_code' => 503, + 'response_headers' => [ + 'retry-after' => $retryAfter, + ], + ]), + new MockResponse('', [ + 'http_code' => 200, + ]), + ]), + new GenericRetryStrategy(), + 1, + $logger = new class() extends TestLogger { + public $context = []; + + public function log($level, $message, array $context = []): void + { + $this->context = $context; + parent::log($level, $message, $context); + } + } + ); + + $client->request('GET', 'http://example.com/foo-bar')->getContent(); + + $delay = $logger->context['delay'] ?? null; + + $this->assertArrayHasKey('delay', $logger->context); + $this->assertNotNull($delay); + $this->assertSame((int) ($retryAfter * 1000), $delay); + } + + public function testRetryOnErrorAssertContent() + { + $client = new RetryableHttpClient( + new MockHttpClient([ + new MockResponse('', ['http_code' => 500]), + new MockResponse('Test out content', ['http_code' => 200]), + ]), + new GenericRetryStrategy([500], 0), + 1 + ); + + $response = $client->request('GET', 'http://example.com/foo-bar'); + + self::assertSame(200, $response->getStatusCode()); + self::assertSame('Test out content', $response->getContent()); + self::assertSame('Test out content', $response->getContent(), 'Content should be buffered'); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/ScopingHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/ScopingHttpClientTest.php new file mode 100644 index 0000000000..078475bf10 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/ScopingHttpClientTest.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\ScopingHttpClient; + +class ScopingHttpClientTest extends TestCase +{ + public function testRelativeUrl() + { + $mockClient = new MockHttpClient(); + $client = new ScopingHttpClient($mockClient, []); + + $this->expectException(InvalidArgumentException::class); + $client->request('GET', '/foo'); + } + + public function testRelativeUrlWithDefaultRegexp() + { + $mockClient = new MockHttpClient(); + $client = new ScopingHttpClient($mockClient, ['.*' => ['base_uri' => 'http://example.com', 'query' => ['a' => 'b']]], '.*'); + + $this->assertSame('http://example.com/foo?f=g&a=b', $client->request('GET', '/foo?f=g')->getInfo('url')); + } + + /** + * @dataProvider provideMatchingUrls + */ + public function testMatchingUrls(string $regexp, string $url, array $options) + { + $mockClient = new MockHttpClient(); + $client = new ScopingHttpClient($mockClient, $options); + + $response = $client->request('GET', $url); + $requestedOptions = $response->getRequestOptions(); + + $this->assertSame($options[$regexp]['case'], $requestedOptions['case']); + } + + public function provideMatchingUrls() + { + $defaultOptions = [ + '.*/foo-bar' => ['case' => 1], + '.*' => ['case' => 2], + ]; + + yield ['regexp' => '.*/foo-bar', 'url' => 'http://example.com/foo-bar', 'default_options' => $defaultOptions]; + yield ['regexp' => '.*', 'url' => 'http://example.com/bar-foo', 'default_options' => $defaultOptions]; + yield ['regexp' => '.*', 'url' => 'http://example.com/foobar', 'default_options' => $defaultOptions]; + } + + public function testMatchingUrlsAndOptions() + { + $defaultOptions = [ + '.*/foo-bar' => ['headers' => ['X-FooBar' => 'unit-test-foo-bar']], + '.*' => ['headers' => ['Content-Type' => 'text/html']], + ]; + + $mockClient = new MockHttpClient(); + $client = new ScopingHttpClient($mockClient, $defaultOptions); + + $response = $client->request('GET', 'http://example.com/foo-bar', ['json' => ['url' => 'http://example.com']]); + $requestOptions = $response->getRequestOptions(); + $this->assertSame('Content-Type: application/json', $requestOptions['headers'][1]); + $requestJson = json_decode($requestOptions['body'], true); + $this->assertSame('http://example.com', $requestJson['url']); + $this->assertSame('X-FooBar: '.$defaultOptions['.*/foo-bar']['headers']['X-FooBar'], $requestOptions['headers'][0]); + + $response = $client->request('GET', 'http://example.com/bar-foo', ['headers' => ['X-FooBar' => 'unit-test']]); + $requestOptions = $response->getRequestOptions(); + $this->assertSame('X-FooBar: unit-test', $requestOptions['headers'][0]); + $this->assertSame('Content-Type: text/html', $requestOptions['headers'][1]); + + $response = $client->request('GET', 'http://example.com/foobar-foo', ['headers' => ['X-FooBar' => 'unit-test']]); + $requestOptions = $response->getRequestOptions(); + $this->assertSame('X-FooBar: unit-test', $requestOptions['headers'][0]); + $this->assertSame('Content-Type: text/html', $requestOptions['headers'][1]); + } + + public function testForBaseUri() + { + $client = ScopingHttpClient::forBaseUri(new MockHttpClient(null, null), 'http://example.com/foo'); + + $response = $client->request('GET', '/bar'); + $this->assertSame('http://example.com/foo', implode('', $response->getRequestOptions()['base_uri'])); + $this->assertSame('http://example.com/bar', $response->getInfo('url')); + + $response = $client->request('GET', 'http://foo.bar/'); + $this->assertNull($response->getRequestOptions()['base_uri']); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/TestLogger.php b/sites/all/libraries/vendor/symfony/http-client/Tests/TestLogger.php new file mode 100644 index 0000000000..83aa096889 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/TestLogger.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Psr\Log\AbstractLogger; + +class TestLogger extends AbstractLogger +{ + public $logs = []; + + public function log($level, $message, array $context = []): void + { + $this->logs[] = $message; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/Tests/TraceableHttpClientTest.php b/sites/all/libraries/vendor/symfony/http-client/Tests/TraceableHttpClientTest.php new file mode 100755 index 0000000000..5f20e1989d --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/Tests/TraceableHttpClientTest.php @@ -0,0 +1,235 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\ClientException; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\TraceableHttpClient; +use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\Test\TestHttpServer; + +class TraceableHttpClientTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + TestHttpServer::start(); + } + + public function testItTracesRequest() + { + $httpClient = $this->createMock(HttpClientInterface::class); + $httpClient + ->expects($this->any()) + ->method('request') + ->with( + 'GET', + '/foo/bar', + $this->callback(function ($subject) { + $onprogress = $subject['on_progress']; + unset($subject['on_progress'], $subject['extra']); + $this->assertEquals(['options1' => 'foo'], $subject); + + return true; + }) + ) + ->willReturn(MockResponse::fromRequest('GET', '/foo/bar', ['options1' => 'foo'], new MockResponse('hello'))) + ; + + $sut = new TraceableHttpClient($httpClient); + + $sut->request('GET', '/foo/bar', ['options1' => 'foo'])->getContent(); + + $this->assertCount(1, $tracedRequests = $sut->getTracedRequests()); + $actualTracedRequest = $tracedRequests[0]; + $this->assertEquals([ + 'method' => 'GET', + 'url' => '/foo/bar', + 'options' => ['options1' => 'foo'], + 'info' => [], + 'content' => 'hello', + ], $actualTracedRequest); + + $sut->request('GET', '/foo/bar', ['options1' => 'foo', 'extra' => ['trace_content' => false]])->getContent(); + + $this->assertCount(2, $tracedRequests = $sut->getTracedRequests()); + $actualTracedRequest = $tracedRequests[1]; + $this->assertEquals([ + 'method' => 'GET', + 'url' => '/foo/bar', + 'options' => ['options1' => 'foo', 'extra' => ['trace_content' => false]], + 'info' => [], + 'content' => null, + ], $actualTracedRequest); + } + + public function testItCollectsInfoOnRealRequest() + { + $sut = new TraceableHttpClient(new MockHttpClient()); + $sut->request('GET', 'http://localhost:8057'); + $this->assertCount(1, $tracedRequests = $sut->getTracedRequests()); + $actualTracedRequest = $tracedRequests[0]; + $this->assertSame('GET', $actualTracedRequest['info']['http_method']); + $this->assertSame('http://localhost:8057/', $actualTracedRequest['info']['url']); + } + + public function testItExecutesOnProgressOption() + { + $sut = new TraceableHttpClient(new MockHttpClient()); + $foo = 0; + $sut->request('GET', 'http://localhost:8057', ['on_progress' => function (int $dlNow, int $dlSize, array $info) use (&$foo) { + ++$foo; + }]); + $this->assertCount(1, $tracedRequests = $sut->getTracedRequests()); + $actualTracedRequest = $tracedRequests[0]; + $this->assertGreaterThan(0, $foo); + } + + public function testItResetsTraces() + { + $sut = new TraceableHttpClient(new MockHttpClient()); + $sut->request('GET', 'https://example.com/foo/bar'); + $sut->reset(); + $this->assertCount(0, $sut->getTracedRequests()); + } + + public function testStream() + { + $sut = new TraceableHttpClient(new NativeHttpClient()); + $response = $sut->request('GET', 'http://localhost:8057/chunked'); + $chunks = []; + foreach ($sut->stream($response) as $r => $chunk) { + $chunks[] = $chunk->getContent(); + } + $this->assertSame($response, $r); + $this->assertGreaterThan(1, \count($chunks)); + $this->assertSame('Symfony is awesome!', implode('', $chunks)); + } + + public function testToArrayChecksStatusCodeBeforeDecoding() + { + $this->expectException(ClientExceptionInterface::class); + + $sut = new TraceableHttpClient(new MockHttpClient($responseFactory = function (): MockResponse { + return new MockResponse('Errored.', ['http_code' => 400]); + })); + + $response = $sut->request('GET', 'https://example.com/foo/bar'); + $response->toArray(); + } + + public function testStopwatch() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $response = $sut->request('GET', 'http://localhost:8057'); + + $response->getStatusCode(); + $response->getHeaders(); + $response->getContent(); + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057', $events); + $this->assertCount(3, $events['GET http://localhost:8057']->getPeriods()); + $this->assertGreaterThan(0.0, $events['GET http://localhost:8057']->getDuration()); + } + + public function testStopwatchError() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $response = $sut->request('GET', 'http://localhost:8057/404'); + + try { + $response->getContent(); + $this->fail('Response should have thrown an exception'); + } catch (ClientException $e) { + // no-op + } + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057/404', $events); + $this->assertCount(1, $events['GET http://localhost:8057/404']->getPeriods()); + } + + public function testStopwatchStream() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $response = $sut->request('GET', 'http://localhost:8057'); + + $chunkCount = 0; + foreach ($sut->stream([$response]) as $chunk) { + ++$chunkCount; + } + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057', $events); + $this->assertGreaterThanOrEqual($chunkCount, \count($events['GET http://localhost:8057']->getPeriods())); + } + + public function testStopwatchStreamError() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $response = $sut->request('GET', 'http://localhost:8057/404'); + + try { + $chunkCount = 0; + foreach ($sut->stream([$response]) as $chunk) { + ++$chunkCount; + } + $this->fail('Response should have thrown an exception'); + } catch (ClientException $e) { + // no-op + } + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057/404', $events); + $this->assertGreaterThanOrEqual($chunkCount, \count($events['GET http://localhost:8057/404']->getPeriods())); + } + + public function testStopwatchDestruct() + { + $sw = new Stopwatch(true); + $sut = new TraceableHttpClient(new NativeHttpClient(), $sw); + $sut->request('GET', 'http://localhost:8057'); + + $this->assertArrayHasKey('__root__', $sections = $sw->getSections()); + $this->assertCount(1, $events = $sections['__root__']->getEvents()); + $this->assertArrayHasKey('GET http://localhost:8057', $events); + $this->assertCount(1, $events['GET http://localhost:8057']->getPeriods()); + $this->assertGreaterThan(0.0, $events['GET http://localhost:8057']->getDuration()); + } + + public function testWithOptions() + { + $sut = new TraceableHttpClient(new NativeHttpClient()); + + $sut2 = $sut->withOptions(['base_uri' => 'http://localhost:8057']); + + $response = $sut2->request('GET', '/'); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('http://localhost:8057/', $response->getInfo('url')); + + $this->assertCount(1, $sut->getTracedRequests()); + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/TraceableHttpClient.php b/sites/all/libraries/vendor/symfony/http-client/TraceableHttpClient.php new file mode 100644 index 0000000000..76c9282243 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/TraceableHttpClient.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Component\HttpClient\Response\TraceableResponse; +use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * @author Jérémy Romey + */ +final class TraceableHttpClient implements HttpClientInterface, ResetInterface, LoggerAwareInterface +{ + private $client; + private $stopwatch; + private $tracedRequests; + + public function __construct(HttpClientInterface $client, Stopwatch $stopwatch = null) + { + $this->client = $client; + $this->stopwatch = $stopwatch; + $this->tracedRequests = new \ArrayObject(); + } + + /** + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + $content = null; + $traceInfo = []; + $this->tracedRequests[] = [ + 'method' => $method, + 'url' => $url, + 'options' => $options, + 'info' => &$traceInfo, + 'content' => &$content, + ]; + $onProgress = $options['on_progress'] ?? null; + + if (false === ($options['extra']['trace_content'] ?? true)) { + unset($content); + $content = false; + } + + $options['on_progress'] = function (int $dlNow, int $dlSize, array $info) use (&$traceInfo, $onProgress) { + $traceInfo = $info; + + if (null !== $onProgress) { + $onProgress($dlNow, $dlSize, $info); + } + }; + + return new TraceableResponse($this->client, $this->client->request($method, $url, $options), $content, null === $this->stopwatch ? null : $this->stopwatch->start("$method $url", 'http_client')); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof TraceableResponse) { + $responses = [$responses]; + } elseif (!is_iterable($responses)) { + throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of TraceableResponse objects, "%s" given.', __METHOD__, get_debug_type($responses))); + } + + return new ResponseStream(TraceableResponse::stream($this->client, $responses, $timeout)); + } + + public function getTracedRequests(): array + { + return $this->tracedRequests->getArrayCopy(); + } + + public function reset() + { + if ($this->client instanceof ResetInterface) { + $this->client->reset(); + } + + $this->tracedRequests->exchangeArray([]); + } + + /** + * {@inheritdoc} + */ + public function setLogger(LoggerInterface $logger): void + { + if ($this->client instanceof LoggerAwareInterface) { + $this->client->setLogger($logger); + } + } + + /** + * {@inheritdoc} + */ + public function withOptions(array $options): self + { + $clone = clone $this; + $clone->client = $this->client->withOptions($options); + + return $clone; + } +} diff --git a/sites/all/libraries/vendor/symfony/http-client/composer.json b/sites/all/libraries/vendor/symfony/http-client/composer.json new file mode 100644 index 0000000000..084c258121 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/composer.json @@ -0,0 +1,53 @@ +{ + "name": "symfony/http-client", + "type": "library", + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "2.4" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/http-client-contracts": "^2.4", + "symfony/polyfill-php73": "^1.11", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.0|^2|^3" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4.13|^5.1.5|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\HttpClient\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/sites/all/libraries/vendor/symfony/http-client/phpunit.xml.dist b/sites/all/libraries/vendor/symfony/http-client/phpunit.xml.dist new file mode 100644 index 0000000000..4a055dcf50 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/http-client/phpunit.xml.dist @@ -0,0 +1,30 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Tests + ./vendor + + + + diff --git a/sites/all/libraries/vendor/symfony/polyfill-php73/LICENSE b/sites/all/libraries/vendor/symfony/polyfill-php73/LICENSE new file mode 100644 index 0000000000..3f853aaf35 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php73/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2019 Fabien Potencier + +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/sites/all/libraries/vendor/symfony/polyfill-php73/Php73.php b/sites/all/libraries/vendor/symfony/polyfill-php73/Php73.php new file mode 100644 index 0000000000..65c35a6a11 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php73/Php73.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php73; + +/** + * @author Gabriel Caruso + * @author Ion Bazan + * + * @internal + */ +final class Php73 +{ + public static $startAt = 1533462603; + + /** + * @param bool $asNum + * + * @return array|float|int + */ + public static function hrtime($asNum = false) + { + $ns = microtime(false); + $s = substr($ns, 11) - self::$startAt; + $ns = 1E9 * (float) $ns; + + if ($asNum) { + $ns += $s * 1E9; + + return \PHP_INT_SIZE === 4 ? $ns : (int) $ns; + } + + return [$s, (int) $ns]; + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php73/README.md b/sites/all/libraries/vendor/symfony/polyfill-php73/README.md new file mode 100644 index 0000000000..032fafbda0 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php73/README.md @@ -0,0 +1,18 @@ +Symfony Polyfill / Php73 +======================== + +This component provides functions added to PHP 7.3 core: + +- [`array_key_first`](https://php.net/array_key_first) +- [`array_key_last`](https://php.net/array_key_last) +- [`hrtime`](https://php.net/function.hrtime) +- [`is_countable`](https://php.net/is_countable) +- [`JsonException`](https://php.net/JsonException) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/sites/all/libraries/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php b/sites/all/libraries/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php new file mode 100644 index 0000000000..f06d6c2694 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 70300) { + class JsonException extends Exception + { + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php73/bootstrap.php b/sites/all/libraries/vendor/symfony/polyfill-php73/bootstrap.php new file mode 100644 index 0000000000..d6b2153823 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php73/bootstrap.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php73 as p; + +if (\PHP_VERSION_ID >= 70300) { + return; +} + +if (!function_exists('is_countable')) { + function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; } +} +if (!function_exists('hrtime')) { + require_once __DIR__.'/Php73.php'; + p\Php73::$startAt = (int) microtime(true); + function hrtime($as_number = false) { return p\Php73::hrtime($as_number); } +} +if (!function_exists('array_key_first')) { + function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } } +} +if (!function_exists('array_key_last')) { + function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php73/composer.json b/sites/all/libraries/vendor/symfony/polyfill-php73/composer.json new file mode 100644 index 0000000000..b5c58ec193 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php73/composer.json @@ -0,0 +1,36 @@ +{ + "name": "symfony/polyfill-php73", + "type": "library", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php73\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/LICENSE b/sites/all/libraries/vendor/symfony/polyfill-php80/LICENSE new file mode 100644 index 0000000000..5593b1d84f --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020 Fabien Potencier + +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/sites/all/libraries/vendor/symfony/polyfill-php80/Php80.php b/sites/all/libraries/vendor/symfony/polyfill-php80/Php80.php new file mode 100644 index 0000000000..362dd1a959 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/Php80.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Ion Bazan + * @author Nico Oelgart + * @author Nicolas Grekas + * + * @internal + */ +final class Php80 +{ + public static function fdiv(float $dividend, float $divisor): float + { + return @($dividend / $divisor); + } + + public static function get_debug_type($value): string + { + switch (true) { + case null === $value: return 'null'; + case \is_bool($value): return 'bool'; + case \is_string($value): return 'string'; + case \is_array($value): return 'array'; + case \is_int($value): return 'int'; + case \is_float($value): return 'float'; + case \is_object($value): break; + case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; + default: + if (null === $type = @get_resource_type($value)) { + return 'unknown'; + } + + if ('Unknown' === $type) { + $type = 'closed'; + } + + return "resource ($type)"; + } + + $class = \get_class($value); + + if (false === strpos($class, '@')) { + return $class; + } + + return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; + } + + public static function get_resource_id($res): int + { + if (!\is_resource($res) && null === @get_resource_type($res)) { + throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); + } + + return (int) $res; + } + + public static function preg_last_error_msg(): string + { + switch (preg_last_error()) { + case \PREG_INTERNAL_ERROR: + return 'Internal error'; + case \PREG_BAD_UTF8_ERROR: + return 'Malformed UTF-8 characters, possibly incorrectly encoded'; + case \PREG_BAD_UTF8_OFFSET_ERROR: + return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; + case \PREG_BACKTRACK_LIMIT_ERROR: + return 'Backtrack limit exhausted'; + case \PREG_RECURSION_LIMIT_ERROR: + return 'Recursion limit exhausted'; + case \PREG_JIT_STACKLIMIT_ERROR: + return 'JIT stack limit exhausted'; + case \PREG_NO_ERROR: + return 'No error'; + default: + return 'Unknown error'; + } + } + + public static function str_contains(string $haystack, string $needle): bool + { + return '' === $needle || false !== strpos($haystack, $needle); + } + + public static function str_starts_with(string $haystack, string $needle): bool + { + return 0 === strncmp($haystack, $needle, \strlen($needle)); + } + + public static function str_ends_with(string $haystack, string $needle): bool + { + if ('' === $needle || $needle === $haystack) { + return true; + } + + if ('' === $haystack) { + return false; + } + + $needleLength = \strlen($needle); + + return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength); + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/PhpToken.php b/sites/all/libraries/vendor/symfony/polyfill-php80/PhpToken.php new file mode 100644 index 0000000000..fe6e691056 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/PhpToken.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Fedonyuk Anton + * + * @internal + */ +class PhpToken implements \Stringable +{ + /** + * @var int + */ + public $id; + + /** + * @var string + */ + public $text; + + /** + * @var int + */ + public $line; + + /** + * @var int + */ + public $pos; + + public function __construct(int $id, string $text, int $line = -1, int $position = -1) + { + $this->id = $id; + $this->text = $text; + $this->line = $line; + $this->pos = $position; + } + + public function getTokenName(): ?string + { + if ('UNKNOWN' === $name = token_name($this->id)) { + $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text; + } + + return $name; + } + + /** + * @param int|string|array $kind + */ + public function is($kind): bool + { + foreach ((array) $kind as $value) { + if (\in_array($value, [$this->id, $this->text], true)) { + return true; + } + } + + return false; + } + + public function isIgnorable(): bool + { + return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true); + } + + public function __toString(): string + { + return (string) $this->text; + } + + /** + * @return static[] + */ + public static function tokenize(string $code, int $flags = 0): array + { + $line = 1; + $position = 0; + $tokens = token_get_all($code, $flags); + foreach ($tokens as $index => $token) { + if (\is_string($token)) { + $id = \ord($token); + $text = $token; + } else { + [$id, $text, $line] = $token; + } + $tokens[$index] = new static($id, $text, $line, $position); + $position += \strlen($text); + } + + return $tokens; + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/README.md b/sites/all/libraries/vendor/symfony/polyfill-php80/README.md new file mode 100644 index 0000000000..3816c559d5 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/README.md @@ -0,0 +1,25 @@ +Symfony Polyfill / Php80 +======================== + +This component provides features added to PHP 8.0 core: + +- [`Stringable`](https://php.net/stringable) interface +- [`fdiv`](https://php.net/fdiv) +- [`ValueError`](https://php.net/valueerror) class +- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class +- `FILTER_VALIDATE_BOOL` constant +- [`get_debug_type`](https://php.net/get_debug_type) +- [`PhpToken`](https://php.net/phptoken) class +- [`preg_last_error_msg`](https://php.net/preg_last_error_msg) +- [`str_contains`](https://php.net/str_contains) +- [`str_starts_with`](https://php.net/str_starts_with) +- [`str_ends_with`](https://php.net/str_ends_with) +- [`get_resource_id`](https://php.net/get_resource_id) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php new file mode 100644 index 0000000000..2b955423fc --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#[Attribute(Attribute::TARGET_CLASS)] +final class Attribute +{ + public const TARGET_CLASS = 1; + public const TARGET_FUNCTION = 2; + public const TARGET_METHOD = 4; + public const TARGET_PROPERTY = 8; + public const TARGET_CLASS_CONSTANT = 16; + public const TARGET_PARAMETER = 32; + public const TARGET_ALL = 63; + public const IS_REPEATABLE = 64; + + /** @var int */ + public $flags; + + public function __construct(int $flags = self::TARGET_ALL) + { + $this->flags = $flags; + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php new file mode 100644 index 0000000000..bd1212f6e4 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) { + class PhpToken extends Symfony\Polyfill\Php80\PhpToken + { + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php new file mode 100644 index 0000000000..7c62d7508b --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + interface Stringable + { + /** + * @return string + */ + public function __toString(); + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php new file mode 100644 index 0000000000..01c6c6c8ab --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + class UnhandledMatchError extends Error + { + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php new file mode 100644 index 0000000000..783dbc28c7 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + class ValueError extends Error + { + } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/bootstrap.php b/sites/all/libraries/vendor/symfony/polyfill-php80/bootstrap.php new file mode 100644 index 0000000000..e5f7dbc1a4 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/bootstrap.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php80 as p; + +if (\PHP_VERSION_ID >= 80000) { + return; +} + +if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) { + define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); +} + +if (!function_exists('fdiv')) { + function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); } +} +if (!function_exists('preg_last_error_msg')) { + function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } +} +if (!function_exists('str_contains')) { + function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_starts_with')) { + function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_ends_with')) { + function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('get_debug_type')) { + function get_debug_type($value): string { return p\Php80::get_debug_type($value); } +} +if (!function_exists('get_resource_id')) { + function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); } +} diff --git a/sites/all/libraries/vendor/symfony/polyfill-php80/composer.json b/sites/all/libraries/vendor/symfony/polyfill-php80/composer.json new file mode 100644 index 0000000000..bd9a3262a9 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/polyfill-php80/composer.json @@ -0,0 +1,40 @@ +{ + "name": "symfony/polyfill-php80", + "type": "library", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/sites/all/libraries/vendor/symfony/service-contracts/Attribute/Required.php b/sites/all/libraries/vendor/symfony/service-contracts/Attribute/Required.php new file mode 100644 index 0000000000..9df851189a --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/Attribute/Required.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Attribute; + +/** + * A required dependency. + * + * This attribute indicates that a property holds a required dependency. The annotated property or method should be + * considered during the instantiation process of the containing class. + * + * @author Alexander M. Turek + */ +#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] +final class Required +{ +} diff --git a/sites/all/libraries/vendor/symfony/service-contracts/Attribute/SubscribedService.php b/sites/all/libraries/vendor/symfony/service-contracts/Attribute/SubscribedService.php new file mode 100644 index 0000000000..10d1bc38e8 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/Attribute/SubscribedService.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Attribute; + +use Symfony\Contracts\Service\ServiceSubscriberTrait; + +/** + * Use with {@see ServiceSubscriberTrait} to mark a method's return type + * as a subscribed service. + * + * @author Kevin Bond + */ +#[\Attribute(\Attribute::TARGET_METHOD)] +final class SubscribedService +{ + /** + * @param string|null $key The key to use for the service + * If null, use "ClassName::methodName" + */ + public function __construct( + public ?string $key = null + ) { + } +} diff --git a/sites/all/libraries/vendor/symfony/service-contracts/CHANGELOG.md b/sites/all/libraries/vendor/symfony/service-contracts/CHANGELOG.md new file mode 100644 index 0000000000..7932e26132 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/sites/all/libraries/vendor/symfony/service-contracts/LICENSE b/sites/all/libraries/vendor/symfony/service-contracts/LICENSE new file mode 100644 index 0000000000..74cdc2dbf6 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +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/sites/all/libraries/vendor/symfony/service-contracts/README.md b/sites/all/libraries/vendor/symfony/service-contracts/README.md new file mode 100644 index 0000000000..41e054a101 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/README.md @@ -0,0 +1,9 @@ +Symfony Service Contracts +========================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful - and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/sites/all/libraries/vendor/symfony/service-contracts/ResetInterface.php b/sites/all/libraries/vendor/symfony/service-contracts/ResetInterface.php new file mode 100644 index 0000000000..1af1075eee --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/ResetInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * Provides a way to reset an object to its initial state. + * + * When calling the "reset()" method on an object, it should be put back to its + * initial state. This usually means clearing any internal buffers and forwarding + * the call to internal dependencies. All properties of the object should be put + * back to the same state it had when it was first ready to use. + * + * This method could be called, for example, to recycle objects that are used as + * services, so that they can be used to handle several requests in the same + * process loop (note that we advise making your services stateless instead of + * implementing this interface when possible.) + */ +interface ResetInterface +{ + public function reset(); +} diff --git a/sites/all/libraries/vendor/symfony/service-contracts/ServiceLocatorTrait.php b/sites/all/libraries/vendor/symfony/service-contracts/ServiceLocatorTrait.php new file mode 100644 index 0000000000..74dfa4362e --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/ServiceLocatorTrait.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(ContainerExceptionInterface::class); +class_exists(NotFoundExceptionInterface::class); + +/** + * A trait to help implement ServiceProviderInterface. + * + * @author Robin Chalas + * @author Nicolas Grekas + */ +trait ServiceLocatorTrait +{ + private $factories; + private $loading = []; + private $providedTypes; + + /** + * @param callable[] $factories + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function has(string $id) + { + return isset($this->factories[$id]); + } + + /** + * {@inheritdoc} + * + * @return mixed + */ + public function get(string $id) + { + if (!isset($this->factories[$id])) { + throw $this->createNotFoundException($id); + } + + if (isset($this->loading[$id])) { + $ids = array_values($this->loading); + $ids = \array_slice($this->loading, array_search($id, $ids)); + $ids[] = $id; + + throw $this->createCircularReferenceException($id, $ids); + } + + $this->loading[$id] = $id; + try { + return $this->factories[$id]($this); + } finally { + unset($this->loading[$id]); + } + } + + /** + * {@inheritdoc} + */ + public function getProvidedServices(): array + { + if (null === $this->providedTypes) { + $this->providedTypes = []; + + foreach ($this->factories as $name => $factory) { + if (!\is_callable($factory)) { + $this->providedTypes[$name] = '?'; + } else { + $type = (new \ReflectionFunction($factory))->getReturnType(); + + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; + } + } + } + + return $this->providedTypes; + } + + private function createNotFoundException(string $id): NotFoundExceptionInterface + { + if (!$alternatives = array_keys($this->factories)) { + $message = 'is empty...'; + } else { + $last = array_pop($alternatives); + if ($alternatives) { + $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + } else { + $message = sprintf('only knows about the "%s" service.', $last); + } + } + + if ($this->loading) { + $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + } else { + $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + } + + return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { + }; + } + + private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface + { + return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + }; + } +} diff --git a/sites/all/libraries/vendor/symfony/service-contracts/ServiceProviderInterface.php b/sites/all/libraries/vendor/symfony/service-contracts/ServiceProviderInterface.php new file mode 100644 index 0000000000..c60ad0bd4b --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/ServiceProviderInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; + +/** + * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container. + * + * @author Nicolas Grekas + * @author Mateusz Sip + */ +interface ServiceProviderInterface extends ContainerInterface +{ + /** + * Returns an associative array of service types keyed by the identifiers provided by the current container. + * + * Examples: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface + * * ['foo' => '?'] means the container provides service name "foo" of unspecified type + * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null + * + * @return string[] The provided service types, keyed by service names + */ + public function getProvidedServices(): array; +} diff --git a/sites/all/libraries/vendor/symfony/service-contracts/ServiceSubscriberInterface.php b/sites/all/libraries/vendor/symfony/service-contracts/ServiceSubscriberInterface.php new file mode 100644 index 0000000000..098ab908cd --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/ServiceSubscriberInterface.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. + * + * The getSubscribedServices method returns an array of service types required by such instances, + * optionally keyed by the service names used internally. Service types that start with an interrogation + * mark "?" are optional, while the other ones are mandatory service dependencies. + * + * The injected service locators SHOULD NOT allow access to any other services not specified by the method. + * + * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. + * This interface does not dictate any injection method for these service locators, although constructor + * injection is recommended. + * + * @author Nicolas Grekas + */ +interface ServiceSubscriberInterface +{ + /** + * Returns an array of service types required by such instances, optionally keyed by the service names used internally. + * + * For mandatory dependencies: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name + * internally to fetch a service which must implement Psr\Log\LoggerInterface. + * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name + * internally to fetch an iterable of Psr\Log\LoggerInterface instances. + * * ['Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] + * + * otherwise: + * + * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency + * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency + * * ['?Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] + * + * @return string[] The required service types, optionally keyed by service names + */ + public static function getSubscribedServices(); +} diff --git a/sites/all/libraries/vendor/symfony/service-contracts/ServiceSubscriberTrait.php b/sites/all/libraries/vendor/symfony/service-contracts/ServiceSubscriberTrait.php new file mode 100644 index 0000000000..16e3eb2c19 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/ServiceSubscriberTrait.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\SubscribedService; + +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services from + * method return types. Service ids are available as "ClassName::methodName". + * + * @author Kevin Bond + */ +trait ServiceSubscriberTrait +{ + /** @var ContainerInterface */ + protected $container; + + /** + * {@inheritdoc} + */ + public static function getSubscribedServices(): array + { + $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + $attributeOptIn = false; + + if (\PHP_VERSION_ID >= 80000) { + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { + continue; + } + + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + + if (!$returnType = $method->getReturnType()) { + throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + + $serviceId = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; + + if ($returnType->allowsNull()) { + $serviceId = '?'.$serviceId; + } + + $services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = $serviceId; + $attributeOptIn = true; + } + } + + if (!$attributeOptIn) { + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + continue; + } + + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!($returnType = $method->getReturnType()) instanceof \ReflectionNamedType) { + continue; + } + + if ($returnType->isBuiltin()) { + continue; + } + + if (\PHP_VERSION_ID >= 80000) { + trigger_deprecation('symfony/service-contracts', '2.5', 'Using "%s" in "%s" without using the "%s" attribute on any method is deprecated.', ServiceSubscriberTrait::class, self::class, SubscribedService::class); + } + + $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); + } + } + + return $services; + } + + /** + * @required + * + * @return ContainerInterface|null + */ + public function setContainer(ContainerInterface $container) + { + $this->container = $container; + + if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) { + return parent::setContainer($container); + } + + return null; + } +} diff --git a/sites/all/libraries/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php b/sites/all/libraries/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php new file mode 100644 index 0000000000..2a1b565f50 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Test; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceLocatorTrait; + +abstract class ServiceLocatorTest extends TestCase +{ + /** + * @return ContainerInterface + */ + protected function getServiceLocator(array $factories) + { + return new class($factories) implements ContainerInterface { + use ServiceLocatorTrait; + }; + } + + public function testHas() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + function () { return 'dummy'; }, + ]); + + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + + public function testGet() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$i) { + ++$i; + + return 'bar'; + }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + + public function testThrowsOnUndefinedInternalService() + { + if (!$this->getExpectedException()) { + $this->expectException(\Psr\Container\NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } + + public function testThrowsOnCircularReference() + { + $this->expectException(\Psr\Container\ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + 'bar' => function () use (&$locator) { return $locator->get('baz'); }, + 'baz' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } +} diff --git a/sites/all/libraries/vendor/symfony/service-contracts/composer.json b/sites/all/libraries/vendor/symfony/service-contracts/composer.json new file mode 100644 index 0000000000..f058637010 --- /dev/null +++ b/sites/all/libraries/vendor/symfony/service-contracts/composer.json @@ -0,0 +1,42 @@ +{ + "name": "symfony/service-contracts", + "type": "library", + "description": "Generic abstractions related to writing services", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\Service\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/sites/all/modules/contrib/lexicon/lexicon.module b/sites/all/modules/contrib/lexicon/lexicon.module index 3b39227264..67c5440b53 100644 --- a/sites/all/modules/contrib/lexicon/lexicon.module +++ b/sites/all/modules/contrib/lexicon/lexicon.module @@ -1086,10 +1086,7 @@ function _lexicon_get_terms(&$vids, $langcode = LANGUAGE_NONE) { } // Add extra information to each term in the tree. - foreach ($tree as $term) { - if (!$term->processing){ - continue; - } + foreach ($tree as $term) { _lexicon_term_add_info($term, TRUE); $terms[$langcode][] = $term; } diff --git a/sites/all/modules/custom/scratchpads/scratchpads_backend/scratchpads_backend.module b/sites/all/modules/custom/scratchpads/scratchpads_backend/scratchpads_backend.module index 90d8374692..8877f3cf0d 100644 --- a/sites/all/modules/custom/scratchpads/scratchpads_backend/scratchpads_backend.module +++ b/sites/all/modules/custom/scratchpads/scratchpads_backend/scratchpads_backend.module @@ -313,4 +313,4 @@ function scratchpads_backend_ckeditor_plugin(){ 'path' => drupal_get_path('module', 'scratchpads_backend') . '/ckeditor/' ) ); -} \ No newline at end of file +} diff --git a/sites/all/modules/custom/scratchpads/scratchpads_species/modules/iucn/iucn.info b/sites/all/modules/custom/scratchpads/scratchpads_species/modules/iucn/iucn.info index a2462445f6..9004cb15f4 100644 --- a/sites/all/modules/custom/scratchpads/scratchpads_species/modules/iucn/iucn.info +++ b/sites/all/modules/custom/scratchpads/scratchpads_species/modules/iucn/iucn.info @@ -3,6 +3,7 @@ name = "IUCN Widget" description = "Displays an International Union for Conservation of Nature widget on a taxonomy term page." package = "Widgets" dependencies[] = scratchpads_species +dependencies[] = libraries tool=yes l10n server = localize.scratchpads.eu l10n url = http://localize.scratchpads.eu/files/l10n_packager/l10n_server.xml diff --git a/sites/all/modules/custom/scratchpads/scratchpads_species/modules/iucn/iucn.module b/sites/all/modules/custom/scratchpads/scratchpads_species/modules/iucn/iucn.module index d07a6269d6..4bd40ddf1c 100644 --- a/sites/all/modules/custom/scratchpads/scratchpads_species/modules/iucn/iucn.module +++ b/sites/all/modules/custom/scratchpads/scratchpads_species/modules/iucn/iucn.module @@ -1,5 +1,7 @@ 'hidden', - '#default_value' => FALSE, - ); $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array( '#type' => 'submit',