├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── composer.json ├── composer.lock ├── docs └── Color.md ├── doctrine └── mapping │ └── Money.Money.php ├── phpunit.xml ├── src ├── Color.php ├── DateRange.php ├── EmailAddress.php ├── FullName.php ├── GeoPoint.php ├── IpAddress.php └── IpRange.php └── tests ├── ColorTest.php ├── DateRangeTest.php ├── EmailAddressTest.php ├── FullNameTest.php ├── GeoPointTest.php ├── IpAddressTest.php └── IpRangeTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | ### PHP Storm 4 | .idea 5 | 6 | ### APP Specific ### 7 | data/coverage/ 8 | 9 | ### SublimeText ### 10 | # cache files for sublime text 11 | *.tmlanguage.cache 12 | *.tmPreferences.cache 13 | *.stTheme.cache 14 | 15 | # workspace files are user-specific 16 | *.sublime-workspace 17 | 18 | # project files should be checked into the repository, unless a significant 19 | # proportion of contributors will probably not be using SublimeText 20 | # *.sublime-project 21 | 22 | # sftp configuration file 23 | sftp-config.json 24 | 25 | # Package control specific files 26 | Package Control.last-run 27 | Package Control.ca-list 28 | Package Control.ca-bundle 29 | Package Control.system-ca-bundle 30 | Package Control.cache/ 31 | Package Control.ca-certs/ 32 | bh_unicode_properties.cache 33 | 34 | # Sublime-github package stores a github token in this file 35 | # https://packagecontrol.io/packages/sublime-github 36 | GitHub.sublime-settings 37 | 38 | 39 | ### macOS ### 40 | *.DS_Store 41 | .AppleDouble 42 | .LSOverride 43 | 44 | # Icon must end with two \r 45 | Icon 46 | 47 | # Thumbnails 48 | ._* 49 | 50 | # Files that might appear in the root of a volume 51 | .DocumentRevisions-V100 52 | .fseventsd 53 | .Spotlight-V100 54 | .TemporaryItems 55 | .Trashes 56 | .VolumeIcon.icns 57 | .com.apple.timemachine.donotpresent 58 | 59 | # Directories potentially created on remote AFP share 60 | .AppleDB 61 | .AppleDesktop 62 | Network Trash Folder 63 | Temporary Items 64 | .apdisk 65 | 66 | 67 | ### Composer ### 68 | composer.phar 69 | /vendor/ 70 | 71 | ### Git ### 72 | *.orig 73 | 74 | ### PHPUnit ### 75 | .phpunit.* -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | build: 2 | environment: 3 | php: 4 | version: 8.0 5 | tests: 6 | override: 7 | - 8 | command: 'phpunit --coverage-clover=embeddables-coverage' 9 | coverage: 10 | file: 'embeddables-coverage' 11 | format: 'clover' 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | sudo: false 3 | 4 | php: 5 | - 8.0 6 | - 8.1 7 | 8 | env: 9 | global: 10 | - TEST_COMMAND="composer test" 11 | 12 | before_install: 13 | - travis_retry composer self-update 14 | 15 | install: 16 | - travis_retry composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction 17 | 18 | script: 19 | - $TEST_COMMAND 20 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to Contribute 2 | Please feel free to create a new issue about any problem(s) you saw. We love pull requests from everyone. Some things that will increase the chance that your pull request is accepted: 3 | 4 | - Follow the PSR-1 and PSR-2 standards, **always**. 5 | - Write a [good commit message](https://gist.github.com/matthewhudson/1475276). 6 | - Write unit tests. 7 | 8 | Please use `develop` branch to send pull request. Don't send any pull request directly `master`. 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## MIT License 2 | 3 | Copyright (c) 2016 Biberlabs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DDD Embeddables 2 | 3 | ---- 4 | 5 | [![Build Status](https://secure.travis-ci.org/biberlabs/ddd-embeddables.svg?branch=master)](https://secure.travis-ci.org/biberlabs/ddd-embeddables) 6 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/biberlabs/ddd-embeddables/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/biberlabs/ddd-embeddables/?branch=master) 7 | [![Code Coverage](https://scrutinizer-ci.com/g/biberlabs/ddd-embeddables/badges/coverage.png?b=master&rand=123)](https://scrutinizer-ci.com/g/biberlabs/ddd-embeddables/?branch=master) 8 | 9 | A collection of reusable value objects written in PHP and targeting versions 8.0 and above. Value objects are essential building blocks of **Domain Driven Design** approach and described by Martin Fowler in _P of EAA page 486_ as below: 10 | 11 | > "Value object is a small simple object, like money or a date range, whose equality isn't based on identity." 12 | 13 | > – Martin Fowler 14 | 15 | All classes in this library annotated as `ORM\Embeddable` with appropriately adjusted column attributes. This makes them ready to use in any project with Doctrine ORM as [Embeddables](http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/tutorials/embeddables.html). 16 | 17 | ## Installation & Usage 18 | Install the library using [composer](https://getcomposer.org). 19 | 20 | ```bash 21 | $ composer require biberlabs/ddd-embeddables 22 | ``` 23 | 24 | and use it in your entities: 25 | 26 | ```php 27 | 1000 59 | -- OR 60 | SELECT u FROM User u WHERE u.name.surname = :surname 61 | SELECT u FROM User u WHERE u.name.title = :title 62 | ``` 63 | 64 | Value objects enables us to write much more cleaner and readable rules when dealing with the domain rules, application-wide. For example: 65 | 66 | ```php 67 | $username = $user->getEmail()->getLocalpart(); 68 | ``` 69 | 70 | or 71 | 72 | ```php 73 | $blacklist = ['spam4me.io', 'foo.com']; 74 | if(in_array($user->getEmail()->getDomain(), $blacklist)) { 75 | // ... 76 | } 77 | ``` 78 | 79 | even 80 | 81 | ```php 82 | if($company->hasMap()) { 83 | $latLng = $company->getAddress()->getGeoPoint()->toArray(); 84 | //.. 85 | } 86 | 87 | class Company 88 | { 89 | // ... 90 | 91 | /** 92 | * Returns a boolean TRUE if the geolocation of the company is known, 93 | * FALSE otherwise. 94 | * 95 | * @return bool 96 | */ 97 | public function hasMap() 98 | { 99 | return $this->getAddress()->getGeoPoint() !== null; 100 | } 101 | } 102 | ``` 103 | 104 | ## Running Tests 105 | You can run unit tests locally via issuing the command below: 106 | 107 | ```bash 108 | $ composer test 109 | ``` 110 | 111 | Please make sure that all test are green before creating a PR. 112 | 113 | ``` 114 | PHPUnit 9.5.25 #StandWithUkraine 115 | 116 | ................................................................. 65 / 75 ( 86%) 117 | .......... 75 / 75 (100%) 118 | 119 | Time: 00:00.037, Memory: 6.00 MB 120 | 121 | OK (75 tests, 124 assertions) 122 | ``` 123 | 124 | ## Contributing 125 | If you want to contribute to **ddd-embeddables** and make it better, your help is very welcome. 126 | 127 | Please take a look our [CONTRIBUTING.md](CONTRIBUTING.md) before creating a pull request. 128 | 129 | ## Further Reading 130 | Are you interested in Domain Driven Design? Here is a list of good resources to dig in-depth. 131 | 132 | - [Value Objects](http://martinfowler.com/bliki/ValueObject.html) - Martin Fowler 133 | - [Separating Concerns using Embeddables](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/embeddables.html) - Doctrine ORM documentation 134 | - [Domain-Driven Design in PHP](https://leanpub.com/ddd-in-php/read) - Leanpub 380 pages e-book. 135 | - [Agregate Componenet Pattern In Action](https://lostechies.com/jimmybogard/2009/02/05/ddd-aggregate-component-pattern-in-action/) - Another good article from 2009 136 | - [Domain Driven Design Concepts in ZF2](https://olegkrivtcov.wordpress.com/2014/03/22/domain-driven-design-ddd-concepts-in-zf2/) - An article written by Oleg Krivtsov in 2014 137 | - [Domain Driven Design Quickly](https://www.infoq.com/minibooks/domain-driven-design-quickly) - A quickly-readable minibook and introduction to the fundamentals of DDD by InfoQ. 138 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "biberlabs/ddd-embeddables", 3 | "description": "A collection of re-usable value objects ready to use as Embeddable in Doctrine entities", 4 | "type": "library", 5 | "license": "MIT", 6 | "require": { 7 | "php": "^8.0", 8 | "doctrine/orm": "^2.11", 9 | "composer-runtime-api": "^2" 10 | }, 11 | "require-dev": { 12 | "phpunit/phpunit": "^9.5" 13 | }, 14 | "suggest": { 15 | "ext-gmp": "Calculate without integer limits", 16 | "ext-intl": "Format Money objects with intl" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "DDD\\Embeddable\\": "src/" 21 | } 22 | }, 23 | "autoload-dev": { 24 | "psr-4": { 25 | "Test\\Embeddable\\": "tests/" 26 | } 27 | }, 28 | "authors": [ 29 | { 30 | "name": "M. Yilmaz SUSLU", 31 | "email": "yilmazsuslu@gmail.com" 32 | } 33 | ], 34 | "scripts": { 35 | "test": "vendor/bin/phpunit --coverage-text" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /docs/Color.md: -------------------------------------------------------------------------------- 1 | # Color Value Object 2 | `DDD\Embeddebles\Color` is a simple value object, it helps developer when persisting and using color information application-wide, in DDD way. 3 | 4 | An example use case, there is a `Product` entity: 5 | 6 | ``` 7 | setColor(new Color('#FF00FF')); 36 | // or 37 | $prod->setColor(new Color('F0F')); 38 | // or 39 | $prod->setColor(Color::fromRGB(255,0,255)); 40 | 41 | $name = $prod->getName(); 42 | $background = $prod->getColor()->toHex(); 43 | $label = $prod->getColor()->getName(); // "Fuchsia" 44 | 45 | // Directly convert to json 46 | $json = json_encode($prod->getColor()); 47 | // {"hex":"#FF00FF","rgb":[255,0,255],"name":"Fuchsia"} 48 | 49 | $rgb = $prod->getColor()->toRGB(); // [255,0,255] 50 | ``` -------------------------------------------------------------------------------- /doctrine/mapping/Money.Money.php: -------------------------------------------------------------------------------- 1 | addDriver(new PhpMappingDriver($dir), 'Money\Money'); 14 | */ 15 | $metadata->isEmbeddedClass = true; 16 | 17 | $metadata->mapField(array( 18 | 'fieldName' => 'amount', 19 | 'type' => 'integer', 20 | 'nullable' => true 21 | )); 22 | 23 | $metadata->mapField(array( 24 | 'fieldName' => 'currency', 25 | 'type' => 'string', 26 | 'nullable' => true, 27 | 'length' => 3, 28 | )); 29 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | src 6 | 7 | 8 | 9 | 10 | ./tests 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Color.php: -------------------------------------------------------------------------------- 1 | 'White' 7 | * 8 | * Partially implements the flow in this good SO answer: 9 | * 10 | * @see http://stackoverflow.com/a/2994015/199593 11 | * 12 | * @author M. Yilmaz SUSLU 13 | * @license MIT 14 | * 15 | * @since Oct 2016 16 | */ 17 | 18 | namespace DDD\Embeddable; 19 | 20 | use Doctrine\ORM\Mapping as ORM; 21 | use InvalidArgumentException; 22 | use JsonSerializable; 23 | use function preg_match; 24 | 25 | /** 26 | * @ORM\Embeddable 27 | */ 28 | class Color implements JsonSerializable 29 | { 30 | /** 31 | * persistable, hexadecimal representation of the color 32 | * 33 | * Persisted hex value is always upper-cased and doesn't contain a '#' prefix. 34 | * 35 | * @ORM\Column(type="string", length=6, nullable=true) 36 | */ 37 | private ?string $color = null; 38 | 39 | public function __construct(?string $hex = null) 40 | { 41 | if (! $hex) { 42 | return; 43 | } 44 | 45 | $hex = $this->normalize($hex); 46 | 47 | if (! $this->isValidHex($hex)) { 48 | throw new InvalidArgumentException(sprintf('Given hex value %s is invalid', $hex)); 49 | } 50 | 51 | $this->color = $hex; 52 | } 53 | 54 | /** 55 | * Returns the color in hexadecimal format 56 | */ 57 | public function toHex() : string 58 | { 59 | return ($this->color) ? '#' . $this->color : ''; 60 | } 61 | 62 | /** 63 | * Returns the color in RGB format, empty array if color is not set. 64 | */ 65 | public function toRGB() : array 66 | { 67 | if ($this->isEmpty()) { 68 | return []; 69 | } 70 | 71 | [$r, $g, $b] = sscanf($this->color, "%02x%02x%02x"); 72 | 73 | return [$r, $g, $b]; 74 | } 75 | 76 | /** 77 | * Returns the color as RGB string 78 | * 79 | * Example: "rgb(60,60,240)" 80 | */ 81 | public function toRGBString() : string 82 | { 83 | $rgb = $this->toRGB(); 84 | 85 | return 'rgb(' . implode(',', $rgb) . ')'; 86 | } 87 | 88 | /** 89 | * Returns programmatically generated, the nearest name for the color. 90 | * 91 | * Note: This method is pretty slow even for a single call because 92 | * iterates all over the color name => [r,g,b] stack below to find 93 | * the nearest color in whole haystack, this means approx. ~3500 iteration. 94 | * 95 | * Caching a serialized version of this object is highly recommended. 96 | * 97 | * @todo There may faster algorithms exists to achieve same thing. 98 | */ 99 | public function getName() : string 100 | { 101 | return $this->generateName($this->toRGB()); 102 | } 103 | 104 | /** 105 | * Array representation of the color 106 | */ 107 | public function toArray() : array 108 | { 109 | if ($this->isEmpty()) { 110 | return []; 111 | } 112 | 113 | $rgb = $this->toRGB(); 114 | 115 | return [ 116 | 'hex' => $this->toHex(), 117 | 'rgb' => $rgb, 118 | 'name' => $this->getName(), 119 | ]; 120 | } 121 | 122 | /** 123 | * Implement json serializable interface. 124 | */ 125 | public function jsonSerialize() : array 126 | { 127 | return $this->toArray(); 128 | } 129 | 130 | /** 131 | * Creates a new Color instance from r,g,b values. 132 | */ 133 | public static function fromRGB(int $r, int $g, int $b) : Color 134 | { 135 | $hex = dechex($r) . dechex($g) . dechex($b); 136 | 137 | return new self($hex); 138 | } 139 | 140 | /** 141 | * String representation of the color, an upper-cased hex value. 142 | * 143 | * @return string Example: #FFCC60 144 | */ 145 | public function __toString() 146 | { 147 | return $this->toHex(); 148 | } 149 | 150 | /** 151 | * Returns a boolean TRUE if color is literally empty 152 | */ 153 | public function isEmpty() : bool 154 | { 155 | return empty($this->color); 156 | } 157 | 158 | /** 159 | * Returns distance between two colors. 160 | * 161 | * @see https://stackoverflow.com/questions/4057475/rounding-colours 162 | * @param array $color2 RGB color 163 | * 164 | * @param array $color1 RGB color 165 | */ 166 | private function distanceL2(array $color1, array $color2) : float 167 | { 168 | return sqrt( 169 | (($color1[0] - $color2[0]) ** 2) + 170 | (($color1[1] - $color2[1]) ** 2) + 171 | (($color1[2] - $color2[2]) ** 2) 172 | ); 173 | } 174 | 175 | /** 176 | * Generates a proper name for given RGB color. 177 | */ 178 | private function generateName(array $rgb) : string 179 | { 180 | $distances = []; 181 | foreach ($this->getColorNames() as $name => $rgbValue) { 182 | $distances[$name] = $this->distanceL2($rgbValue, $rgb); 183 | } 184 | 185 | $minColor = ''; 186 | $minVal = 2 ** 30; 187 | /** A big value */ 188 | 189 | foreach ($distances as $k => $v) { 190 | if ($v < $minVal) { 191 | $minVal = $v; 192 | $minColor = $k; 193 | } 194 | } 195 | 196 | // Closest color name to given RGB code 197 | return $minColor; 198 | } 199 | 200 | /** 201 | * Validates given hex color code, returns a boolean TRUE if it is valid. 202 | * 203 | * @param string $hex Three or six digit HEX code like #FFAC43, #000 204 | */ 205 | private function isValidHex(string $hex) : bool 206 | { 207 | // Allow both #FFF and #FFFFFF conventions 208 | return preg_match('/^[A-F0-9]{6}$/', $hex) || preg_match('/^[A-F0-9]{3}$/', $hex); 209 | } 210 | 211 | /** 212 | * Filters and normalizes given hexadecimal color code. 213 | * 214 | * @param string $hex An unfiltered hex value. 215 | */ 216 | private function normalize(string $hex) : string 217 | { 218 | // Get rid of first # sign if it exists 219 | if ($hex[0] === '#') { 220 | $hex = substr($hex, 1); 221 | } 222 | 223 | if (strlen($hex) === 3) { 224 | // Convert to 6 digit version 225 | $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; 226 | } 227 | 228 | return strtoupper($hex); 229 | } 230 | 231 | /** 232 | * Returns a (pretty big) static list of well-known color names 233 | * with their RGB codes. 234 | * 235 | * Including, caching or requiring these values from an external 236 | * resource is always possible, but it would be costlier than this. 237 | * 238 | * Since all PHP classes cached by Opcache in runtime, this will 239 | * run pretty fast on a production box. As a drawback, instance size of Color 240 | * in memory will be higher (in kilobytes). There is no free lunch. 241 | * 242 | * For a simple entity which needs just a "color" property (such as Product), 243 | * this value object may fit perfectly. 244 | */ 245 | private function getColorNames() : array 246 | { 247 | return [ 248 | 'Acid Green' => [176, 191, 26], 249 | 'Aero Blue' => [201, 255, 229], 250 | 'Aero' => [124, 185, 232], 251 | 'African Violet' => [178, 132, 190], 252 | 'Air Force Blue (RAF)' => [93, 138, 168], 253 | 'Air Force Blue (USAF)' => [0, 48, 143], 254 | 'Air Superiority Blue' => [114, 160, 193], 255 | 'Alabama Crimson' => [175, 0, 42], 256 | 'Alice Blue' => [240, 248, 255], 257 | 'Alizarin Crimson' => [227, 38, 54], 258 | 'Alloy Orange' => [196, 98, 16], 259 | 'Almond' => [239, 222, 205], 260 | 'Amaranth Deep Purple' => [171, 39, 79], 261 | 'Amaranth Pink' => [241, 156, 187], 262 | 'Amaranth Purple' => [171, 39, 79], 263 | 'Amaranth Red' => [211, 33, 45], 264 | 'Amaranth' => [229, 43, 80], 265 | 'Amazon' => [59, 122, 87], 266 | 'Amber (SAE/ECE)' => [255, 126, 0], 267 | 'Amber' => [255, 191, 0], 268 | 'American Rose' => [255, 3, 62], 269 | 'Amethyst' => [153, 102, 204], 270 | 'Android Green' => [164, 198, 57], 271 | 'Anti-Flash White' => [242, 243, 244], 272 | 'Antique Brass' => [205, 149, 117], 273 | 'Antique Bronze' => [102, 93, 30], 274 | 'Antique Fuchsia' => [145, 92, 131], 275 | 'Antique Ruby' => [132, 27, 45], 276 | 'Antique White' => [250, 235, 215], 277 | 'Ao (English)' => [0, 128, 0], 278 | 'Apple Green' => [141, 182, 0], 279 | 'Apricot' => [251, 206, 177], 280 | 'Aqua' => [0, 255, 255], 281 | 'Aquamarine' => [127, 255, 212], 282 | 'Arctic Lime' => [208, 255, 20], 283 | 'Army Green' => [75, 83, 32], 284 | 'Arsenic' => [59, 68, 75], 285 | 'Artichoke' => [143, 151, 121], 286 | 'Arylide Yellow' => [233, 214, 107], 287 | 'Ash Grey' => [178, 190, 181], 288 | 'Asparagus' => [135, 169, 107], 289 | 'Atomic Tangerine' => [255, 153, 102], 290 | 'Auburn' => [165, 42, 42], 291 | 'Aureolin' => [253, 238, 0], 292 | 'Auro Metal Saurus' => [110, 127, 128], 293 | 'Avocado' => [86, 130, 3], 294 | 'Azure (Web Color)' => [240, 255, 255], 295 | 'Azure Mist' => [240, 255, 255], 296 | 'Azure' => [0, 127, 255], 297 | 'Azureish White' => [219, 233, 244], 298 | "B'dazzled Blue" => [46, 88, 148], 299 | 'Baby Blue Eyes' => [161, 202, 241], 300 | 'Baby Blue' => [137, 207, 240], 301 | 'Baby Pink' => [244, 194, 194], 302 | 'Baby Powder' => [254, 254, 250], 303 | 'Baker-Miller Pink' => [255, 145, 175], 304 | 'Ball Blue' => [33, 171, 205], 305 | 'Banana Mania' => [250, 231, 181], 306 | 'Banana Yellow' => [255, 225, 53], 307 | 'Bangladesh Green' => [0, 106, 78], 308 | 'Barbie Pink' => [224, 33, 138], 309 | 'Barn Red' => [124, 10, 2], 310 | 'Battleship Grey' => [132, 132, 130], 311 | 'Bazaar' => [152, 119, 123], 312 | 'Beau Blue' => [188, 212, 230], 313 | 'Beaver' => [159, 129, 112], 314 | 'Beige' => [245, 245, 220], 315 | 'Big Dip O’ruby' => [156, 37, 66], 316 | 'Bisque' => [255, 228, 196], 317 | 'Bistre Brown' => [150, 113, 23], 318 | 'Bistre' => [61, 43, 31], 319 | 'Bitter Lemon' => [202, 224, 13], 320 | 'Bitter Lime' => [191, 255, 0], 321 | 'Bittersweet Shimmer' => [191, 79, 81], 322 | 'Bittersweet' => [254, 111, 94], 323 | 'Black Bean' => [61, 12, 2], 324 | 'Black Leather Jacket' => [37, 53, 41], 325 | 'Black Olive' => [59, 60, 54], 326 | 'Black' => [0, 0, 0], 327 | 'Blanched Almond' => [255, 235, 205], 328 | 'Blast-Off Bronze' => [165, 113, 100], 329 | 'Bleu De France' => [49, 140, 231], 330 | 'Blizzard Blue' => [172, 229, 238], 331 | 'Blond' => [250, 240, 190], 332 | 'Blue (Crayola)' => [31, 117, 254], 333 | 'Blue (Munsell)' => [0, 147, 175], 334 | 'Blue (NCS)' => [0, 135, 189], 335 | 'Blue (Pantone)' => [0, 24, 168], 336 | 'Blue (Pigment)' => [51, 51, 153], 337 | 'Blue (RYB)' => [2, 71, 254], 338 | 'Blue Bell' => [162, 162, 208], 339 | 'Blue Lagoon' => [172, 229, 238], 340 | 'Blue Sapphire' => [18, 97, 128], 341 | 'Blue Yonder' => [80, 114, 167], 342 | 'Blue' => [0, 0, 255], 343 | 'Blue-Gray' => [102, 153, 204], 344 | 'Blue-Green' => [13, 152, 186], 345 | 'Blue-Magenta Violet' => [85, 53, 146], 346 | 'Blue-Violet' => [138, 43, 226], 347 | 'Blueberry' => [79, 134, 247], 348 | 'Bluebonnet' => [28, 28, 240], 349 | 'Blush' => [222, 93, 131], 350 | 'Bole' => [121, 68, 59], 351 | 'Bondi Blue' => [0, 149, 182], 352 | 'Bone' => [227, 218, 201], 353 | 'Boston University Red' => [204, 0, 0], 354 | 'Bottle Green' => [0, 106, 78], 355 | 'Boysenberry' => [135, 50, 96], 356 | 'Brandeis Blue' => [0, 112, 255], 357 | 'Brass' => [181, 166, 66], 358 | 'Brick Red' => [203, 65, 84], 359 | 'Bright Cerulean' => [29, 172, 214], 360 | 'Bright Green' => [102, 255, 0], 361 | 'Bright Lavender' => [191, 148, 228], 362 | 'Bright Lilac' => [216, 145, 239], 363 | 'Bright Maroon' => [195, 33, 72], 364 | 'Bright Navy Blue' => [25, 116, 210], 365 | 'Bright Pink' => [255, 0, 127], 366 | 'Bright Turquoise' => [8, 232, 222], 367 | 'Bright Ube' => [209, 159, 232], 368 | 'Brilliant Azure' => [51, 153, 255], 369 | 'Brilliant Lavender' => [244, 187, 255], 370 | 'Brilliant Rose' => [255, 85, 163], 371 | 'Brink Pink' => [251, 96, 127], 372 | 'British Racing Green' => [0, 66, 37], 373 | 'Bronze Yellow' => [115, 112, 0], 374 | 'Bronze' => [205, 127, 50], 375 | 'Brown (Traditional)' => [150, 75, 0], 376 | 'Brown (Web)' => [165, 42, 42], 377 | 'Brown Yellow' => [204, 153, 102], 378 | 'Brown-Nose' => [107, 68, 35], 379 | 'Brunswick Green' => [27, 77, 62], 380 | 'Bubble Gum' => [255, 193, 204], 381 | 'Bubbles' => [231, 254, 255], 382 | 'Bud Green' => [123, 182, 97], 383 | 'Buff' => [240, 220, 130], 384 | 'Bulgarian Rose' => [72, 6, 7], 385 | 'Burgundy' => [128, 0, 32], 386 | 'Burlywood' => [222, 184, 135], 387 | 'Burnt Orange' => [204, 85, 0], 388 | 'Burnt Sienna' => [233, 116, 81], 389 | 'Burnt Umber' => [138, 51, 36], 390 | 'Byzantine' => [189, 51, 164], 391 | 'Byzantium' => [112, 41, 99], 392 | 'Cadet Blue' => [95, 158, 160], 393 | 'Cadet Grey' => [145, 163, 176], 394 | 'Cadet' => [83, 104, 114], 395 | 'Cadmium Green' => [0, 107, 60], 396 | 'Cadmium Orange' => [237, 135, 45], 397 | 'Cadmium Red' => [227, 0, 34], 398 | 'Cadmium Yellow' => [255, 246, 0], 399 | 'Café Au Lait' => [166, 123, 91], 400 | 'Café Noir' => [75, 54, 33], 401 | 'Cal Poly Green' => [30, 77, 43], 402 | 'Cambridge Blue' => [163, 193, 173], 403 | 'Camel' => [193, 154, 107], 404 | 'Cameo Pink' => [239, 187, 204], 405 | 'Camouflage Green' => [120, 134, 107], 406 | 'Canary Yellow' => [255, 239, 0], 407 | 'Candy Apple Red' => [255, 8, 0], 408 | 'Candy Pink' => [228, 113, 122], 409 | 'Capri' => [0, 191, 255], 410 | 'Caput Mortuum' => [89, 39, 32], 411 | 'Cardinal' => [196, 30, 58], 412 | 'Caribbean Green' => [0, 204, 153], 413 | 'Carmine (M&P)' => [215, 0, 64], 414 | 'Carmine Pink' => [235, 76, 66], 415 | 'Carmine Red' => [255, 0, 56], 416 | 'Carmine' => [150, 0, 24], 417 | 'Carnation Pink' => [255, 166, 201], 418 | 'Carnelian' => [179, 27, 27], 419 | 'Carolina Blue' => [86, 160, 211], 420 | 'Carrot Orange' => [237, 145, 33], 421 | 'Castleton Green' => [0, 86, 63], 422 | 'Catalina Blue' => [6, 42, 120], 423 | 'Catawba' => [112, 54, 66], 424 | 'Cedar Chest' => [201, 90, 73], 425 | 'Ceil' => [146, 161, 207], 426 | 'Celadon Blue' => [0, 123, 167], 427 | 'Celadon Green' => [47, 132, 124], 428 | 'Celadon' => [172, 225, 175], 429 | 'Celeste' => [178, 255, 255], 430 | 'Celestial Blue' => [73, 151, 208], 431 | 'Cerise Pink' => [236, 59, 131], 432 | 'Cerise' => [222, 49, 99], 433 | 'Cerulean Blue' => [42, 82, 190], 434 | 'Cerulean Frost' => [109, 155, 195], 435 | 'Cerulean' => [0, 123, 167], 436 | 'CG Blue' => [0, 122, 165], 437 | 'CG Red' => [224, 60, 49], 438 | 'Chamoisee' => [160, 120, 90], 439 | 'Champagne' => [247, 231, 206], 440 | 'Charcoal' => [54, 69, 79], 441 | 'Charleston Green' => [35, 43, 43], 442 | 'Charm Pink' => [230, 143, 172], 443 | 'Chartreuse (Traditional)' => [223, 255, 0], 444 | 'Chartreuse (Web)' => [127, 255, 0], 445 | 'Cherry Blossom Pink' => [255, 183, 197], 446 | 'Cherry' => [222, 49, 99], 447 | 'Chestnut' => [149, 69, 53], 448 | 'China Pink' => [222, 111, 161], 449 | 'China Rose' => [168, 81, 110], 450 | 'Chinese Red' => [170, 56, 30], 451 | 'Chinese Violet' => [133, 96, 136], 452 | 'Chocolate (Traditional)' => [123, 63, 0], 453 | 'Chocolate (Web)' => [210, 105, 30], 454 | 'Chrome Yellow' => [255, 167, 0], 455 | 'Cinereous' => [152, 129, 123], 456 | 'Cinnabar' => [227, 66, 52], 457 | 'Cinnamon' => [210, 105, 30], 458 | 'Citrine' => [228, 208, 10], 459 | 'Citron' => [159, 169, 31], 460 | 'Claret' => [127, 23, 52], 461 | 'Classic Rose' => [251, 204, 231], 462 | 'Cobalt Blue' => [0, 71, 171], 463 | 'Cocoa Brown' => [210, 105, 30], 464 | 'Coconut' => [150, 90, 62], 465 | 'Coffee' => [111, 78, 55], 466 | 'Columbia Blue' => [196, 216, 226], 467 | 'Congo Pink' => [248, 131, 121], 468 | 'Cool Black' => [0, 46, 99], 469 | 'Cool Grey' => [140, 146, 172], 470 | 'Copper (Crayola)' => [218, 138, 103], 471 | 'Copper Penny' => [173, 111, 105], 472 | 'Copper Red' => [203, 109, 81], 473 | 'Copper Rose' => [153, 102, 102], 474 | 'Copper' => [184, 115, 51], 475 | 'Coquelicot' => [255, 56, 0], 476 | 'Coral Pink' => [248, 131, 121], 477 | 'Coral Red' => [255, 64, 64], 478 | 'Coral' => [255, 127, 80], 479 | 'Cordovan' => [137, 63, 69], 480 | 'Corn' => [251, 236, 93], 481 | 'Cornell Red' => [179, 27, 27], 482 | 'Cornflower Blue' => [100, 149, 237], 483 | 'Cornsilk' => [255, 248, 220], 484 | 'Cosmic Latte' => [255, 248, 231], 485 | 'Cotton Candy' => [255, 188, 217], 486 | 'Coyote Brown' => [129, 97, 62], 487 | 'Cream' => [255, 253, 208], 488 | 'Crimson Glory' => [190, 0, 50], 489 | 'Crimson Red' => [153, 0, 0], 490 | 'Crimson' => [220, 20, 60], 491 | 'Cyan (Process)' => [0, 183, 235], 492 | 'Cyan Azure' => [78, 130, 180], 493 | 'Cyan Cobalt Blue' => [40, 88, 156], 494 | 'Cyan Cornflower Blue' => [24, 139, 194], 495 | 'Cyan' => [0, 255, 255], 496 | 'Cyan-Blue Azure' => [70, 130, 191], 497 | 'Cyber Grape' => [88, 66, 124], 498 | 'Cyber Yellow' => [255, 211, 0], 499 | 'Daffodil' => [255, 255, 49], 500 | 'Dandelion' => [240, 225, 48], 501 | 'Dark Blue' => [0, 0, 139], 502 | 'Dark Blue-Gray' => [102, 102, 153], 503 | 'Dark Brown' => [101, 67, 33], 504 | 'Dark Brown-Tangelo' => [136, 101, 78], 505 | 'Dark Byzantium' => [93, 57, 84], 506 | 'Dark Candy Apple Red' => [164, 0, 0], 507 | 'Dark Cerulean' => [8, 69, 126], 508 | 'Dark Chestnut' => [152, 105, 96], 509 | 'Dark Coral' => [205, 91, 69], 510 | 'Dark Cyan' => [0, 139, 139], 511 | 'Dark Electric Blue' => [83, 104, 120], 512 | 'Dark Goldenrod' => [184, 134, 11], 513 | 'Dark Gray (X11)' => [169, 169, 169], 514 | 'Dark Green (X11)' => [0, 100, 0], 515 | 'Dark Green' => [1, 50, 32], 516 | 'Dark Gunmetal' => [0, 100, 0], 517 | 'Dark Imperial Blue' => [110, 110, 249], 518 | 'Dark Jungle Green' => [26, 36, 33], 519 | 'Dark Khaki' => [189, 183, 107], 520 | 'Dark Lava' => [72, 60, 50], 521 | 'Dark Lavender' => [115, 79, 150], 522 | 'Dark Liver (Horses)' => [84, 61, 55], 523 | 'Dark Liver' => [83, 75, 79], 524 | 'Dark Magenta' => [139, 0, 139], 525 | 'Dark Medium Gray' => [169, 169, 169], 526 | 'Dark Midnight Blue' => [0, 51, 102], 527 | 'Dark Moss Green' => [74, 93, 35], 528 | 'Dark Olive Green' => [85, 107, 47], 529 | 'Dark Orange' => [255, 140, 0], 530 | 'Dark Orchid' => [153, 50, 204], 531 | 'Dark Pastel Blue' => [119, 158, 203], 532 | 'Dark Pastel Green' => [3, 192, 60], 533 | 'Dark Pastel Purple' => [150, 111, 214], 534 | 'Dark Pastel Red' => [194, 59, 34], 535 | 'Dark Pink' => [231, 84, 128], 536 | 'Dark Powder Blue' => [0, 51, 153], 537 | 'Dark Puce' => [79, 58, 60], 538 | 'Dark Purple' => [48, 25, 52], 539 | 'Dark Raspberry' => [135, 38, 87], 540 | 'Dark Red' => [139, 0, 0], 541 | 'Dark Salmon' => [233, 150, 122], 542 | 'Dark Scarlet' => [86, 3, 25], 543 | 'Dark Sea Green' => [143, 188, 143], 544 | 'Dark Sienna' => [60, 20, 20], 545 | 'Dark Sky Blue' => [140, 190, 214], 546 | 'Dark Slate Blue' => [72, 61, 139], 547 | 'Dark Slate Gray' => [47, 79, 79], 548 | 'Dark Spring Green' => [23, 114, 69], 549 | 'Dark Tan' => [145, 129, 81], 550 | 'Dark Tangerine' => [255, 168, 18], 551 | 'Dark Taupe' => [72, 60, 50], 552 | 'Dark Terra Cotta' => [204, 78, 92], 553 | 'Dark Turquoise' => [0, 206, 209], 554 | 'Dark Vanilla' => [209, 190, 168], 555 | 'Dark Violet' => [148, 0, 211], 556 | 'Dark Yellow' => [155, 135, 12], 557 | 'Dartmouth Green' => [0, 112, 60], 558 | 'Davy\'s Grey' => [85, 85, 85], 559 | 'Debian Red' => [215, 10, 83], 560 | 'Deep Aquamarine' => [64, 130, 109], 561 | 'Deep Carmine Pink' => [239, 48, 56], 562 | 'Deep Carmine' => [169, 32, 62], 563 | 'Deep Carrot Orange' => [233, 105, 44], 564 | 'Deep Cerise' => [218, 50, 135], 565 | 'Deep Champagne' => [250, 214, 165], 566 | 'Deep Chestnut' => [185, 78, 72], 567 | 'Deep Coffee' => [112, 66, 65], 568 | 'Deep Fuchsia' => [193, 84, 193], 569 | 'Deep Green' => [5, 102, 8], 570 | 'Deep Green-Cyan Turquoise' => [14, 124, 97], 571 | 'Deep Jungle Green' => [0, 75, 73], 572 | 'Deep Koamaru' => [51, 51, 102], 573 | 'Deep Lemon' => [245, 199, 26], 574 | 'Deep Lilac' => [153, 85, 187], 575 | 'Deep Magenta' => [204, 0, 204], 576 | 'Deep Maroon' => [130, 0, 0], 577 | 'Deep Mauve' => [212, 115, 212], 578 | 'Deep Moss Green' => [53, 94, 59], 579 | 'Deep Peach' => [255, 203, 164], 580 | 'Deep Pink' => [255, 20, 147], 581 | 'Deep Puce' => [169, 92, 104], 582 | 'Deep Red' => [133, 1, 1], 583 | 'Deep Ruby' => [132, 63, 91], 584 | 'Deep Saffron' => [255, 153, 51], 585 | 'Deep Sky Blue' => [0, 191, 255], 586 | 'Deep Space Sparkle' => [74, 100, 108], 587 | 'Deep Spring Bud' => [85, 107, 47], 588 | 'Deep Taupe' => [126, 94, 96], 589 | 'Deep Tuscan Red' => [102, 66, 77], 590 | 'Deep Violet' => [51, 0, 102], 591 | 'Deer' => [186, 135, 89], 592 | 'Denim' => [21, 96, 189], 593 | 'Desaturated Cyan' => [102, 153, 153], 594 | 'Desert Sand' => [237, 201, 175], 595 | 'Desert' => [193, 154, 107], 596 | 'Desire' => [234, 60, 83], 597 | 'Diamond' => [185, 242, 255], 598 | 'Dim Gray' => [105, 105, 105], 599 | 'Dirt' => [155, 118, 83], 600 | 'Dodger Blue' => [30, 144, 255], 601 | 'Dogwood Rose' => [215, 24, 104], 602 | 'Dollar Bill' => [133, 187, 101], 603 | 'Donkey Brown' => [102, 76, 40], 604 | 'Drab' => [150, 113, 23], 605 | 'Duke Blue' => [0, 0, 156], 606 | 'Dust Storm' => [229, 204, 201], 607 | 'Dutch White' => [239, 223, 187], 608 | 'Earth Yellow' => [225, 169, 95], 609 | 'Ebony' => [85, 93, 80], 610 | 'Ecru' => [194, 178, 128], 611 | 'Eerie Black' => [27, 27, 27], 612 | 'Eggplant' => [97, 64, 81], 613 | 'Eggshell' => [240, 234, 214], 614 | 'Egyptian Blue' => [16, 52, 166], 615 | 'Electric Blue' => [125, 249, 255], 616 | 'Electric Crimson' => [255, 0, 63], 617 | 'Electric Cyan' => [0, 255, 255], 618 | 'Electric Green' => [0, 255, 0], 619 | 'Electric Indigo' => [111, 0, 255], 620 | 'Electric Lavender' => [244, 187, 255], 621 | 'Electric Lime' => [204, 255, 0], 622 | 'Electric Purple' => [191, 0, 255], 623 | 'Electric Ultramarine' => [63, 0, 255], 624 | 'Electric Violet' => [143, 0, 255], 625 | 'Electric Yellow' => [255, 255, 51], 626 | 'Emerald' => [80, 200, 120], 627 | 'Eminence' => [108, 48, 130], 628 | 'English Green' => [27, 77, 62], 629 | 'English Lavender' => [180, 131, 149], 630 | 'English Red' => [171, 75, 82], 631 | 'English Violet' => [86, 60, 92], 632 | 'Eton Blue' => [150, 200, 162], 633 | 'Eucalyptus' => [68, 215, 168], 634 | 'Fallow' => [193, 154, 107], 635 | 'Falu Red' => [128, 24, 24], 636 | 'Fandango Pink' => [222, 82, 133], 637 | 'Fandango' => [181, 51, 137], 638 | 'Fashion Fuchsia' => [244, 0, 161], 639 | 'Fawn' => [229, 170, 112], 640 | 'Feldgrau' => [77, 93, 83], 641 | 'Feldspar' => [253, 213, 177], 642 | 'Fern Green' => [79, 121, 66], 643 | 'Ferrari Red' => [255, 40, 0], 644 | 'Field Drab' => [108, 84, 30], 645 | 'Fire Engine Red' => [206, 32, 41], 646 | 'Firebrick' => [178, 34, 34], 647 | 'Flame' => [226, 88, 34], 648 | 'Flamingo Pink' => [252, 142, 172], 649 | 'Flattery' => [107, 68, 35], 650 | 'Flavescent' => [247, 233, 142], 651 | 'Flax' => [238, 220, 130], 652 | 'Flirt' => [162, 0, 109], 653 | 'Floral White' => [255, 250, 240], 654 | 'Fluorescent Orange' => [255, 191, 0], 655 | 'Fluorescent Pink' => [255, 20, 147], 656 | 'Fluorescent Yellow' => [204, 255, 0], 657 | 'Folly' => [255, 0, 79], 658 | 'Forest Green (Traditional)' => [1, 68, 33], 659 | 'Forest Green (Web)' => [34, 139, 34], 660 | 'French Beige' => [166, 123, 91], 661 | 'French Bistre' => [133, 109, 77], 662 | 'French Blue' => [0, 114, 187], 663 | 'French Fuchsia' => [253, 63, 146], 664 | 'French Lilac' => [134, 96, 142], 665 | 'French Lime' => [158, 253, 56], 666 | 'French Mauve' => [212, 115, 212], 667 | 'French Pink' => [253, 108, 158], 668 | 'French Plum' => [129, 20, 83], 669 | 'French Puce' => [78, 22, 9], 670 | 'French Raspberry' => [199, 44, 72], 671 | 'French Rose' => [246, 74, 138], 672 | 'French Sky Blue' => [119, 181, 254], 673 | 'French Violet' => [136, 6, 206], 674 | 'French Wine' => [172, 30, 68], 675 | 'Fresh Air' => [166, 231, 255], 676 | 'Fuchsia (Crayola)' => [193, 84, 193], 677 | 'Fuchsia Pink' => [255, 119, 255], 678 | 'Fuchsia Purple' => [204, 57, 123], 679 | 'Fuchsia Rose' => [199, 67, 117], 680 | 'Fuchsia' => [255, 0, 255], 681 | 'Fulvous' => [228, 132, 0], 682 | 'Fuzzy Wuzzy' => [204, 102, 102], 683 | 'Gainsboro' => [220, 220, 220], 684 | 'Gamboge Orange (Brown)' => [153, 102, 0], 685 | 'Gamboge' => [228, 155, 15], 686 | 'Generic Viridian' => [0, 127, 102], 687 | 'Ghost White' => [248, 248, 255], 688 | 'Giants Orange' => [254, 90, 29], 689 | 'Ginger' => [176, 101, 0], 690 | 'Glaucous' => [96, 130, 182], 691 | 'Glitter' => [230, 232, 250], 692 | 'GO Green' => [0, 171, 102], 693 | 'Gold (Metallic)' => [212, 175, 55], 694 | 'Gold (Web, Golden)' => [255, 215, 0], 695 | 'Gold Fusion' => [133, 117, 78], 696 | 'Golden Brown' => [153, 101, 21], 697 | 'Golden Poppy' => [252, 194, 0], 698 | 'Golden Yellow' => [255, 223, 0], 699 | 'Goldenrod' => [218, 165, 32], 700 | 'Granny Smith Apple' => [168, 228, 160], 701 | 'Grape' => [111, 45, 168], 702 | 'Gray (HTML/CSS Gray)' => [128, 128, 128], 703 | 'Gray (X11 Gray)' => [190, 190, 190], 704 | 'Gray' => [128, 128, 128], 705 | 'Gray-Asparagus' => [70, 89, 69], 706 | 'Gray-Blue' => [140, 146, 172], 707 | 'Green (Color Wheel, X11 Green)' => [0, 255, 0], 708 | 'Green (Crayola)' => [28, 172, 120], 709 | 'Green (HTML/CSS Color)' => [0, 128, 0], 710 | 'Green (Munsell)' => [0, 168, 119], 711 | 'Green (NCS)' => [0, 159, 107], 712 | 'Green (Pantone)' => [0, 173, 67], 713 | 'Green (Pigment)' => [0, 165, 80], 714 | 'Green (RYB)' => [102, 176, 50], 715 | 'Green-Blue' => [17, 100, 180], 716 | 'Green-Cyan' => [0, 153, 102], 717 | 'Green-Yellow' => [173, 255, 47], 718 | 'Grizzly' => [136, 88, 24], 719 | 'Grullo' => [169, 154, 134], 720 | 'Gunmetal' => [42, 52, 57], 721 | 'Guppie Green' => [0, 255, 127], 722 | 'Halayà Úbe' => [102, 56, 84], 723 | 'Han Blue' => [68, 108, 207], 724 | 'Han Purple' => [82, 24, 250], 725 | 'Hansa Yellow' => [233, 214, 107], 726 | 'Harlequin Green' => [70, 203, 24], 727 | 'Harlequin' => [63, 255, 0], 728 | 'Harvard Crimson' => [201, 0, 22], 729 | 'Harvest Gold' => [218, 145, 0], 730 | 'Heart Gold' => [128, 128, 0], 731 | 'Heliotrope Gray' => [170, 152, 169], 732 | 'Heliotrope Magenta' => [170, 0, 187], 733 | 'Heliotrope' => [223, 115, 255], 734 | 'Hollywood Cerise' => [244, 0, 161], 735 | 'Honeydew' => [240, 255, 240], 736 | 'Honolulu Blue' => [0, 109, 176], 737 | 'Hooker\'s Green' => [73, 121, 107], 738 | 'Hot Magenta' => [255, 29, 206], 739 | 'Hot Pink' => [255, 105, 180], 740 | 'Hunter Green' => [53, 94, 59], 741 | 'Iceberg' => [113, 166, 210], 742 | 'Icterine' => [252, 247, 94], 743 | 'Illuminating Emerald' => [49, 145, 119], 744 | 'Imperial Blue' => [0, 35, 149], 745 | 'Imperial Purple' => [102, 2, 60], 746 | 'Imperial Red' => [237, 41, 57], 747 | 'Imperial' => [96, 47, 107], 748 | 'Inchworm' => [178, 236, 93], 749 | 'Independence' => [76, 81, 109], 750 | 'India Green' => [19, 136, 8], 751 | 'Indian Red' => [205, 92, 92], 752 | 'Indian Yellow' => [227, 168, 87], 753 | 'Indigo (Web)' => [75, 0, 130], 754 | 'Indigo Dye' => [9, 31, 146], 755 | 'Indigo' => [75, 0, 130], 756 | 'International Klein Blue' => [0, 47, 167], 757 | 'Iris' => [90, 79, 207], 758 | 'Irresistible' => [179, 68, 108], 759 | 'Isabelline' => [244, 240, 236], 760 | 'Islamic Green' => [0, 144, 0], 761 | 'Italian Sky Blue' => [178, 255, 255], 762 | 'Ivory' => [255, 255, 240], 763 | 'Jade' => [0, 168, 107], 764 | 'Japanese Carmine' => [157, 41, 51], 765 | 'Japanese Indigo' => [38, 67, 72], 766 | 'Japanese Violet' => [91, 50, 86], 767 | 'Jasmine' => [248, 222, 126], 768 | 'Jasper' => [215, 59, 62], 769 | 'Jazzberry Jam' => [165, 11, 94], 770 | 'Jelly Bean' => [218, 97, 78], 771 | 'Jet' => [52, 52, 52], 772 | 'Jonquil' => [244, 202, 22], 773 | 'Jordy Blue' => [138, 185, 241], 774 | 'June Bud' => [189, 218, 87], 775 | 'Jungle Green' => [41, 171, 135], 776 | 'Kelly Green' => [76, 187, 23], 777 | 'Kenyan Copper' => [124, 28, 5], 778 | 'Keppel' => [58, 176, 158], 779 | 'Khaki (HTML/CSS, Khaki)' => [195, 176, 145], 780 | 'Khaki (X11, Light Khaki)' => [240, 230, 140], 781 | 'Kobe' => [136, 45, 23], 782 | 'Kobi' => [231, 159, 196], 783 | 'Kobicha' => [107, 68, 35], 784 | 'Kombu Green' => [53, 66, 48], 785 | 'KU Crimson' => [232, 0, 13], 786 | 'La Salle Green' => [8, 120, 48], 787 | 'Languid Lavender' => [214, 202, 221], 788 | 'Lapis Lazuli' => [38, 97, 156], 789 | 'Laser Lemon' => [255, 255, 102], 790 | 'Laurel Green' => [169, 186, 157], 791 | 'Lava' => [207, 16, 32], 792 | 'Lavender (Floral)' => [181, 126, 220], 793 | 'Lavender (Web)' => [230, 230, 250], 794 | 'Lavender Blue' => [204, 204, 255], 795 | 'Lavender Blush' => [255, 240, 245], 796 | 'Lavender Gray' => [196, 195, 208], 797 | 'Lavender Indigo' => [148, 87, 235], 798 | 'Lavender Magenta' => [238, 130, 238], 799 | 'Lavender Mist' => [230, 230, 250], 800 | 'Lavender Pink' => [251, 174, 210], 801 | 'Lavender Purple' => [150, 123, 182], 802 | 'Lavender Rose' => [251, 160, 227], 803 | 'Lawn Green' => [124, 252, 0], 804 | 'Lemon Chiffon' => [255, 250, 205], 805 | 'Lemon Curry' => [204, 160, 29], 806 | 'Lemon Glacier' => [253, 255, 0], 807 | 'Lemon Lime' => [227, 255, 0], 808 | 'Lemon Meringue' => [246, 234, 190], 809 | 'Lemon Yellow' => [255, 244, 79], 810 | 'Lemon' => [255, 247, 0], 811 | 'Lenurple' => [186, 147, 216], 812 | 'Liberty' => [84, 90, 167], 813 | 'Licorice' => [26, 17, 16], 814 | 'Light Apricot' => [253, 213, 177], 815 | 'Light Blue' => [173, 216, 230], 816 | 'Light Brilliant Red' => [254, 46, 46], 817 | 'Light Brown' => [181, 101, 29], 818 | 'Light Carmine Pink' => [230, 103, 113], 819 | 'Light Cobalt Blue' => [136, 172, 224], 820 | 'Light Coral' => [240, 128, 128], 821 | 'Light Cornflower Blue' => [147, 204, 234], 822 | 'Light Crimson' => [245, 105, 145], 823 | 'Light Cyan' => [224, 255, 255], 824 | 'Light Deep Pink' => [255, 92, 205], 825 | 'Light French Beige' => [200, 173, 127], 826 | 'Light Fuchsia Pink' => [249, 132, 239], 827 | 'Light Goldenrod Yellow' => [250, 250, 210], 828 | 'Light Gray' => [211, 211, 211], 829 | 'Light Grayish Magenta' => [204, 153, 204], 830 | 'Light Green' => [144, 238, 144], 831 | 'Light Hot Pink' => [255, 179, 222], 832 | 'Light Khaki' => [240, 230, 140], 833 | 'Light Medium Orchid' => [211, 155, 203], 834 | 'Light Moss Green' => [173, 223, 173], 835 | 'Light Orchid' => [230, 168, 215], 836 | 'Light Pastel Purple' => [177, 156, 217], 837 | 'Light Pink' => [255, 182, 193], 838 | 'Light Red Ochre' => [233, 116, 81], 839 | 'Light Salmon Pink' => [255, 153, 153], 840 | 'Light Salmon' => [255, 160, 122], 841 | 'Light Sea Green' => [32, 178, 170], 842 | 'Light Sky Blue' => [135, 206, 250], 843 | 'Light Slate Gray' => [119, 136, 153], 844 | 'Light Steel Blue' => [176, 196, 222], 845 | 'Light Taupe' => [179, 139, 109], 846 | 'Light Thulian Pink' => [230, 143, 172], 847 | 'Light Yellow' => [255, 255, 224], 848 | 'Lilac' => [200, 162, 200], 849 | 'Lime (Color Wheel)' => [191, 255, 0], 850 | 'Lime (Web, X11 Green)' => [0, 255, 0], 851 | 'Lime Green' => [50, 205, 50], 852 | 'Limerick' => [157, 194, 9], 853 | 'Lincoln Green' => [25, 89, 5], 854 | 'Linen' => [250, 240, 230], 855 | 'Lion' => [193, 154, 107], 856 | 'Liseran Purple' => [222, 111, 161], 857 | 'Little Boy Blue' => [108, 160, 220], 858 | 'Liver (Dogs)' => [184, 109, 41], 859 | 'Liver (Organ)' => [108, 46, 31], 860 | 'Liver Chestnut' => [152, 116, 86], 861 | 'Liver' => [103, 76, 71], 862 | 'Livid' => [102, 153, 204], 863 | 'Lumber' => [255, 228, 205], 864 | 'Lust' => [230, 32, 32], 865 | 'Macaroni And Cheese' => [255, 189, 136], 866 | 'Magenta (Crayola)' => [255, 85, 163], 867 | 'Magenta (Dye)' => [202, 31, 123], 868 | 'Magenta (Pantone)' => [208, 65, 126], 869 | 'Magenta (Process)' => [255, 0, 144], 870 | 'Magenta Haze' => [159, 69, 118], 871 | 'Magenta' => [255, 0, 255], 872 | 'Magenta-Pink' => [204, 51, 139], 873 | 'Magic Mint' => [170, 240, 209], 874 | 'Magnolia' => [248, 244, 255], 875 | 'Mahogany' => [192, 64, 0], 876 | 'Maize' => [251, 236, 93], 877 | 'Majorelle Blue' => [96, 80, 220], 878 | 'Malachite' => [11, 218, 81], 879 | 'Manatee' => [151, 154, 170], 880 | 'Mango Tango' => [255, 130, 67], 881 | 'Mantis' => [116, 195, 101], 882 | 'Mardi Gras' => [136, 0, 133], 883 | 'Marigold' => [234, 162, 33], 884 | 'Maroon (Crayola)' => [195, 33, 72], 885 | 'Maroon (HTML/CSS)' => [128, 0, 0], 886 | 'Maroon (X11)' => [176, 48, 96], 887 | 'Mauve Taupe' => [145, 95, 109], 888 | 'Mauve' => [224, 176, 255], 889 | 'Mauvelous' => [239, 152, 170], 890 | 'May Green' => [76, 145, 65], 891 | 'Maya Blue' => [115, 194, 251], 892 | 'Meat Brown' => [229, 183, 59], 893 | 'Medium Aquamarine' => [102, 221, 170], 894 | 'Medium Blue' => [0, 0, 205], 895 | 'Medium Candy Apple Red' => [226, 6, 44], 896 | 'Medium Carmine' => [175, 64, 53], 897 | 'Medium Champagne' => [243, 229, 171], 898 | 'Medium Electric Blue' => [3, 80, 150], 899 | 'Medium Jungle Green' => [28, 53, 45], 900 | 'Medium Lavender Magenta' => [221, 160, 221], 901 | 'Medium Orchid' => [186, 85, 211], 902 | 'Medium Persian Blue' => [0, 103, 165], 903 | 'Medium Purple' => [147, 112, 219], 904 | 'Medium Red-Violet' => [187, 51, 133], 905 | 'Medium Ruby' => [170, 64, 105], 906 | 'Medium Sea Green' => [60, 179, 113], 907 | 'Medium Sky Blue' => [128, 218, 235], 908 | 'Medium Slate Blue' => [123, 104, 238], 909 | 'Medium Spring Bud' => [201, 220, 135], 910 | 'Medium Spring Green' => [0, 250, 154], 911 | 'Medium Taupe' => [103, 76, 71], 912 | 'Medium Turquoise' => [72, 209, 204], 913 | 'Medium Tuscan Red' => [121, 68, 59], 914 | 'Medium Vermilion' => [217, 96, 59], 915 | 'Medium Violet-Red' => [199, 21, 133], 916 | 'Mellow Apricot' => [248, 184, 120], 917 | 'Mellow Yellow' => [248, 222, 126], 918 | 'Melon' => [253, 188, 180], 919 | 'Metallic Seaweed' => [10, 126, 140], 920 | 'Metallic Sunburst' => [156, 124, 56], 921 | 'Mexican Pink' => [228, 0, 124], 922 | 'Midnight Blue' => [25, 25, 112], 923 | 'Midnight Green (Eagle Green)' => [0, 73, 83], 924 | 'Mikado Yellow' => [255, 196, 12], 925 | 'Mindaro' => [227, 249, 136], 926 | 'Ming' => [54, 116, 125], 927 | 'Mint Cream' => [245, 255, 250], 928 | 'Mint Green' => [152, 255, 152], 929 | 'Mint' => [62, 180, 137], 930 | 'Misty Rose' => [255, 228, 225], 931 | 'Moccasin' => [250, 235, 215], 932 | 'Mode Beige' => [150, 113, 23], 933 | 'Moonstone Blue' => [115, 169, 194], 934 | 'Mordant Red 19' => [174, 12, 0], 935 | 'Moss Green' => [138, 154, 91], 936 | 'Mountain Meadow' => [48, 186, 143], 937 | 'Mountbatten Pink' => [153, 122, 141], 938 | 'MSU Green' => [24, 69, 59], 939 | 'Mughal Green' => [48, 96, 48], 940 | 'Mulberry' => [197, 75, 140], 941 | 'Mustard' => [255, 219, 88], 942 | 'Myrtle Green' => [49, 120, 115], 943 | 'Nadeshiko Pink' => [246, 173, 198], 944 | 'Napier Green' => [42, 128, 0], 945 | 'Naples Yellow' => [250, 218, 94], 946 | 'Navajo White' => [255, 222, 173], 947 | 'Navy Purple' => [148, 87, 235], 948 | 'Navy' => [0, 0, 128], 949 | 'Neon Carrot' => [255, 163, 67], 950 | 'Neon Fuchsia' => [254, 65, 100], 951 | 'Neon Green' => [57, 255, 20], 952 | 'New Car' => [33, 79, 198], 953 | 'New York Pink' => [215, 131, 127], 954 | 'Non-Photo Blue' => [164, 221, 237], 955 | 'North Texas Green' => [5, 144, 51], 956 | 'Nyanza' => [233, 255, 219], 957 | 'Ocean Boat Blue' => [0, 119, 190], 958 | 'Ochre' => [204, 119, 34], 959 | 'Office Green' => [0, 128, 0], 960 | 'Old Burgundy' => [67, 48, 46], 961 | 'Old Gold' => [207, 181, 59], 962 | 'Old Heliotrope' => [86, 60, 92], 963 | 'Old Lace' => [253, 245, 230], 964 | 'Old Lavender' => [121, 104, 120], 965 | 'Old Mauve' => [103, 49, 71], 966 | 'Old Moss Green' => [134, 126, 54], 967 | 'Old Rose' => [192, 128, 129], 968 | 'Old Silver' => [132, 132, 130], 969 | 'Olive Drab (' => [107, 142, 35], 970 | 'Olive Drab' => [60, 52, 31], 971 | 'Olive' => [128, 128, 0], 972 | 'Olivine' => [154, 185, 115], 973 | 'Onyx' => [53, 56, 57], 974 | 'Opera Mauve' => [183, 132, 167], 975 | 'Orange (Aerospace)' => [255, 79, 0], 976 | 'Orange (Color Wheel)' => [255, 127, 0], 977 | 'Orange (Crayola)' => [255, 117, 56], 978 | 'Orange (Engineering)' => [186, 22, 12], 979 | 'Orange (Golden Gate)' => [192, 54, 44], 980 | 'Orange (Pantone)' => [255, 88, 0], 981 | 'Orange (RYB)' => [251, 153, 2], 982 | 'Orange (Web)' => [255, 165, 0], 983 | 'Orange Peel' => [255, 159, 0], 984 | 'Orange-Red' => [255, 69, 0], 985 | 'Orange-Yellow' => [248, 213, 104], 986 | 'Orchid Pink' => [242, 189, 205], 987 | 'Orchid' => [218, 112, 214], 988 | 'Orioles Orange' => [251, 79, 20], 989 | 'Otter Brown' => [101, 67, 33], 990 | 'OU Crimson Red' => [153, 0, 0], 991 | 'Outer Space' => [65, 74, 76], 992 | 'Outrageous Orange' => [255, 110, 74], 993 | 'Oxford Blue' => [0, 33, 71], 994 | 'Pacific Blue' => [28, 169, 201], 995 | 'Pakistan Green' => [0, 102, 0], 996 | 'Palatinate Blue' => [39, 59, 226], 997 | 'Palatinate Purple' => [104, 40, 96], 998 | 'Pale Aqua' => [188, 212, 230], 999 | 'Pale Blue' => [175, 238, 238], 1000 | 'Pale Brown' => [152, 118, 84], 1001 | 'Pale Carmine' => [175, 64, 53], 1002 | 'Pale Cerulean' => [155, 196, 226], 1003 | 'Pale Chestnut' => [221, 173, 175], 1004 | 'Pale Copper' => [218, 138, 103], 1005 | 'Pale Cornflower Blue' => [171, 205, 239], 1006 | 'Pale Cyan' => [135, 211, 248], 1007 | 'Pale Gold' => [230, 190, 138], 1008 | 'Pale Goldenrod' => [238, 232, 170], 1009 | 'Pale Green' => [152, 251, 152], 1010 | 'Pale Lavender' => [220, 208, 255], 1011 | 'Pale Magenta' => [249, 132, 229], 1012 | 'Pale Magenta-Pink' => [255, 153, 204], 1013 | 'Pale Pink' => [250, 218, 221], 1014 | 'Pale Plum' => [221, 160, 221], 1015 | 'Pale Red-Violet' => [219, 112, 147], 1016 | 'Pale Robin Egg Blue' => [150, 222, 209], 1017 | 'Pale Silver' => [201, 192, 187], 1018 | 'Pale Spring Bud' => [236, 235, 189], 1019 | 'Pale Taupe' => [188, 152, 126], 1020 | 'Pale Turquoise' => [175, 238, 238], 1021 | 'Pale Violet' => [204, 153, 255], 1022 | 'Pale Violet-Red' => [219, 112, 147], 1023 | 'Pansy Purple' => [120, 24, 74], 1024 | 'Paolo Veronese Green' => [0, 155, 125], 1025 | 'Papaya Whip' => [255, 239, 213], 1026 | 'Paradise Pink' => [230, 62, 98], 1027 | 'Paris Green' => [80, 200, 120], 1028 | 'Pastel Blue' => [174, 198, 207], 1029 | 'Pastel Brown' => [131, 105, 83], 1030 | 'Pastel Gray' => [207, 207, 196], 1031 | 'Pastel Green' => [119, 221, 119], 1032 | 'Pastel Magenta' => [244, 154, 194], 1033 | 'Pastel Orange' => [255, 179, 71], 1034 | 'Pastel Pink' => [222, 165, 164], 1035 | 'Pastel Purple' => [179, 158, 181], 1036 | 'Pastel Red' => [255, 105, 97], 1037 | 'Pastel Violet' => [203, 153, 201], 1038 | 'Pastel Yellow' => [253, 253, 150], 1039 | 'Patriarch' => [128, 0, 128], 1040 | 'Payne\'s Grey' => [83, 104, 120], 1041 | 'Peach Puff' => [255, 218, 185], 1042 | 'Peach' => [255, 203, 164], 1043 | 'Peach-Orange' => [255, 204, 153], 1044 | 'Peach-Yellow' => [250, 223, 173], 1045 | 'Pear' => [209, 226, 49], 1046 | 'Pearl Aqua' => [136, 216, 192], 1047 | 'Pearl' => [234, 224, 200], 1048 | 'Pearly Purple' => [183, 104, 162], 1049 | 'Peridot' => [230, 226, 0], 1050 | 'Periwinkle' => [204, 204, 255], 1051 | 'Permanent Geranium Lake' => [225, 44, 44], 1052 | 'Persian Blue' => [28, 57, 187], 1053 | 'Persian Green' => [0, 166, 147], 1054 | 'Persian Indigo' => [50, 18, 122], 1055 | 'Persian Orange' => [217, 144, 88], 1056 | 'Persian Pink' => [247, 127, 190], 1057 | 'Persian Plum' => [112, 28, 28], 1058 | 'Persian Red' => [204, 51, 51], 1059 | 'Persian Rose' => [254, 40, 162], 1060 | 'Persimmon' => [236, 88, 0], 1061 | 'Peru' => [205, 133, 63], 1062 | 'Phlox' => [223, 0, 255], 1063 | 'Phthalo Blue' => [0, 15, 137], 1064 | 'Phthalo Green' => [18, 53, 36], 1065 | 'Picton Blue' => [69, 177, 232], 1066 | 'Pictorial Carmine' => [195, 11, 78], 1067 | 'Piggy Pink' => [253, 221, 230], 1068 | 'Pine Green' => [1, 121, 111], 1069 | 'Pineapple' => [86, 60, 92], 1070 | 'Pink (Pantone)' => [215, 72, 148], 1071 | 'Pink Flamingo' => [252, 116, 253], 1072 | 'Pink Lace' => [255, 221, 244], 1073 | 'Pink Lavender' => [216, 178, 209], 1074 | 'Pink Pearl' => [231, 172, 207], 1075 | 'Pink Raspberry' => [152, 0, 54], 1076 | 'Pink Sherbet' => [247, 143, 167], 1077 | 'Pink' => [255, 192, 203], 1078 | 'Pink-Orange' => [255, 153, 102], 1079 | 'Pistachio' => [147, 197, 114], 1080 | 'Platinum' => [229, 228, 226], 1081 | 'Plum (Web)' => [221, 160, 221], 1082 | 'Plum' => [142, 69, 133], 1083 | 'Pomp And Power' => [134, 96, 142], 1084 | 'Popstar' => [190, 79, 98], 1085 | 'Portland Orange' => [255, 90, 54], 1086 | 'Powder Blue' => [176, 224, 230], 1087 | 'Princeton Orange' => [245, 128, 37], 1088 | 'Prune' => [112, 28, 28], 1089 | 'Prussian Blue' => [0, 49, 83], 1090 | 'Psychedelic Purple' => [223, 0, 255], 1091 | 'Puce Red' => [114, 47, 55], 1092 | 'Puce' => [204, 136, 153], 1093 | 'Pullman Brown (UPS Brown)' => [100, 65, 23], 1094 | 'Pullman Green' => [59, 51, 28], 1095 | 'Pumpkin' => [255, 117, 24], 1096 | 'Purple (HTML)' => [128, 0, 128], 1097 | 'Purple (Munsell)' => [159, 0, 197], 1098 | 'Purple (X11)' => [160, 32, 240], 1099 | 'Purple Heart' => [105, 53, 156], 1100 | 'Purple Mountain Majesty' => [150, 120, 182], 1101 | 'Purple Navy' => [78, 81, 128], 1102 | 'Purple Pizzazz' => [254, 78, 218], 1103 | 'Purple Taupe' => [80, 64, 77], 1104 | 'Purpureus' => [154, 78, 174], 1105 | 'Quartz' => [81, 72, 79], 1106 | 'Queen Blue' => [67, 107, 149], 1107 | 'Queen Pink' => [232, 204, 215], 1108 | 'Quinacridone Magenta' => [142, 58, 89], 1109 | 'Rackley' => [93, 138, 168], 1110 | 'Radical Red' => [255, 53, 94], 1111 | 'Raisin Black' => [36, 33, 36], 1112 | 'Rajah' => [251, 171, 96], 1113 | 'Raspberry Glace' => [145, 95, 109], 1114 | 'Raspberry Pink' => [226, 80, 152], 1115 | 'Raspberry Rose' => [179, 68, 108], 1116 | 'Raspberry' => [227, 11, 93], 1117 | 'Raw Sienna' => [214, 138, 89], 1118 | 'Raw Umber' => [130, 102, 68], 1119 | 'Razzle Dazzle Rose' => [255, 51, 204], 1120 | 'Razzmatazz' => [227, 37, 107], 1121 | 'Razzmic Berry' => [141, 78, 133], 1122 | 'Rebecca Purple' => [102, 51, 153], 1123 | 'Red (Crayola)' => [238, 32, 77], 1124 | 'Red (Munsell)' => [242, 0, 60], 1125 | 'Red (NCS)' => [196, 2, 51], 1126 | 'Red (Pantone)' => [237, 41, 57], 1127 | 'Red (Pigment)' => [237, 28, 36], 1128 | 'Red (RYB)' => [254, 39, 18], 1129 | 'Red Devil' => [134, 1, 17], 1130 | 'Red' => [255, 0, 0], 1131 | 'Red-Brown' => [165, 42, 42], 1132 | 'Red-Orange' => [255, 83, 73], 1133 | 'Red-Purple' => [228, 0, 120], 1134 | 'Red-Violet' => [199, 21, 133], 1135 | 'Redwood' => [164, 90, 82], 1136 | 'Regalia' => [82, 45, 128], 1137 | 'Registration Black' => [0, 0, 0], 1138 | 'Resolution Blue' => [0, 35, 135], 1139 | 'Rhythm' => [119, 118, 150], 1140 | 'Rich Black (FOGRA29)' => [1, 11, 19], 1141 | 'Rich Black (FOGRA39)' => [1, 2, 3], 1142 | 'Rich Black' => [0, 64, 64], 1143 | 'Rich Brilliant Lavender' => [241, 167, 254], 1144 | 'Rich Carmine' => [215, 0, 64], 1145 | 'Rich Electric Blue' => [8, 146, 208], 1146 | 'Rich Lavender' => [167, 107, 207], 1147 | 'Rich Lilac' => [182, 102, 210], 1148 | 'Rich Maroon' => [176, 48, 96], 1149 | 'Rifle Green' => [68, 76, 56], 1150 | 'Roast Coffee' => [112, 66, 65], 1151 | 'Robin Egg Blue' => [0, 204, 204], 1152 | 'Rocket Metallic' => [138, 127, 128], 1153 | 'Roman Silver' => [131, 137, 150], 1154 | 'Rose Bonbon' => [249, 66, 158], 1155 | 'Rose Ebony' => [103, 72, 70], 1156 | 'Rose Gold' => [183, 110, 121], 1157 | 'Rose Madder' => [227, 38, 54], 1158 | 'Rose Pink' => [255, 102, 204], 1159 | 'Rose Quartz' => [170, 152, 169], 1160 | 'Rose Red' => [194, 30, 86], 1161 | 'Rose Taupe' => [144, 93, 93], 1162 | 'Rose Vale' => [171, 78, 82], 1163 | 'Rose' => [255, 0, 127], 1164 | 'Rosewood' => [101, 0, 11], 1165 | 'Rosso Corsa' => [212, 0, 0], 1166 | 'Rosy Brown' => [188, 143, 143], 1167 | 'Royal Azure' => [0, 56, 168], 1168 | 'Royal Blue' => [65, 105, 225], 1169 | 'Royal Fuchsia' => [202, 44, 146], 1170 | 'Royal Purple' => [120, 81, 169], 1171 | 'Royal Yellow' => [250, 218, 94], 1172 | 'Ruber' => [206, 70, 118], 1173 | 'Rubine Red' => [209, 0, 86], 1174 | 'Ruby Red' => [155, 17, 30], 1175 | 'Ruby' => [224, 17, 95], 1176 | 'Ruddy Brown' => [187, 101, 40], 1177 | 'Ruddy Pink' => [225, 142, 150], 1178 | 'Ruddy' => [255, 0, 40], 1179 | 'Rufous' => [168, 28, 7], 1180 | 'Russet' => [128, 70, 27], 1181 | 'Russian Green' => [103, 146, 103], 1182 | 'Russian Violet' => [50, 23, 77], 1183 | 'Rust' => [183, 65, 14], 1184 | 'Rusty Red' => [218, 44, 67], 1185 | 'Sacramento State Green' => [0, 86, 63], 1186 | 'Saddle Brown' => [139, 69, 19], 1187 | 'Safety Orange (Blaze Orange)' => [255, 103, 0], 1188 | 'Safety Orange' => [255, 120, 0], 1189 | 'Safety Yellow' => [238, 210, 2], 1190 | 'Saffron' => [244, 196, 48], 1191 | 'Sage' => [188, 184, 138], 1192 | 'Salmon Pink' => [255, 145, 164], 1193 | 'Salmon' => [250, 128, 114], 1194 | 'Sand Dune' => [150, 113, 23], 1195 | 'Sand' => [194, 178, 128], 1196 | 'Sandstorm' => [236, 213, 64], 1197 | 'Sandy Brown' => [244, 164, 96], 1198 | 'Sandy Taupe' => [150, 113, 23], 1199 | 'Sangria' => [146, 0, 10], 1200 | 'Sap Green' => [80, 125, 42], 1201 | 'Sapphire Blue' => [0, 103, 165], 1202 | 'Sapphire' => [15, 82, 186], 1203 | 'Satin Sheen Gold' => [203, 161, 53], 1204 | 'Scarlet' => [253, 14, 53], 1205 | 'Schauss Pink' => [255, 145, 175], 1206 | 'School Bus Yellow' => [255, 216, 0], 1207 | 'Screamin\' Green' => [118, 255, 122], 1208 | 'Sea Blue' => [0, 105, 148], 1209 | 'Sea Green' => [46, 139, 87], 1210 | 'Seal Brown' => [89, 38, 11], 1211 | 'Seashell' => [255, 245, 238], 1212 | 'Selective Yellow' => [255, 186, 0], 1213 | 'Sepia' => [112, 66, 20], 1214 | 'Shadow Blue' => [119, 139, 165], 1215 | 'Shadow' => [138, 121, 93], 1216 | 'Shampoo' => [255, 207, 241], 1217 | 'Shamrock Green' => [0, 158, 96], 1218 | 'Sheen Green' => [143, 212, 0], 1219 | 'Shimmering Blush' => [217, 134, 149], 1220 | 'Shocking Pink (Crayola)' => [255, 111, 255], 1221 | 'Shocking Pink' => [252, 15, 192], 1222 | 'Sienna' => [136, 45, 23], 1223 | 'Silver Chalice' => [172, 172, 172], 1224 | 'Silver Lake Blue' => [93, 137, 186], 1225 | 'Silver Pink' => [196, 174, 173], 1226 | 'Silver Sand' => [191, 193, 194], 1227 | 'Silver' => [192, 192, 192], 1228 | 'Sinopia' => [203, 65, 11], 1229 | 'Skobeloff' => [0, 116, 116], 1230 | 'Sky Blue' => [135, 206, 235], 1231 | 'Sky Magenta' => [207, 113, 175], 1232 | 'Slate Blue' => [106, 90, 205], 1233 | 'Slate Gray' => [112, 128, 144], 1234 | 'Smalt (Dark Powder Blue)' => [0, 51, 153], 1235 | 'Smitten' => [200, 65, 134], 1236 | 'Smoke' => [115, 130, 118], 1237 | 'Smoky Black' => [16, 12, 8], 1238 | 'Smoky Topaz' => [147, 61, 65], 1239 | 'Snow' => [255, 250, 250], 1240 | 'Soap' => [206, 200, 239], 1241 | 'Solid Pink' => [137, 56, 67], 1242 | 'Sonic Silver' => [117, 117, 117], 1243 | 'Space Cadet' => [29, 41, 81], 1244 | 'Spanish Bistre' => [128, 117, 50], 1245 | 'Spanish Blue' => [0, 112, 184], 1246 | 'Spanish Carmine' => [209, 0, 71], 1247 | 'Spanish Crimson' => [229, 26, 76], 1248 | 'Spanish Gray' => [152, 152, 152], 1249 | 'Spanish Green' => [0, 145, 80], 1250 | 'Spanish Orange' => [232, 97, 0], 1251 | 'Spanish Pink' => [247, 191, 190], 1252 | 'Spanish Red' => [230, 0, 38], 1253 | 'Spanish Sky Blue' => [0, 255, 255], 1254 | 'Spanish Violet' => [76, 40, 130], 1255 | 'Spanish Viridian' => [0, 127, 92], 1256 | 'Spartan Crimson' => [158, 19, 22], 1257 | 'Spicy Mix' => [139, 95, 77], 1258 | 'Spiro Disco Ball' => [15, 192, 252], 1259 | 'Spring Bud' => [167, 252, 0], 1260 | 'Spring Green' => [0, 255, 127], 1261 | 'St. Patrick\'s Blue' => [35, 41, 122], 1262 | 'Star Command Blue' => [0, 123, 184], 1263 | 'Steel Blue' => [70, 130, 180], 1264 | 'Steel Pink' => [204, 51, 204], 1265 | 'Stil De Grain Yellow' => [250, 218, 94], 1266 | 'Stizza' => [153, 0, 0], 1267 | 'Stormcloud' => [79, 102, 106], 1268 | 'Straw' => [228, 217, 111], 1269 | 'Strawberry' => [252, 90, 141], 1270 | 'Sunglow' => [255, 204, 51], 1271 | 'Sunray' => [227, 171, 87], 1272 | 'Sunset Orange' => [253, 94, 83], 1273 | 'Sunset' => [250, 214, 165], 1274 | 'Super Pink' => [207, 107, 169], 1275 | 'Tan' => [210, 180, 140], 1276 | 'Tangelo' => [249, 77, 0], 1277 | 'Tangerine Yellow' => [255, 204, 0], 1278 | 'Tangerine' => [242, 133, 0], 1279 | 'Tango Pink' => [228, 113, 122], 1280 | 'Taupe Gray' => [139, 133, 137], 1281 | 'Taupe' => [72, 60, 50], 1282 | 'Tea Green' => [208, 240, 192], 1283 | 'Tea Rose' => [244, 194, 194], 1284 | 'Teal Blue' => [54, 117, 136], 1285 | 'Teal Deer' => [153, 230, 179], 1286 | 'Teal Green' => [0, 130, 127], 1287 | 'Teal' => [0, 128, 128], 1288 | 'Telemagenta' => [207, 52, 118], 1289 | 'Tenné' => [205, 87, 0], 1290 | 'Terra Cotta' => [226, 114, 91], 1291 | 'Thistle' => [216, 191, 216], 1292 | 'Thulian Pink' => [222, 111, 161], 1293 | 'Tickle Me Pink' => [252, 137, 172], 1294 | 'Tiffany Blue' => [10, 186, 181], 1295 | 'Tiger\'s Eye' => [224, 141, 60], 1296 | 'Timberwolf' => [219, 215, 210], 1297 | 'Titanium Yellow' => [238, 230, 0], 1298 | 'Tomato' => [255, 99, 71], 1299 | 'Toolbox' => [116, 108, 192], 1300 | 'Topaz' => [255, 200, 124], 1301 | 'Tractor Red' => [253, 14, 53], 1302 | 'Trolley Grey' => [128, 128, 128], 1303 | 'Tropical Rain Forest' => [0, 117, 94], 1304 | 'Tropical Violet' => [205, 164, 222], 1305 | 'True Blue' => [0, 115, 207], 1306 | 'Tufts Blue' => [65, 125, 193], 1307 | 'Tulip' => [255, 135, 141], 1308 | 'Tumbleweed' => [222, 170, 136], 1309 | 'Turkish Rose' => [181, 114, 129], 1310 | 'Turquoise Blue' => [0, 255, 239], 1311 | 'Turquoise Green' => [160, 214, 180], 1312 | 'Turquoise' => [64, 224, 208], 1313 | 'Tuscan Brown' => [111, 78, 55], 1314 | 'Tuscan Red' => [124, 72, 72], 1315 | 'Tuscan Tan' => [166, 123, 91], 1316 | 'Tuscan' => [250, 214, 165], 1317 | 'Tuscany' => [192, 153, 153], 1318 | 'Twilight Lavender' => [138, 73, 107], 1319 | 'Tyrian Purple' => [102, 2, 60], 1320 | 'UA Blue' => [0, 51, 170], 1321 | 'UA Red' => [217, 0, 76], 1322 | 'Ube' => [136, 120, 195], 1323 | 'UCLA Blue' => [83, 104, 149], 1324 | 'UCLA Gold' => [255, 179, 0], 1325 | 'UFO Green' => [60, 208, 112], 1326 | 'Ultra Pink' => [255, 111, 255], 1327 | 'Ultra Red' => [252, 108, 133], 1328 | 'Ultramarine Blue' => [65, 102, 245], 1329 | 'Ultramarine' => [63, 0, 255], 1330 | 'Umber' => [99, 81, 71], 1331 | 'Unbleached Silk' => [255, 221, 202], 1332 | 'United Nations Blue' => [91, 146, 229], 1333 | 'University of California Gold' => [183, 135, 39], 1334 | 'University of Tennessee Orange' => [247, 127, 0], 1335 | 'Unmellow Yellow' => [255, 255, 102], 1336 | 'UP Forest Green' => [1, 68, 33], 1337 | 'UP Maroon' => [123, 17, 19], 1338 | 'Upsdell Red' => [174, 32, 41], 1339 | 'Urobilin' => [225, 173, 33], 1340 | 'USAFA Blue' => [0, 79, 152], 1341 | 'USC Cardinal' => [153, 0, 0], 1342 | 'USC Gold' => [255, 204, 0], 1343 | 'Utah Crimson' => [211, 0, 63], 1344 | 'Vanilla Ice' => [243, 143, 169], 1345 | 'Vanilla' => [243, 229, 171], 1346 | 'Vegas Gold' => [197, 179, 88], 1347 | 'Venetian Red' => [200, 8, 21], 1348 | 'Verdigris' => [67, 179, 174], 1349 | 'Vermilion' => [217, 56, 30], 1350 | 'Veronica' => [160, 32, 240], 1351 | 'Very Light Azure' => [116, 187, 251], 1352 | 'Very Light Blue' => [102, 102, 255], 1353 | 'Very Light Malachite Green' => [100, 233, 134], 1354 | 'Very Light Tangelo' => [255, 176, 119], 1355 | 'Very Pale Orange' => [255, 223, 191], 1356 | 'Very Pale Yellow' => [255, 255, 191], 1357 | 'Violet (Color Wheel)' => [127, 0, 255], 1358 | 'Violet (RYB)' => [134, 1, 175], 1359 | 'Violet (Web)' => [238, 130, 238], 1360 | 'Violet' => [143, 0, 255], 1361 | 'Violet-Blue' => [50, 74, 178], 1362 | 'Violet-Red' => [247, 83, 148], 1363 | 'Viridian Green' => [0, 150, 152], 1364 | 'Viridian' => [64, 130, 109], 1365 | 'Vista Blue' => [124, 158, 217], 1366 | 'Vivid Amber' => [204, 153, 0], 1367 | 'Vivid Auburn' => [146, 39, 36], 1368 | 'Vivid Burgundy' => [159, 29, 53], 1369 | 'Vivid Cerise' => [218, 29, 129], 1370 | 'Vivid Cerulean' => [0, 170, 238], 1371 | 'Vivid Crimson' => [204, 0, 51], 1372 | 'Vivid Gamboge' => [255, 153, 0], 1373 | 'Vivid Lime Green' => [166, 214, 8], 1374 | 'Vivid Malachite' => [0, 204, 51], 1375 | 'Vivid Mulberry' => [184, 12, 227], 1376 | 'Vivid Orange Peel' => [255, 160, 0], 1377 | 'Vivid Orange' => [255, 95, 0], 1378 | 'Vivid Orchid' => [204, 0, 255], 1379 | 'Vivid Raspberry' => [255, 0, 108], 1380 | 'Vivid Red' => [247, 13, 26], 1381 | 'Vivid Red-Tangelo' => [223, 97, 36], 1382 | 'Vivid Sky Blue' => [0, 204, 255], 1383 | 'Vivid Tangelo' => [240, 116, 39], 1384 | 'Vivid Tangerine' => [255, 160, 137], 1385 | 'Vivid Vermilion' => [229, 96, 36], 1386 | 'Vivid Violet' => [159, 0, 255], 1387 | 'Vivid Yellow' => [255, 227, 2], 1388 | 'Volt' => [206, 255, 0], 1389 | 'Warm Black' => [0, 66, 66], 1390 | 'Waterspout' => [164, 244, 249], 1391 | 'Weldon Blue' => [124, 152, 171], 1392 | 'Wenge' => [100, 84, 82], 1393 | 'Wheat' => [245, 222, 179], 1394 | 'White Smoke' => [245, 245, 245], 1395 | 'White' => [255, 255, 255], 1396 | 'Wild Blue Yonder' => [162, 173, 208], 1397 | 'Wild Orchid' => [212, 112, 162], 1398 | 'Wild Strawberry' => [255, 67, 164], 1399 | 'Wild Watermelon' => [252, 108, 133], 1400 | 'Willpower Orange' => [253, 88, 0], 1401 | 'Windsor Tan' => [167, 85, 2], 1402 | 'Wine Dregs' => [103, 49, 71], 1403 | 'Wine' => [114, 47, 55], 1404 | 'Wisteria' => [201, 160, 220], 1405 | 'Wood Brown' => [193, 154, 107], 1406 | 'Xanadu' => [115, 134, 120], 1407 | 'Yale Blue' => [15, 77, 146], 1408 | 'Yankees Blue' => [28, 40, 65], 1409 | 'Yellow (Crayola)' => [252, 232, 131], 1410 | 'Yellow (Munsell)' => [239, 204, 0], 1411 | 'Yellow (NCS)' => [255, 211, 0], 1412 | 'Yellow (Pantone)' => [254, 223, 0], 1413 | 'Yellow (Process)' => [255, 239, 0], 1414 | 'Yellow (RYB)' => [254, 254, 51], 1415 | 'Yellow Orange' => [255, 174, 66], 1416 | 'Yellow Rose' => [255, 240, 0], 1417 | 'Yellow' => [255, 255, 0], 1418 | 'Yellow-Green' => [154, 205, 50], 1419 | 'Zaffre' => [0, 20, 168], 1420 | 'Zinnwaldite Brown' => [44, 22, 8], 1421 | 'Zomp' => [57, 167, 14], 1422 | ]; 1423 | } 1424 | } 1425 | -------------------------------------------------------------------------------- /src/DateRange.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Sep 2016 9 | */ 10 | namespace DDD\Embeddable; 11 | 12 | use DateTime; 13 | use Doctrine\ORM\Mapping as ORM; 14 | use InvalidArgumentException; 15 | use JsonSerializable; 16 | 17 | /** 18 | * @ORM\Embeddable 19 | */ 20 | class DateRange implements JsonSerializable 21 | { 22 | /** 23 | * start date 24 | * 25 | * @ORM\Column(type="datetime", nullable=true) 26 | */ 27 | private ?DateTime $dateFrom = null; 28 | 29 | /** 30 | * end date 31 | * 32 | * @ORM\Column(type="datetime", nullable=true) 33 | */ 34 | private ?DateTime $dateTo = null; 35 | 36 | public function __construct(DateTime $start = null, DateTime $end = null) 37 | { 38 | if ($start === null || $end === null) { 39 | return; 40 | } 41 | 42 | if ($start >= $end) { 43 | throw new InvalidArgumentException('Start date is greater or equal to end date'); 44 | } 45 | 46 | $this->dateFrom = $start; 47 | $this->dateTo = $end; 48 | } 49 | 50 | public function getDateFrom() : DateTime 51 | { 52 | return $this->dateFrom; 53 | } 54 | 55 | public function getDateTo() : DateTime 56 | { 57 | return $this->dateTo; 58 | } 59 | 60 | /** 61 | * Formats date range to string using given $format 62 | * 63 | * @param string $f Any format accepted by php date() 64 | */ 65 | public function format(string $f = 'c') : string 66 | { 67 | if ($this->isEmpty()) { 68 | return ''; 69 | } 70 | 71 | return $this->getDateFrom()->format($f).' - '.$this->getDateTo()->format($f); 72 | } 73 | 74 | /** 75 | * String representation of date range. 76 | * 77 | * @return string 78 | */ 79 | public function __toString() 80 | { 81 | return $this->format('c'); 82 | } 83 | 84 | /** 85 | * Returns duration of the date range in seconds. 86 | */ 87 | public function getDurationInSeconds() : float|int 88 | { 89 | if (!$this->dateFrom) { 90 | return 0; 91 | } 92 | 93 | $interval = $this->dateFrom->diff($this->dateTo); 94 | 95 | return ($interval->y * 365 * 24 * 60 * 60) + 96 | ($interval->m * 30 * 24 * 60 * 60) + 97 | ($interval->d * 24 * 60 * 60) + 98 | ($interval->h * 60 * 60) + 99 | ($interval->i * 60) + 100 | $interval->s; 101 | } 102 | 103 | /** 104 | * Array representation of the range 105 | * 106 | * @return array 107 | */ 108 | public function toArray($format = 'c') 109 | { 110 | if ($this->isEmpty()) { 111 | return []; 112 | } 113 | 114 | return [ 115 | 'start' => $this->getDateFrom()->format($format), 116 | 'end' => $this->getDateTo()->format($format), 117 | ]; 118 | } 119 | 120 | /** 121 | * Implement json serializable interface. 122 | */ 123 | public function jsonSerialize(): array 124 | { 125 | return $this->toArray(); 126 | } 127 | 128 | /** 129 | * Returns a boolean TRUE if the range instance is 130 | * literally empty, FALSE otherwise. 131 | */ 132 | public function isEmpty() : bool 133 | { 134 | return !$this->dateFrom || !$this->dateTo; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/EmailAddress.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Sep 2016 9 | */ 10 | 11 | namespace DDD\Embeddable; 12 | 13 | use Doctrine\ORM\Mapping as ORM; 14 | use InvalidArgumentException; 15 | 16 | /** 17 | * @ORM\Embeddable 18 | */ 19 | class EmailAddress 20 | { 21 | /** 22 | * @ORM\Column(type="string", length=100, nullable=true) 23 | */ 24 | private ?string $address = null; 25 | 26 | public function __construct(string $email = null) 27 | { 28 | // This is only a soft validation to reduce headaches earlier. 29 | // You SHOULD sanitize & validate actual email according to your needs, before using it as a value object! 30 | if ($email && ! filter_var($email, FILTER_VALIDATE_EMAIL)) { 31 | throw new InvalidArgumentException('Given e-mail address ' . $email . ' is not a valid'); 32 | } 33 | 34 | $this->address = $email; 35 | } 36 | 37 | /** 38 | * String representation of an email. 39 | */ 40 | public function __toString(): string 41 | { 42 | return $this->address ?: ''; 43 | } 44 | 45 | /** 46 | * Returns domain part of the email address like gmail.com, yahoo.com etc. 47 | */ 48 | public function getDomain() : ?string 49 | { 50 | return $this->address ? explode('@', $this->address)[1] : null; 51 | } 52 | 53 | /** 54 | * Returns local part of the email address 55 | */ 56 | public function getLocalPart() : ?string 57 | { 58 | return $this->address ? explode('@', $this->address, 2)[0] : null; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/FullName.php: -------------------------------------------------------------------------------- 1 | 7 | * @license MIT 8 | * 9 | * @since Sep 2016 10 | */ 11 | 12 | namespace DDD\Embeddable; 13 | 14 | use Doctrine\ORM\Mapping as ORM; 15 | use InvalidArgumentException; 16 | use JsonSerializable; 17 | 18 | /** 19 | * @ORM\Embeddable 20 | */ 21 | class FullName implements JsonSerializable 22 | { 23 | /** 24 | * Simple honorific title enumeration. 25 | * 26 | * It mainly helps keeping titles consistent and easily validating them. 27 | * Also, very useful to populate title dropdowns. 28 | */ 29 | public const TITLES = [ 30 | 'Mr.', 31 | 'Ms.', // for women regardless of their marital status 32 | 'Mrs.', 33 | 'Miss', 34 | 'Mx.', // a title that does not indicate gender 35 | 'Adv.', // advocate 36 | 'Capt.', // captain 37 | 'Dr.', 38 | 'Prof.', // professor 39 | ]; 40 | 41 | /** 42 | * honorific title prefixing a person's name. 43 | * 44 | * @ORM\Column(type="string", length=5, nullable=true) 45 | */ 46 | private ?string $title = null; 47 | 48 | /** 49 | * first name of the person. 50 | * 51 | * @ORM\Column(type="string", length=64, nullable=true) 52 | */ 53 | private ?string $name = null; 54 | 55 | /** 56 | * middle name of the person. 57 | * 58 | * @ORM\Column(type="string", length=64, nullable=true) 59 | */ 60 | private ?string $middleName = null; 61 | 62 | /** 63 | * last name of the person. 64 | * 65 | * @ORM\Column(type="string", length=64, nullable=true) 66 | */ 67 | private ?string $surname = null; 68 | 69 | /** 70 | * String representation of a full name. 71 | */ 72 | public function __toString() 73 | { 74 | // Array filter removes empty items. 75 | return implode(' ', array_filter([$this->title, $this->name, $this->middleName, $this->surname])); 76 | } 77 | 78 | /** 79 | * @param string|null $fullName Space separated full name. Ex: Steven Paul Jobs 80 | */ 81 | public function __construct(string $fullName = null, string $title = null) 82 | { 83 | if ($fullName) { 84 | $this->buildFromString($fullName); 85 | } 86 | 87 | if ($title) { 88 | $this->setTitle($title); 89 | } 90 | } 91 | 92 | /** 93 | * A private setter for title. 94 | * 95 | * @throws InvalidArgumentException 96 | */ 97 | private function setTitle(string $title) : void 98 | { 99 | if (! str_ends_with($title, '.')) { 100 | // Allow titles without dots too 101 | $title .= '.'; 102 | } 103 | 104 | if (! in_array($title, self::TITLES)) { 105 | throw new InvalidArgumentException('Given title is invalid: ' . $title); 106 | } 107 | 108 | $this->title = $title; 109 | } 110 | 111 | /** 112 | * Set name, surname and last fields using. 113 | */ 114 | private function buildFromString(string $fullName) : void 115 | { 116 | $names = array_filter(explode(' ', $fullName)); // explode from spaces 117 | $i = 1; 118 | $total = count($names); 119 | 120 | foreach ($names as $word) { 121 | // skip trailing/double spaces 122 | if ($i === 1) { 123 | $this->name = $word; 124 | } elseif ($i >= 2) { 125 | if ($i === $total) { 126 | $this->surname = $word; 127 | } else { 128 | // merge all middle names 129 | $this->middleName = trim($this->middleName . ' ' . $word); 130 | } 131 | } 132 | 133 | ++$i; 134 | } 135 | } 136 | 137 | /** 138 | * Gets the honorific title prefixing person's name. 139 | */ 140 | public function getTitle() : ?string 141 | { 142 | return $this->title; 143 | } 144 | 145 | /** 146 | * Gets the first name of the person. 147 | */ 148 | public function getName() : ?string 149 | { 150 | return $this->name; 151 | } 152 | 153 | /** 154 | * Gets the middle name of the person. 155 | */ 156 | public function getMiddleName() : ?string 157 | { 158 | return $this->middleName; 159 | } 160 | 161 | /** 162 | * Gets the last name of the person. 163 | */ 164 | public function getSurname() : ?string 165 | { 166 | return $this->surname; 167 | } 168 | 169 | /** 170 | * Returns array representation of the full name. 171 | */ 172 | public function toArray() : array 173 | { 174 | return [ 175 | 'title' => $this->title, 176 | 'name' => $this->name, 177 | 'middleName' => $this->middleName, 178 | 'surname' => $this->surname, 179 | ]; 180 | } 181 | 182 | /** 183 | * Returns array representation of the full name. 184 | */ 185 | public function jsonSerialize() : array 186 | { 187 | return $this->toArray(); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/GeoPoint.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Sep 2016 9 | */ 10 | namespace DDD\Embeddable; 11 | 12 | use Doctrine\ORM\Mapping as ORM; 13 | use InvalidArgumentException; 14 | use JsonSerializable; 15 | 16 | /** 17 | * @ORM\Embeddable 18 | */ 19 | class GeoPoint implements JsonSerializable 20 | { 21 | /** 22 | * geo point value, stored as associative array 23 | * 24 | * @ORM\Column(type="json", nullable=true) 25 | */ 26 | private array $point = []; 27 | 28 | public function __construct(float $latitude = null, float $longitude = null) 29 | { 30 | if ($latitude && $longitude) { 31 | if ($latitude < -90.0 || $latitude > 90.0 || $longitude < -180.0 || $longitude > 180.0) { 32 | throw new InvalidArgumentException('Given latitude longitude pair is invalid.'); 33 | } 34 | 35 | $this->point = [ 36 | 'lat' => $latitude, 37 | 'lng' => $longitude, 38 | ]; 39 | } 40 | } 41 | 42 | /** 43 | * return elasticsearch-friendly geo point format. 44 | * 45 | * Beware: Elastic uses lat/lon as keys. Google uses lat/lng. 46 | */ 47 | public function toElastic() : array 48 | { 49 | if (empty($this->point)) { 50 | return []; 51 | } 52 | 53 | return [ 54 | 'lat' => $this->point['lat'], 55 | 'lon' => $this->point['lng'], 56 | ]; 57 | } 58 | 59 | /** 60 | * Array representation of the geo point 61 | */ 62 | public function toArray() : array 63 | { 64 | return $this->point; 65 | } 66 | 67 | /** 68 | * Implement json serializable interface. 69 | */ 70 | public function jsonSerialize() : array 71 | { 72 | return $this->toArray(); 73 | } 74 | 75 | /** 76 | * String representation of the point, lat lng order, separated by a space. 77 | */ 78 | public function __toString(): string 79 | { 80 | if (empty($this->point)) { 81 | return ''; 82 | } 83 | 84 | return $this->point['lat'].' '.$this->point['lng']; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/IpAddress.php: -------------------------------------------------------------------------------- 1 | 8 | * @license MIT 9 | * 10 | * @since Sep 2016 11 | */ 12 | 13 | namespace DDD\Embeddable; 14 | 15 | use Doctrine\ORM\Mapping as ORM; 16 | use InvalidArgumentException; 17 | 18 | /** 19 | * @ORM\Embeddable 20 | */ 21 | class IpAddress 22 | { 23 | /** 24 | * ipv4 or v6 address 25 | * 26 | * @ORM\Column(type="string", length=45, nullable=true) 27 | */ 28 | private ?string $address = null; 29 | 30 | /** 31 | * Constructor 32 | * 33 | * @see https://secure.php.net/manual/en/filter.filters.flags.php 34 | * 35 | * @throws InvalidArgumentException 36 | */ 37 | public function __construct(string $addr = null) 38 | { 39 | if (! $addr) { 40 | return; 41 | } 42 | 43 | $filtered = filter_var($addr, FILTER_VALIDATE_IP); 44 | if ($filtered === false) { 45 | throw new InvalidArgumentException('Given IP ' . $addr . ' is not a valid IP address'); 46 | } 47 | 48 | $this->address = $filtered; 49 | } 50 | 51 | /** 52 | * String representation of ip address. 53 | */ 54 | public function __toString(): string 55 | { 56 | return $this->address ?: ''; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/IpRange.php: -------------------------------------------------------------------------------- 1 | 9 | * @license MIT 10 | * 11 | * @since Sep 2016 12 | */ 13 | 14 | namespace DDD\Embeddable; 15 | 16 | use Doctrine\ORM\Mapping as ORM; 17 | use JsonSerializable; 18 | 19 | /** 20 | * @ORM\Embeddable 21 | */ 22 | class IpRange implements JsonSerializable 23 | { 24 | /** 25 | * beginning IP address of the range 26 | * 27 | * @ORM\Embedded(class="DDD\Embeddable\IpAddress") 28 | */ 29 | protected ?IpAddress $startIp = null; 30 | 31 | /** 32 | * high IP address of the range 33 | * 34 | * @ORM\Embedded(class="DDD\Embeddable\IpAddress") 35 | */ 36 | protected ?IpAddress $endIp = null; 37 | 38 | public function __construct(IpAddress $startIp = null, IpAddress $endIp = null) 39 | { 40 | $this->startIp = $startIp; 41 | $this->endIp = $endIp; 42 | } 43 | 44 | /** 45 | * Returns the low IP addresses of this range. 46 | */ 47 | public function getStartIp() : ?IpAddress 48 | { 49 | return $this->startIp; 50 | } 51 | 52 | /** 53 | * Returns the high IP addresses of this range. 54 | */ 55 | public function getEndIp() : ?IpAddress 56 | { 57 | return $this->endIp; 58 | } 59 | 60 | /** 61 | * Create a new range from CIDR notation. 62 | * CIDR notation is a compact representation of an IP address(es) and its associated routing prefix. 63 | */ 64 | public static function fromCIDR(string $cidr) : IpRange 65 | { 66 | [$subnet, $bits] = explode('/', $cidr); 67 | $start = long2ip((ip2long($subnet)) & ((-1 << (32 - (int)$bits)))); 68 | $end = long2ip((ip2long($subnet)) + pow(2, (32 - (int)$bits))-1); 69 | 70 | return new IpRange(new IpAddress($start), new IpAddress($end)); 71 | } 72 | 73 | /** 74 | * String representation of a range. 75 | * 76 | * Example output: "192.168.0.10 - 192.168.0.255" 77 | */ 78 | public function __toString() : string 79 | { 80 | return $this->isEmpty() ? '' : $this->startIp . ' - ' . $this->endIp; 81 | } 82 | 83 | /** 84 | * Array representation of the ip range 85 | */ 86 | public function toArray() : array 87 | { 88 | if ($this->isEmpty()) { 89 | return []; 90 | } 91 | 92 | return [ 93 | 'startIp' => (string)$this->getStartIp(), 94 | 'endIp' => (string)$this->getEndIp(), 95 | ]; 96 | } 97 | 98 | /** 99 | * Returns boolean TRUE if the range is empty, false otherwise. 100 | */ 101 | public function isEmpty() : bool 102 | { 103 | return $this->startIp === null || $this->endIp === null; 104 | } 105 | 106 | /** 107 | * Implement json serializable interface. 108 | */ 109 | public function jsonSerialize() : array 110 | { 111 | return $this->toArray(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /tests/ColorTest.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Oct 2016 9 | */ 10 | 11 | namespace Test\Embeddable; 12 | 13 | use DDD\Embeddable\Color; 14 | use InvalidArgumentException; 15 | use JsonSerializable; 16 | use PHPUnit\Framework\TestCase; 17 | 18 | class ColorTest extends TestCase 19 | { 20 | /** 21 | * @dataProvider badHexCodes 22 | */ 23 | public function testInvalidHexNotAccepted(mixed $hex) : void 24 | { 25 | $this->expectException(InvalidArgumentException::class); 26 | new Color($hex); 27 | } 28 | 29 | /** 30 | * @dataProvider goodHexCodes 31 | */ 32 | public function testAlwaysNormalizeHexValues(string $val, string $normalized) : void 33 | { 34 | $color = new Color($val); 35 | $this->assertSame($normalized, (string)$color); 36 | } 37 | 38 | public function testRGBConversionWorks() : void 39 | { 40 | // Given 41 | $underTest = new Color('FFF'); 42 | 43 | // When then 44 | $this->assertSame([255, 255, 255], $underTest->toRGB()); 45 | $this->assertSame('rgb(255,255,255)', $underTest->toRGBString()); 46 | $this->assertInstanceOf(JsonSerializable::class, $underTest); 47 | $this->assertSame($underTest->jsonSerialize(), $underTest->toArray()); 48 | } 49 | 50 | public function testFromRgb() : void 51 | { 52 | $actual = Color::fromRGB(255, 255, 255)->toHex(); 53 | $this->assertSame('#FFFFFF', $actual); 54 | } 55 | 56 | public function testEmptyState() : void 57 | { 58 | // Given 59 | $underTest = new Color(); 60 | 61 | // When then 62 | $this->assertSame([], $underTest->toArray()); 63 | $this->assertSame([], $underTest->toRGB()); 64 | $this->assertSame('', (string)$underTest); 65 | } 66 | 67 | /** 68 | * @dataProvider sampleColorNames 69 | */ 70 | public function testSerializedColorHasAName(string $hex, string $expectedName) : void 71 | { 72 | $arr = (new Color($hex))->toArray(); 73 | $this->assertSame($expectedName, $arr['name']); 74 | } 75 | 76 | public function goodHexCodes() : array 77 | { 78 | return [ 79 | ['#CCA', '#CCCCAA'], 80 | ['#cca', '#CCCCAA'], 81 | ['#ccccaa', '#CCCCAA'], 82 | ['CCA', '#CCCCAA'], 83 | ['c9a', '#CC99AA'], 84 | ['aba', '#AABBAA'], 85 | ['000', '#000000'], 86 | ['9A4', '#99AA44'], 87 | ]; 88 | } 89 | 90 | public function badHexCodes() : array 91 | { 92 | return [ 93 | ['#FFFA'], 94 | ['#CACAC'], 95 | ['TXDFA8'], 96 | ['#TXDFA8'], 97 | [-1], 98 | ['rgb(1,2,3)'], 99 | ['Hello'], 100 | ]; 101 | } 102 | 103 | public function sampleColorNames() : array 104 | { 105 | return [ 106 | ['CCCCCC', 'Pastel Gray'], 107 | ['FF0000', 'Red'], 108 | ['0F0', 'Electric Green'], 109 | ['00F', 'Blue'], 110 | ['FF00FF', 'Fuchsia'], 111 | ['FE00FE', 'Fuchsia'], 112 | ]; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /tests/DateRangeTest.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Sep 2016 9 | */ 10 | 11 | namespace Test\Embeddable; 12 | 13 | use DateTime; 14 | use DDD\Embeddable\DateRange; 15 | use InvalidArgumentException; 16 | use PHPUnit\Framework\TestCase; 17 | 18 | class DateRangeTest extends TestCase 19 | { 20 | public function testDateRanges() : void 21 | { 22 | // Given 23 | $start = new DateTime('31 December 2016'); 24 | $end = new DateTime('1 January 2017'); 25 | $startStr = '2016-12-31T00:00:00+00:00'; 26 | $endStr = '2017-01-01T00:00:00+00:00'; 27 | 28 | // When 29 | $underTest = new DateRange($start, $end); 30 | 31 | // Then 32 | $this->assertSame('2016 - 2017', $underTest->format('Y')); 33 | $this->assertSame('2016-12 - 2017-01', $underTest->format('Y-m')); 34 | $this->assertStringStartsWith('2016-12-31', $underTest->format()); 35 | $this->assertSame(86400, $underTest->getDurationInSeconds()); 36 | $this->assertSame(['start' => $startStr, 'end' => $endStr], $underTest->toArray()); 37 | $this->assertSame(['start' => $startStr, 'end' => $endStr], $underTest->jsonSerialize()); 38 | $this->assertSame($start->format('c') . ' - ' . $end->format('c'), (string)$underTest); 39 | } 40 | 41 | public function testEmptyState() : void 42 | { 43 | $underTest = new DateRange(); 44 | $this->assertInstanceOf(DateRange::class, $underTest); 45 | $this->assertSame([], $underTest->toArray()); 46 | $this->assertSame('', (string)$underTest); 47 | $this->assertSame(0, $underTest->getDurationInSeconds()); 48 | } 49 | 50 | public function testOlderDateRages() : void 51 | { 52 | // Given 53 | $start = new DateTime('23 April 1923'); 54 | $end = new DateTime('24 April 1923'); 55 | 56 | // When 57 | $actual = (new DateRange($start, $end))->getDurationInSeconds(); 58 | 59 | // Then 60 | $this->assertSame(86400, $actual); 61 | } 62 | 63 | public function testEqualDatesNotAccepted() : void 64 | { 65 | $this->expectException(InvalidArgumentException::class); 66 | 67 | // same dates 68 | $start = new DateTime('23 April 1923'); 69 | $end = new DateTime('23 April 1923'); 70 | 71 | new DateRange($start, $end); 72 | } 73 | 74 | public function testEndDateShouldGreaterThanStartDate() : void 75 | { 76 | $this->expectException(InvalidArgumentException::class); 77 | 78 | // end date is before the start date 79 | $start = new DateTime('23 April 1923'); 80 | $end = new DateTime('21 April 1923'); 81 | 82 | new DateRange($start, $end); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tests/EmailAddressTest.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Sep 2016 9 | */ 10 | namespace Test\Embeddable; 11 | 12 | use DDD\Embeddable\EmailAddress; 13 | use InvalidArgumentException; 14 | use PHPUnit\Framework\TestCase; 15 | 16 | class EmailAddressTest extends TestCase 17 | { 18 | /** 19 | * @dataProvider invalidEmailProvider 20 | */ 21 | public function testInvalidAddressesAreNotAccepted(string $email) : void 22 | { 23 | $this->expectException(InvalidArgumentException::class); 24 | new EmailAddress($email); 25 | } 26 | 27 | /** 28 | * @dataProvider validEmailProvider 29 | */ 30 | public function testValidAddressesAreAccepted(string $email, string $expectedDomain, string $expectedLocalPart) : void 31 | { 32 | // Given 33 | $underTest = new EmailAddress($email); 34 | 35 | // When Then 36 | $this->assertSame($email, (string) $underTest); 37 | $this->assertSame($expectedDomain, $underTest->getDomain()); 38 | $this->assertSame($expectedLocalPart, $underTest->getLocalPart()); 39 | } 40 | 41 | public function testEmptyState() : void 42 | { 43 | // Given 44 | $underTest = new EmailAddress(); 45 | 46 | // When Then 47 | $this->assertInstanceOf(EmailAddress::class, $underTest); 48 | $this->assertNull($underTest->getDomain()); 49 | $this->assertNull($underTest->getLocalPart()); 50 | } 51 | 52 | private function invalidEmailProvider() : array 53 | { 54 | return [ 55 | ['fake-email'], 56 | ['fake-mail@'], 57 | ['w@fake mail.com'], 58 | ['v@for.vendetta/com'], 59 | ['!?#- 1*@bad.c0m'], 60 | ['Abc.example.com'], 61 | ['A@b@c@example.com'], 62 | ['a"b(c)d,e:f;gi[j\k]l@example.com'], 63 | ['just"not"right@example.com'], 64 | ['john..doe@example.com'], 65 | ]; 66 | } 67 | 68 | private function validEmailProvider() : array 69 | { 70 | return [ 71 | ['devil@hell.travel', 'hell.travel', 'devil'], 72 | ['jack+london@gmail.com', 'gmail.com', 'jack+london'], 73 | ['cool@mail.com', 'mail.com', 'cool'], 74 | ['great@mail.co.uk', 'mail.co.uk', 'great'], 75 | ['good@email.address.com', 'email.address.com', 'good'], 76 | ['so-good@sub.domain.com.br', 'sub.domain.com.br', 'so-good'], 77 | ['a1@b2.eu', 'b2.eu', 'a1'], 78 | ]; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/FullNameTest.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Sep 2016 9 | */ 10 | 11 | namespace Test\Embeddable; 12 | 13 | use DDD\Embeddable\FullName; 14 | use InvalidArgumentException; 15 | use PHPUnit\Framework\TestCase; 16 | 17 | class FullNameTest extends TestCase 18 | { 19 | /** 20 | * @dataProvider nameProvider 21 | */ 22 | public function testFullNameBuilderFlow(?string $name, ?string $title, ?string $midName, ?string $expected) : void 23 | { 24 | $obj = new FullName($name, $title); 25 | $this->assertSame($expected, (string)$obj); 26 | } 27 | 28 | public function testInvalidTitleIsNotAccepted() : void 29 | { 30 | $this->expectException(InvalidArgumentException::class); 31 | new FullName('John Doe', 'Mz.'); 32 | } 33 | 34 | /** 35 | * @throws \JsonException 36 | */ 37 | public function testGettersWorkingProperly() : void 38 | { 39 | $obj = new FullName('Steven Paul Jobs', 'Mr'); 40 | $this->assertSame('Steven', $obj->getName()); 41 | $this->assertSame('Paul', $obj->getMiddleName()); 42 | $this->assertSame('Jobs', $obj->getSurname()); 43 | $this->assertSame('Mr.', $obj->getTitle()); 44 | 45 | $obj2 = new FullName("Nazim Hikmet Ran"); 46 | $this->assertNull($obj2->getTitle()); 47 | 48 | $expected = '{"title":null,"name":"Nazim","middleName":"Hikmet","surname":"Ran"}'; 49 | $this->assertSame($expected, json_encode($obj2, JSON_THROW_ON_ERROR)); 50 | } 51 | 52 | public function testEmptyState() : void 53 | { 54 | $name = new FullName(); 55 | $this->assertInstanceOf(FullName::class, $name); 56 | $this->assertSame('', (string)$name); 57 | } 58 | 59 | private function nameProvider() : array 60 | { 61 | return [ 62 | 'title without dot' => ['Steve Jobs', 'Mr', null, 'Mr. Steve Jobs'], 63 | 'just one name' => ['Richard', null, null, 'Richard'], 64 | 'with a middle name' => ['Steven Paul Jobs', null, 'Paul', 'Steven Paul Jobs'], 65 | 'middle name with dots' => ['John D. Carmack', null, 'D.', 'John D. Carmack'], 66 | 'multiple spaces' => ['Steven Paul Jobs', null, 'Paul', 'Steven Paul Jobs'], 67 | 'name and surname only' => ['Steve Jobs', null, null, 'Steve Jobs'], 68 | 'title with a dot' => ['Steve Jobs', 'Mr.', null, 'Mr. Steve Jobs'], 69 | 'nickname as middle name' => ['Richard "rms" Stallman', null, '"rms"', 'Richard "rms" Stallman'], 70 | 'real name of Audrey Hepburn which is really long' => [ 71 | 'Edda Kathleen van Heemstra Hepburn', 72 | 'Mrs', 73 | 'Kathleen van Heemstra', 74 | 'Mrs. Edda Kathleen van Heemstra Hepburn' 75 | ], 76 | 'trailing slashes' => [' Steve Wozniak ', null, null, 'Steve Wozniak'], 77 | 'empty strings' => ['', null, null, ''], 78 | ]; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/GeoPointTest.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Sep 2016 9 | */ 10 | 11 | namespace Test\Embeddable; 12 | 13 | use DDD\Embeddable\GeoPoint; 14 | use PHPUnit\Framework\TestCase; 15 | 16 | class GeoPointTest extends TestCase 17 | { 18 | public function testValidGeoPoint() : void 19 | { 20 | $underTest = new GeoPoint(24, 34); 21 | $this->assertSame(['lat' => 24.0, 'lng' => 34.0], $underTest->toArray()); 22 | $this->assertSame(['lat' => 24.0, 'lng' => 34.0], $underTest->jsonSerialize()); 23 | $this->assertSame(['lat' => 24.0, 'lon' => 34.0], $underTest->toElastic()); 24 | } 25 | 26 | public function testInvalidGeoPoint() : void 27 | { 28 | $this->expectException(\InvalidArgumentException::class); 29 | new GeoPoint(-300, 300); 30 | } 31 | 32 | public function testEmptyState() : void 33 | { 34 | $underTest = new GeoPoint(); 35 | $this->assertInstanceOf(GeoPoint::class, $underTest); 36 | $this->assertSame([], $underTest->toArray()); 37 | $this->assertSame([], $underTest->toElastic()); 38 | $this->assertSame('', (string)$underTest); 39 | } 40 | 41 | public function testStringRepresentation() : void 42 | { 43 | $underTest = new GeoPoint(41.520112, 29.453401); 44 | $this->assertSame('41.520112 29.453401', (string)$underTest); 45 | } 46 | 47 | public function testToElastic() : void 48 | { 49 | // Given 50 | $underTest = new GeoPoint(41, 29); 51 | $expected = ['lat' => 41.0, 'lon' => 29.0]; 52 | 53 | // When 54 | $actual = $underTest->toElastic(); 55 | 56 | // Then 57 | $this->assertSame($expected, $actual); 58 | } 59 | 60 | public function testToArray() : void 61 | { 62 | // Given 63 | $underTest = new GeoPoint(42, 30); 64 | $expected = ['lat' => 42.0, 'lng' => 30.0]; 65 | 66 | // When 67 | $actual = $underTest->toArray(); 68 | 69 | // Then 70 | $this->assertSame($expected, $actual); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/IpAddressTest.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Sep 2016 9 | */ 10 | 11 | namespace Test\Embeddable; 12 | 13 | use DDD\Embeddable\IpAddress; 14 | use InvalidArgumentException; 15 | use PHPUnit\Framework\TestCase; 16 | 17 | class IpAddressTest extends TestCase 18 | { 19 | public function testInvalidAddressesAreNotAccepted() : void 20 | { 21 | $this->expectException(InvalidArgumentException::class); 22 | new IpAddress('0.0.0'); 23 | } 24 | 25 | /** 26 | * @dataProvider ipProvider 27 | */ 28 | public function testValidAddressesAreAccepted(string $addr, string $expected) : void 29 | { 30 | $underTest = new IpAddress($addr); 31 | $this->assertSame($expected, (string)$underTest); 32 | } 33 | 34 | public function testEmptyState() : void 35 | { 36 | $underTest = new IpAddress(); 37 | $this->assertSame('', (string)$underTest); 38 | } 39 | 40 | private function ipProvider() : array 41 | { 42 | return [ 43 | ['127.0.0.1', '127.0.0.1'], 44 | ['192.168.1.1', '192.168.1.1'], 45 | ]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/IpRangeTest.php: -------------------------------------------------------------------------------- 1 | 6 | * @license MIT 7 | * 8 | * @since Sep 2016 9 | */ 10 | 11 | namespace Test\Embeddable; 12 | 13 | use DDD\Embeddable\IpRange; 14 | use PHPUnit\Framework\TestCase; 15 | 16 | class IpRangeTest extends TestCase 17 | { 18 | /** 19 | * @dataProvider cidrList 20 | */ 21 | public function testCIDRNotationWorks(string $cidr, string $expectedLow, string $expectedHigh) : void 22 | { 23 | // Given 24 | $underTest = IpRange::fromCIDR($cidr); 25 | $expected = [ 26 | 'startIp' => $expectedLow, 27 | 'endIp' => $expectedHigh, 28 | ]; 29 | 30 | // When 31 | $actual = $underTest->toArray(); 32 | $this->assertSame($expected, $actual); 33 | 34 | // Then 35 | $this->assertSame($expectedLow, (string)$underTest->getStartIp()); 36 | $this->assertSame($expectedHigh, (string)$underTest->getEndIp()); 37 | } 38 | 39 | public function testEmptyState() : void 40 | { 41 | // Given 42 | $underTest = new IpRange(); 43 | 44 | // When 45 | $actual = $underTest->toArray(); 46 | 47 | // Then 48 | $this->assertSame([], $actual); 49 | $this->assertSame('', (string)$underTest); 50 | $this->assertTrue($underTest->isEmpty()); 51 | } 52 | 53 | private function cidrList() : array 54 | { 55 | return [ 56 | ['176.240.112.0/24', '176.240.112.0', '176.240.112.255'], 57 | ['176.240.112.0/32', '176.240.112.0', '176.240.112.0'], 58 | ['10.0.0.0/22', '10.0.0.0', '10.0.3.255'], 59 | ]; 60 | } 61 | } 62 | --------------------------------------------------------------------------------