diff --git a/karma.conf.js b/karma.conf.js index 6adc76ac3f1..42e310a6c66 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -4,18 +4,30 @@ if (!process.env.TRAVIS){ process.env.CHROME_BIN = require('puppeteer').executablePath(); } +function getTestFiles(){ + switch (process.env.BROWSER_BUNDLE_TEST){ + case 'publishedDist': return ["packages/web3/dist/web3.min.js", "test/e2e.minified.js"] + case 'gitRepoDist': return ["dist/web3.min.js", "test/e2e.minified.js"] + default: return ["test/**/e2e*.js"] + } +} + +// Only loads preprocessor for the logic unit tests +function getPreprocessors(){ + if (!process.env.BROWSER_BUNDLE_TEST){ + return { 'test/**/e2e*.js': [ 'browserify' ] } + } +} + module.exports = function (config) { var configuration = { frameworks: [ 'mocha', 'browserify' ], - files: [ - 'test/**/e2e*.js' - ], - preprocessors: { - 'test/**/e2e*.js': [ 'browserify' ] - }, + files: getTestFiles(), + preprocessors: getPreprocessors(), + failOnEmptyTestSuite: false, plugins: [ 'karma-chrome-launcher', 'karma-firefox-launcher', @@ -52,4 +64,4 @@ module.exports = function (config) { } config.set(configuration); -}; +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 259c1e268da..cf75f92ce07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "web3", - "version": "1.2.3", + "version": "1.2.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3789,6 +3789,15 @@ "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", "dev": true }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "requires": { + "inherits": "~2.0.0" + } + }, "bluebird": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.3.1.tgz", @@ -4590,6 +4599,50 @@ "restore-cursor": "^2.0.0" } }, + "cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", @@ -5327,6 +5380,12 @@ "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", "dev": true }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true + }, "cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -5557,6 +5616,20 @@ "type-detect": "^4.0.0" } }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dev": true, + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -6980,6 +7053,12 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true + }, "fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", @@ -7938,6 +8017,18 @@ } } }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -9868,6 +9959,12 @@ "ms": "^2.0.0" } }, + "i": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", + "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=", + "dev": true + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -10218,6 +10315,12 @@ } } }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -10314,6 +10417,12 @@ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", "dev": true }, + "is-domain": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/is-domain/-/is-domain-0.0.1.tgz", + "integrity": "sha1-f/sojVzO1rB8Ty35HJvpFTURNI4=", + "dev": true + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -12311,6 +12420,12 @@ } } }, + "moniker": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/moniker/-/moniker-0.1.2.tgz", + "integrity": "sha1-hy37pXXc6o+gSlE1sT1fJL7MyX4=", + "dev": true + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -12403,6 +12518,12 @@ "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==", "dev": true }, + "ncp": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", + "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", + "dev": true + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -12415,6 +12536,12 @@ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, + "netrc": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/netrc/-/netrc-0.1.4.tgz", + "integrity": "sha1-a+lPysqNd63gqWcNxGCRTJRHJEQ=", + "dev": true + }, "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", @@ -12725,6 +12852,12 @@ } } }, + "object-is": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", + "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", + "dev": true + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -13452,6 +13585,12 @@ } } }, + "pkginfo": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", + "integrity": "sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=", + "dev": true + }, "plexer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plexer/-/plexer-1.0.1.tgz", @@ -13636,6 +13775,19 @@ "retry": "^0.10.0" } }, + "prompt": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-0.2.14.tgz", + "integrity": "sha1-V3VPZPVD/XsIRXB8gY7OYY8F/9w=", + "dev": true, + "requires": { + "pkginfo": "0.x.x", + "read": "1.0.x", + "revalidator": "0.1.x", + "utile": "0.2.x", + "winston": "0.8.x" + } + }, "promzard": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", @@ -14088,6 +14240,15 @@ "safe-regex": "^1.1.0" } }, + "regexp.prototype.flags": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", + "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2" + } + }, "regexpu-core": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", @@ -14347,6 +14508,12 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=", + "dev": true + }, "rfdc": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", @@ -15394,6 +15561,78 @@ } } }, + "surge": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/surge/-/surge-0.21.3.tgz", + "integrity": "sha512-2rTlyC6ku3alrMAyI/8xexCZeiQu0X11rc3Sg8k2SC+9+V+X2dsohCnsTgFbDANZzlL2WojzxmnzLsJFEu/WIQ==", + "dev": true, + "requires": { + "cli-table3": "^0.5.1", + "inquirer": "^6.2.2", + "is-domain": "0.0.1", + "minimist": "1.1.1", + "moniker": "0.1.2", + "netrc": "0.1.4", + "progress": "1.1.8", + "prompt": "~0.2.14", + "read": "1.0.5", + "request": "^2.88.0", + "split": "0.3.1", + "surge-fstream-ignore": "^1.0.6", + "surge-ignore": "0.2.0", + "tarr": "1.1.0", + "url-parse-as-address": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.1.tgz", + "integrity": "sha1-G8K8cWWM3KVxJHVoQ2NhWwtPaVs=", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "read": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.5.tgz", + "integrity": "sha1-AHo9FpR4qnEKSRcn5FPv+5LnYgM=", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "split": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.1.tgz", + "integrity": "sha1-zrzxQr9hu7ZLFBYo5ttIKikUZUw=", + "dev": true, + "requires": { + "through": "2" + } + } + } + }, + "surge-fstream-ignore": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/surge-fstream-ignore/-/surge-fstream-ignore-1.0.6.tgz", + "integrity": "sha512-hNN52cz2fYCAzhlHmWPn4aE3bFbpBt01AkWFLljrtSzFvxlipLAeLuLtQ3t4f0RKoUkjzXWCAFK13WoET2iM1A==", + "dev": true, + "requires": { + "fstream": ">=1.0.12", + "inherits": "2", + "minimatch": "^3.0.0" + } + }, + "surge-ignore": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/surge-ignore/-/surge-ignore-0.2.0.tgz", + "integrity": "sha1-Wn+KIKcRiM+edaLP6OsYLekNrzs=", + "dev": true + }, "sver-compat": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", @@ -15570,6 +15809,17 @@ "xtend": "^4.0.0" } }, + "tarr": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tarr/-/tarr-1.1.0.tgz", + "integrity": "sha512-tENbQ43IQckay71stp1p1lljRhoEZpZk10FzEZKW2tJcMcnLwV3CfZdxBAERlH6nwnFvnHMS9eJOJl6IzSsG0g==", + "dev": true, + "requires": { + "block-stream": "*", + "fstream": ">=1.0.12", + "inherits": "2" + } + }, "temp-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", @@ -16167,6 +16417,12 @@ } } }, + "url-parse-as-address": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-as-address/-/url-parse-as-address-1.0.0.tgz", + "integrity": "sha1-+4CQGIPzOLPL7TU49fqiatr38uc=", + "dev": true + }, "url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", @@ -16234,6 +16490,28 @@ "object.getownpropertydescriptors": "^2.0.3" } }, + "utile": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/utile/-/utile-0.2.1.tgz", + "integrity": "sha1-kwyI6ZCY1iIINMNWy9mncFItkNc=", + "dev": true, + "requires": { + "async": "~0.2.9", + "deep-equal": "*", + "i": "0.3.x", + "mkdirp": "0.x.x", + "ncp": "0.4.x", + "rimraf": "2.x.x" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + } + } + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -16984,6 +17262,41 @@ "execa": "^1.0.0" } }, + "winston": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-0.8.3.tgz", + "integrity": "sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA=", + "dev": true, + "requires": { + "async": "0.2.x", + "colors": "0.6.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "pkginfo": "0.3.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", + "dev": true + }, + "pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=", + "dev": true + } + } + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", diff --git a/package.json b/package.json index 25e86396578..1bc7f74aca0 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,9 @@ }, "bundlesize": [ { - "path": "./packages/web3/dist/web3.min.js", - "maxSize": "1.5 mB", - "compression": "none" + "path": "./packages/web3/dist/web3.min.js", + "maxSize": "1.5 mB", + "compression": "none" } ], "scripts": { @@ -40,6 +40,8 @@ "test:e2e:clients": "npm run test:e2e:ganache; npm run test:e2e:geth:insta; npm run test:e2e:geth:auto", "test:e2e:chrome": "./scripts/e2e.chrome.sh", "test:e2e:firefox": "./scripts/e2e.firefox.sh", + "test:e2e:min": "./scripts/e2e.min.sh", + "test:e2e:surge": "./scripts/e2e.surge.sh", "test:e2e:browsers": "npm run build; npm run test:e2e:chrome; npm run test:e2e:firefox", "test:e2e:publish": "./scripts/e2e.npm.publish.sh", "test:e2e:truffle": "./scripts/e2e.truffle.sh", @@ -133,6 +135,7 @@ "mocha": "^6.2.1", "puppeteer": "^1.20.0", "sandboxed-module": "^2.0.3", + "surge": "^0.21.3", "typescript": "next", "underscore": "^1.9.1", "vinyl-source-stream": "^2.0.0", diff --git a/scripts/ci.sh b/scripts/ci.sh index 72b794663b5..30ff3608410 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -31,6 +31,8 @@ elif [ "$TEST" = "e2e_browsers" ]; then npm run build npm run test:e2e:chrome npm run test:e2e:firefox + npm run test:e2e:min + npm run test:e2e:surge elif [ "$TEST" = "e2e_truffle" ]; then diff --git a/scripts/e2e.min.sh b/scripts/e2e.min.sh new file mode 100755 index 00000000000..ce958f7a3f7 --- /dev/null +++ b/scripts/e2e.min.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# ------------------------------------------------------------------------------------- +# Runs basic min bundle loading check on chrome headless +# ------------------------------------------------------------------------------------- + +# Exit immediately on error +set -o errexit + +echo " " +echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" +echo "E2E: web3/dist/web3.min.js (Chrome). " +echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" +echo " " + +BROWSER_BUNDLE_TEST="publishedDist" karma start \ + --single-run \ + --browsers ChromeHeadless + +echo " " +echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" +echo "E2E: web3/dist/web3.min.js (Chrome). " +echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" +echo " " + +BROWSER_BUNDLE_TEST="gitRepoDist" karma start \ + --single-run \ + --browsers ChromeHeadless \ No newline at end of file diff --git a/scripts/e2e.surge.sh b/scripts/e2e.surge.sh new file mode 100755 index 00000000000..a1e59be9ab0 --- /dev/null +++ b/scripts/e2e.surge.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# -------------------------------------------------------------------- +# Publishes a small test site that uses the packages/web3/dist/min +# -------------------------------------------------------------------- + +if [ -z "$CI" ]; then + + echo "======================================================================" + echo "This script publishes a test site with surge.sh. Only run in CI." + echo "======================================================================" + + exit 1 + +fi + +echo "======================================================================" +echo "Publishing test site with surge.sh. See link below. " +echo "======================================================================" + +cp packages/web3/dist/web3.min.js scripts/html +cd scripts +(echo "" && exit && cat ) | npx surge html + +# Might be running locally in development +rm html/web3.min.js + +# Script doesn't always work... +exit 0 diff --git a/scripts/html/index.html b/scripts/html/index.html new file mode 100644 index 00000000000..b3fb10dc758 --- /dev/null +++ b/scripts/html/index.html @@ -0,0 +1,28 @@ + + +
+ + + +