diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c656199 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.neon] +indent_size = 2 + +[*.xml.dist] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..65c3bcd --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto + +/demo export-ignore +/.editorconfig export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.github export-ignore +/phpstan.neon export-ignore +/phpunit.xml.dist export-ignore +/README.md export-ignore +/**/*Test.php export-ignore diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..c213c06 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,26 @@ +--- +name: build +on: + push: ~ + pull_request: ~ + +jobs: + phpunit: + name: PHPUnit tests on ${{ matrix.php }} ${{ matrix.composer-flags }} + runs-on: ubuntu-latest + strategy: + matrix: + php: ['7.2', '7.3', '7.4', '8.0' ] + composer-flags: [ '' ] + phpunit-flags: [ '--coverage-text' ] + steps: + - uses: actions/checkout@v2 + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: xdebug + tools: composer:v2 + - run: composer update --no-progress ${{ matrix.composer-flags }} + - run: composer phpstan + if: ${{ matrix.php == '7.4' }} + - run: vendor/bin/phpunit ${{ matrix.phpunit-flags }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5fa7987 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build +vendor +.idea +.phpunit.result.cache +composer.lock diff --git a/Multiavatar.php b/Multiavatar.php deleted file mode 100644 index 21c6dd6..0000000 --- a/Multiavatar.php +++ /dev/null @@ -1,655 +0,0 @@ -svgCode = $this->generate(strval($avatarId), $sansEnv, $ver); - } - - - public function getFinal($part, $partV, $theme, $themes, $sP) { - - $colors = $themes[$partV][$theme][$part]; - $svgString = $sP[$partV][$part]; - - if (preg_match_all('/#(.*?)+(?=;)/', $svgString, $result)) { - $i = 0; - foreach ($result[0] as $var) { - $pos = strpos($svgString, $var); - if ($pos !== false) { - $svgString = substr_replace($svgString, $colors[$i], $pos, strlen($var)); - } - $i++; - } - } - - $resultFinal = $svgString; - return $resultFinal; - } - - - public function generate($avatarId, $sansEnv, $ver) { - - $themes = []; - - // Robo - $themes['00']['A']['env'] = [ "#ff2f2b" ]; - $themes['00']['A']['clo'] = ["#fff", "#000"]; - $themes['00']['A']['head'] = ["#fff"]; - $themes['00']['A']['mouth'] = ["#fff", "#000", "#000"]; - $themes['00']['A']['eyes'] = ["#000", "none", "#00FFFF"]; - $themes['00']['A']['top'] = ["#fff", "#fff"]; - - $themes['00']['B']['env'] = ["#ff1ec1"]; - $themes['00']['B']['clo'] = ["#000", "#fff" ]; - $themes['00']['B']['head'] = ["#ffc1c1"]; - $themes['00']['B']['mouth'] = ["#fff", "#000", "#000"]; - $themes['00']['B']['eyes'] = ["#FF2D00", "#fff", "none"]; - $themes['00']['B']['top'] = ["#a21d00", "#fff"]; - - $themes['00']['C']['env'] = ["#0079b1"]; - $themes['00']['C']['clo'] = ["#0e00b1", "#d1fffe"]; - $themes['00']['C']['head'] = ["#f5aa77"]; - $themes['00']['C']['mouth'] = ["#fff", "#000", "#000"]; - $themes['00']['C']['eyes'] = ["#0c00de", "#fff", "none"]; - $themes['00']['C']['top'] = ["#acfffd", "#acfffd"]; - - // Girl - $themes['01']['A']['env'] = ["#a50000"]; - $themes['01']['A']['clo'] = ["#f06", "#8e0039"]; - $themes['01']['A']['head'] = ["#85492C"]; - $themes['01']['A']['mouth'] = ["#000"]; - $themes['01']['A']['eyes'] = ["#000", "#ff9809"]; - $themes['01']['A']['top'] = ["#ff9809", "#ff9809", "none", "none"]; - - $themes['01']['B']['env'] = ["#40E83B"]; - $themes['01']['B']['clo'] = ["#00650b", "#62ce5a"]; - $themes['01']['B']['head'] = ["#f7c1a6"]; - $themes['01']['B']['mouth'] = ["#6e1c1c"]; - $themes['01']['B']['eyes'] = ["#000", "#ff833b"]; - $themes['01']['B']['top'] = ["#67FFCC", "none", "none", "#ecff3b"]; - - $themes['01']['C']['env'] = ["#ff2c2c"]; - $themes['01']['C']['clo'] = ["#fff", "#000"]; - $themes['01']['C']['head'] = ["#ffce8b"]; - $themes['01']['C']['mouth'] = ["#000"]; - $themes['01']['C']['eyes'] = ["#000", "#0072ff"]; - $themes['01']['C']['top'] = ["#ff9809", "none", "#ffc809", "none"]; - - // Blonde - $themes['02']['A']['env'] = ["#ff7520"]; - $themes['02']['A']['clo'] = ["#d12823"]; - $themes['02']['A']['head'] = ["#fee3c5"]; - $themes['02']['A']['mouth'] = ["#d12823"]; - $themes['02']['A']['eyes'] = ["#000", "none"]; - $themes['02']['A']['top'] = ["#000", "none", "none", "#FFCC00", "red"]; - - $themes['02']['B']['env'] = ["#ff9700"]; - $themes['02']['B']['clo'] = ["#000"]; - $themes['02']['B']['head'] = ["#d2ad6d"]; - $themes['02']['B']['mouth'] = ["#000"]; - $themes['02']['B']['eyes'] = ["#000", "#00ffdc"]; - $themes['02']['B']['top'] = ["#fdff00", "#fdff00", "none", "none", "none"]; - - $themes['02']['C']['env'] = ["#26a7ff"]; - $themes['02']['C']['clo'] = ["#d85cd7"]; - $themes['02']['C']['head'] = ["#542e02"]; - $themes['02']['C']['mouth'] = ["#f70014"]; - $themes['02']['C']['eyes'] = ["#000", "magenta"]; - $themes['02']['C']['top'] = ["#FFCC00", "#FFCC00", "#FFCC00", "#ff0000", "yellow"]; - - // Evilnormie - $themes['03']['A']['env'] = ["#6FC30E"]; - $themes['03']['A']['clo'] = ["#b4e1fa", "#5b5d6e", "#515262", "#a0d2f0", "#a0d2f0"]; - $themes['03']['A']['head'] = ["#fae3b9"]; - $themes['03']['A']['mouth'] = ["#fff", "#000"]; - $themes['03']['A']['eyes'] = ["#000"]; - $themes['03']['A']['top'] = ["#8eff45", "#8eff45", "none", "none"]; - - $themes['03']['B']['env'] = ["#00a58c"]; - $themes['03']['B']['clo'] = ["#000", "#5b00", "#5100", "#a000", "#a000"]; - $themes['03']['B']['head'] = ["#FAD2B9"]; - $themes['03']['B']['mouth'] = ["#fff", "#000"]; - $themes['03']['B']['eyes'] = ["#000"]; - $themes['03']['B']['top'] = ["#FFC600", "none", "#FFC600", "none"]; - - $themes['03']['C']['env'] = ["#ff501f"]; - $themes['03']['C']['clo'] = ["#000", "#ff0000", "#ff0000", "#7d7d7d", "#7d7d7d"]; - $themes['03']['C']['head'] = ["#fff3dc"]; - $themes['03']['C']['mouth'] = ["#d2001b", "none"]; - $themes['03']['C']['eyes'] = ["#000"]; - $themes['03']['C']['top'] = ["#D2001B", "none", "none", "#D2001B"]; - - // Country - $themes['04']['A']['env'] = ["#fc0"]; - $themes['04']['A']['clo'] = ["#901e0e", "#ffbe1e", "#ffbe1e", "#c55f54"]; - $themes['04']['A']['head'] = ["#f8d9ad"]; - $themes['04']['A']['mouth'] = ["#000", "none", "#000", "none"]; - $themes['04']['A']['eyes'] = ["#000"]; - $themes['04']['A']['top'] = ["#583D00", "#AF892E", "#462D00", "#a0a0a0"]; - - $themes['04']['B']['env'] = ["#386465"]; - $themes['04']['B']['clo'] = ["#fff", "#333", "#333", "#333"]; - $themes['04']['B']['head'] = ["#FFD79D"]; - $themes['04']['B']['mouth'] = ["#000", "#000", "#000", "#000"]; - $themes['04']['B']['eyes'] = ["#000"]; - $themes['04']['B']['top'] = ["#27363C", "#5DCAD4", "#314652", "#333"]; - - $themes['04']['C']['env'] = ["#DFFF00"]; - $themes['04']['C']['clo'] = ["#304267", "#aab0b1", "#aab0b1", "#aab0b1"]; - $themes['04']['C']['head'] = ["#e6b876"]; - $themes['04']['C']['mouth'] = ["#50230a", "#50230a", "#50230a", "#50230a"]; - $themes['04']['C']['eyes'] = ["#000"]; - $themes['04']['C']['top'] = ["#333", "#afafaf", "#222", "#6d3a1d"]; - - // Johnyold - $themes['05']['A']['env'] = ["#a09300"]; - $themes['05']['A']['clo'] = ["#c7d4e2", "#435363", "#435363", "#141720", "#141720", "#e7ecf2", "#e7ecf2"]; - $themes['05']['A']['head'] = ["#f5d4a6"]; - $themes['05']['A']['mouth'] = ["#000", "#cf9f76"]; - $themes['05']['A']['eyes'] = ["#000", "#000", "#000", "#000", "#000", "#000", "#fff", "#fff", "#fff", "#fff", "#000", "#000"]; - $themes['05']['A']['top'] = ["none", "#fdff00"]; - - $themes['05']['B']['env'] = ["#b3003e"]; - $themes['05']['B']['clo'] = ["#000", "#435363", "#435363", "#000", "none", "#e7ecf2", "#e7ecf2"]; - $themes['05']['B']['head'] = ["#f5d4a6"]; - $themes['05']['B']['mouth'] = ["#000", "#af9f94"]; - $themes['05']['B']['eyes'] = ["#9ff3ffdb", "#000", "#9ff3ffdb", "#000", "#2f508a", "#000", "#000", "#000", "none", "none", "none", "none"]; - $themes['05']['B']['top'] = ["#ff9a00", "#ff9a00"]; - - $themes['05']['C']['env'] = ["#884f00"]; - $themes['05']['C']['clo'] = ["#ff0000", "#fff", "#fff", "#141720", "#141720", "#e7ecf2", "#e7ecf2"]; - $themes['05']['C']['head'] = ["#c57b14"]; - $themes['05']['C']['mouth'] = ["#000", "#cf9f76"]; - $themes['05']['C']['eyes'] = ["none", "#000", "none", "#000", "#5a0000", "#000", "#000", "#000", "none", "none", "none", "none"]; - $themes['05']['C']['top'] = ["#efefef", "none"]; - - // Asian - $themes['06']['A']['env'] = ["#8acf00"]; - $themes['06']['A']['clo'] = ["#ee2829", "#ff0"]; - $themes['06']['A']['head'] = ["#ffce73"]; - $themes['06']['A']['mouth'] = ["#fff", "#000"]; - $themes['06']['A']['eyes'] = ["#000"]; - $themes['06']['A']['top'] = ["#000","#000","none", "#000", "#ff4e4e", "#000"]; - - $themes['06']['B']['env'] = ["#00d2a3"]; - $themes['06']['B']['clo'] = ["#0D0046", "#ffce73"]; - $themes['06']['B']['head'] = ["#ffce73"]; - $themes['06']['B']['mouth'] = ["#000", "none"]; - $themes['06']['B']['eyes'] = ["#000"]; - $themes['06']['B']['top'] = ["#000","#000","#000", "none", "#ffb358", "#000", "none", "none"]; - - $themes['06']['C']['env'] = ["#ff184e"]; - $themes['06']['C']['clo'] = ["#000", "none"]; - $themes['06']['C']['head'] = ["#ffce73"]; - $themes['06']['C']['mouth'] = ["#ff0000", "none"]; - $themes['06']['C']['eyes'] = ["#000"]; - $themes['06']['C']['top'] = ["none","none","none", "none", "none", "#ffc107", "none", "none"]; - - // Punk - $themes['07']['A']['env'] = ["#00deae"]; - $themes['07']['A']['clo'] = ["#ff0000"]; - $themes['07']['A']['head'] = ["#ffce94"]; - $themes['07']['A']['mouth'] = ["#f73b6c", "#000"]; - $themes['07']['A']['eyes'] = ["#e91e63", "#000", "#e91e63", "#000", "#000", "#000"]; - $themes['07']['A']['top'] = ["#dd104f", "#dd104f", "#f73b6c", "#dd104f"]; - - $themes['07']['B']['env'] = ["#181284"]; - $themes['07']['B']['clo'] = ["#491f49", "#ff9809", "#491f49"]; - $themes['07']['B']['head'] = ["#f6ba97"]; - $themes['07']['B']['mouth'] = ["#ff9809", "#000"]; - $themes['07']['B']['eyes'] = ["#c4ffe4", "#000", "#c4ffe4", "#000", "#000", "#000"]; - $themes['07']['B']['top'] = [ "none", "none", "#d6f740", "#516303"]; - - $themes['07']['C']['env'] = ["#bcf700"]; - $themes['07']['C']['clo'] = ["#ff14e4", "#000", "#14fffd"]; - $themes['07']['C']['head'] = ["#7b401e"]; - $themes['07']['C']['mouth'] = ["#666", "#000"]; - $themes['07']['C']['eyes'] = ["#00b5b4", "#000", "#00b5b4", "#000", "#000", "#000"]; - $themes['07']['C']['top'] = ["#14fffd", "#14fffd", "#14fffd", "#0d3a62"]; - - // Afrohair - $themes['08']['A']['env'] = ["#0df"]; - $themes['08']['A']['clo'] = ["#571e57", "#ff0"]; - $themes['08']['A']['head'] = ["#f2c280"]; - $themes['08']['A']['mouth'] = ["#795548", "#000"]; - $themes['08']['A']['eyes'] = ["#ff0000"]; - $themes['08']['A']['top'] = ["#de3b00", "none"]; - - $themes['08']['B']['env'] = ["#B400C2"]; - $themes['08']['B']['clo'] = ["#0D204A", "#00ffdf"]; - $themes['08']['B']['head'] = ["#ca8628"]; - $themes['08']['B']['mouth'] = ["#cbbdaf", "#000"]; - $themes['08']['B']['eyes'] = ["#1a1a1a"]; - $themes['08']['B']['top'] = ["#000", "#000"]; - - $themes['08']['C']['env'] = ["#ffe926"]; - $themes['08']['C']['clo'] = ["#00d6af", "#000"]; - $themes['08']['C']['head'] = ["#8c5100"]; - $themes['08']['C']['mouth'] = ["none", "#000"]; - $themes['08']['C']['eyes'] = ["#7d0000"]; - $themes['08']['C']['top'] = ["#f7f7f7", "none"]; - - // Normie female - $themes['09']['A']['env'] = ["#4aff0c"]; - $themes['09']['A']['clo'] = ["#101010", "#fff", "#fff"]; - $themes['09']['A']['head'] = ["#dbbc7f"]; - $themes['09']['A']['mouth'] = ["#000"]; - $themes['09']['A']['eyes'] = [ "#000", "none", "none"]; - $themes['09']['A']['top'] = ["#531148", "#531148", "#531148", "none"]; - - $themes['09']['B']['env'] = ["#FFC107"]; - $themes['09']['B']['clo'] = ["#033c58", "#fff", "#fff"]; - $themes['09']['B']['head'] = ["#dbc97f"]; - $themes['09']['B']['mouth'] = ["#000"]; - $themes['09']['B']['eyes'] = ["none", "#fff", "#000"]; - $themes['09']['B']['top'] = ["#FFEB3B", "#FFEB3B", "none", "#FFEB3B"]; - - $themes['09']['C']['env'] = ["#FF9800"]; - $themes['09']['C']['clo'] = ["#b40000", "#fff", "#fff"]; - $themes['09']['C']['head'] = ["#E2AF6B"]; - $themes['09']['C']['mouth'] = ["#000"]; - $themes['09']['C']['eyes'] = ["none", "#fff", "#000"]; - $themes['09']['C']['top'] = ["#ec0000", "#ec0000", "none", "none"]; - - // Older - $themes['10']['A']['env'] = ["#104c8c"]; - $themes['10']['A']['clo'] = ["#354B65", "#3D8EBB", "#89D0DA", "#00FFFD" ]; - $themes['10']['A']['head'] = ["#cc9a5c"]; - $themes['10']['A']['mouth'] = ["#222", "#fff"]; - $themes['10']['A']['eyes'] = ["#000", "#000"]; - $themes['10']['A']['top'] = ["#fff", "#fff", "none"]; - - $themes['10']['B']['env'] = ["#0DC15C"]; - $themes['10']['B']['clo'] = ["#212121", "#fff", "#212121", "#fff", ]; - $themes['10']['B']['head'] = ["#dca45f"]; - $themes['10']['B']['mouth'] = ["#111", "#633b1d"]; - $themes['10']['B']['eyes'] = ["#000", "#000"]; - $themes['10']['B']['top'] = ["none", "#792B74", "#792B74"]; - - $themes['10']['C']['env'] = ["#ffe500"]; - $themes['10']['C']['clo'] = ["#1e5e80", "#fff", "#1e5e80", "#fff"]; - $themes['10']['C']['head'] = ["#e8bc86"]; - $themes['10']['C']['mouth'] = ["#111", "none"]; - $themes['10']['C']['eyes'] = ["#000", "#000"]; - $themes['10']['C']['top'] = ["none", "none", "#633b1d"]; - - // Firehair - $themes['11']['A']['env'] = ["#4a3f73"]; - $themes['11']['A']['clo'] = ["#e6e9ee", "#f1543f", "#ff7058", "#fff", "#fff"]; - $themes['11']['A']['head'] = ["#b27e5b"]; - $themes['11']['A']['mouth'] = ["#191919", "#191919"]; - $themes['11']['A']['eyes'] = ["#000", "#000", "#57FFFD"]; - $themes['11']['A']['top'] = ["#ffc", "#ffc", "#ffc"]; - - $themes['11']['B']['env'] = ["#00a08d"]; - $themes['11']['B']['clo'] = ["#FFBA32", "#484848", "#4e4e4e", "#fff", "#fff"]; - $themes['11']['B']['head'] = ["#ab5f2c"]; - $themes['11']['B']['mouth'] = ["#191919", "#191919"]; - $themes['11']['B']['eyes'] = ["#000", "#ff23fa63", "#000"]; - $themes['11']['B']['top'] = ["#ff90f4", "#ff90f4", "#ff90f4"]; - - $themes['11']['C']['env'] = ["#22535d"]; - $themes['11']['C']['clo'] = ["#000", "#ff2500", "#ff2500", "#fff", "#fff"]; - $themes['11']['C']['head'] = ["#a76c44"]; - $themes['11']['C']['mouth'] = ["#191919", "#191919"]; - $themes['11']['C']['eyes'] = ["#000", "none", "#000"]; - $themes['11']['C']['top'] = ["none", "#00efff", "none"]; - - // Blond - $themes['12']['A']['env'] = ["#2668DC"]; - $themes['12']['A']['clo'] = ["#2385c6", "#b8d0e0", "#b8d0e0"]; - $themes['12']['A']['head'] = ["#ad8a60"]; - $themes['12']['A']['mouth'] = ["#000", "#4d4d4d"]; - $themes['12']['A']['eyes'] = ["#7fb5a2", "#d1eddf", "#301e19"]; - $themes['12']['A']['top'] = ["#fff510", "#fff510"]; - - $themes['12']['B']['env'] = ["#643869"]; - $themes['12']['B']['clo'] = ["#D67D1B", "#b8d0e0", "#b8d0e0"]; - $themes['12']['B']['head'] = ["#CC985A", "none0000"]; - $themes['12']['B']['mouth'] = ["#000", "#ececec"]; - $themes['12']['B']['eyes'] = ["#1f2644", "#9b97ce", "#301e19"]; - $themes['12']['B']['top'] = ["#00eaff", "none"]; - - $themes['12']['C']['env'] = ["#F599FF"]; - $themes['12']['C']['clo'] = ["#2823C6", "#b8d0e0", "#b8d0e0"]; - $themes['12']['C']['head'] = ["#C7873A"]; - $themes['12']['C']['mouth'] = ["#000", "#4d4d4d"]; - $themes['12']['C']['eyes'] = ["#581b1b", "#FF8B8B", "#000"]; - $themes['12']['C']['top'] = ["none", "#9c0092"]; - - // Ateam - $themes['13']['A']['env'] = ["#d10084"]; - $themes['13']['A']['clo'] = ["#efedee", "#00a1e0", "#00a1e0", "#efedee", "#ffce1c"]; - $themes['13']['A']['head'] = ["#b35f49"]; - $themes['13']['A']['mouth'] = ["#3a484a", "#000"]; - $themes['13']['A']['eyes'] = ["#000"]; - $themes['13']['A']['top'] = ["#000", "none", "#000", "none"]; - - $themes['13']['B']['env'] = ["#E6C117"]; - $themes['13']['B']['clo'] = ["#efedee", "#ec0033", "#ec0033", "#efedee", "#f2ff05"]; - $themes['13']['B']['head'] = ["#ffc016"]; - $themes['13']['B']['mouth'] = ["#4a3737", "#000"]; - $themes['13']['B']['eyes'] = ["#000"]; - $themes['13']['B']['top'] = ["#ffe900", "#ffe900", "none", "#ffe900"]; - - $themes['13']['C']['env'] = ["#1d8c00"]; - $themes['13']['C']['clo'] = ["#e000cb", "#fff", "#fff", "#e000cb", "#ffce1c"]; - $themes['13']['C']['head'] = ["#b96438"]; - $themes['13']['C']['mouth'] = ["#000", "#000"]; - $themes['13']['C']['eyes'] = ["#000"]; - $themes['13']['C']['top'] = ["#53ffff", "#53ffff", "none", "none"]; - - // Rasta - $themes['14']['A']['env'] = ["#fc0065"]; - $themes['14']['A']['clo'] = ["#708913", "#fdea14", "#708913", "#fdea14", "#708913"]; - $themes['14']['A']['head'] = ["#DEA561"]; - $themes['14']['A']['mouth'] = ["#444", "#000"]; - $themes['14']['A']['eyes'] = ["#000"]; - $themes['14']['A']['top'] = ["#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f" ]; - - $themes['14']['B']['env'] = ["#81f72e"]; - $themes['14']['B']['clo'] = ["#ff0000", "#ffc107", "#ff0000", "#ffc107", "#ff0000"]; - $themes['14']['B']['head'] = ["#ef9831"]; - $themes['14']['B']['mouth'] = ["#6b0000", "#000"]; - $themes['14']['B']['eyes'] = ["#000"]; - $themes['14']['B']['top'] = ["#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "none", "none", "none", "none"]; - - $themes['14']['C']['env'] = ["#00D872"]; - $themes['14']['C']['clo'] = ["#590D00", "#FD1336", "#590D00", "#FD1336", "#590D00"]; - $themes['14']['C']['head'] = ["#c36c00"]; - $themes['14']['C']['mouth'] = ["#56442b", "#000"]; - $themes['14']['C']['eyes'] = ["#000"]; - $themes['14']['C']['top'] = ["#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "none", "none", "none", "none", "none", "none", "none", "none"]; - - // Meta - $themes['15']['A']['env'] = ["#111"]; - $themes['15']['A']['clo'] = ["#000", "#00FFFF"]; - $themes['15']['A']['head'] = ["#755227"]; - $themes['15']['A']['mouth'] = ["#fff", "#000"]; - $themes['15']['A']['eyes'] = ["black", "#008a", "aqua"]; - $themes['15']['A']['top'] = ["#fff", "#fff", "#fff", "#fff", "#fff"]; - - $themes['15']['B']['env'] = ["#00D0D4"]; - $themes['15']['B']['clo'] = ["#000", "#fff"]; - $themes['15']['B']['head'] = ["#755227"]; - $themes['15']['B']['mouth'] = ["#fff", "#000"]; - $themes['15']['B']['eyes'] = ["black", "#1df7ffa3", "#fcff2c"]; - $themes['15']['B']['top'] = ["#fff539", "none", "#fff539", "none", "#fff539"]; - - $themes['15']['C']['env'] = ["#DC75FF"]; - $themes['15']['C']['clo'] = ["#000", "#FFBDEC"]; - $themes['15']['C']['head'] = ["#997549"]; - $themes['15']['C']['mouth'] = ["#fff", "#000"]; - $themes['15']['C']['eyes'] = ["black", "black", "aqua"]; - $themes['15']['C']['top'] = ["#00fffd", "none", "none", "none", "none"]; - - - // Optimization - $sP = []; - $svgStart = ''; - $svgEnd = ''; - $env = ''; - $head = ''; - $str = 'stroke-linecap:round;stroke-linejoin:round;stroke-width:'; - - - // SHAPES - - // Robo - $sP['00']['env'] = $env; - $sP['00']['clo'] = ''; - $sP['00']['head'] = $head; - $sP['00']['mouth'] = ''; - $sP['00']['eyes'] = ''; - $sP['00']['top'] = ''; - - // Girl - $sP['01'] = []; - $sP['01']['env'] = $env; - $sP['01']['clo'] = ''; - $sP['01']['head'] = $head; - $sP['01']['mouth'] = ''; - $sP['01']['eyes'] = ''; - $sP['01']['top'] = ''; - - // Blonde - $sP['02'] = []; - $sP['02']['env'] = $env; - $sP['02']['clo'] = ''; - $sP['02']['head'] = $head; - $sP['02']['mouth'] = ''; - $sP['02']['eyes'] = ''; - $sP['02']['top'] = ''; - - // Guy - $sP['03'] = []; - $sP['03']['env'] = $env; - $sP['03']['clo'] = ''; - $sP['03']['head'] = $head; - $sP['03']['mouth'] = ''; - $sP['03']['eyes'] = ''; - $sP['03']['top'] = ''; - - // Country - $sP['04'] = []; - $sP['04']['env'] = $env; - $sP['04']['clo'] = ''; - $sP['04']['head'] = $head; - $sP['04']['mouth'] = ''; - $sP['04']['eyes'] = ''; - $sP['04']['top'] = ''; - - // Geeknot - $sP['05'] = []; - $sP['05']['env'] = $env; - $sP['05']['clo'] = ''; - $sP['05']['head'] = $head; - $sP['05']['mouth'] = ''; - $sP['05']['eyes'] = ''; - $sP['05']['top'] = ''; - - // Asian - $sP['06'] = []; - $sP['06']['env'] = $env; - $sP['06']['clo'] = ''; - $sP['06']['head'] = $head; - $sP['06']['mouth'] = ''; - $sP['06']['eyes'] = ''; - $sP['06']['top'] = ''; - - // Punk - $sP['07'] = []; - $sP['07']['env'] = $env; - $sP['07']['clo'] = ''; - $sP['07']['head'] = $head; - $sP['07']['mouth'] = ''; - $sP['07']['eyes'] = ''; - $sP['07']['top'] = ''; - - // Afrohair - $sP['08'] = []; - $sP['08']['env'] = $env; - $sP['08']['clo'] = ''; - $sP['08']['head'] = $head; - $sP['08']['mouth'] = ''; - $sP['08']['eyes'] = ''; - $sP['08']['top'] = ''; - - // Normie Female - $sP['09'] = []; - $sP['09']['env'] = $env; - $sP['09']['clo'] = ''; - $sP['09']['head'] = $head; - $sP['09']['mouth'] = ''; - $sP['09']['eyes'] = ''; - $sP['09']['top'] = ''; - - // Older - $sP['10'] = []; - $sP['10']['env'] = $env; - $sP['10']['clo'] = ''; - $sP['10']['head'] = $head; - $sP['10']['mouth'] = ''; - $sP['10']['eyes'] = ''; - $sP['10']['top'] = ''; - - // Firehair - $sP['11'] = []; - $sP['11']['env'] = $env; - $sP['11']['clo'] = ''; - $sP['11']['head'] = $head; - $sP['11']['mouth'] = ''; - $sP['11']['eyes'] = ''; - $sP['11']['top'] = ''; - - // Blond - $sP['12'] = []; - $sP['12']['env'] = $env; - $sP['12']['clo'] = ''; - $sP['12']['head'] = $head; - $sP['12']['mouth'] = ''; - $sP['12']['eyes'] = ''; - $sP['12']['top'] = ''; - - // Ateam - $sP['13'] = []; - $sP['13']['env'] = $env; - $sP['13']['clo'] = ''; - $sP['13']['head'] = $head; - $sP['13']['mouth'] = ''; - $sP['13']['eyes'] = ''; - $sP['13']['top'] = ''; - - // Rasta - $sP['14'] = []; - $sP['14']['env'] = $env; - $sP['14']['clo'] = ''; - $sP['14']['head'] = $head; - $sP['14']['mouth'] = ''; - $sP['14']['eyes'] = ''; - $sP['14']['top'] = ''; - - // Meta - $sP['15'] = []; - $sP['15']['env'] = $env; - $sP['15']['clo'] = ''; - $sP['15']['head'] = $head; - $sP['15']['mouth'] = ''; - $sP['15']['eyes'] = ''; - $sP['15']['top'] = ''; - - - // Multiavatar algorithm - $hash = ''; - - if (strlen($avatarId) == 0) return $hash; - - $sha256Hash = hash('sha256', $avatarId); - $sha256Numbers = preg_replace("/[^0-9]/", "", $sha256Hash); - $hash = substr($sha256Numbers, 0, 12); - - - // Parts - $p = []; - - // Get parts (range 0-47) - $p['env'] = $hash[0] . '' . $hash[1]; - $p['env'] = round((47/100)*$p['env']); - - // Freeze a single part - // e.g. '0' = 01A; '16' = 01B; '32' = 01C; '1' = 02A; '17' = 02B; - // p['env'] = '16'; - - $p['clo'] = $hash[2] . '' . $hash[3]; - $p['clo'] = round((47/100)*$p['clo']); - - // p['clo'] = '16'; - - $p['head'] = $hash[4] . '' . $hash[5]; - $p['head'] = round((47/100)*$p['head']); - - // p['head'] = '01'; - - $p['mouth'] = $hash[6] . '' . $hash[7]; - $p['mouth'] = round((47/100)*$p['mouth']); - - // p['mouth'] = '16'; - - $p['eyes'] = $hash[8] . '' . $hash[9]; - $p['eyes'] = round((47/100)*$p['eyes']); - - // p['eyes'] = '16'; - - $p['top'] = $hash[10] . '' . $hash[11]; - $p['top'] = round((47/100)*$p['top']); - - // p['top'] = '25'; - - - // Get parts (range 0-15) + define themes - foreach ($p as $key => $part) { - $nr = $part; - - if ($nr > 31) { - $nr = $nr - 32 . ''; - if ($nr < 10) $nr = '0' . $nr; - $p[$key] = $nr . 'C'; - } - else if ($nr > 15) { - $nr = $nr - 16; - if ($nr < 10) $nr = '0' . $nr; - $p[$key] = $nr . 'B'; - } - else { - if ($nr < 10) $p[$key] = '0' . $nr . 'A'; - else $p[$key] = $nr . 'A'; - } - } - - - // Get the SVG code for each part - $final = []; - - foreach ($p as $key => $part) { - $partV = substr($p[$key], 0, 2); - $theme = substr($p[$key], 2, 3); - - if ($ver != null) { - $partV = $ver['part']; - $theme = $ver['theme']; - } - - // Freeze a single base version - // $partV = '00'; $theme = 'A'; - - $final[$key] = $this->getFinal($key, $partV, $theme, $themes, $sP); - } - - - // Without 'env' - if ($sansEnv) { - $final['env'] = ''; - } - - return($svgStart . $final['env'] . $final['head'] . $final['clo'] . $final['top'] . $final['eyes'] . $final['mouth'] . $svgEnd); - } -} diff --git a/README.md b/README.md index d10aadc..8d22f4e 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,12 @@ Initially coded in JavaScript, this version of Multiavatar is re-created in PHP. For more details about the Multiavatar Generator, please refer to the readme available in the JS [repository](https://github.com/multiavatar/Multiavatar). - ### Installation ### -If you don't use composer, just include `Multiavatar.php` in your application. +If you don't use composer, just include the autoloader in the root of the directory in your application. ``` -require_once('Multiavatar.php'); +require_once '/path/to/directory/Multiavatar/autoload.php'; ``` Via Composer: @@ -25,27 +24,100 @@ Via Composer: composer require multiavatar/multiavatar-php ``` - ### Usage ### -``` +```php +svgCode); +echo $multiavatar($avatarId); ``` -For advanced usage, pass boolean `true` as the second parameter if you wish to generate an avatar without the environment part. +For advanced usage, you can pass an array as a second and last parameter as shown below: + +```php + [ + 'part' => '11', + 'theme' => 'C', + ], + 'sansEnv' => true, +]; + +echo $multiavatar($avatarId, $options); ``` -$avatarId = "ANY_STRING"; -$multiavatar = new Multiavatar($avatarId, true, array("part" => 11, "theme" => "C")); -echo($multiavatar->svgCode); +The option array contains the following indexes: + +- `sansEnv`: Tells whether the environment should be display or not. By default, the environment is display. + To remove the environment you should set the value to `true. + +- `version`: Indicate which theme and shape should be used to generate the avatar. + There is 3 themes that you specify with the `theme` index named from `A` to `C` + and 16 shapes specified with the `part` index whose named ranged from `00` to `15`. + +Each of those values can be set independently of each other. + +```php + true]); + +// Generate a specific version +// version shape can be express in integer or in string containing only numbers. +$avatarId = "Pandalion"; +echo $multiavatar($avatarId, ['sansEnv' => false, 'ver' => ['part' => 11, 'theme' => 'C']]); + +// The avatarId can be a string or an integer +// version theme are case insensitive. +// The shape will be selected from the $avatarId +$avatarId = 123456789; +echo $multiavatar($avatarId, ['sansEnv' => false, 'ver' => ['theme' => 'b']]); + +// Test with a specific shape +// The theme will be selected from the avatarId +$avatarId = "a86f755add37fe0b649c"; +echo $multiavatar($avatarId, ['ver' => ['part' => '08']]); + +$avatarId = "f7542474d54d2d2d97e4"; +echo $multiavatar($avatarId); ``` -See `index.php` for examples. +### Testing ### + +The library has a : + +- a [PHPUnit](https://phpunit.de) test suite +- a code analysis compliance test suite using [PHPStan](https://phpstan.org). +To run the tests, run the following command from the project folder. + +``` bash +$ composer test +``` ### API ### @@ -65,7 +137,6 @@ fetch('https://api.multiavatar.com/v1/' .then(svg => console.log(svg)) ``` - ### License ### You can use Multiavatar for free, as long as the conditions described in the [LICENSE](https://multiavatar.com/license) are followed. @@ -88,4 +159,4 @@ For additional information and extended functionality, visit the [multiavatar.co The app is based on static html for the home page, and on Laravel 8 + Vue.js for extended functionality, including the web store. -The product mockup generator for the [Merch Maker](https://multiavatar.com/merch-maker) is based on the ImageMagick PHP library. \ No newline at end of file +The product mockup generator for the [Merch Maker](https://multiavatar.com/merch-maker) is based on the ImageMagick PHP library. diff --git a/autoload.php b/autoload.php new file mode 100644 index 0000000..9b27649 --- /dev/null +++ b/autoload.php @@ -0,0 +1,16 @@ +=7.1", + "phpunit/phpunit": "^8.0 || ^9.5", + "phpstan/phpstan": "^0.12.63", + "phpstan/phpstan-strict-rules": "^0.12.7", + "phpstan/phpstan-phpunit": "^0.12.17" + }, + "scripts": { + "phpstan": "phpstan analyse src -c phpstan.neon --ansi", + "phpunit": "phpunit --coverage-text", + "test": [ + "@phpunit", + "@phpstan" + ] + }, + "scripts-descriptions": { + "phpstan": "Static analysis of PHP scripts", + "phpunit": "Runs unit and functional testing" } } diff --git a/demo/index.php b/demo/index.php new file mode 100644 index 0000000..4d01963 --- /dev/null +++ b/demo/index.php @@ -0,0 +1,61 @@ + ['part' => $part, 'theme' => $theme]]); + } +} +?> + + + + + + + Multiavatar - All 48 Initial Avatar Designs + + + +
+ $svg): ?> +
+ +
+
+ + diff --git a/index.php b/index.php deleted file mode 100644 index 9cc950b..0000000 --- a/index.php +++ /dev/null @@ -1,36 +0,0 @@ -svgCode); - - -// Without the environment part -$avatarId = "Pandalion"; -$multiavatar = new Multiavatar($avatarId, true, null); -echo($multiavatar->svgCode); - - -// Generate a specific version -$avatarId = "Pandalion"; -$multiavatar = new Multiavatar($avatarId, null, array("part" => 11, "theme" => "C")); -echo($multiavatar->svgCode); - - -// Test with integer -$avatarId = 123456789; -$multiavatar = new Multiavatar($avatarId, null, null); -echo($multiavatar->svgCode); - - -// $avatarId = "a86f755add37fe0b649c"; -// $multiavatar = new Multiavatar($avatarId, null, null); -// echo($multiavatar->svgCode); - - -// $avatarId = "f7542474d54d2d2d97e4"; -// $multiavatar = new Multiavatar($avatarId, null, null); -// echo($multiavatar->svgCode); \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..6f33fba --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,8 @@ +includes: + - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/phpstan/phpstan-phpunit/rules.neon +parameters: + level: max + checkMissingIterableValueType: false + ignoreErrors: + reportUnmatchedIgnoredErrors: true diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..eda5739 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,36 @@ + + + + + src + + + src + + + + + + + + + + src + + + + + + diff --git a/src/Multiavatar.php b/src/Multiavatar.php new file mode 100644 index 0000000..8937067 --- /dev/null +++ b/src/Multiavatar.php @@ -0,0 +1,773 @@ +'; + private const SVG_ROOT_CLOSE_TAG = ''; + private const SVG_ELEMENT_ENV = ''; + private const SVG_ELEMENT_HEAD = ''; + private const SVG_ELEMENT_BASE_STYLE_PROPERTIES = 'stroke-linecap:round;stroke-linejoin:round;stroke-width:'; + private const THEME_LIST = [0 => 'A', 1 => 'B', 2 => 'C']; + private const BODY_PARTS = ['env', 'head', 'clo', 'top', 'eyes', 'mouth']; + + public const DEFAULT_OPTIONS = [ + 'ver' => [ + 'part' => null, // string|int - the version part between '00' and '15' + 'theme' => null, // string - the version theme to choose between 'A' and 'C' + ], + 'sansEnv' => false, // boolean - Tells whether to display or not the environment (by default the environment is shown) + ]; + + /** + * @var array>>> + */ + private static $themes = []; + + /** + * @var array> + */ + private static $shapes = []; + + /** + * @param mixed $avatarId the avatar id if it is an object it must implement the __toString method + * @param array $options + */ + public function __invoke($avatarId, array $options = self::DEFAULT_OPTIONS): string + { + $avatarId = $this->filterAvatar($avatarId); + $options = $this->filterOptions($options); + if ('' === $avatarId) { + return ''; + } + + $parts = $this->setParts($avatarId, $options); + $elements = $this->partsToElements($parts); + $elements = $this->filterElements($elements, $options); + + return self::SVG_ROOT_OPEN_TAG + . $elements['env'] + . $elements['head'] + . $elements['clo'] + . $elements['top'] + . $elements['eyes'] + . $elements['mouth'] + . self::SVG_ROOT_CLOSE_TAG; + } + + /** + * @param mixed $avatarId the avatar Id + */ + private function filterAvatar($avatarId): string + { + if (is_object($avatarId) && method_exists($avatarId, '__toString')) { + $avatarId = (string) $avatarId; + } + + if (!is_scalar($avatarId)) { + throw new TypeError('Expected a scalar or a Stringable object; got: ' . (is_object($avatarId) ? get_class($avatarId) : gettype($avatarId))); + } + + return trim((string) $avatarId); + } + + /** + * @return array{ver:array{part:string|null, theme:string|null}, sansEnv:bool} + */ + private function filterOptions(array $inputOptions): array + { + $options = self::DEFAULT_OPTIONS; + $options['sansEnv'] = filter_var($inputOptions['sansEnv'] ?? false, FILTER_VALIDATE_BOOLEAN); + + if (isset($inputOptions['ver']['part'])) { + if (!is_string($inputOptions['ver']['part']) && !is_numeric($inputOptions['ver']['part'])) { + throw new InvalidArgumentException('The version part is expected to be a scalar; '.gettype($inputOptions['ver']['part']).' was given.'); + } + + $part = sprintf("%'.02d", $inputOptions['ver']['part']); + if (1 !== preg_match('/^(0[0-9])|(1[0-5])$/', $part)) { + throw new InvalidArgumentException('The version part does not exists; expecting a value between `00` and `15`.'); + } + + $options['ver']['part'] = $part; + } + + if (!isset($inputOptions['ver']['theme'])) { + return $options; + } + + if (!is_string($inputOptions['ver']['theme'])) { + throw new InvalidArgumentException('The version theme is expected to be a string; '.gettype($inputOptions['ver']['theme']).' was given.'); + } + + if (1 !== preg_match('/^[a-c]$/i', $inputOptions['ver']['theme'])) { + throw new InvalidArgumentException('The version theme does not exists; expecting a value between `A`, `B` and `C`.'); + } + + $options['ver']['theme'] = strtoupper($inputOptions['ver']['theme']); + + return $options; + } + + /** + * @param array{ver:array{part:string|null, theme:string|null}, sansEnv:bool} $options + * + * @return array{env:array{part:string, theme:string}, clo:array{part:string, theme:string}, head:array{part:string, theme:string}, mouth:array{part:string, theme:string}, eyes:array{part:string, theme:string}, top:array{part:string, theme:string}} + */ + private function setParts(string $avatarId, array $options): array + { + if (isset($options['ver']['theme'], $options['ver']['part'])) { + return array_fill_keys(self::BODY_PARTS, $options['ver']); + } + + /** @var string $str */ + $str = preg_replace('/\D/', '', hash('sha256', $avatarId)); + $hash = substr($str, 0, 12); + + /** @var array{env:array{part:string, theme:string}, clo:array{part:string, theme:string}, head:array{part:string, theme:string}, mouth:array{part:string, theme:string}, eyes:array{part:string, theme:string}, top:array{part:string, theme:string}} $parts */ + $parts = array_combine(self::BODY_PARTS, array_map([$this, 'stringToVersion'], str_split($hash, 2))); + + if (isset($options['ver']['theme'])) { + $theme = $options['ver']['theme']; + + /** @var array{env:array{part:string, theme:string}, clo:array{part:string, theme:string}, head:array{part:string, theme:string}, mouth:array{part:string, theme:string}, eyes:array{part:string, theme:string}, top:array{part:string, theme:string}} $parts */ + $parts = array_map(function (array $settings) use ($theme): array { + $settings['theme'] = $theme; + + return $settings; + }, $parts); + + return $parts; + } + + if (isset($options['ver']['part'])) { + $part = $options['ver']['part']; + + /** @var array{env:array{part:string, theme:string}, clo:array{part:string, theme:string}, head:array{part:string, theme:string}, mouth:array{part:string, theme:string}, eyes:array{part:string, theme:string}, top:array{part:string, theme:string}} $parts */ + $parts = array_map(function (array $settings) use ($part): array { + $settings['part'] = $part; + + return $settings; + }, $parts); + } + + return $parts; + } + + /** + * @return array{part:string, theme:string} + */ + private function stringToVersion(string $part): array + { + $part = (int) round(47 / 100 * (int) $part); + + return [ + 'part' => sprintf("%'.02d", $part % 16), + 'theme' => self::THEME_LIST[intdiv($part, 16)], + ]; + } + + /** + * @param array{env:array{part:string, theme:string}, clo:array{part:string, theme:string}, head:array{part:string, theme:string}, mouth:array{part:string, theme:string}, eyes:array{part:string, theme:string}, top:array{part:string, theme:string}} $parts + * + * @return array{env:string, clo:string, head:string, mouth:string, eyes:string, top:string} + */ + private function partsToElements(array $parts): array + { + $reducer = function(array $elements, string $name) use ($parts): array { + $elements[$name] = $this->createElement($name, $parts[$name]['part'], $parts[$name]['theme']); + + return $elements; + }; + + /** @var array{env:string, clo:string, head:string, mouth:string, eyes:string, top:string} $elements */ + $elements = array_reduce(self::BODY_PARTS, $reducer, []); + + return $elements; + } + + private function createElement(string $name, string $part, string $theme): string + { + $colors = self::themes()[$part][$theme][$name]; + $index = 0; + $replace = function (array $result) use ($colors, &$index): string { + return $colors[$index++]; + }; + + /** @var string $element */ + $element = preg_replace_callback('/#(.*?)+(?=;)/', $replace, self::shapes()[$part][$name]); + + return $element; + } + + /** + * @param array{env:string, clo:string, head:string, mouth:string, eyes:string, top:string} $elements + * @param array{ver:array{part:string|null, theme:string|null}, sansEnv:bool} $options + * + * @return array{env:string, clo:string, head:string, mouth:string, eyes:string, top:string} + */ + private function filterElements(array $elements, array $options): array + { + if ($options['sansEnv']) { + $elements['env'] = ''; + } + + return $elements; + } + + /** + * @return array> + */ + private static function shapes(): array + { + if ([] !== self::$shapes) { + return self::$shapes; + } + + // Robo + self::$shapes['00']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['00']['clo'] = ''; + self::$shapes['00']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['00']['mouth'] = ''; + self::$shapes['00']['eyes'] = ''; + self::$shapes['00']['top'] = ''; + + // Girl + self::$shapes['01'] = []; + self::$shapes['01']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['01']['clo'] = ''; + self::$shapes['01']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['01']['mouth'] = ''; + self::$shapes['01']['eyes'] = ''; + self::$shapes['01']['top'] = ''; + + // Blonde + self::$shapes['02'] = []; + self::$shapes['02']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['02']['clo'] = ''; + self::$shapes['02']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['02']['mouth'] = ''; + self::$shapes['02']['eyes'] = ''; + self::$shapes['02']['top'] = ''; + + // Guy + self::$shapes['03'] = []; + self::$shapes['03']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['03']['clo'] = ''; + self::$shapes['03']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['03']['mouth'] = ''; + self::$shapes['03']['eyes'] = ''; + self::$shapes['03']['top'] = ''; + + // Country + self::$shapes['04'] = []; + self::$shapes['04']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['04']['clo'] = ''; + self::$shapes['04']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['04']['mouth'] = ''; + self::$shapes['04']['eyes'] = ''; + self::$shapes['04']['top'] = ''; + + // Geeknot + self::$shapes['05'] = []; + self::$shapes['05']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['05']['clo'] = ''; + self::$shapes['05']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['05']['mouth'] = ''; + self::$shapes['05']['eyes'] = ''; + self::$shapes['05']['top'] = ''; + + // Asian + self::$shapes['06'] = []; + self::$shapes['06']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['06']['clo'] = ''; + self::$shapes['06']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['06']['mouth'] = ''; + self::$shapes['06']['eyes'] = ''; + self::$shapes['06']['top'] = ''; + + // Punk + self::$shapes['07'] = []; + self::$shapes['07']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['07']['clo'] = ''; + self::$shapes['07']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['07']['mouth'] = ''; + self::$shapes['07']['eyes'] = ''; + self::$shapes['07']['top'] = ''; + + // Afrohair + self::$shapes['08'] = []; + self::$shapes['08']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['08']['clo'] = ''; + self::$shapes['08']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['08']['mouth'] = ''; + self::$shapes['08']['eyes'] = ''; + self::$shapes['08']['top'] = ''; + + // Normie Female + self::$shapes['09'] = []; + self::$shapes['09']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['09']['clo'] = ''; + self::$shapes['09']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['09']['mouth'] = ''; + self::$shapes['09']['eyes'] = ''; + self::$shapes['09']['top'] = ''; + + // Older + self::$shapes['10'] = []; + self::$shapes['10']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['10']['clo'] = ''; + self::$shapes['10']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['10']['mouth'] = ''; + self::$shapes['10']['eyes'] = ''; + self::$shapes['10']['top'] = ''; + + // Firehair + self::$shapes['11'] = []; + self::$shapes['11']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['11']['clo'] = ''; + self::$shapes['11']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['11']['mouth'] = ''; + self::$shapes['11']['eyes'] = ''; + self::$shapes['11']['top'] = ''; + + // Blond + self::$shapes['12'] = []; + self::$shapes['12']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['12']['clo'] = ''; + self::$shapes['12']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['12']['mouth'] = ''; + self::$shapes['12']['eyes'] = ''; + self::$shapes['12']['top'] = ''; + + // Ateam + self::$shapes['13'] = []; + self::$shapes['13']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['13']['clo'] = ''; + self::$shapes['13']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['13']['mouth'] = ''; + self::$shapes['13']['eyes'] = ''; + self::$shapes['13']['top'] = ''; + + // Rasta + self::$shapes['14'] = []; + self::$shapes['14']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['14']['clo'] = ''; + self::$shapes['14']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['14']['mouth'] = ''; + self::$shapes['14']['eyes'] = ''; + self::$shapes['14']['top'] = ''; + + // Meta + self::$shapes['15'] = []; + self::$shapes['15']['env'] = self::SVG_ELEMENT_ENV; + self::$shapes['15']['clo'] = ''; + self::$shapes['15']['head'] = self::SVG_ELEMENT_HEAD; + self::$shapes['15']['mouth'] = ''; + self::$shapes['15']['eyes'] = ''; + self::$shapes['15']['top'] = ''; + + return self::$shapes; + } + + /** + * @return array>>> + */ + private static function themes(): array + { + if ([] !== self::$themes) { + return self::$themes; + } + + // Robo + self::$themes['00']['A']['env'] = [ "#ff2f2b" ]; + self::$themes['00']['A']['clo'] = ["#fff", "#000"]; + self::$themes['00']['A']['head'] = ["#fff"]; + self::$themes['00']['A']['mouth'] = ["#fff", "#000", "#000"]; + self::$themes['00']['A']['eyes'] = ["#000", "none", "#00FFFF"]; + self::$themes['00']['A']['top'] = ["#fff", "#fff"]; + + self::$themes['00']['B']['env'] = ["#ff1ec1"]; + self::$themes['00']['B']['clo'] = ["#000", "#fff" ]; + self::$themes['00']['B']['head'] = ["#ffc1c1"]; + self::$themes['00']['B']['mouth'] = ["#fff", "#000", "#000"]; + self::$themes['00']['B']['eyes'] = ["#FF2D00", "#fff", "none"]; + self::$themes['00']['B']['top'] = ["#a21d00", "#fff"]; + + self::$themes['00']['C']['env'] = ["#0079b1"]; + self::$themes['00']['C']['clo'] = ["#0e00b1", "#d1fffe"]; + self::$themes['00']['C']['head'] = ["#f5aa77"]; + self::$themes['00']['C']['mouth'] = ["#fff", "#000", "#000"]; + self::$themes['00']['C']['eyes'] = ["#0c00de", "#fff", "none"]; + self::$themes['00']['C']['top'] = ["#acfffd", "#acfffd"]; + + // Girl + self::$themes['01']['A']['env'] = ["#a50000"]; + self::$themes['01']['A']['clo'] = ["#f06", "#8e0039"]; + self::$themes['01']['A']['head'] = ["#85492C"]; + self::$themes['01']['A']['mouth'] = ["#000"]; + self::$themes['01']['A']['eyes'] = ["#000", "#ff9809"]; + self::$themes['01']['A']['top'] = ["#ff9809", "#ff9809", "none", "none"]; + + self::$themes['01']['B']['env'] = ["#40E83B"]; + self::$themes['01']['B']['clo'] = ["#00650b", "#62ce5a"]; + self::$themes['01']['B']['head'] = ["#f7c1a6"]; + self::$themes['01']['B']['mouth'] = ["#6e1c1c"]; + self::$themes['01']['B']['eyes'] = ["#000", "#ff833b"]; + self::$themes['01']['B']['top'] = ["#67FFCC", "none", "none", "#ecff3b"]; + + self::$themes['01']['C']['env'] = ["#ff2c2c"]; + self::$themes['01']['C']['clo'] = ["#fff", "#000"]; + self::$themes['01']['C']['head'] = ["#ffce8b"]; + self::$themes['01']['C']['mouth'] = ["#000"]; + self::$themes['01']['C']['eyes'] = ["#000", "#0072ff"]; + self::$themes['01']['C']['top'] = ["#ff9809", "none", "#ffc809", "none"]; + + // Blonde + self::$themes['02']['A']['env'] = ["#ff7520"]; + self::$themes['02']['A']['clo'] = ["#d12823"]; + self::$themes['02']['A']['head'] = ["#fee3c5"]; + self::$themes['02']['A']['mouth'] = ["#d12823"]; + self::$themes['02']['A']['eyes'] = ["#000", "none"]; + self::$themes['02']['A']['top'] = ["#000", "none", "none", "#FFCC00", "red"]; + + self::$themes['02']['B']['env'] = ["#ff9700"]; + self::$themes['02']['B']['clo'] = ["#000"]; + self::$themes['02']['B']['head'] = ["#d2ad6d"]; + self::$themes['02']['B']['mouth'] = ["#000"]; + self::$themes['02']['B']['eyes'] = ["#000", "#00ffdc"]; + self::$themes['02']['B']['top'] = ["#fdff00", "#fdff00", "none", "none", "none"]; + + self::$themes['02']['C']['env'] = ["#26a7ff"]; + self::$themes['02']['C']['clo'] = ["#d85cd7"]; + self::$themes['02']['C']['head'] = ["#542e02"]; + self::$themes['02']['C']['mouth'] = ["#f70014"]; + self::$themes['02']['C']['eyes'] = ["#000", "magenta"]; + self::$themes['02']['C']['top'] = ["#FFCC00", "#FFCC00", "#FFCC00", "#ff0000", "yellow"]; + + // Evilnormie + self::$themes['03']['A']['env'] = ["#6FC30E"]; + self::$themes['03']['A']['clo'] = ["#b4e1fa", "#5b5d6e", "#515262", "#a0d2f0", "#a0d2f0"]; + self::$themes['03']['A']['head'] = ["#fae3b9"]; + self::$themes['03']['A']['mouth'] = ["#fff", "#000"]; + self::$themes['03']['A']['eyes'] = ["#000"]; + self::$themes['03']['A']['top'] = ["#8eff45", "#8eff45", "none", "none"]; + + self::$themes['03']['B']['env'] = ["#00a58c"]; + self::$themes['03']['B']['clo'] = ["#000", "#5b00", "#5100", "#a000", "#a000"]; + self::$themes['03']['B']['head'] = ["#FAD2B9"]; + self::$themes['03']['B']['mouth'] = ["#fff", "#000"]; + self::$themes['03']['B']['eyes'] = ["#000"]; + self::$themes['03']['B']['top'] = ["#FFC600", "none", "#FFC600", "none"]; + + self::$themes['03']['C']['env'] = ["#ff501f"]; + self::$themes['03']['C']['clo'] = ["#000", "#ff0000", "#ff0000", "#7d7d7d", "#7d7d7d"]; + self::$themes['03']['C']['head'] = ["#fff3dc"]; + self::$themes['03']['C']['mouth'] = ["#d2001b", "none"]; + self::$themes['03']['C']['eyes'] = ["#000"]; + self::$themes['03']['C']['top'] = ["#D2001B", "none", "none", "#D2001B"]; + + // Country + self::$themes['04']['A']['env'] = ["#fc0"]; + self::$themes['04']['A']['clo'] = ["#901e0e", "#ffbe1e", "#ffbe1e", "#c55f54"]; + self::$themes['04']['A']['head'] = ["#f8d9ad"]; + self::$themes['04']['A']['mouth'] = ["#000", "none", "#000", "none"]; + self::$themes['04']['A']['eyes'] = ["#000"]; + self::$themes['04']['A']['top'] = ["#583D00", "#AF892E", "#462D00", "#a0a0a0"]; + + self::$themes['04']['B']['env'] = ["#386465"]; + self::$themes['04']['B']['clo'] = ["#fff", "#333", "#333", "#333"]; + self::$themes['04']['B']['head'] = ["#FFD79D"]; + self::$themes['04']['B']['mouth'] = ["#000", "#000", "#000", "#000"]; + self::$themes['04']['B']['eyes'] = ["#000"]; + self::$themes['04']['B']['top'] = ["#27363C", "#5DCAD4", "#314652", "#333"]; + + self::$themes['04']['C']['env'] = ["#DFFF00"]; + self::$themes['04']['C']['clo'] = ["#304267", "#aab0b1", "#aab0b1", "#aab0b1"]; + self::$themes['04']['C']['head'] = ["#e6b876"]; + self::$themes['04']['C']['mouth'] = ["#50230a", "#50230a", "#50230a", "#50230a"]; + self::$themes['04']['C']['eyes'] = ["#000"]; + self::$themes['04']['C']['top'] = ["#333", "#afafaf", "#222", "#6d3a1d"]; + + // Johnyold + self::$themes['05']['A']['env'] = ["#a09300"]; + self::$themes['05']['A']['clo'] = ["#c7d4e2", "#435363", "#435363", "#141720", "#141720", "#e7ecf2", "#e7ecf2"]; + self::$themes['05']['A']['head'] = ["#f5d4a6"]; + self::$themes['05']['A']['mouth'] = ["#000", "#cf9f76"]; + self::$themes['05']['A']['eyes'] = ["#000", "#000", "#000", "#000", "#000", "#000", "#000", "#000", "#fff", "#fff", "#fff", "#fff"]; + self::$themes['05']['A']['top'] = ["none", "#fdff00"]; + + self::$themes['05']['B']['env'] = ["#b3003e"]; + self::$themes['05']['B']['clo'] = ["#000", "#435363", "#435363", "#000", "none", "#e7ecf2", "#e7ecf2"]; + self::$themes['05']['B']['head'] = ["#f5d4a6"]; + self::$themes['05']['B']['mouth'] = ["#000", "#af9f94"]; + self::$themes['05']['B']['eyes'] = ["#9ff3ffdb", "#000", "#9ff3ffdb", "#000", "#2f508a", "#000", "#000", "#000", "none", "none", "none", "none"]; + self::$themes['05']['B']['top'] = ["#ff9a00", "#ff9a00"]; + + self::$themes['05']['C']['env'] = ["#884f00"]; + self::$themes['05']['C']['clo'] = ["#ff0000", "#fff", "#fff", "#141720", "#141720", "#e7ecf2", "#e7ecf2"]; + self::$themes['05']['C']['head'] = ["#c57b14"]; + self::$themes['05']['C']['mouth'] = ["#000", "#cf9f76"]; + self::$themes['05']['C']['eyes'] = ["none", "#000", "none", "#000", "#5a0000", "#000", "#000", "#000", "none", "none", "none", "none"]; + self::$themes['05']['C']['top'] = ["#efefef", "none"]; + + // Asian + self::$themes['06']['A']['env'] = ["#8acf00"]; + self::$themes['06']['A']['clo'] = ["#ee2829", "#ff0"]; + self::$themes['06']['A']['head'] = ["#ffce73"]; + self::$themes['06']['A']['mouth'] = ["#fff", "#000"]; + self::$themes['06']['A']['eyes'] = ["#000"]; + self::$themes['06']['A']['top'] = ["#000","#000","none", "#000", "#ff4e4e", "#000"]; + + self::$themes['06']['B']['env'] = ["#00d2a3"]; + self::$themes['06']['B']['clo'] = ["#0D0046", "#ffce73"]; + self::$themes['06']['B']['head'] = ["#ffce73"]; + self::$themes['06']['B']['mouth'] = ["#000", "none"]; + self::$themes['06']['B']['eyes'] = ["#000"]; + self::$themes['06']['B']['top'] = ["#000","#000","#000", "none", "#ffb358", "#000", "none", "none"]; + + self::$themes['06']['C']['env'] = ["#ff184e"]; + self::$themes['06']['C']['clo'] = ["#000", "none"]; + self::$themes['06']['C']['head'] = ["#ffce73"]; + self::$themes['06']['C']['mouth'] = ["#ff0000", "none"]; + self::$themes['06']['C']['eyes'] = ["#000"]; + self::$themes['06']['C']['top'] = ["none","none","none", "none", "none", "#ffc107", "none", "none"]; + + // Punk + self::$themes['07']['A']['env'] = ["#00deae"]; + self::$themes['07']['A']['clo'] = ["#ff0000"]; + self::$themes['07']['A']['head'] = ["#ffce94"]; + self::$themes['07']['A']['mouth'] = ["#f73b6c", "#000"]; + self::$themes['07']['A']['eyes'] = ["#e91e63", "#000", "#e91e63", "#000", "#000", "#000"]; + self::$themes['07']['A']['top'] = ["#dd104f", "#dd104f", "#f73b6c", "#dd104f"]; + + self::$themes['07']['B']['env'] = ["#181284"]; + self::$themes['07']['B']['clo'] = ["#491f49", "#ff9809", "#491f49"]; + self::$themes['07']['B']['head'] = ["#f6ba97"]; + self::$themes['07']['B']['mouth'] = ["#ff9809", "#000"]; + self::$themes['07']['B']['eyes'] = ["#c4ffe4", "#000", "#c4ffe4", "#000", "#000", "#000"]; + self::$themes['07']['B']['top'] = [ "none", "none", "#d6f740", "#516303"]; + + self::$themes['07']['C']['env'] = ["#bcf700"]; + self::$themes['07']['C']['clo'] = ["#ff14e4", "#000", "#14fffd"]; + self::$themes['07']['C']['head'] = ["#7b401e"]; + self::$themes['07']['C']['mouth'] = ["#666", "#000"]; + self::$themes['07']['C']['eyes'] = ["#00b5b4", "#000", "#00b5b4", "#000", "#000", "#000"]; + self::$themes['07']['C']['top'] = ["#14fffd", "#14fffd", "#14fffd", "#0d3a62"]; + + // Afrohair + self::$themes['08']['A']['env'] = ["#0df"]; + self::$themes['08']['A']['clo'] = ["#571e57", "#ff0"]; + self::$themes['08']['A']['head'] = ["#f2c280"]; + self::$themes['08']['A']['mouth'] = ["#ff0000"]; + self::$themes['08']['A']['eyes'] = ["#795548", "#000"]; + self::$themes['08']['A']['top'] = ["#de3b00", "none"]; + + self::$themes['08']['B']['env'] = ["#B400C2"]; + self::$themes['08']['B']['clo'] = ["#0D204A", "#00ffdf"]; + self::$themes['08']['B']['head'] = ["#ca8628"]; + self::$themes['08']['B']['mouth'] = ["#1a1a1a"]; + self::$themes['08']['B']['eyes'] = ["#cbbdaf", "#000"]; + self::$themes['08']['B']['top'] = ["#000", "#000"]; + + self::$themes['08']['C']['env'] = ["#ffe926"]; + self::$themes['08']['C']['clo'] = ["#00d6af", "#000"]; + self::$themes['08']['C']['head'] = ["#8c5100"]; + self::$themes['08']['C']['mouth'] = ["#7d0000"]; + self::$themes['08']['C']['eyes'] = ["none", "#000"]; + self::$themes['08']['C']['top'] = ["#f7f7f7", "none"]; + + // Normie female + self::$themes['09']['A']['env'] = ["#4aff0c"]; + self::$themes['09']['A']['clo'] = ["#101010", "#fff", "#fff"]; + self::$themes['09']['A']['head'] = ["#dbbc7f"]; + self::$themes['09']['A']['mouth'] = ["#000"]; + self::$themes['09']['A']['eyes'] = [ "#000", "none", "none"]; + self::$themes['09']['A']['top'] = ["#531148", "#531148", "#531148", "none"]; + + self::$themes['09']['B']['env'] = ["#FFC107"]; + self::$themes['09']['B']['clo'] = ["#033c58", "#fff", "#fff"]; + self::$themes['09']['B']['head'] = ["#dbc97f"]; + self::$themes['09']['B']['mouth'] = ["#000"]; + self::$themes['09']['B']['eyes'] = ["none", "#000", "#fff"]; + self::$themes['09']['B']['top'] = ["#FFEB3B", "#FFEB3B", "none", "#FFEB3B"]; + + self::$themes['09']['C']['env'] = ["#FF9800"]; + self::$themes['09']['C']['clo'] = ["#b40000", "#fff", "#fff"]; + self::$themes['09']['C']['head'] = ["#E2AF6B"]; + self::$themes['09']['C']['mouth'] = ["#000"]; + self::$themes['09']['C']['eyes'] = ["none", "#000", "#fff"]; + self::$themes['09']['C']['top'] = ["#ec0000", "#ec0000", "none", "none"]; + + // Older + self::$themes['10']['A']['env'] = ["#104c8c"]; + self::$themes['10']['A']['clo'] = ["#354B65", "#3D8EBB", "#89D0DA", "#00FFFD" ]; + self::$themes['10']['A']['head'] = ["#cc9a5c"]; + self::$themes['10']['A']['mouth'] = ["#222", "#fff"]; + self::$themes['10']['A']['eyes'] = ["#000", "#000"]; + self::$themes['10']['A']['top'] = ["#fff", "#fff", "none"]; + + self::$themes['10']['B']['env'] = ["#0DC15C"]; + self::$themes['10']['B']['clo'] = ["#212121", "#fff", "#212121", "#fff", ]; + self::$themes['10']['B']['head'] = ["#dca45f"]; + self::$themes['10']['B']['mouth'] = ["#111", "#633b1d"]; + self::$themes['10']['B']['eyes'] = ["#000", "#000"]; + self::$themes['10']['B']['top'] = ["none", "#792B74", "#792B74"]; + + self::$themes['10']['C']['env'] = ["#ffe500"]; + self::$themes['10']['C']['clo'] = ["#1e5e80", "#fff", "#1e5e80", "#fff"]; + self::$themes['10']['C']['head'] = ["#e8bc86"]; + self::$themes['10']['C']['mouth'] = ["#111", "none"]; + self::$themes['10']['C']['eyes'] = ["#000", "#000"]; + self::$themes['10']['C']['top'] = ["none", "none", "#633b1d"]; + + // Firehair + self::$themes['11']['A']['env'] = ["#4a3f73"]; + self::$themes['11']['A']['clo'] = ["#e6e9ee", "#f1543f", "#ff7058", "#fff", "#fff"]; + self::$themes['11']['A']['head'] = ["#b27e5b"]; + self::$themes['11']['A']['mouth'] = ["#191919", "#191919"]; + self::$themes['11']['A']['eyes'] = ["#000", "#000", "#57FFFD"]; + self::$themes['11']['A']['top'] = ["#ffc", "#ffc", "#ffc"]; + + self::$themes['11']['B']['env'] = ["#00a08d"]; + self::$themes['11']['B']['clo'] = ["#FFBA32", "#484848", "#4e4e4e", "#fff", "#fff"]; + self::$themes['11']['B']['head'] = ["#ab5f2c"]; + self::$themes['11']['B']['mouth'] = ["#191919", "#191919"]; + self::$themes['11']['B']['eyes'] = ["#000", "#ff23fa63", "#000"]; + self::$themes['11']['B']['top'] = ["#ff90f4", "#ff90f4", "#ff90f4"]; + + self::$themes['11']['C']['env'] = ["#22535d"]; + self::$themes['11']['C']['clo'] = ["#000", "#ff2500", "#ff2500", "#fff", "#fff"]; + self::$themes['11']['C']['head'] = ["#a76c44"]; + self::$themes['11']['C']['mouth'] = ["#191919", "#191919"]; + self::$themes['11']['C']['eyes'] = ["#000", "none", "#000"]; + self::$themes['11']['C']['top'] = ["none", "#00efff", "none"]; + + // Blond + self::$themes['12']['A']['env'] = ["#2668DC"]; + self::$themes['12']['A']['clo'] = ["#2385c6", "#b8d0e0", "#b8d0e0"]; + self::$themes['12']['A']['head'] = ["#ad8a60"]; + self::$themes['12']['A']['mouth'] = ["#000", "#4d4d4d"]; + self::$themes['12']['A']['eyes'] = ["#7fb5a2", "#d1eddf", "#301e19"]; + self::$themes['12']['A']['top'] = ["#fff510", "#fff510"]; + + self::$themes['12']['B']['env'] = ["#643869"]; + self::$themes['12']['B']['clo'] = ["#D67D1B", "#b8d0e0", "#b8d0e0"]; + self::$themes['12']['B']['head'] = ["#CC985A", "none0000"]; + self::$themes['12']['B']['mouth'] = ["#000", "#ececec"]; + self::$themes['12']['B']['eyes'] = ["#1f2644", "#9b97ce", "#301e19"]; + self::$themes['12']['B']['top'] = ["#00eaff", "none"]; + + self::$themes['12']['C']['env'] = ["#F599FF"]; + self::$themes['12']['C']['clo'] = ["#2823C6", "#b8d0e0", "#b8d0e0"]; + self::$themes['12']['C']['head'] = ["#C7873A"]; + self::$themes['12']['C']['mouth'] = ["#000", "#4d4d4d"]; + self::$themes['12']['C']['eyes'] = ["#581b1b", "#FF8B8B", "#000"]; + self::$themes['12']['C']['top'] = ["none", "#9c0092"]; + + // Ateam + self::$themes['13']['A']['env'] = ["#d10084"]; + self::$themes['13']['A']['clo'] = ["#efedee", "#00a1e0", "#00a1e0", "#efedee", "#ffce1c"]; + self::$themes['13']['A']['head'] = ["#b35f49"]; + self::$themes['13']['A']['mouth'] = ["#3a484a", "#000"]; + self::$themes['13']['A']['eyes'] = ["#000"]; + self::$themes['13']['A']['top'] = ["#000", "none", "#000", "none"]; + + self::$themes['13']['B']['env'] = ["#E6C117"]; + self::$themes['13']['B']['clo'] = ["#efedee", "#ec0033", "#ec0033", "#efedee", "#f2ff05"]; + self::$themes['13']['B']['head'] = ["#ffc016"]; + self::$themes['13']['B']['mouth'] = ["#4a3737", "#000"]; + self::$themes['13']['B']['eyes'] = ["#000"]; + self::$themes['13']['B']['top'] = ["#ffe900", "#ffe900", "none", "#ffe900"]; + + self::$themes['13']['C']['env'] = ["#1d8c00"]; + self::$themes['13']['C']['clo'] = ["#e000cb", "#fff", "#fff", "#e000cb", "#ffce1c"]; + self::$themes['13']['C']['head'] = ["#b96438"]; + self::$themes['13']['C']['mouth'] = ["#000", "#000"]; + self::$themes['13']['C']['eyes'] = ["#000"]; + self::$themes['13']['C']['top'] = ["#53ffff", "#53ffff", "none", "none"]; + + // Rasta + self::$themes['14']['A']['env'] = ["#fc0065"]; + self::$themes['14']['A']['clo'] = ["#708913", "#fdea14", "#708913", "#fdea14", "#708913"]; + self::$themes['14']['A']['head'] = ["#DEA561"]; + self::$themes['14']['A']['mouth'] = ["#444", "#000"]; + self::$themes['14']['A']['eyes'] = ["#000"]; + self::$themes['14']['A']['top'] = ["#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f", "#32393f" ]; + + self::$themes['14']['B']['env'] = ["#81f72e"]; + self::$themes['14']['B']['clo'] = ["#ff0000", "#ffc107", "#ff0000", "#ffc107", "#ff0000"]; + self::$themes['14']['B']['head'] = ["#ef9831"]; + self::$themes['14']['B']['mouth'] = ["#6b0000", "#000"]; + self::$themes['14']['B']['eyes'] = ["#000"]; + self::$themes['14']['B']['top'] = ["#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "#FFFAAD", "none", "none", "none", "none"]; + + self::$themes['14']['C']['env'] = ["#00D872"]; + self::$themes['14']['C']['clo'] = ["#590D00", "#FD1336", "#590D00", "#FD1336", "#590D00"]; + self::$themes['14']['C']['head'] = ["#c36c00"]; + self::$themes['14']['C']['mouth'] = ["#56442b", "#000"]; + self::$themes['14']['C']['eyes'] = ["#000"]; + self::$themes['14']['C']['top'] = ["#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "#004E4C", "none", "none", "none", "none", "none", "none", "none", "none"]; + + // Meta + self::$themes['15']['A']['env'] = ["#111"]; + self::$themes['15']['A']['clo'] = ["#000", "#00FFFF"]; + self::$themes['15']['A']['head'] = ["#755227"]; + self::$themes['15']['A']['mouth'] = ["#fff", "#000"]; + self::$themes['15']['A']['eyes'] = ["black", "#008a", "aqua"]; + self::$themes['15']['A']['top'] = ["#fff", "#fff", "#fff", "#fff", "#fff"]; + + self::$themes['15']['B']['env'] = ["#00D0D4"]; + self::$themes['15']['B']['clo'] = ["#000", "#fff"]; + self::$themes['15']['B']['head'] = ["#755227"]; + self::$themes['15']['B']['mouth'] = ["#fff", "#000"]; + self::$themes['15']['B']['eyes'] = ["black", "#1df7ffa3", "#fcff2c"]; + self::$themes['15']['B']['top'] = ["#fff539", "none", "#fff539", "none", "#fff539"]; + + self::$themes['15']['C']['env'] = ["#DC75FF"]; + self::$themes['15']['C']['clo'] = ["#000", "#FFBDEC"]; + self::$themes['15']['C']['head'] = ["#997549"]; + self::$themes['15']['C']['mouth'] = ["#fff", "#000"]; + self::$themes['15']['C']['eyes'] = ["black", "black", "aqua"]; + self::$themes['15']['C']['top'] = ["#00fffd", "none", "none", "none", "none"]; + + return self::$themes; + } +} diff --git a/src/MultiavatarTest.php b/src/MultiavatarTest.php new file mode 100644 index 0000000..b499977 --- /dev/null +++ b/src/MultiavatarTest.php @@ -0,0 +1,164 @@ +multiavatar = new Multiavatar(); + } + + /** @test */ + public function it_will_throw_if_the_ver_part_is_not_valid(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The version part does not exists; expecting a value between `00` and `15`'); + + ($this->multiavatar)('foobar', ['ver' => ['part' => 16]]); + } + + /** @test */ + public function it_will_throw_if_the_ver_part_is_not_a_valid_type(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The version part is expected to be a scalar; array was given.'); + + ($this->multiavatar)('foobar', ['ver' => ['part' => []]]); + } + + /** @test */ + public function it_will_throw_if_the_ver_theme_is_not_a_supported_type(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The version theme is expected to be a string; object was given.'); + + ($this->multiavatar)('foobar', ['ver' => ['theme' => new \stdClass()]]); + } + + /** @test */ + public function it_will_throw_if_the_ver_theme_is_not_valid(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The version theme does not exists; expecting a value between `A`, `B` and `C`.'); + + ($this->multiavatar)('foobar', ['ver' => ['theme' => 'D']]); + } + + /** @test */ + public function it_will_throw_if_the_avatar_type_is_not_valid(): void + { + $this->expectException(TypeError::class); + $this->expectExceptionMessage('Expected a scalar or a Stringable object; got: stdClass'); + + ($this->multiavatar)(new \stdClass()); + } + + /** @test */ + public function it_will_return_the_same_svg_with_a_numeric_or_string_part(): void + { + $svgNumericPart = ($this->multiavatar)('foobar', ['ver' => ['part' => 5]]); + $svgNumericStringWithLeadingZeroPart = ($this->multiavatar)('foobar', ['ver' => ['part' => '0005']]); + $svgNumericStringPart = ($this->multiavatar)('foobar', ['ver' => ['part' => '5']]); + + self::assertSame($svgNumericPart, $svgNumericStringWithLeadingZeroPart); + self::assertSame($svgNumericPart, $svgNumericStringPart); + } + + /** @test */ + public function it_will_return_the_same_svg_with_a_case_insensitive_theme(): void + { + $svgLowerTheme = ($this->multiavatar)('foobar', ['ver' => ['theme' => 'A']]); + $svgUpperTheme = ($this->multiavatar)('foobar', ['ver' => ['theme' => 'a']]); + + self::assertSame($svgLowerTheme, $svgUpperTheme); + } + + /** @test */ + public function it_will_return_the_same_svg_if_the_ver_is_fully_setting_independently_of_the_avatar_id_value(): void + { + $options = ['ver' => ['theme' => 'A', 'part' => 3]]; + + $svgWithFixedVer1 = ($this->multiavatar)('first-avatar', $options); + $svgWithFixedVer2 = ($this->multiavatar)('second-avatar', $options); + + self::assertSame($svgWithFixedVer1, $svgWithFixedVer2); + } + + /** @test */ + public function it_will_return_the_same_svg_with_sans_env_truthy_values(): void + { + $svgSansEnvTrueBoolean = ($this->multiavatar)('foobar', ['sansEnv' => true]); + $svgSansEnvTruthyNumeric = ($this->multiavatar)('foobar', ['sansEnv' => 1]); + $svgSansEnvTruthyString = ($this->multiavatar)('foobar', ['sansEnv' => 'yes']); + + self::assertSame($svgSansEnvTrueBoolean, $svgSansEnvTruthyNumeric); + self::assertSame($svgSansEnvTrueBoolean, $svgSansEnvTruthyString); + } + + /** @test */ + public function it_will_return_the_same_svg_with_sans_env_falsy_values(): void + { + $svgSansEnvFalseBoolean = ($this->multiavatar)('foobar', ['sansEnv' => false]); + $svgSansEnvWrongValueIsFalse = ($this->multiavatar)('foobar', ['sansEnv' => 'fdsdf']); + $svgSansEnvNullValue = ($this->multiavatar)('foobar', ['sansEnv' => null]); + + self::assertSame($svgSansEnvFalseBoolean, $svgSansEnvNullValue); + self::assertSame($svgSansEnvFalseBoolean, $svgSansEnvWrongValueIsFalse); + } + + /** @test */ + public function it_will_return_different_svg_with_sans_env_values(): void + { + $svgSansEnvFalse = ($this->multiavatar)('foobar', ['sansEnv' => false]); + $svgSansEnvTrue = ($this->multiavatar)('foobar', ['sansEnv' => true]); + + self::assertNotSame($svgSansEnvFalse, $svgSansEnvTrue); + } + + /** @test */ + public function it_will_return_the_same_svg_with_avatar_id_numeric_or_string(): void + { + $svgAvatarIdIsString = ($this->multiavatar)('1234567890'); + $svgAvatarIdIsNumeric = ($this->multiavatar)(1234567890); + + self::assertSame($svgAvatarIdIsNumeric, $svgAvatarIdIsString); + } + + /** + * @test + * @dataProvider getEmptySvgProvider + * @param object|string $avatarId + */ + public function it_will_return_an_empty_svg($avatarId): void + { + self::assertSame('', ($this->multiavatar)($avatarId)); + } + + /** + * @return iterable + */ + public function getEmptySvgProvider(): iterable + { + yield 'avatar is an empty string' => ['avatarId' => '']; + yield 'avatar is an empty string after being trimmed' => ['avatarId' => ' ']; + yield 'avatar can be a stringable object' => [ + 'avatarId' => new class { + public function __toString(): string { + return ''; + } + }, + ]; + } +}