summaryrefslogtreecommitdiff
path: root/vendor/chillerlan
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2021-02-26 19:16:17 +0300
committerAndrew Dolgov <[email protected]>2021-02-26 19:16:17 +0300
commit3fd785654372d493c031d9b541ab33a881023a32 (patch)
tree0a76cb410217074378de3d7012b95754cd3c7e6f /vendor/chillerlan
parentbc4475b6698f5a74e475674aa7af43253c459892 (diff)
* switch to composer for qrcode and otp dependencies
* move most OTP-related stuff into userhelper * remove old phpqrcode and otphp libraries
Diffstat (limited to 'vendor/chillerlan')
-rw-r--r--vendor/chillerlan/php-qrcode/.github/FUNDING.yml1
-rw-r--r--vendor/chillerlan/php-qrcode/.github/workflows/tests.yml55
-rw-r--r--vendor/chillerlan/php-qrcode/.gitignore5
-rw-r--r--vendor/chillerlan/php-qrcode/.scrutinizer.yml5
-rw-r--r--vendor/chillerlan/php-qrcode/.travis.yml19
-rw-r--r--vendor/chillerlan/php-qrcode/LICENSE21
-rw-r--r--vendor/chillerlan/php-qrcode/README.md392
-rw-r--r--vendor/chillerlan/php-qrcode/composer.json51
-rw-r--r--vendor/chillerlan/php-qrcode/examples/MyCustomOutput.php36
-rw-r--r--vendor/chillerlan/php-qrcode/examples/QRImageWithLogo.php81
-rw-r--r--vendor/chillerlan/php-qrcode/examples/QRImageWithText.php104
-rw-r--r--vendor/chillerlan/php-qrcode/examples/custom_output.php38
-rw-r--r--vendor/chillerlan/php-qrcode/examples/example_image.pngbin0 -> 2279 bytes
-rw-r--r--vendor/chillerlan/php-qrcode/examples/example_svg.pngbin0 -> 15925 bytes
-rw-r--r--vendor/chillerlan/php-qrcode/examples/fpdf.php47
-rw-r--r--vendor/chillerlan/php-qrcode/examples/html.php102
-rw-r--r--vendor/chillerlan/php-qrcode/examples/image.php60
-rw-r--r--vendor/chillerlan/php-qrcode/examples/imageWithLogo.php44
-rw-r--r--vendor/chillerlan/php-qrcode/examples/imageWithText.php33
-rw-r--r--vendor/chillerlan/php-qrcode/examples/imagick.php59
-rw-r--r--vendor/chillerlan/php-qrcode/examples/octocat.pngbin0 -> 2468 bytes
-rw-r--r--vendor/chillerlan/php-qrcode/examples/svg.php77
-rw-r--r--vendor/chillerlan/php-qrcode/examples/text.php68
-rw-r--r--vendor/chillerlan/php-qrcode/phpdoc.xml15
-rw-r--r--vendor/chillerlan/php-qrcode/phpmd.xml34
-rw-r--r--vendor/chillerlan/php-qrcode/phpunit.xml23
-rw-r--r--vendor/chillerlan/php-qrcode/public/index.html163
-rw-r--r--vendor/chillerlan/php-qrcode/public/qrcode.php97
-rw-r--r--vendor/chillerlan/php-qrcode/src/Data/AlphaNum.php65
-rw-r--r--vendor/chillerlan/php-qrcode/src/Data/Byte.php47
-rw-r--r--vendor/chillerlan/php-qrcode/src/Data/Kanji.php70
-rw-r--r--vendor/chillerlan/php-qrcode/src/Data/MaskPatternTester.php203
-rw-r--r--vendor/chillerlan/php-qrcode/src/Data/Number.php82
-rw-r--r--vendor/chillerlan/php-qrcode/src/Data/QRCodeDataException.php17
-rw-r--r--vendor/chillerlan/php-qrcode/src/Data/QRDataAbstract.php351
-rw-r--r--vendor/chillerlan/php-qrcode/src/Data/QRDataInterface.php187
-rw-r--r--vendor/chillerlan/php-qrcode/src/Data/QRMatrix.php733
-rw-r--r--vendor/chillerlan/php-qrcode/src/Helpers/BitBuffer.php75
-rw-r--r--vendor/chillerlan/php-qrcode/src/Helpers/Polynomial.php184
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QRCodeOutputException.php17
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QRFpdf.php112
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QRImage.php208
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QRImagick.php123
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QRMarkup.php151
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php130
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QROutputInterface.php55
-rw-r--r--vendor/chillerlan/php-qrcode/src/Output/QRString.php76
-rw-r--r--vendor/chillerlan/php-qrcode/src/QRCode.php310
-rw-r--r--vendor/chillerlan/php-qrcode/src/QRCodeException.php15
-rw-r--r--vendor/chillerlan/php-qrcode/src/QROptions.php61
-rw-r--r--vendor/chillerlan/php-qrcode/src/QROptionsTrait.php408
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Data/AlphaNumTest.php44
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Data/ByteTest.php38
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Data/DatainterfaceTestAbstract.php65
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Data/KanjiTest.php50
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Data/MaskPatternTesterTest.php29
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Data/NumberTest.php44
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Data/QRMatrixTest.php260
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Helpers/BitBufferTest.php53
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Helpers/PolynomialTest.php42
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Output/QRFpdfTest.php83
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Output/QRImageTest.php69
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Output/QRImagickTest.php66
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Output/QRMarkupTest.php79
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Output/QROutputTestAbstract.php71
-rw-r--r--vendor/chillerlan/php-qrcode/tests/Output/QRStringTest.php56
-rw-r--r--vendor/chillerlan/php-qrcode/tests/QRCodeTest.php140
-rw-r--r--vendor/chillerlan/php-qrcode/tests/QROptionsTest.php80
-rw-r--r--vendor/chillerlan/php-qrcode/tests/QRTestAbstract.php72
-rw-r--r--vendor/chillerlan/php-settings-container/.gitignore4
-rw-r--r--vendor/chillerlan/php-settings-container/.scrutinizer.yml5
-rw-r--r--vendor/chillerlan/php-settings-container/.travis.yml18
-rw-r--r--vendor/chillerlan/php-settings-container/LICENSE21
-rw-r--r--vendor/chillerlan/php-settings-container/README.md153
-rw-r--r--vendor/chillerlan/php-settings-container/composer.json40
-rw-r--r--vendor/chillerlan/php-settings-container/examples/advanced.php46
-rw-r--r--vendor/chillerlan/php-settings-container/examples/simple.php30
-rw-r--r--vendor/chillerlan/php-settings-container/phpmd.xml35
-rw-r--r--vendor/chillerlan/php-settings-container/phpunit.xml22
-rw-r--r--vendor/chillerlan/php-settings-container/src/SettingsContainerAbstract.php172
-rw-r--r--vendor/chillerlan/php-settings-container/src/SettingsContainerInterface.php104
-rw-r--r--vendor/chillerlan/php-settings-container/tests/ContainerTest.php105
-rw-r--r--vendor/chillerlan/php-settings-container/tests/TestContainer.php29
-rw-r--r--vendor/chillerlan/php-settings-container/tests/TestOptionsTrait.php42
84 files changed, 7477 insertions, 0 deletions
diff --git a/vendor/chillerlan/php-qrcode/.github/FUNDING.yml b/vendor/chillerlan/php-qrcode/.github/FUNDING.yml
new file mode 100644
index 000000000..fc89a6739
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/.github/FUNDING.yml
@@ -0,0 +1 @@
+ko_fi: codemasher
diff --git a/vendor/chillerlan/php-qrcode/.github/workflows/tests.yml b/vendor/chillerlan/php-qrcode/.github/workflows/tests.yml
new file mode 100644
index 000000000..5dd343abd
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/.github/workflows/tests.yml
@@ -0,0 +1,55 @@
+# https://help.github.com/en/categories/automating-your-workflow-with-github-actions
+# https://github.com/localheinz/php-library-template/blob/master/.github/workflows/continuous-integration.yml
+# https://github.com/sebastianbergmann/phpunit/blob/master/.github/workflows/ci.yml
+
+on:
+ - pull_request
+ - push
+
+name: "Continuous Integration"
+
+jobs:
+
+ tests:
+ name: "Unit Tests"
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ php-binary:
+ - php7.2
+ - php7.3
+ - php7.4
+
+ steps:
+ - name: "Checkout"
+ uses: actions/[email protected]
+
+ - name: "Install dependencies with composer"
+ run: ${{ matrix.php-binary }} $(which composer) update --no-interaction --no-progress --no-suggest
+
+ - name: "Run unit tests with phpunit"
+ run: ${{ matrix.php-binary }} vendor/bin/phpunit --configuration=phpunit.xml --no-coverage
+
+
+ code-coverage:
+ name: "Code Coverage"
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: "Checkout"
+ uses: actions/[email protected]
+
+ - name: "Install locked dependencies with composer"
+ run: php7.4 $(which composer) install --no-interaction --no-progress --no-suggest
+
+ - name: "Dump Xdebug filter with phpunit/phpunit"
+ run: php7.4 vendor/bin/phpunit --configuration=phpunit.xml --dump-xdebug-filter=.build/phpunit/xdebug-filter.php
+
+ - name: "Collect code coverage with Xdebug and phpunit/phpunit"
+ run: php7.4 vendor/bin/phpunit --configuration=phpunit.xml --prepend=.build/phpunit/xdebug-filter.php
+
+ - name: "Send code coverage report to Codecov.io"
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+ run: bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/chillerlan/php-qrcode/.gitignore b/vendor/chillerlan/php-qrcode/.gitignore
new file mode 100644
index 000000000..ecebb9964
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/.gitignore
@@ -0,0 +1,5 @@
+.build/*
+.idea/*
+vendor/*
+composer.lock
+*.phpunit.result.cache
diff --git a/vendor/chillerlan/php-qrcode/.scrutinizer.yml b/vendor/chillerlan/php-qrcode/.scrutinizer.yml
new file mode 100644
index 000000000..7fdd2a4dc
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/.scrutinizer.yml
@@ -0,0 +1,5 @@
+filter:
+ excluded_paths:
+ - examples/*
+ - tests/*
+ - vendor/*
diff --git a/vendor/chillerlan/php-qrcode/.travis.yml b/vendor/chillerlan/php-qrcode/.travis.yml
new file mode 100644
index 000000000..78b8d79e9
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/.travis.yml
@@ -0,0 +1,19 @@
+addons:
+ apt:
+ packages:
+ - imagemagick
+
+language: php
+
+matrix:
+ include:
+ - php: 7.2
+ - php: 7.3
+ - php: 7.4
+
+before_install:
+ - pecl channel-update pecl.php.net
+ - printf "\n" | pecl install imagick
+install: travis_retry composer install --no-interaction --prefer-source
+script: vendor/bin/phpunit --configuration phpunit.xml --coverage-clover clover.xml
+after_script: bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/chillerlan/php-qrcode/LICENSE b/vendor/chillerlan/php-qrcode/LICENSE
new file mode 100644
index 000000000..dac852818
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Smiley <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/chillerlan/php-qrcode/README.md b/vendor/chillerlan/php-qrcode/README.md
new file mode 100644
index 000000000..075b2a376
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/README.md
@@ -0,0 +1,392 @@
+# chillerlan/php-qrcode
+
+A PHP7.2+ QR Code library based on the [implementation](https://github.com/kazuhikoarase/qrcode-generator) by [Kazuhiko Arase](https://github.com/kazuhikoarase),
+namespaced, cleaned up, improved and other stuff.
+
+[![Packagist version][packagist-badge]][packagist]
+[![License][license-badge]][license]
+[![Travis CI][travis-badge]][travis]
+[![CodeCov][coverage-badge]][coverage]
+[![Scrunitizer CI][scrutinizer-badge]][scrutinizer]
+[![Packagist downloads][downloads-badge]][downloads]
+[![PayPal donate][donate-badge]][donate]
+
+[![Continuous Integration][gh-action-badge]][gh-action]
+
+[packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-qrcode.svg?style=flat-square
+[packagist]: https://packagist.org/packages/chillerlan/php-qrcode
+[license-badge]: https://img.shields.io/github/license/chillerlan/php-qrcode.svg?style=flat-square
+[license]: https://github.com/chillerlan/php-qrcode/blob/main/LICENSE
+[travis-badge]: https://img.shields.io/travis/chillerlan/php-qrcode.svg?style=flat-square
+[travis]: https://travis-ci.org/chillerlan/php-qrcode
+[coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-qrcode.svg?style=flat-square
+[coverage]: https://codecov.io/github/chillerlan/php-qrcode
+[scrutinizer-badge]: https://img.shields.io/scrutinizer/g/chillerlan/php-qrcode.svg?style=flat-square
+[scrutinizer]: https://scrutinizer-ci.com/g/chillerlan/php-qrcode
+[downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-qrcode.svg?style=flat-square
+[downloads]: https://packagist.org/packages/chillerlan/php-qrcode/stats
+[donate-badge]: https://img.shields.io/badge/donate-paypal-ff33aa.svg?style=flat-square
+[donate]: https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4
+[gh-action-badge]: https://github.com/chillerlan/php-qrcode/workflows/Continuous%20Integration/badge.svg
+[gh-action]: https://github.com/chillerlan/php-qrcode/actions
+
+## Documentation
+
+### Requirements
+- PHP 7.2+
+ - `ext-mbstring`
+ - optional:
+ - `ext-json`, `ext-gd`
+ - `ext-imagick` with [ImageMagick](https://imagemagick.org) installed
+ - [`setasign/fpdf`](https://github.com/setasign/fpdf) for the PDF output module
+
+### Installation
+**requires [composer](https://getcomposer.org)**
+
+via terminal: `composer require chillerlan/php-qrcode`
+
+*composer.json* (note: replace `dev-master` with a [version boundary](https://getcomposer.org/doc/articles/versions.md), e.g. `^3.2`)
+```json
+{
+ "require": {
+ "php": "^7.2",
+ "chillerlan/php-qrcode": "^3.4"
+ }
+}
+```
+
+### Usage
+We want to encode this URI for a mobile authenticator into a QRcode image:
+```php
+$data = 'otpauth://totp/test?secret=B3JX4VCVJDVNXNZ5&issuer=chillerlan.net';
+
+//quick and simple:
+echo '<img src="'.(new QRCode)->render($data).'" alt="QR Code" />';
+```
+
+<p align="center">
+ <img alt="QR codes are awesome!" src="https://raw.githubusercontent.com/chillerlan/php-qrcode/main/examples/example_image.png">
+ <img alt="QR codes are awesome!" src="https://raw.githubusercontent.com/chillerlan/php-qrcode/main/examples/example_svg.png">
+</p>
+
+Wait, what was that? Please again, slower!
+
+### Advanced usage
+
+Ok, step by step. First you'll need a `QRCode` instance, which can be optionally invoked with a `QROptions` (or a [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/master/src/SettingsContainerInterface.php), respectively) object as the only parameter.
+
+```php
+$options = new QROptions([
+ 'version' => 5,
+ 'outputType' => QRCode::OUTPUT_MARKUP_SVG,
+ 'eccLevel' => QRCode::ECC_L,
+]);
+
+// invoke a fresh QRCode instance
+$qrcode = new QRCode($options);
+
+// and dump the output
+$qrcode->render($data);
+
+// ...with additional cache file
+$qrcode->render($data, '/path/to/file.svg');
+```
+
+In case you just want the raw QR code matrix, call `QRCode::getMatrix()` - this method is also called internally from `QRCode::render()`. See also [Custom output modules](#custom-qroutputinterface).
+
+```php
+$matrix = $qrcode->getMatrix($data);
+
+foreach($matrix->matrix() as $y => $row){
+ foreach($row as $x => $module){
+
+ // get a module's value
+ $value = $module;
+ $value = $matrix->get($x, $y);
+
+ // boolean check a module
+ if($matrix->check($x, $y)){ // if($module >> 8 > 0)
+ // do stuff, the module is dark
+ }
+ else{
+ // do other stuff, the module is light
+ }
+
+ }
+}
+```
+
+Have a look [in this folder](https://github.com/chillerlan/php-qrcode/tree/master/examples) for some more usage examples.
+
+#### Custom module values
+Previous versions of `QRCode` held only boolean matrix values that only allowed to determine whether a module was dark or not. Now you can distinguish between different parts of the matrix, namely the several required patterns from the QR Code specification, and use them in different ways.
+
+The dark value is the module (light) value shifted by 8 bits to the left: `$value = $M_TYPE << ($bool ? 8 : 0);`, where `$M_TYPE` is one of the `QRMatrix::M_*` constants.
+You can check the value for a type explicitly like...
+```php
+// for true (dark)
+$value >> 8 === $M_TYPE;
+
+//for false (light)
+$value === $M_TYPE;
+```
+...or you can perform a loose check, ignoring the module value
+```php
+// for true
+$value >> 8 > 0;
+
+// for false
+$value >> 8 === 0
+```
+
+See also `QRMatrix::set()`, `QRMatrix::check()` and [`QRMatrix` constants](#qrmatrix-constants).
+
+To map the values and properly render the modules for the given `QROutputInterface`, it's necessary to overwrite the default values:
+```php
+$options = new QROptions;
+
+// for HTML, SVG and ImageMagick
+$options->moduleValues = [
+ // finder
+ 1536 => '#A71111', // dark (true)
+ 6 => '#FFBFBF', // light (false)
+ // alignment
+ 2560 => '#A70364',
+ 10 => '#FFC9C9',
+ // timing
+ 3072 => '#98005D',
+ 12 => '#FFB8E9',
+ // format
+ 3584 => '#003804',
+ 14 => '#00FB12',
+ // version
+ 4096 => '#650098',
+ 16 => '#E0B8FF',
+ // data
+ 1024 => '#4A6000',
+ 4 => '#ECF9BE',
+ // darkmodule
+ 512 => '#080063',
+ // separator
+ 8 => '#AFBFBF',
+ // quietzone
+ 18 => '#FFFFFF',
+];
+
+// for the image output types
+$options->moduleValues = [
+ 512 => [0, 0, 0],
+ // ...
+];
+
+// for string/text output
+$options->moduleValues = [
+ 512 => '#',
+ // ...
+];
+```
+
+#### Custom `QROutputInterface`
+Instead of bloating your code you can simply create your own output interface by extending `QROutputAbstract`. Have a look at the [built-in output modules](https://github.com/chillerlan/php-qrcode/tree/master/src/Output).
+
+```php
+class MyCustomOutput extends QROutputAbstract{
+
+ // inherited from QROutputAbstract
+ protected $matrix; // QRMatrix
+ protected $moduleCount; // modules QRMatrix::size()
+ protected $options; // MyCustomOptions or QROptions
+ protected $scale; // scale factor from options
+ protected $length; // length of the matrix ($moduleCount * $scale)
+
+ // ...check/set default module values (abstract method, called by the constructor)
+ protected function setModuleValues():void{
+ // $this->moduleValues = ...
+ }
+
+ // QROutputInterface::dump()
+ public function dump(string $file = null):string{
+ $output = '';
+
+ for($row = 0; $row < $this->moduleCount; $row++){
+ for($col = 0; $col < $this->moduleCount; $col++){
+ $output .= (int)$this->matrix->check($col, $row);
+ }
+ }
+
+ return $output;
+ }
+
+}
+```
+
+In case you need additional settings for your output module, just extend `QROptions`...
+```
+class MyCustomOptions extends QROptions{
+ protected $myParam = 'defaultValue';
+
+ // ...
+}
+```
+...or use the [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/master/src/SettingsContainerInterface.php), which is the more flexible approach.
+
+```php
+trait MyCustomOptionsTrait{
+ protected $myParam = 'defaultValue';
+
+ // ...
+}
+```
+set the options:
+```php
+$myOptions = [
+ 'version' => 5,
+ 'eccLevel' => QRCode::ECC_L,
+ 'outputType' => QRCode::OUTPUT_CUSTOM,
+ 'outputInterface' => MyCustomOutput::class,
+ // your custom settings
+ 'myParam' => 'whatever value',
+ ];
+
+// extends QROptions
+$myCustomOptions = new MyCustomOptions($myOptions);
+
+// using the SettingsContainerInterface
+$myCustomOptions = new class($myOptions) extends SettingsContainerAbstract{
+ use QROptionsTrait, MyCustomOptionsTrait;
+};
+
+```
+
+You can then call `QRCode` with the custom modules...
+```php
+(new QRCode($myCustomOptions))->render($data);
+```
+...or invoke the `QROutputInterface` manually.
+```php
+$qrOutputInterface = new MyCustomOutput($myCustomOptions, (new QRCode($myCustomOptions))->getMatrix($data));
+
+//dump the output, which is equivalent to QRCode::render()
+$qrOutputInterface->dump();
+```
+
+### API
+
+#### `QRCode` methods
+method | return | description
+------ | ------ | -----------
+`__construct(QROptions $options = null)` | - | see [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/master/src/SettingsContainerInterface.php)
+`render(string $data, string $file = null)` | mixed, `QROutputInterface::dump()` | renders a QR Code for the given `$data` and `QROptions`, saves `$file` optional
+`getMatrix(string $data)` | `QRMatrix` | returns a `QRMatrix` object for the given `$data` and current `QROptions`
+`initDataInterface(string $data)` | `QRDataInterface` | returns a fresh `QRDataInterface` for the given `$data`
+`isNumber(string $string)` | bool | checks if a string qualifies for `Number`
+`isAlphaNum(string $string)` | bool | checks if a string qualifies for `AlphaNum`
+`isKanji(string $string)` | bool | checks if a string qualifies for `Kanji`
+
+#### `QRCode` constants
+name | description
+---- | -----------
+`VERSION_AUTO` | `QROptions::$version`
+`MASK_PATTERN_AUTO` | `QROptions::$maskPattern`
+`OUTPUT_MARKUP_SVG`, `OUTPUT_MARKUP_HTML` | `QROptions::$outputType` markup
+`OUTPUT_IMAGE_PNG`, `OUTPUT_IMAGE_JPG`, `OUTPUT_IMAGE_GIF` | `QROptions::$outputType` image
+`OUTPUT_STRING_JSON`, `OUTPUT_STRING_TEXT` | `QROptions::$outputType` string
+`OUTPUT_IMAGICK` | `QROptions::$outputType` ImageMagick
+`OUTPUT_FPDF` | `QROptions::$outputType` PDF, using [FPDF](https://github.com/setasign/fpdf)
+`OUTPUT_CUSTOM` | `QROptions::$outputType`, requires `QROptions::$outputInterface`
+`ECC_L`, `ECC_M`, `ECC_Q`, `ECC_H`, | ECC-Level: 7%, 15%, 25%, 30% in `QROptions::$eccLevel`
+`DATA_NUMBER`, `DATA_ALPHANUM`, `DATA_BYTE`, `DATA_KANJI` | `QRDataInterface::$datamode`
+
+#### `QROptions` properties
+property | type | default | allowed | description
+-------- | ---- | ------- | ------- | -----------
+`$version` | int | `QRCode::VERSION_AUTO` | 1...40 | the [QR Code version number](http://www.qrcode.com/en/about/version.html)
+`$versionMin` | int | 1 | 1...40 | Minimum QR version (if `$version = QRCode::VERSION_AUTO`)
+`$versionMax` | int | 40 | 1...40 | Maximum QR version (if `$version = QRCode::VERSION_AUTO`)
+`$eccLevel` | int | `QRCode::ECC_L` | `QRCode::ECC_X` | Error correct level, where X = L (7%), M (15%), Q (25%), H (30%)
+`$maskPattern` | int | `QRCode::MASK_PATTERN_AUTO` | 0...7 | Mask Pattern to use
+`$addQuietzone` | bool | `true` | - | Add a "quiet zone" (margin) according to the QR code spec
+`$quietzoneSize` | int | 4 | clamped to 0 ... `$matrixSize / 2` | Size of the quiet zone
+`$dataMode` | string | `null` | `Number`, `AlphaNum`, `Kanji`, `Byte` | allows overriding the data type detection
+`$outputType` | string | `QRCode::OUTPUT_IMAGE_PNG` | `QRCode::OUTPUT_*` | built-in output type
+`$outputInterface` | string | `null` | * | FQCN of the custom `QROutputInterface` if `QROptions::$outputType` is set to `QRCode::OUTPUT_CUSTOM`
+`$cachefile` | string | `null` | * | optional cache file path
+`$eol` | string | `PHP_EOL` | * | newline string (HTML, SVG, TEXT)
+`$scale` | int | 5 | * | size of a QR code pixel (SVG, IMAGE_*), HTML -> via CSS
+`$cssClass` | string | `null` | * | a common css class
+`$svgOpacity` | float | 1.0 | 0...1 |
+`$svgDefs` | string | * | * | anything between [`<defs>`](https://developer.mozilla.org/docs/Web/SVG/Element/defs)
+`$svgViewBoxSize` | int | `null` | * | a positive integer which defines width/height of the [viewBox attribute](https://css-tricks.com/scale-svg/#article-header-id-3)
+`$textDark` | string | '🔴' | * | string substitute for dark
+`$textLight` | string | '⭕' | * | string substitute for light
+`$markupDark` | string | '#000' | * | markup substitute for dark (CSS value)
+`$markupLight` | string | '#fff' | * | markup substitute for light (CSS value)
+`$imageBase64` | bool | `true` | - | whether to return the image data as base64 or raw like from `file_get_contents()`
+`$imageTransparent` | bool | `true` | - | toggle transparency (no jpeg support)
+`$imageTransparencyBG` | array | `[255, 255, 255]` | `[R, G, B]` | the RGB values for the transparent color, see [`imagecolortransparent()`](http://php.net/manual/function.imagecolortransparent.php)
+`$pngCompression` | int | -1 | -1 ... 9 | `imagepng()` compression level, -1 = auto
+`$jpegQuality` | int | 85 | 0 - 100 | `imagejpeg()` quality
+`$imagickFormat` | string | 'png' | * | ImageMagick output type, see `Imagick::setType()`
+`$imagickBG` | string | `null` | * | ImageMagick background color, see `ImagickPixel::__construct()`
+`$moduleValues` | array | `null` | * | Module values map, see [Custom output modules](#custom-qroutputinterface) and `QROutputInterface::DEFAULT_MODULE_VALUES`
+
+#### `QRMatrix` methods
+method | return | description
+------ | ------ | -----------
+`__construct(int $version, int $eclevel)` | - | -
+`matrix()` | array | the internal matrix representation as a 2 dimensional array
+`version()` | int | the current QR Code version
+`eccLevel()` | int | current ECC level
+`maskPattern()` | int | the used mask pattern
+`size()` | int | the absoulute size of the matrix, including quiet zone (if set). `$version * 4 + 17 + 2 * $quietzone`
+`get(int $x, int $y)` | int | returns the value of the module
+`set(int $x, int $y, bool $value, int $M_TYPE)` | `QRMatrix` | sets the `$M_TYPE` value for the module
+`check(int $x, int $y)` | bool | checks whether a module is true (dark) or false (light)
+`setLogoSpace(int $width, int $height, int $startX = null, int $startY = null)` | `QRMatrix` | creates a logo space in the matrix
+
+#### `QRMatrix` constants
+name | light (false) | dark (true) | description
+---- | ------------- | ----------- | -----------
+`M_NULL` | 0 | - | module not set (should never appear. if so, there's an error)
+`M_DARKMODULE` | - | 512 | once per matrix at `$xy = [8, 4 * $version + 9]`
+`M_DATA` | 4 | 1024 | the actual encoded data
+`M_FINDER` | 6 | 1536 | the 7x7 finder patterns
+`M_SEPARATOR` | 8 | - | separator lines around the finder patterns
+`M_ALIGNMENT` | 10 | 2560 | the 5x5 alignment patterns
+`M_TIMING` | 12 | 3072 | the timing pattern lines
+`M_FORMAT` | 14 | 3584 | format information pattern
+`M_VERSION` | 16 | 4096 | version information pattern
+`M_QUIETZONE` | 18 | - | margin around the QR Code
+`M_LOGO` | 20 | - | space for a logo image (not used yet)
+`M_TEST` | 255 | 65280 | test value
+
+
+### Notes
+The QR encoder, especially the subroutines for mask pattern testing, can cause high CPU load on increased matrix size.
+You can avoid a part of this load by choosing a fast output module, like `OUTPUT_IMAGE_*` and setting the mask pattern manually (which may result in unreadable QR Codes).
+Oh hey and don't forget to sanitize any user input!
+
+### Disclaimer!
+I don't take responsibility for molten CPUs, misled applications, failed log-ins etc.. Use at your own risk!
+
+#### Trademark Notice
+
+The word "QR Code" is registered trademark of *DENSO WAVE INCORPORATED*<br>
+http://www.denso-wave.com/qrcode/faqpatent-e.html
+
+### Framework Integration
+- Drupal [Google Authenticator Login `ga_login`](https://www.drupal.org/project/ga_login)
+- WordPress [`wp-two-factor-auth`](https://github.com/sjinks/wp-two-factor-auth)
+- WordPress [Simple 2FA `simple-2fa`](https://wordpress.org/plugins/simple-2fa/)
+- WoltLab Suite [two-step-verification](http://pluginstore.woltlab.com/file/3007-two-step-verification/)
+- [Cachet](https://github.com/CachetHQ/Cachet)
+- [Appwrite](https://github.com/appwrite/appwrite)
+- other uses: [dependents](https://github.com/chillerlan/php-qrcode/network/dependents) / [packages](https://github.com/chillerlan/php-qrcode/network/dependents?dependent_type=PACKAGE)
+
+
+Hi, please check out my other projects that are way cooler than qrcodes!
+
+- [php-oauth-core](https://github.com/chillerlan/php-oauth-core) - an OAuth 1/2 client library along with a bunch of [providers](https://github.com/chillerlan/php-oauth-providers)
+- [php-httpinterface](https://github.com/chillerlan/php-httpinterface) - a PSR-7/15/17/18 implemetation
+- [php-database](https://github.com/chillerlan/php-database) - a database client & querybuilder for MySQL, Postgres, SQLite, MSSQL, Firebird
+
diff --git a/vendor/chillerlan/php-qrcode/composer.json b/vendor/chillerlan/php-qrcode/composer.json
new file mode 100644
index 000000000..c2299a350
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/composer.json
@@ -0,0 +1,51 @@
+{
+ "name": "chillerlan/php-qrcode",
+ "description": "A QR code generator. PHP 7.2+",
+ "homepage": "https://github.com/chillerlan/php-qrcode",
+ "license": "MIT",
+ "minimum-stability": "stable",
+ "type": "library",
+ "keywords": [
+ "QR code", "qrcode", "qr", "qrcode-generator", "phpqrcode"
+ ],
+ "authors": [
+ {
+ "name": "Kazuhiko Arase",
+ "homepage": "https://github.com/kazuhikoarase"
+ },
+ {
+ "name": "Smiley",
+ "email": "[email protected]",
+ "homepage": "https://github.com/codemasher"
+ },
+ {
+ "name": "Contributors",
+ "homepage":"https://github.com/chillerlan/php-qrcode/graphs/contributors"
+ }
+ ],
+ "require": {
+ "php": "^7.2",
+ "ext-mbstring": "*",
+ "chillerlan/php-settings-container": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5",
+ "setasign/fpdf": "^1.8.2"
+ },
+ "suggest": {
+ "chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.",
+ "setasign/fpdf": "Required to use the QR FPDF output."
+ },
+ "autoload": {
+ "psr-4": {
+ "chillerlan\\QRCode\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "chillerlan\\QRCodePublic\\": "public/",
+ "chillerlan\\QRCodeTest\\": "tests/",
+ "chillerlan\\QRCodeExamples\\": "examples/"
+ }
+ }
+}
diff --git a/vendor/chillerlan/php-qrcode/examples/MyCustomOutput.php b/vendor/chillerlan/php-qrcode/examples/MyCustomOutput.php
new file mode 100644
index 000000000..3c01f8646
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/MyCustomOutput.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Class MyCustomOutput
+ *
+ * @filesource MyCustomOutput.php
+ * @created 24.12.2017
+ * @package chillerlan\QRCodeExamples
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\Output\QROutputAbstract;
+
+class MyCustomOutput extends QROutputAbstract{
+
+ protected function setModuleValues():void{
+ // TODO: Implement setModuleValues() method.
+ }
+
+ public function dump(string $file = null){
+
+ $output = '';
+
+ for($row = 0; $row < $this->moduleCount; $row++){
+ for($col = 0; $col < $this->moduleCount; $col++){
+ $output .= (int)$this->matrix->check($col, $row);
+ }
+ }
+
+ return $output;
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/examples/QRImageWithLogo.php b/vendor/chillerlan/php-qrcode/examples/QRImageWithLogo.php
new file mode 100644
index 000000000..f9d94ae34
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/QRImageWithLogo.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Class QRImageWithLogo
+ *
+ * @filesource QRImageWithLogo.php
+ * @created 18.11.2020
+ * @package chillerlan\QRCodeExamples
+ * @author smiley <[email protected]>
+ * @copyright 2020 smiley
+ * @license MIT
+ *
+ * @noinspection PhpComposerExtensionStubsInspection
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\Output\{QRCodeOutputException, QRImage};
+
+use function imagecopyresampled, imagecreatefrompng, imagesx, imagesy, is_file, is_readable;
+
+/**
+ * @property \chillerlan\QRCodeExamples\LogoOptions $options
+ */
+class QRImageWithLogo extends QRImage{
+
+ /**
+ * @param string|null $file
+ * @param string|null $logo
+ *
+ * @return string
+ * @throws \chillerlan\QRCode\Output\QRCodeOutputException
+ */
+ public function dump(string $file = null, string $logo = null):string{
+ // set returnResource to true to skip further processing for now
+ $this->options->returnResource = true;
+
+ // of course you could accept other formats too (such as resource or Imagick)
+ // i'm not checking for the file type either for simplicity reasons (assuming PNG)
+ if(!is_file($logo) || !is_readable($logo)){
+ throw new QRCodeOutputException('invalid logo');
+ }
+
+ $this->matrix->setLogoSpace(
+ $this->options->logoWidth,
+ $this->options->logoHeight
+ // not utilizing the position here
+ );
+
+ // there's no need to save the result of dump() into $this->image here
+ parent::dump($file);
+
+ $im = imagecreatefrompng($logo);
+
+ // get logo image size
+ $w = imagesx($im);
+ $h = imagesy($im);
+
+ // set new logo size, leave a border of 1 module
+ $lw = ($this->options->logoWidth - 2) * $this->options->scale;
+ $lh = ($this->options->logoHeight - 2) * $this->options->scale;
+
+ // get the qrcode size
+ $ql = $this->matrix->size() * $this->options->scale;
+
+ // scale the logo and copy it over. done!
+ imagecopyresampled($this->image, $im, ($ql - $lw) / 2, ($ql - $lh) / 2, 0, 0, $lw, $lh, $w, $h);
+
+ $imageData = $this->dumpImage();
+
+ if($file !== null){
+ $this->saveToFile($imageData, $file);
+ }
+
+ if($this->options->imageBase64){
+ $imageData = 'data:image/'.$this->options->outputType.';base64,'.base64_encode($imageData);
+ }
+
+ return $imageData;
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/examples/QRImageWithText.php b/vendor/chillerlan/php-qrcode/examples/QRImageWithText.php
new file mode 100644
index 000000000..5ca572f30
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/QRImageWithText.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Class QRImageWithText
+ *
+ * example for additional text
+ *
+ * @link https://github.com/chillerlan/php-qrcode/issues/35
+ *
+ * @filesource QRImageWithText.php
+ * @created 22.06.2019
+ * @package chillerlan\QRCodeExamples
+ * @author smiley <[email protected]>
+ * @copyright 2019 smiley
+ * @license MIT
+ *
+ * @noinspection PhpComposerExtensionStubsInspection
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\Output\QRImage;
+use function base64_encode, imagechar, imagecolorallocate, imagecolortransparent, imagecopymerge, imagecreatetruecolor,
+ imagedestroy, imagefilledrectangle, imagefontwidth, in_array, round, str_split, strlen;
+
+class QRImageWithText extends QRImage{
+
+ /**
+ * @param string|null $file
+ * @param string|null $text
+ *
+ * @return string
+ */
+ public function dump(string $file = null, string $text = null):string{
+ $this->image = imagecreatetruecolor($this->length, $this->length);
+ $background = imagecolorallocate($this->image, ...$this->options->imageTransparencyBG);
+
+ if((bool)$this->options->imageTransparent && in_array($this->options->outputType, $this::TRANSPARENCY_TYPES, true)){
+ imagecolortransparent($this->image, $background);
+ }
+
+ imagefilledrectangle($this->image, 0, 0, $this->length, $this->length, $background);
+
+ foreach($this->matrix->matrix() as $y => $row){
+ foreach($row as $x => $M_TYPE){
+ $this->setPixel($x, $y, $this->moduleValues[$M_TYPE]);
+ }
+ }
+
+ // render text output if a string is given
+ if($text !== null){
+ $this->addText($text);
+ }
+
+ $imageData = $this->dumpImage($file);
+
+ if((bool)$this->options->imageBase64){
+ $imageData = 'data:image/'.$this->options->outputType.';base64,'.base64_encode($imageData);
+ }
+
+ return $imageData;
+ }
+
+ /**
+ * @param string $text
+ */
+ protected function addText(string $text):void{
+ // save the qrcode image
+ $qrcode = $this->image;
+
+ // options things
+ $textSize = 3; // see imagefontheight() and imagefontwidth()
+ $textBG = [200, 200, 200];
+ $textColor = [50, 50, 50];
+
+ $bgWidth = $this->length;
+ $bgHeight = $bgWidth + 20; // 20px extra space
+
+ // create a new image with additional space
+ $this->image = imagecreatetruecolor($bgWidth, $bgHeight);
+ $background = imagecolorallocate($this->image, ...$textBG);
+
+ // allow transparency
+ if((bool)$this->options->imageTransparent && in_array($this->options->outputType, $this::TRANSPARENCY_TYPES, true)){
+ imagecolortransparent($this->image, $background);
+ }
+
+ // fill the background
+ imagefilledrectangle($this->image, 0, 0, $bgWidth, $bgHeight, $background);
+
+ // copy over the qrcode
+ imagecopymerge($this->image, $qrcode, 0, 0, 0, 0, $this->length, $this->length, 100);
+ imagedestroy($qrcode);
+
+ $fontColor = imagecolorallocate($this->image, ...$textColor);
+ $w = imagefontwidth($textSize);
+ $x = round(($bgWidth - strlen($text) * $w) / 2);
+
+ // loop through the string and draw the letters
+ foreach(str_split($text) as $i => $chr){
+ imagechar($this->image, $textSize, $i * $w + $x, $this->length, $chr, $fontColor);
+ }
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/examples/custom_output.php b/vendor/chillerlan/php-qrcode/examples/custom_output.php
new file mode 100644
index 000000000..71ea62682
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/custom_output.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ *
+ * @filesource custom_output.php
+ * @created 24.12.2017
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+
+// invoke the QROutputInterface manually
+$options = new QROptions([
+ 'version' => 5,
+ 'eccLevel' => QRCode::ECC_L,
+]);
+
+$qrOutputInterface = new MyCustomOutput($options, (new QRCode($options))->getMatrix($data));
+
+var_dump($qrOutputInterface->dump());
+
+
+// or just
+$options = new QROptions([
+ 'version' => 5,
+ 'eccLevel' => QRCode::ECC_L,
+ 'outputType' => QRCode::OUTPUT_CUSTOM,
+ 'outputInterface' => MyCustomOutput::class,
+]);
+
+var_dump((new QRCode($options))->render($data));
diff --git a/vendor/chillerlan/php-qrcode/examples/example_image.png b/vendor/chillerlan/php-qrcode/examples/example_image.png
new file mode 100644
index 000000000..b4a80f2ab
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/example_image.png
Binary files differ
diff --git a/vendor/chillerlan/php-qrcode/examples/example_svg.png b/vendor/chillerlan/php-qrcode/examples/example_svg.png
new file mode 100644
index 000000000..f1e7b32f7
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/example_svg.png
Binary files differ
diff --git a/vendor/chillerlan/php-qrcode/examples/fpdf.php b/vendor/chillerlan/php-qrcode/examples/fpdf.php
new file mode 100644
index 000000000..9c690a7f7
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/fpdf.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once __DIR__ . '/../vendor/autoload.php';
+
+$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+
+$options = new QROptions([
+ 'version' => 7,
+ 'outputType' => QRCode::OUTPUT_FPDF,
+ 'eccLevel' => QRCode::ECC_L,
+ 'scale' => 5,
+ 'imageBase64' => false,
+ 'moduleValues' => [
+ // finder
+ 1536 => [0, 63, 255], // dark (true)
+ 6 => [255, 255, 255], // light (false), white is the transparency color and is enabled by default
+ // alignment
+ 2560 => [255, 0, 255],
+ 10 => [255, 255, 255],
+ // timing
+ 3072 => [255, 0, 0],
+ 12 => [255, 255, 255],
+ // format
+ 3584 => [67, 191, 84],
+ 14 => [255, 255, 255],
+ // version
+ 4096 => [62, 174, 190],
+ 16 => [255, 255, 255],
+ // data
+ 1024 => [0, 0, 0],
+ 4 => [255, 255, 255],
+ // darkmodule
+ 512 => [0, 0, 0],
+ // separator
+ 8 => [255, 255, 255],
+ // quietzone
+ 18 => [255, 255, 255],
+ ],
+]);
+
+\header('Content-type: application/pdf');
+
+echo (new QRCode($options))->render($data);
diff --git a/vendor/chillerlan/php-qrcode/examples/html.php b/vendor/chillerlan/php-qrcode/examples/html.php
new file mode 100644
index 000000000..aa5305d24
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/html.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ *
+ * @filesource html.php
+ * @created 21.12.2017
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once '../vendor/autoload.php';
+
+header('Content-Type: text/html; charset=utf-8');
+
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
+ <title>QRCode test</title>
+ <style>
+ body{
+ margin: 5em;
+ padding: 0;
+ }
+
+ div.qrcode{
+ margin: 0;
+ padding: 0;
+ }
+
+ /* rows */
+ div.qrcode > div {
+ margin: 0;
+ padding: 0;
+ height: 10px;
+ }
+
+ /* modules */
+ div.qrcode > div > span {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ }
+
+ div.qrcode > div > span {
+ background-color: #ccc;
+ }
+ </style>
+</head>
+<body>
+ <div class="qrcode">
+<?php
+
+ $data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+
+ $options = new QROptions([
+ 'version' => 5,
+ 'outputType' => QRCode::OUTPUT_MARKUP_HTML,
+ 'eccLevel' => QRCode::ECC_L,
+ 'moduleValues' => [
+ // finder
+ 1536 => '#A71111', // dark (true)
+ 6 => '#FFBFBF', // light (false)
+ // alignment
+ 2560 => '#A70364',
+ 10 => '#FFC9C9',
+ // timing
+ 3072 => '#98005D',
+ 12 => '#FFB8E9',
+ // format
+ 3584 => '#003804',
+ 14 => '#00FB12',
+ // version
+ 4096 => '#650098',
+ 16 => '#E0B8FF',
+ // data
+ 1024 => '#4A6000',
+ 4 => '#ECF9BE',
+ // darkmodule
+ 512 => '#080063',
+ // separator
+ 8 => '#AFBFBF',
+ // quietzone
+ 18 => '#FFFFFF',
+ ],
+ ]);
+
+ echo (new QRCode($options))->render($data);
+
+?>
+ </div>
+</body>
+</html>
+
+
+
diff --git a/vendor/chillerlan/php-qrcode/examples/image.php b/vendor/chillerlan/php-qrcode/examples/image.php
new file mode 100644
index 000000000..89ba2a9a8
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/image.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ *
+ * @filesource image.php
+ * @created 24.12.2017
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+
+$options = new QROptions([
+ 'version' => 7,
+ 'outputType' => QRCode::OUTPUT_IMAGE_PNG,
+ 'eccLevel' => QRCode::ECC_L,
+ 'scale' => 5,
+ 'imageBase64' => false,
+ 'moduleValues' => [
+ // finder
+ 1536 => [0, 63, 255], // dark (true)
+ 6 => [255, 255, 255], // light (false), white is the transparency color and is enabled by default
+ // alignment
+ 2560 => [255, 0, 255],
+ 10 => [255, 255, 255],
+ // timing
+ 3072 => [255, 0, 0],
+ 12 => [255, 255, 255],
+ // format
+ 3584 => [67, 191, 84],
+ 14 => [255, 255, 255],
+ // version
+ 4096 => [62, 174, 190],
+ 16 => [255, 255, 255],
+ // data
+ 1024 => [0, 0, 0],
+ 4 => [255, 255, 255],
+ // darkmodule
+ 512 => [0, 0, 0],
+ // separator
+ 8 => [255, 255, 255],
+ // quietzone
+ 18 => [255, 255, 255],
+ ],
+]);
+
+header('Content-type: image/png');
+
+echo (new QRCode($options))->render($data);
+
+
+
+
+
diff --git a/vendor/chillerlan/php-qrcode/examples/imageWithLogo.php b/vendor/chillerlan/php-qrcode/examples/imageWithLogo.php
new file mode 100644
index 000000000..987e10c11
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/imageWithLogo.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ *
+ * @filesource imageWithLogo.php
+ * @created 18.11.2020
+ * @author smiley <[email protected]>
+ * @copyright 2020 smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+/**
+ * @property int $logoWidth
+ * @property int $logoHeight
+ *
+ * @noinspection PhpIllegalPsrClassPathInspection
+ */
+class LogoOptions extends QROptions{
+ protected $logoWidth;
+ protected $logoHeight;
+}
+
+$options = new LogoOptions;
+
+$options->version = 7;
+$options->eccLevel = QRCode::ECC_H;
+$options->imageBase64 = false;
+$options->logoWidth = 13;
+$options->logoHeight = 13;
+$options->scale = 5;
+$options->imageTransparent = false;
+
+header('Content-type: image/png');
+
+$qrOutputInterface = new QRImageWithLogo($options, (new QRCode($options))->getMatrix($data));
+
+// dump the output, with an additional logo
+echo $qrOutputInterface->dump(null, __DIR__.'/octocat.png');
diff --git a/vendor/chillerlan/php-qrcode/examples/imageWithText.php b/vendor/chillerlan/php-qrcode/examples/imageWithText.php
new file mode 100644
index 000000000..050781cba
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/imageWithText.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * example for additional text
+ * @link https://github.com/chillerlan/php-qrcode/issues/35
+ *
+ * @filesource imageWithText.php
+ * @created 22.06.2019
+ * @author Smiley <[email protected]>
+ * @copyright 2019 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+
+$options = new QROptions([
+ 'version' => 7,
+ 'outputType' => QRCode::OUTPUT_IMAGE_PNG,
+ 'scale' => 3,
+ 'imageBase64' => false,
+]);
+
+header('Content-type: image/png');
+
+$qrOutputInterface = new QRImageWithText($options, (new QRCode($options))->getMatrix($data));
+
+// dump the output, with additional text
+echo $qrOutputInterface->dump(null, 'example text');
diff --git a/vendor/chillerlan/php-qrcode/examples/imagick.php b/vendor/chillerlan/php-qrcode/examples/imagick.php
new file mode 100644
index 000000000..6bec4d02e
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/imagick.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ *
+ * @filesource image.php
+ * @created 24.12.2017
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+
+$options = new QROptions([
+ 'version' => 7,
+ 'outputType' => QRCode::OUTPUT_IMAGICK,
+ 'eccLevel' => QRCode::ECC_L,
+ 'scale' => 5,
+ 'moduleValues' => [
+ // finder
+ 1536 => '#A71111', // dark (true)
+ 6 => '#FFBFBF', // light (false)
+ // alignment
+ 2560 => '#A70364',
+ 10 => '#FFC9C9',
+ // timing
+ 3072 => '#98005D',
+ 12 => '#FFB8E9',
+ // format
+ 3584 => '#003804',
+ 14 => '#00FB12',
+ // version
+ 4096 => '#650098',
+ 16 => '#E0B8FF',
+ // data
+ 1024 => '#4A6000',
+ 4 => '#ECF9BE',
+ // darkmodule
+ 512 => '#080063',
+ // separator
+ 8 => '#DDDDDD',
+ // quietzone
+ 18 => '#DDDDDD',
+ ],
+]);
+
+header('Content-type: image/png');
+
+echo (new QRCode($options))->render($data);
+
+
+
+
+
diff --git a/vendor/chillerlan/php-qrcode/examples/octocat.png b/vendor/chillerlan/php-qrcode/examples/octocat.png
new file mode 100644
index 000000000..f9050b935
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/octocat.png
Binary files differ
diff --git a/vendor/chillerlan/php-qrcode/examples/svg.php b/vendor/chillerlan/php-qrcode/examples/svg.php
new file mode 100644
index 000000000..a7a159d70
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/svg.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ *
+ * @filesource svg.php
+ * @created 21.12.2017
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+$gzip = true;
+
+$options = new QROptions([
+ 'version' => 7,
+ 'outputType' => QRCode::OUTPUT_MARKUP_SVG,
+ 'eccLevel' => QRCode::ECC_L,
+ 'svgViewBoxSize' => 530,
+ 'addQuietzone' => true,
+ 'cssClass' => 'my-css-class',
+ 'svgOpacity' => 1.0,
+ 'svgDefs' => '
+ <linearGradient id="g2">
+ <stop offset="0%" stop-color="#39F" />
+ <stop offset="100%" stop-color="#F3F" />
+ </linearGradient>
+ <linearGradient id="g1">
+ <stop offset="0%" stop-color="#F3F" />
+ <stop offset="100%" stop-color="#39F" />
+ </linearGradient>
+ <style>rect{shape-rendering:crispEdges}</style>',
+ 'moduleValues' => [
+ // finder
+ 1536 => 'url(#g1)', // dark (true)
+ 6 => '#fff', // light (false)
+ // alignment
+ 2560 => 'url(#g1)',
+ 10 => '#fff',
+ // timing
+ 3072 => 'url(#g1)',
+ 12 => '#fff',
+ // format
+ 3584 => 'url(#g1)',
+ 14 => '#fff',
+ // version
+ 4096 => 'url(#g1)',
+ 16 => '#fff',
+ // data
+ 1024 => 'url(#g2)',
+ 4 => '#fff',
+ // darkmodule
+ 512 => 'url(#g1)',
+ // separator
+ 8 => '#fff',
+ // quietzone
+ 18 => '#fff',
+ ],
+]);
+
+$qrcode = (new QRCode($options))->render($data);
+
+header('Content-type: image/svg+xml');
+
+if($gzip === true){
+ header('Vary: Accept-Encoding');
+ header('Content-Encoding: gzip');
+ $qrcode = gzencode($qrcode ,9);
+}
+echo $qrcode;
+
+
diff --git a/vendor/chillerlan/php-qrcode/examples/text.php b/vendor/chillerlan/php-qrcode/examples/text.php
new file mode 100644
index 000000000..9bdf154f0
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/examples/text.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ *
+ * @filesource text.php
+ * @created 21.12.2017
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeExamples;
+
+use chillerlan\QRCode\{QRCode, QROptions};
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
+
+$options = new QROptions([
+ 'version' => 5,
+ 'outputType' => QRCode::OUTPUT_STRING_TEXT,
+ 'eccLevel' => QRCode::ECC_L,
+]);
+
+// <pre> to view it in a browser
+echo '<pre style="font-size: 75%; line-height: 1;">'.(new QRCode($options))->render($data).'</pre>';
+
+
+// custom values
+$options = new QROptions([
+ 'version' => 5,
+ 'outputType' => QRCode::OUTPUT_STRING_TEXT,
+ 'eccLevel' => QRCode::ECC_L,
+ 'moduleValues' => [
+ // finder
+ 1536 => 'A', // dark (true)
+ 6 => 'a', // light (false)
+ // alignment
+ 2560 => 'B',
+ 10 => 'b',
+ // timing
+ 3072 => 'C',
+ 12 => 'c',
+ // format
+ 3584 => 'D',
+ 14 => 'd',
+ // version
+ 4096 => 'E',
+ 16 => 'e',
+ // data
+ 1024 => 'F',
+ 4 => 'f',
+ // darkmodule
+ 512 => 'G',
+ // separator
+ 8 => 'h',
+ // quietzone
+ 18 => 'i',
+ ],
+]);
+
+// <pre> to view it in a browser
+echo '<pre style="font-size: 75%; line-height: 1;">'.(new QRCode($options))->render($data).'</pre>';
+
+
+
+
+
diff --git a/vendor/chillerlan/php-qrcode/phpdoc.xml b/vendor/chillerlan/php-qrcode/phpdoc.xml
new file mode 100644
index 000000000..d191e98ee
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/phpdoc.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<phpdoc>
+ <parser>
+ <target>public/docs</target>
+ </parser>
+ <transformer>
+ <target>public/docs</target>
+ </transformer>
+ <files>
+ <directory>src</directory>
+ </files>
+ <transformations>
+ <template name="responsive-twig"/>
+ </transformations>
+</phpdoc> \ No newline at end of file
diff --git a/vendor/chillerlan/php-qrcode/phpmd.xml b/vendor/chillerlan/php-qrcode/phpmd.xml
new file mode 100644
index 000000000..a70f7e3a1
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/phpmd.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<ruleset name="codemasher/php-qrcode PMD ruleset"
+ xmlns="http://pmd.sf.net/ruleset/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
+ xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
+ <description>codemasher/php-qrcode PMD ruleset</description>
+ <exclude-pattern>*/examples/*</exclude-pattern>
+ <exclude-pattern>*/tests/*</exclude-pattern>
+ <rule ref="rulesets/cleancode.xml">
+ <exclude name="BooleanArgumentFlag"/>
+ </rule>
+ <rule ref="rulesets/codesize.xml/CyclomaticComplexity">
+ <priority>1</priority>
+ <properties>
+ <property name="maximum" value="200" />
+ </properties>
+ </rule>
+ <rule ref="rulesets/controversial.xml">
+ <exclude name="CamelCaseMethodName"/>
+ <exclude name="CamelCasePropertyName"/>
+ <exclude name="CamelCaseParameterName"/>
+ <exclude name="CamelCaseVariableName"/>
+ </rule>
+ <rule ref="rulesets/design.xml">
+ </rule>
+ <rule ref="rulesets/naming.xml">
+ <exclude name="LongVariable"/>
+ <exclude name="ShortVariable"/>
+ </rule>
+ <rule ref="rulesets/unusedcode.xml">
+ <exclude name="UnusedFormalParameter"/>
+ </rule>
+</ruleset>
diff --git a/vendor/chillerlan/php-qrcode/phpunit.xml b/vendor/chillerlan/php-qrcode/phpunit.xml
new file mode 100644
index 000000000..3a9b678d2
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/phpunit.xml
@@ -0,0 +1,23 @@
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
+ bootstrap="vendor/autoload.php"
+ cacheResultFile=".build/phpunit.result.cache"
+ colors="true"
+ verbose="true"
+>
+ <filter>
+ <whitelist processUncoveredFilesFromWhitelist="true">
+ <directory suffix=".php">./src</directory>
+ </whitelist>
+ </filter>
+ <testsuites>
+ <testsuite name="php-qrcode test suite">
+ <directory suffix=".php">./tests/</directory>
+ </testsuite>
+ </testsuites>
+ <logging>
+ <log type="coverage-clover" target=".build/coverage/clover.xml"/>
+ <log type="coverage-xml" target=".build/coverage/coverage-xml"/>
+ <log type="junit" target=".build/logs/junit.xml"/>
+ </logging>
+</phpunit>
diff --git a/vendor/chillerlan/php-qrcode/public/index.html b/vendor/chillerlan/php-qrcode/public/index.html
new file mode 100644
index 000000000..d7bf6c891
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/public/index.html
@@ -0,0 +1,163 @@
+<!DOCTYPE html>
+<html lang="en" >
+<head >
+ <meta charset="UTF-8" >
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title >QR Code Generator</title >
+ <style >
+ body{ font-size: 20px; line-height: 1.4em; font-family: "Trebuchet MS", sans-serif; color: #000;}
+ input, textarea, select{font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 75%; line-height: 1.25em; border: 1px solid #aaa; }
+ input:focus, textarea:focus, select:focus{ border: 1px solid #ccc; }
+ label{ cursor: pointer; }
+ #qrcode-settings, div#qrcode-output{ text-align: center; }
+ div#qrcode-output > div {margin: 0;padding: 0;height: 3px;}
+ div#qrcode-output > div > span {display: inline-block;width: 3px;height: 3px;}
+ div#qrcode-output > div > span {background-color: lightgrey;}
+ </style >
+</head >
+<body >
+
+<form id="qrcode-settings" >
+
+ <label for="inputstring" >Input String</label ><br /><textarea name="inputstring" id="inputstring" cols="80" rows="3" autocomplete="off" spellcheck="false"></textarea ><br />
+
+ <label for="version" >Version</label >
+ <input id="version" name="version" class="options" type="number" min="1" max="40" value="5" placeholder="version" />
+
+ <label for="maskpattern" >Mask Pattern</label >
+ <input id="maskpattern" name="maskpattern" class="options" type="number" min="-1" max="7" value="-1" placeholder="mask pattern" />
+
+ <label for="ecc" >ECC</label >
+ <select class="options" id="ecc" name="ecc" >
+ <option value="L" selected="selected" >L - 7%</option >
+ <option value="M" >M - 15%</option >
+ <option value="Q" >Q - 25%</option >
+ <option value="H" >H - 30%</option >
+ </select >
+
+ <br />
+
+ <label for="quietzone" >Quiet Zone
+ <input id="quietzone" name="quietzone" class="options" type="checkbox" value="true" />
+ </label >
+
+ <label for="quietzonesize" >size</label >
+ <input id="quietzonesize" name="quietzonesize" class="options" type="number" min="0" max="100" value="4" placeholder="quiet zone" />
+
+ <br />
+
+ <label for="output_type" >Output</label >
+ <select class="options" id="output_type" name="output_type" >
+ <option value="html" >Markup - HTML</option >
+ <option value="svg" selected="selected" >Markup - SVG</option >
+ <option value="png">Image - png</option >
+ <option value="jpg" >Image - jpg</option >
+ <option value="gif" >Image - gif</option >
+ <option value="text" >String - text</option >
+ <option value="json" >String - json</option >
+ </select >
+
+ <label for="scale" >scale</label >
+ <input id="scale" name="scale" class="options" type="number" min="1" max="10" value="5" placeholder="scale" />
+
+ <div>Finder</div>
+ <label for="m_finder_light" >
+ <input type="text" id="m_finder_light" name="m_finder_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+ <label for="m_finder_dark" >
+ <input type="text" id="m_finder_dark" name="m_finder_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+
+ <div>Alignment</div>
+ <label for="m_alignment_light" >
+ <input type="text" id="m_alignment_light" name="m_alignment_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+ <label for="m_alignment_dark" >
+ <input type="text" id="m_alignment_dark" name="m_alignment_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+
+ <div>Timing</div>
+ <label for="m_timing_light" >
+ <input type="text" id="m_timing_light" name="m_timing_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+ <label for="m_timing_dark" >
+ <input type="text" id="m_timing_dark" name="m_timing_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+
+ <div>Format</div>
+ <label for="m_format_light" >
+ <input type="text" id="m_format_light" name="m_format_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+ <label for="m_format_dark" >
+ <input type="text" id="m_format_dark" name="m_format_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+
+ <div>Version</div>
+ <label for="m_version_light" >
+ <input type="text" id="m_version_light" name="m_version_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+ <label for="m_version_dark" >
+ <input type="text" id="m_version_dark" name="m_version_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+
+ <div>Data</div>
+ <label for="m_data_light" >
+ <input type="text" id="m_data_light" name="m_data_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+ <label for="m_data_dark" >
+ <input type="text" id="m_data_dark" name="m_data_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+
+ <div>Dark Module</div>
+ <label for="m_darkmodule_light" >
+ <input disabled="disabled" type="text" id="m_darkmodule_light" class="options" value="" autocomplete="off" spellcheck="false" />
+ </label >
+ <label for="m_darkmodule_dark" >
+ <input type="text" id="m_darkmodule_dark" name="m_darkmodule_dark" class="jscolor options" value="000000" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+
+ <div>Separator</div>
+ <label for="m_separator_light" >
+ <input type="text" id="m_separator_light" name="m_separator_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+ <label for="m_separator_dark" >
+ <input disabled="disabled" type="text" id="m_separator_dark" class="options" value="" autocomplete="off" spellcheck="false" />
+ </label >
+
+ <div>Quiet Zone</div>
+ <label for="m_quietzone_light" >
+ <input type="text" id="m_quietzone_light" name="m_quietzone_light" class="jscolor options" value="ffffff" autocomplete="off" spellcheck="false" minlength="6" maxlength="6" />
+ </label >
+ <label for="m_quietzone_dark" >
+ <input disabled="disabled" type="text" id="m_quietzone_dark" class="options" value="" autocomplete="off" spellcheck="false" />
+ </label >
+
+ <br />
+ <button type="submit" >generate</button >
+</form >
+<div id="qrcode-output" ></div >
+
+<div><a href="https://play.google.com/store/apps/details?id=com.google.zxing.client.android" >ZXing Barcode Scanner</a ></div>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.3/prototype.js" ></script >
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.js" ></script >
+<script >
+ ((form, output, url) => {
+
+ $(form).observe('submit', ev => {
+ Event.stop(ev);
+
+ new Ajax.Request(url, {
+ method: 'post',
+ parameters: ev.target.serialize(true),
+ onUninitialized: $(output).update(),
+ onLoading: $(output).update('[portlandia_screaming.gif]'),
+ onFailure: response => $(output).update(response.responseJSON.error),
+ onSuccess: response => $(output).update(response.responseJSON.qrcode),
+ });
+
+ });
+ })('qrcode-settings', 'qrcode-output', './qrcode.php');
+</script >
+
+</body >
+</html > \ No newline at end of file
diff --git a/vendor/chillerlan/php-qrcode/public/qrcode.php b/vendor/chillerlan/php-qrcode/public/qrcode.php
new file mode 100644
index 000000000..1f8427c7e
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/public/qrcode.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * @filesource qrcode.php
+ * @created 18.11.2017
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodePublic;
+
+use chillerlan\QRCode\QRCode;
+use chillerlan\QRCode\QROptions;
+
+require_once '../vendor/autoload.php';
+
+try{
+
+ $moduleValues = [
+ // finder
+ 1536 => $_POST['m_finder_dark'],
+ 6 => $_POST['m_finder_light'],
+ // alignment
+ 2560 => $_POST['m_alignment_dark'],
+ 10 => $_POST['m_alignment_light'],
+ // timing
+ 3072 => $_POST['m_timing_dark'],
+ 12 => $_POST['m_timing_light'],
+ // format
+ 3584 => $_POST['m_format_dark'],
+ 14 => $_POST['m_format_light'],
+ // version
+ 4096 => $_POST['m_version_dark'],
+ 16 => $_POST['m_version_light'],
+ // data
+ 1024 => $_POST['m_data_dark'],
+ 4 => $_POST['m_data_light'],
+ // darkmodule
+ 512 => $_POST['m_darkmodule_dark'],
+ // separator
+ 8 => $_POST['m_separator_light'],
+ // quietzone
+ 18 => $_POST['m_quietzone_light'],
+ ];
+
+ $moduleValues = array_map(function($v){
+ if(preg_match('/[a-f\d]{6}/i', $v) === 1){
+ return in_array($_POST['output_type'], ['png', 'jpg', 'gif'])
+ ? array_map('hexdec', str_split($v, 2))
+ : '#'.$v ;
+ }
+ return null;
+ }, $moduleValues);
+
+
+ $ecc = in_array($_POST['ecc'], ['L', 'M', 'Q', 'H'], true) ? $_POST['ecc'] : 'L';
+
+ $qro = new QROptions;
+
+ $qro->version = (int)$_POST['version'];
+ $qro->eccLevel = constant('chillerlan\\QRCode\\QRCode::ECC_'.$ecc);
+ $qro->maskPattern = (int)$_POST['maskpattern'];
+ $qro->addQuietzone = isset($_POST['quietzone']);
+ $qro->quietzoneSize = (int)$_POST['quietzonesize'];
+ $qro->moduleValues = $moduleValues;
+ $qro->outputType = $_POST['output_type'];
+ $qro->scale = (int)$_POST['scale'];
+ $qro->imageTransparent = false;
+
+ $qrcode = (new QRCode($qro))->render($_POST['inputstring']);
+
+ if(in_array($_POST['output_type'], ['png', 'jpg', 'gif'])){
+ $qrcode = '<img src="'.$qrcode.'" />';
+ }
+ elseif($_POST['output_type'] === 'text'){
+ $qrcode = '<pre style="font-size: 75%; line-height: 1;">'.$qrcode.'</pre>';
+ }
+ elseif($_POST['output_type'] === 'json'){
+ $qrcode = '<pre style="font-size: 75%; overflow-x: auto;">'.$qrcode.'</pre>';
+ }
+
+ send_response(['qrcode' => $qrcode]);
+}
+// Pokémon exception handler
+catch(\Exception $e){
+ header('HTTP/1.1 500 Internal Server Error');
+ send_response(['error' => $e->getMessage()]);
+}
+
+/**
+ * @param array $response
+ */
+function send_response(array $response){
+ header('Content-type: application/json;charset=utf-8;');
+ echo json_encode($response);
+ exit;
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Data/AlphaNum.php b/vendor/chillerlan/php-qrcode/src/Data/AlphaNum.php
new file mode 100644
index 000000000..c6d34e76f
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Data/AlphaNum.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Class AlphaNum
+ *
+ * @filesource AlphaNum.php
+ * @created 25.11.2015
+ * @package chillerlan\QRCode\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Data;
+
+use chillerlan\QRCode\QRCode;
+
+use function array_search, ord, sprintf;
+
+/**
+ * Alphanumeric mode: 0 to 9, A to Z, space, $ % * + - . / :
+ */
+class AlphaNum extends QRDataAbstract{
+
+ /**
+ * @inheritdoc
+ */
+ protected $datamode = QRCode::DATA_ALPHANUM;
+
+ /**
+ * @inheritdoc
+ */
+ protected $lengthBits = [9, 11, 13];
+
+ /**
+ * @inheritdoc
+ */
+ protected function write(string $data):void{
+
+ for($i = 0; $i + 1 < $this->strlen; $i += 2){
+ $this->bitBuffer->put($this->getCharCode($data[$i]) * 45 + $this->getCharCode($data[$i + 1]), 11);
+ }
+
+ if($i < $this->strlen){
+ $this->bitBuffer->put($this->getCharCode($data[$i]), 6);
+ }
+
+ }
+
+ /**
+ * @param string $chr
+ *
+ * @return int
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ protected function getCharCode(string $chr):int{
+ $i = array_search($chr, $this::ALPHANUM_CHAR_MAP);
+
+ if($i !== false){
+ return $i;
+ }
+
+ throw new QRCodeDataException(sprintf('illegal char: "%s" [%d]', $chr, ord($chr)));
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Data/Byte.php b/vendor/chillerlan/php-qrcode/src/Data/Byte.php
new file mode 100644
index 000000000..f1955645a
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Data/Byte.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Class Byte
+ *
+ * @filesource Byte.php
+ * @created 25.11.2015
+ * @package chillerlan\QRCode\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Data;
+
+use chillerlan\QRCode\QRCode;
+
+use function ord;
+
+/**
+ * Byte mode, ISO-8859-1 or UTF-8
+ */
+class Byte extends QRDataAbstract{
+
+ /**
+ * @inheritdoc
+ */
+ protected $datamode = QRCode::DATA_BYTE;
+
+ /**
+ * @inheritdoc
+ */
+ protected $lengthBits = [8, 16, 16];
+
+ /**
+ * @inheritdoc
+ */
+ protected function write(string $data):void{
+ $i = 0;
+
+ while($i < $this->strlen){
+ $this->bitBuffer->put(ord($data[$i]), 8);
+ $i++;
+ }
+
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Data/Kanji.php b/vendor/chillerlan/php-qrcode/src/Data/Kanji.php
new file mode 100644
index 000000000..ce600d4ff
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Data/Kanji.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Class Kanji
+ *
+ * @filesource Kanji.php
+ * @created 25.11.2015
+ * @package chillerlan\QRCode\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Data;
+
+use chillerlan\QRCode\QRCode;
+
+use function mb_strlen, ord, sprintf, strlen;
+
+/**
+ * Kanji mode: double-byte characters from the Shift JIS character set
+ */
+class Kanji extends QRDataAbstract{
+
+ /**
+ * @inheritdoc
+ */
+ protected $datamode = QRCode::DATA_KANJI;
+
+ /**
+ * @inheritdoc
+ */
+ protected $lengthBits = [8, 10, 12];
+
+ /**
+ * @inheritdoc
+ */
+ protected function getLength(string $data):int{
+ return mb_strlen($data, 'SJIS');
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function write(string $data):void{
+ $len = strlen($data);
+
+ for($i = 0; $i + 1 < $len; $i += 2){
+ $c = ((0xff & ord($data[$i])) << 8) | (0xff & ord($data[$i + 1]));
+
+ if(0x8140 <= $c && $c <= 0x9FFC){
+ $c -= 0x8140;
+ }
+ elseif(0xE040 <= $c && $c <= 0xEBBF){
+ $c -= 0xC140;
+ }
+ else{
+ throw new QRCodeDataException(sprintf('illegal char at %d [%d]', $i + 1, $c));
+ }
+
+ $this->bitBuffer->put((($c >> 8) & 0xff) * 0xC0 + ($c & 0xff), 13);
+
+ }
+
+ if($i < $len){
+ throw new QRCodeDataException(sprintf('illegal char at %d', $i + 1));
+ }
+
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Data/MaskPatternTester.php b/vendor/chillerlan/php-qrcode/src/Data/MaskPatternTester.php
new file mode 100644
index 000000000..8dfd24180
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Data/MaskPatternTester.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * Class MaskPatternTester
+ *
+ * @filesource MaskPatternTester.php
+ * @created 22.11.2017
+ * @package chillerlan\QRCode\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Data;
+
+use function abs, call_user_func_array;
+
+/**
+ * The sole purpose of this class is to receive a QRMatrix object and run the pattern tests on it.
+ *
+ * @link http://www.thonky.com/qr-code-tutorial/data-masking
+ */
+class MaskPatternTester{
+
+ /**
+ * @var \chillerlan\QRCode\Data\QRMatrix
+ */
+ protected $matrix;
+
+ /**
+ * @var int
+ */
+ protected $moduleCount;
+
+ /**
+ * Receives the matrix an sets the module count
+ *
+ * @see \chillerlan\QRCode\QROptions::$maskPattern
+ * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern
+ * @see \chillerlan\QRCode\QRCode::getBestMaskPattern()
+ *
+ * @param \chillerlan\QRCode\Data\QRMatrix $matrix
+ */
+ public function __construct(QRMatrix $matrix){
+ $this->matrix = $matrix;
+ $this->moduleCount = $this->matrix->size();
+ }
+
+ /**
+ * Returns the penalty for the given mask pattern
+ *
+ * @see \chillerlan\QRCode\QROptions::$maskPattern
+ * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern
+ * @see \chillerlan\QRCode\QRCode::getBestMaskPattern()
+ *
+ * @return int
+ */
+ public function testPattern():int{
+ $penalty = 0;
+
+ for($level = 1; $level <= 4; $level++){
+ $penalty += call_user_func_array([$this, 'testLevel'.$level], [$this->matrix->matrix(true)]);
+ }
+
+ return (int)$penalty;
+ }
+
+ /**
+ * Checks for each group of five or more same-colored modules in a row (or column)
+ *
+ * @return int
+ */
+ protected function testLevel1(array $m):int{
+ $penalty = 0;
+
+ foreach($m as $y => $row){
+ foreach($row as $x => $val){
+ $count = 0;
+
+ for($ry = -1; $ry <= 1; $ry++){
+
+ if($y + $ry < 0 || $this->moduleCount <= $y + $ry){
+ continue;
+ }
+
+ for($rx = -1; $rx <= 1; $rx++){
+
+ if(($ry === 0 && $rx === 0) || (($x + $rx) < 0 || $this->moduleCount <= ($x + $rx))){
+ continue;
+ }
+
+ if($m[$y + $ry][$x + $rx] === $val){
+ $count++;
+ }
+
+ }
+ }
+
+ if($count > 5){
+ $penalty += (3 + $count - 5);
+ }
+
+ }
+ }
+
+ return $penalty;
+ }
+
+ /**
+ * Checks for each 2x2 area of same-colored modules in the matrix
+ *
+ * @return int
+ */
+ protected function testLevel2(array $m):int{
+ $penalty = 0;
+
+ foreach($m as $y => $row){
+
+ if($y > ($this->moduleCount - 2)){
+ break;
+ }
+
+ foreach($row as $x => $val){
+
+ if($x > ($this->moduleCount - 2)){
+ break;
+ }
+
+ if(
+ $val === $m[$y][$x + 1]
+ && $val === $m[$y + 1][$x]
+ && $val === $m[$y + 1][$x + 1]
+ ){
+ $penalty++;
+ }
+ }
+ }
+
+ return 3 * $penalty;
+ }
+
+ /**
+ * Checks if there are patterns that look similar to the finder patterns (1:1:3:1:1 ratio)
+ *
+ * @return int
+ */
+ protected function testLevel3(array $m):int{
+ $penalties = 0;
+
+ foreach($m as $y => $row){
+ foreach($row as $x => $val){
+
+ if(
+ ($x + 6) < $this->moduleCount
+ && $val
+ && !$m[$y][$x + 1]
+ && $m[$y][$x + 2]
+ && $m[$y][$x + 3]
+ && $m[$y][$x + 4]
+ && !$m[$y][$x + 5]
+ && $m[$y][$x + 6]
+ ){
+ $penalties++;
+ }
+
+ if(
+ ($y + 6) < $this->moduleCount
+ && $val
+ && !$m[$y + 1][$x]
+ && $m[$y + 2][$x]
+ && $m[$y + 3][$x]
+ && $m[$y + 4][$x]
+ && !$m[$y + 5][$x]
+ && $m[$y + 6][$x]
+ ){
+ $penalties++;
+ }
+
+ }
+ }
+
+ return $penalties * 40;
+ }
+
+ /**
+ * Checks if more than half of the modules are dark or light, with a larger penalty for a larger difference
+ *
+ * @return float
+ */
+ protected function testLevel4(array $m):float{
+ $count = 0;
+
+ foreach($m as $y => $row){
+ foreach($row as $x => $val){
+ if($val){
+ $count++;
+ }
+ }
+ }
+
+ return (abs(100 * $count / $this->moduleCount / $this->moduleCount - 50) / 5) * 10;
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Data/Number.php b/vendor/chillerlan/php-qrcode/src/Data/Number.php
new file mode 100644
index 000000000..3936d12c3
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Data/Number.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Class Number
+ *
+ * @filesource Number.php
+ * @created 26.11.2015
+ * @package QRCode
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Data;
+
+use chillerlan\QRCode\QRCode;
+
+use function ord, sprintf, substr;
+
+/**
+ * Numeric mode: decimal digits 0 through 9
+ */
+class Number extends QRDataAbstract{
+
+ /**
+ * @inheritdoc
+ */
+ protected $datamode = QRCode::DATA_NUMBER;
+
+ /**
+ * @inheritdoc
+ */
+ protected $lengthBits = [10, 12, 14];
+
+ /**
+ * @inheritdoc
+ */
+ protected function write(string $data):void{
+ $i = 0;
+
+ while($i + 2 < $this->strlen){
+ $this->bitBuffer->put($this->parseInt(substr($data, $i, 3)), 10);
+ $i += 3;
+ }
+
+ if($i < $this->strlen){
+
+ if($this->strlen - $i === 1){
+ $this->bitBuffer->put($this->parseInt(substr($data, $i, $i + 1)), 4);
+ }
+ elseif($this->strlen - $i === 2){
+ $this->bitBuffer->put($this->parseInt(substr($data, $i, $i + 2)), 7);
+ }
+
+ }
+
+ }
+
+ /**
+ * @param string $string
+ *
+ * @return int
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ protected function parseInt(string $string):int{
+ $num = 0;
+
+ $len = strlen($string);
+ for($i = 0; $i < $len; $i++){
+ $c = ord($string[$i]);
+
+ if(!in_array($string[$i], $this::NUMBER_CHAR_MAP, true)){
+ throw new QRCodeDataException(sprintf('illegal char: "%s" [%d]', $string[$i], $c));
+ }
+
+ $c = $c - 48; // ord('0')
+ $num = $num * 10 + $c;
+ }
+
+ return $num;
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Data/QRCodeDataException.php b/vendor/chillerlan/php-qrcode/src/Data/QRCodeDataException.php
new file mode 100644
index 000000000..862f57ba0
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Data/QRCodeDataException.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Class QRCodeDataException
+ *
+ * @filesource QRCodeDataException.php
+ * @created 09.12.2015
+ * @package chillerlan\QRCode\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Data;
+
+use chillerlan\QRCode\QRCodeException;
+
+class QRCodeDataException extends QRCodeException{}
diff --git a/vendor/chillerlan/php-qrcode/src/Data/QRDataAbstract.php b/vendor/chillerlan/php-qrcode/src/Data/QRDataAbstract.php
new file mode 100644
index 000000000..f52767e38
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Data/QRDataAbstract.php
@@ -0,0 +1,351 @@
+<?php
+/**
+ * Class QRDataAbstract
+ *
+ * @filesource QRDataAbstract.php
+ * @created 25.11.2015
+ * @package chillerlan\QRCode\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Data;
+
+use chillerlan\QRCode\{QRCode, QRCodeException};
+use chillerlan\QRCode\Helpers\{BitBuffer, Polynomial};
+use chillerlan\Settings\SettingsContainerInterface;
+
+use function array_fill, array_merge, count, max, mb_convert_encoding, mb_detect_encoding, range, sprintf, strlen;
+
+/**
+ * Processes the binary data and maps it on a matrix which is then being returned
+ */
+abstract class QRDataAbstract implements QRDataInterface{
+
+ /**
+ * the string byte count
+ *
+ * @var int
+ */
+ protected $strlen;
+
+ /**
+ * the current data mode: Num, Alphanum, Kanji, Byte
+ *
+ * @var int
+ */
+ protected $datamode;
+
+ /**
+ * mode length bits for the version breakpoints 1-9, 10-26 and 27-40
+ *
+ * @var array
+ */
+ protected $lengthBits = [0, 0, 0];
+
+ /**
+ * current QR Code version
+ *
+ * @var int
+ */
+ protected $version;
+
+ /**
+ * the raw data that's being passed to QRMatrix::mapData()
+ *
+ * @var array
+ */
+ protected $matrixdata;
+
+ /**
+ * ECC temp data
+ *
+ * @var array
+ */
+ protected $ecdata;
+
+ /**
+ * ECC temp data
+ *
+ * @var array
+ */
+ protected $dcdata;
+
+ /**
+ * @var \chillerlan\QRCode\QROptions
+ */
+ protected $options;
+
+ /**
+ * @var \chillerlan\QRCode\Helpers\BitBuffer
+ */
+ protected $bitBuffer;
+
+ /**
+ * QRDataInterface constructor.
+ *
+ * @param \chillerlan\Settings\SettingsContainerInterface $options
+ * @param string|null $data
+ */
+ public function __construct(SettingsContainerInterface $options, string $data = null){
+ $this->options = $options;
+
+ if($data !== null){
+ $this->setData($data);
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function setData(string $data):QRDataInterface{
+
+ if($this->datamode === QRCode::DATA_KANJI){
+ $data = mb_convert_encoding($data, 'SJIS', mb_detect_encoding($data));
+ }
+
+ $this->strlen = $this->getLength($data);
+ $this->version = $this->options->version === QRCode::VERSION_AUTO
+ ? $this->getMinimumVersion()
+ : $this->options->version;
+
+ $this->matrixdata = $this
+ ->writeBitBuffer($data)
+ ->maskECC()
+ ;
+
+ return $this;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function initMatrix(int $maskPattern, bool $test = null):QRMatrix{
+ return (new QRMatrix($this->version, $this->options->eccLevel))
+ ->setFinderPattern()
+ ->setSeparators()
+ ->setAlignmentPattern()
+ ->setTimingPattern()
+ ->setVersionNumber($test)
+ ->setFormatInfo($maskPattern, $test)
+ ->setDarkModule()
+ ->mapData($this->matrixdata, $maskPattern)
+ ;
+ }
+
+ /**
+ * returns the length bits for the version breakpoints 1-9, 10-26 and 27-40
+ *
+ * @return int
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ * @codeCoverageIgnore
+ */
+ protected function getLengthBits():int{
+
+ foreach([9, 26, 40] as $key => $breakpoint){
+ if($this->version <= $breakpoint){
+ return $this->lengthBits[$key];
+ }
+ }
+
+ throw new QRCodeDataException(sprintf('invalid version number: %d', $this->version));
+ }
+
+ /**
+ * returns the byte count of the $data string
+ *
+ * @param string $data
+ *
+ * @return int
+ */
+ protected function getLength(string $data):int{
+ return strlen($data);
+ }
+
+ /**
+ * returns the minimum version number for the given string
+ *
+ * @return int
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ protected function getMinimumVersion():int{
+ $maxlength = 0;
+
+ // guess the version number within the given range
+ foreach(range($this->options->versionMin, $this->options->versionMax) as $version){
+ $maxlength = $this::MAX_LENGTH[$version][QRCode::DATA_MODES[$this->datamode]][QRCode::ECC_MODES[$this->options->eccLevel]];
+
+ if($this->strlen <= $maxlength){
+ return $version;
+ }
+ }
+
+ throw new QRCodeDataException(sprintf('data exceeds %d characters', $maxlength));
+ }
+
+ /**
+ * writes the actual data string to the BitBuffer
+ *
+ * @see \chillerlan\QRCode\Data\QRDataAbstract::writeBitBuffer()
+ *
+ * @param string $data
+ *
+ * @return void
+ */
+ abstract protected function write(string $data):void;
+
+ /**
+ * creates a BitBuffer and writes the string data to it
+ *
+ * @param string $data
+ *
+ * @return \chillerlan\QRCode\Data\QRDataAbstract
+ * @throws \chillerlan\QRCode\QRCodeException
+ */
+ protected function writeBitBuffer(string $data):QRDataInterface{
+ $this->bitBuffer = new BitBuffer;
+
+ $MAX_BITS = $this::MAX_BITS[$this->version][QRCode::ECC_MODES[$this->options->eccLevel]];
+
+ $this->bitBuffer
+ ->clear()
+ ->put($this->datamode, 4)
+ ->put($this->strlen, $this->getLengthBits())
+ ;
+
+ $this->write($data);
+
+ // there was an error writing the BitBuffer data, which is... unlikely.
+ if($this->bitBuffer->length > $MAX_BITS){
+ throw new QRCodeException(sprintf('code length overflow. (%d > %d bit)', $this->bitBuffer->length, $MAX_BITS)); // @codeCoverageIgnore
+ }
+
+ // end code.
+ if($this->bitBuffer->length + 4 <= $MAX_BITS){
+ $this->bitBuffer->put(0, 4);
+ }
+
+ // padding
+ while($this->bitBuffer->length % 8 !== 0){
+ $this->bitBuffer->putBit(false);
+ }
+
+ // padding
+ while(true){
+
+ if($this->bitBuffer->length >= $MAX_BITS){
+ break;
+ }
+
+ $this->bitBuffer->put(0xEC, 8);
+
+ if($this->bitBuffer->length >= $MAX_BITS){
+ break;
+ }
+
+ $this->bitBuffer->put(0x11, 8);
+ }
+
+ return $this;
+ }
+
+ /**
+ * ECC masking
+ *
+ * @link http://www.thonky.com/qr-code-tutorial/error-correction-coding
+ *
+ * @return array
+ */
+ protected function maskECC():array{
+ [$l1, $l2, $b1, $b2] = $this::RSBLOCKS[$this->version][QRCode::ECC_MODES[$this->options->eccLevel]];
+
+ $rsBlocks = array_fill(0, $l1, [$b1, $b2]);
+ $rsCount = $l1 + $l2;
+ $this->ecdata = array_fill(0, $rsCount, null);
+ $this->dcdata = $this->ecdata;
+
+ if($l2 > 0){
+ $rsBlocks = array_merge($rsBlocks, array_fill(0, $l2, [$b1 + 1, $b2 + 1]));
+ }
+
+ $totalCodeCount = 0;
+ $maxDcCount = 0;
+ $maxEcCount = 0;
+ $offset = 0;
+
+ foreach($rsBlocks as $key => $block){
+ [$rsBlockTotal, $dcCount] = $block;
+
+ $ecCount = $rsBlockTotal - $dcCount;
+ $maxDcCount = max($maxDcCount, $dcCount);
+ $maxEcCount = max($maxEcCount, $ecCount);
+ $this->dcdata[$key] = array_fill(0, $dcCount, null);
+
+ foreach($this->dcdata[$key] as $a => $_z){
+ $this->dcdata[$key][$a] = 0xff & $this->bitBuffer->buffer[$a + $offset];
+ }
+
+ [$num, $add] = $this->poly($key, $ecCount);
+
+ foreach($this->ecdata[$key] as $c => $_z){
+ $modIndex = $c + $add;
+ $this->ecdata[$key][$c] = $modIndex >= 0 ? $num[$modIndex] : 0;
+ }
+
+ $offset += $dcCount;
+ $totalCodeCount += $rsBlockTotal;
+ }
+
+ $data = array_fill(0, $totalCodeCount, null);
+ $index = 0;
+
+ $mask = function($arr, $count) use (&$data, &$index, $rsCount){
+ for($x = 0; $x < $count; $x++){
+ for($y = 0; $y < $rsCount; $y++){
+ if($x < count($arr[$y])){
+ $data[$index] = $arr[$y][$x];
+ $index++;
+ }
+ }
+ }
+ };
+
+ $mask($this->dcdata, $maxDcCount);
+ $mask($this->ecdata, $maxEcCount);
+
+ return $data;
+ }
+
+ /**
+ * @param int $key
+ * @param int $count
+ *
+ * @return int[]
+ */
+ protected function poly(int $key, int $count):array{
+ $rsPoly = new Polynomial;
+ $modPoly = new Polynomial;
+
+ for($i = 0; $i < $count; $i++){
+ $modPoly->setNum([1, $modPoly->gexp($i)]);
+ $rsPoly->multiply($modPoly->getNum());
+ }
+
+ $rsPolyCount = count($rsPoly->getNum());
+
+ $modPoly
+ ->setNum($this->dcdata[$key], $rsPolyCount - 1)
+ ->mod($rsPoly->getNum())
+ ;
+
+ $this->ecdata[$key] = array_fill(0, $rsPolyCount - 1, null);
+ $num = $modPoly->getNum();
+
+ return [
+ $num,
+ count($num) - count($this->ecdata[$key]),
+ ];
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Data/QRDataInterface.php b/vendor/chillerlan/php-qrcode/src/Data/QRDataInterface.php
new file mode 100644
index 000000000..653386222
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Data/QRDataInterface.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * Interface QRDataInterface
+ *
+ * @filesource QRDataInterface.php
+ * @created 01.12.2015
+ * @package chillerlan\QRCode\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Data;
+
+/**
+ *
+ */
+interface QRDataInterface{
+
+ const NUMBER_CHAR_MAP = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
+
+ const ALPHANUM_CHAR_MAP = [
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+ 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*',
+ '+', '-', '.', '/', ':',
+ ];
+
+ /**
+ * @link http://www.qrcode.com/en/about/version.html
+ */
+ const MAX_LENGTH =[
+ // v => [NUMERIC => [L, M, Q, H ], ALPHANUM => [L, M, Q, H], BINARY => [L, M, Q, H ], KANJI => [L, M, Q, H ]] // modules
+ 1 => [[ 41, 34, 27, 17], [ 25, 20, 16, 10], [ 17, 14, 11, 7], [ 10, 8, 7, 4]], // 21
+ 2 => [[ 77, 63, 48, 34], [ 47, 38, 29, 20], [ 32, 26, 20, 14], [ 20, 16, 12, 8]], // 25
+ 3 => [[ 127, 101, 77, 58], [ 77, 61, 47, 35], [ 53, 42, 32, 24], [ 32, 26, 20, 15]], // 29
+ 4 => [[ 187, 149, 111, 82], [ 114, 90, 67, 50], [ 78, 62, 46, 34], [ 48, 38, 28, 21]], // 33
+ 5 => [[ 255, 202, 144, 106], [ 154, 122, 87, 64], [ 106, 84, 60, 44], [ 65, 52, 37, 27]], // 37
+ 6 => [[ 322, 255, 178, 139], [ 195, 154, 108, 84], [ 134, 106, 74, 58], [ 82, 65, 45, 36]], // 41
+ 7 => [[ 370, 293, 207, 154], [ 224, 178, 125, 93], [ 154, 122, 86, 64], [ 95, 75, 53, 39]], // 45
+ 8 => [[ 461, 365, 259, 202], [ 279, 221, 157, 122], [ 192, 152, 108, 84], [ 118, 93, 66, 52]], // 49
+ 9 => [[ 552, 432, 312, 235], [ 335, 262, 189, 143], [ 230, 180, 130, 98], [ 141, 111, 80, 60]], // 53
+ 10 => [[ 652, 513, 364, 288], [ 395, 311, 221, 174], [ 271, 213, 151, 119], [ 167, 131, 93, 74]], // 57
+ 11 => [[ 772, 604, 427, 331], [ 468, 366, 259, 200], [ 321, 251, 177, 137], [ 198, 155, 109, 85]], // 61
+ 12 => [[ 883, 691, 489, 374], [ 535, 419, 296, 227], [ 367, 287, 203, 155], [ 226, 177, 125, 96]], // 65
+ 13 => [[1022, 796, 580, 427], [ 619, 483, 352, 259], [ 425, 331, 241, 177], [ 262, 204, 149, 109]], // 69 NICE!
+ 14 => [[1101, 871, 621, 468], [ 667, 528, 376, 283], [ 458, 362, 258, 194], [ 282, 223, 159, 120]], // 73
+ 15 => [[1250, 991, 703, 530], [ 758, 600, 426, 321], [ 520, 412, 292, 220], [ 320, 254, 180, 136]], // 77
+ 16 => [[1408, 1082, 775, 602], [ 854, 656, 470, 365], [ 586, 450, 322, 250], [ 361, 277, 198, 154]], // 81
+ 17 => [[1548, 1212, 876, 674], [ 938, 734, 531, 408], [ 644, 504, 364, 280], [ 397, 310, 224, 173]], // 85
+ 18 => [[1725, 1346, 948, 746], [1046, 816, 574, 452], [ 718, 560, 394, 310], [ 442, 345, 243, 191]], // 89
+ 19 => [[1903, 1500, 1063, 813], [1153, 909, 644, 493], [ 792, 624, 442, 338], [ 488, 384, 272, 208]], // 93
+ 20 => [[2061, 1600, 1159, 919], [1249, 970, 702, 557], [ 858, 666, 482, 382], [ 528, 410, 297, 235]], // 97
+ 21 => [[2232, 1708, 1224, 969], [1352, 1035, 742, 587], [ 929, 711, 509, 403], [ 572, 438, 314, 248]], // 101
+ 22 => [[2409, 1872, 1358, 1056], [1460, 1134, 823, 640], [1003, 779, 565, 439], [ 618, 480, 348, 270]], // 105
+ 23 => [[2620, 2059, 1468, 1108], [1588, 1248, 890, 672], [1091, 857, 611, 461], [ 672, 528, 376, 284]], // 109
+ 24 => [[2812, 2188, 1588, 1228], [1704, 1326, 963, 744], [1171, 911, 661, 511], [ 721, 561, 407, 315]], // 113
+ 25 => [[3057, 2395, 1718, 1286], [1853, 1451, 1041, 779], [1273, 997, 715, 535], [ 784, 614, 440, 330]], // 117
+ 26 => [[3283, 2544, 1804, 1425], [1990, 1542, 1094, 864], [1367, 1059, 751, 593], [ 842, 652, 462, 365]], // 121
+ 27 => [[3517, 2701, 1933, 1501], [2132, 1637, 1172, 910], [1465, 1125, 805, 625], [ 902, 692, 496, 385]], // 125
+ 28 => [[3669, 2857, 2085, 1581], [2223, 1732, 1263, 958], [1528, 1190, 868, 658], [ 940, 732, 534, 405]], // 129
+ 29 => [[3909, 3035, 2181, 1677], [2369, 1839, 1322, 1016], [1628, 1264, 908, 698], [1002, 778, 559, 430]], // 133
+ 30 => [[4158, 3289, 2358, 1782], [2520, 1994, 1429, 1080], [1732, 1370, 982, 742], [1066, 843, 604, 457]], // 137
+ 31 => [[4417, 3486, 2473, 1897], [2677, 2113, 1499, 1150], [1840, 1452, 1030, 790], [1132, 894, 634, 486]], // 141
+ 32 => [[4686, 3693, 2670, 2022], [2840, 2238, 1618, 1226], [1952, 1538, 1112, 842], [1201, 947, 684, 518]], // 145
+ 33 => [[4965, 3909, 2805, 2157], [3009, 2369, 1700, 1307], [2068, 1628, 1168, 898], [1273, 1002, 719, 553]], // 149
+ 34 => [[5253, 4134, 2949, 2301], [3183, 2506, 1787, 1394], [2188, 1722, 1228, 958], [1347, 1060, 756, 590]], // 153
+ 35 => [[5529, 4343, 3081, 2361], [3351, 2632, 1867, 1431], [2303, 1809, 1283, 983], [1417, 1113, 790, 605]], // 157
+ 36 => [[5836, 4588, 3244, 2524], [3537, 2780, 1966, 1530], [2431, 1911, 1351, 1051], [1496, 1176, 832, 647]], // 161
+ 37 => [[6153, 4775, 3417, 2625], [3729, 2894, 2071, 1591], [2563, 1989, 1423, 1093], [1577, 1224, 876, 673]], // 165
+ 38 => [[6479, 5039, 3599, 2735], [3927, 3054, 2181, 1658], [2699, 2099, 1499, 1139], [1661, 1292, 923, 701]], // 169
+ 39 => [[6743, 5313, 3791, 2927], [4087, 3220, 2298, 1774], [2809, 2213, 1579, 1219], [1729, 1362, 972, 750]], // 173
+ 40 => [[7089, 5596, 3993, 3057], [4296, 3391, 2420, 1852], [2953, 2331, 1663, 1273], [1817, 1435, 1024, 784]], // 177
+ ];
+
+ const MAX_BITS = [
+ // version => [L, M, Q, H ]
+ 1 => [ 152, 128, 104, 72],
+ 2 => [ 272, 224, 176, 128],
+ 3 => [ 440, 352, 272, 208],
+ 4 => [ 640, 512, 384, 288],
+ 5 => [ 864, 688, 496, 368],
+ 6 => [ 1088, 864, 608, 480],
+ 7 => [ 1248, 992, 704, 528],
+ 8 => [ 1552, 1232, 880, 688],
+ 9 => [ 1856, 1456, 1056, 800],
+ 10 => [ 2192, 1728, 1232, 976],
+ 11 => [ 2592, 2032, 1440, 1120],
+ 12 => [ 2960, 2320, 1648, 1264],
+ 13 => [ 3424, 2672, 1952, 1440],
+ 14 => [ 3688, 2920, 2088, 1576],
+ 15 => [ 4184, 3320, 2360, 1784],
+ 16 => [ 4712, 3624, 2600, 2024],
+ 17 => [ 5176, 4056, 2936, 2264],
+ 18 => [ 5768, 4504, 3176, 2504],
+ 19 => [ 6360, 5016, 3560, 2728],
+ 20 => [ 6888, 5352, 3880, 3080],
+ 21 => [ 7456, 5712, 4096, 3248],
+ 22 => [ 8048, 6256, 4544, 3536],
+ 23 => [ 8752, 6880, 4912, 3712],
+ 24 => [ 9392, 7312, 5312, 4112],
+ 25 => [10208, 8000, 5744, 4304],
+ 26 => [10960, 8496, 6032, 4768],
+ 27 => [11744, 9024, 6464, 5024],
+ 28 => [12248, 9544, 6968, 5288],
+ 29 => [13048, 10136, 7288, 5608],
+ 30 => [13880, 10984, 7880, 5960],
+ 31 => [14744, 11640, 8264, 6344],
+ 32 => [15640, 12328, 8920, 6760],
+ 33 => [16568, 13048, 9368, 7208],
+ 34 => [17528, 13800, 9848, 7688],
+ 35 => [18448, 14496, 10288, 7888],
+ 36 => [19472, 15312, 10832, 8432],
+ 37 => [20528, 15936, 11408, 8768],
+ 38 => [21616, 16816, 12016, 9136],
+ 39 => [22496, 17728, 12656, 9776],
+ 40 => [23648, 18672, 13328, 10208],
+ ];
+
+ /**
+ * @link http://www.thonky.com/qr-code-tutorial/error-correction-table
+ */
+ const RSBLOCKS = [
+ 1 => [[ 1, 0, 26, 19], [ 1, 0, 26, 16], [ 1, 0, 26, 13], [ 1, 0, 26, 9]],
+ 2 => [[ 1, 0, 44, 34], [ 1, 0, 44, 28], [ 1, 0, 44, 22], [ 1, 0, 44, 16]],
+ 3 => [[ 1, 0, 70, 55], [ 1, 0, 70, 44], [ 2, 0, 35, 17], [ 2, 0, 35, 13]],
+ 4 => [[ 1, 0, 100, 80], [ 2, 0, 50, 32], [ 2, 0, 50, 24], [ 4, 0, 25, 9]],
+ 5 => [[ 1, 0, 134, 108], [ 2, 0, 67, 43], [ 2, 2, 33, 15], [ 2, 2, 33, 11]],
+ 6 => [[ 2, 0, 86, 68], [ 4, 0, 43, 27], [ 4, 0, 43, 19], [ 4, 0, 43, 15]],
+ 7 => [[ 2, 0, 98, 78], [ 4, 0, 49, 31], [ 2, 4, 32, 14], [ 4, 1, 39, 13]],
+ 8 => [[ 2, 0, 121, 97], [ 2, 2, 60, 38], [ 4, 2, 40, 18], [ 4, 2, 40, 14]],
+ 9 => [[ 2, 0, 146, 116], [ 3, 2, 58, 36], [ 4, 4, 36, 16], [ 4, 4, 36, 12]],
+ 10 => [[ 2, 2, 86, 68], [ 4, 1, 69, 43], [ 6, 2, 43, 19], [ 6, 2, 43, 15]],
+ 11 => [[ 4, 0, 101, 81], [ 1, 4, 80, 50], [ 4, 4, 50, 22], [ 3, 8, 36, 12]],
+ 12 => [[ 2, 2, 116, 92], [ 6, 2, 58, 36], [ 4, 6, 46, 20], [ 7, 4, 42, 14]],
+ 13 => [[ 4, 0, 133, 107], [ 8, 1, 59, 37], [ 8, 4, 44, 20], [12, 4, 33, 11]],
+ 14 => [[ 3, 1, 145, 115], [ 4, 5, 64, 40], [11, 5, 36, 16], [11, 5, 36, 12]],
+ 15 => [[ 5, 1, 109, 87], [ 5, 5, 65, 41], [ 5, 7, 54, 24], [11, 7, 36, 12]],
+ 16 => [[ 5, 1, 122, 98], [ 7, 3, 73, 45], [15, 2, 43, 19], [ 3, 13, 45, 15]],
+ 17 => [[ 1, 5, 135, 107], [10, 1, 74, 46], [ 1, 15, 50, 22], [ 2, 17, 42, 14]],
+ 18 => [[ 5, 1, 150, 120], [ 9, 4, 69, 43], [17, 1, 50, 22], [ 2, 19, 42, 14]],
+ 19 => [[ 3, 4, 141, 113], [ 3, 11, 70, 44], [17, 4, 47, 21], [ 9, 16, 39, 13]],
+ 20 => [[ 3, 5, 135, 107], [ 3, 13, 67, 41], [15, 5, 54, 24], [15, 10, 43, 15]],
+ 21 => [[ 4, 4, 144, 116], [17, 0, 68, 42], [17, 6, 50, 22], [19, 6, 46, 16]],
+ 22 => [[ 2, 7, 139, 111], [17, 0, 74, 46], [ 7, 16, 54, 24], [34, 0, 37, 13]],
+ 23 => [[ 4, 5, 151, 121], [ 4, 14, 75, 47], [11, 14, 54, 24], [16, 14, 45, 15]],
+ 24 => [[ 6, 4, 147, 117], [ 6, 14, 73, 45], [11, 16, 54, 24], [30, 2, 46, 16]],
+ 25 => [[ 8, 4, 132, 106], [ 8, 13, 75, 47], [ 7, 22, 54, 24], [22, 13, 45, 15]],
+ 26 => [[10, 2, 142, 114], [19, 4, 74, 46], [28, 6, 50, 22], [33, 4, 46, 16]],
+ 27 => [[ 8, 4, 152, 122], [22, 3, 73, 45], [ 8, 26, 53, 23], [12, 28, 45, 15]],
+ 28 => [[ 3, 10, 147, 117], [ 3, 23, 73, 45], [ 4, 31, 54, 24], [11, 31, 45, 15]],
+ 29 => [[ 7, 7, 146, 116], [21, 7, 73, 45], [ 1, 37, 53, 23], [19, 26, 45, 15]],
+ 30 => [[ 5, 10, 145, 115], [19, 10, 75, 47], [15, 25, 54, 24], [23, 25, 45, 15]],
+ 31 => [[13, 3, 145, 115], [ 2, 29, 74, 46], [42, 1, 54, 24], [23, 28, 45, 15]],
+ 32 => [[17, 0, 145, 115], [10, 23, 74, 46], [10, 35, 54, 24], [19, 35, 45, 15]],
+ 33 => [[17, 1, 145, 115], [14, 21, 74, 46], [29, 19, 54, 24], [11, 46, 45, 15]],
+ 34 => [[13, 6, 145, 115], [14, 23, 74, 46], [44, 7, 54, 24], [59, 1, 46, 16]],
+ 35 => [[12, 7, 151, 121], [12, 26, 75, 47], [39, 14, 54, 24], [22, 41, 45, 15]],
+ 36 => [[ 6, 14, 151, 121], [ 6, 34, 75, 47], [46, 10, 54, 24], [ 2, 64, 45, 15]],
+ 37 => [[17, 4, 152, 122], [29, 14, 74, 46], [49, 10, 54, 24], [24, 46, 45, 15]],
+ 38 => [[ 4, 18, 152, 122], [13, 32, 74, 46], [48, 14, 54, 24], [42, 32, 45, 15]],
+ 39 => [[20, 4, 147, 117], [40, 7, 75, 47], [43, 22, 54, 24], [10, 67, 45, 15]],
+ 40 => [[19, 6, 148, 118], [18, 31, 75, 47], [34, 34, 54, 24], [20, 61, 45, 15]],
+ ];
+
+ /**
+ * Sets the data string (internally called by the constructor)
+ *
+ * @param string $data
+ *
+ * @return \chillerlan\QRCode\Data\QRDataInterface
+ */
+ public function setData(string $data):QRDataInterface;
+
+ /**
+ * returns a fresh matrix object with the data written for the given $maskPattern
+ *
+ * @param int $maskPattern
+ * @param bool|null $test
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function initMatrix(int $maskPattern, bool $test = null):QRMatrix;
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Data/QRMatrix.php b/vendor/chillerlan/php-qrcode/src/Data/QRMatrix.php
new file mode 100644
index 000000000..a6d8b09e2
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Data/QRMatrix.php
@@ -0,0 +1,733 @@
+<?php
+/**
+ * Class QRMatrix
+ *
+ * @filesource QRMatrix.php
+ * @created 15.11.2017
+ * @package chillerlan\QRCode\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Data;
+
+use chillerlan\QRCode\QRCode;
+use Closure;
+
+use function array_fill, array_key_exists, array_push, array_unshift, count, floor, in_array, max, min, range;
+
+/**
+ * @link http://www.thonky.com/qr-code-tutorial/format-version-information
+ */
+class QRMatrix{
+
+ public const M_NULL = 0x00;
+ public const M_DARKMODULE = 0x02;
+ public const M_DATA = 0x04;
+ public const M_FINDER = 0x06;
+ public const M_SEPARATOR = 0x08;
+ public const M_ALIGNMENT = 0x0a;
+ public const M_TIMING = 0x0c;
+ public const M_FORMAT = 0x0e;
+ public const M_VERSION = 0x10;
+ public const M_QUIETZONE = 0x12;
+ public const M_LOGO = 0x14;
+ public const M_FINDER_DOT = 0x16;
+
+ public const M_TEST = 0xff;
+
+ /**
+ * @link http://www.thonky.com/qr-code-tutorial/alignment-pattern-locations
+ *
+ * version -> pattern
+ */
+ protected const alignmentPattern = [
+ 1 => [],
+ 2 => [6, 18],
+ 3 => [6, 22],
+ 4 => [6, 26],
+ 5 => [6, 30],
+ 6 => [6, 34],
+ 7 => [6, 22, 38],
+ 8 => [6, 24, 42],
+ 9 => [6, 26, 46],
+ 10 => [6, 28, 50],
+ 11 => [6, 30, 54],
+ 12 => [6, 32, 58],
+ 13 => [6, 34, 62],
+ 14 => [6, 26, 46, 66],
+ 15 => [6, 26, 48, 70],
+ 16 => [6, 26, 50, 74],
+ 17 => [6, 30, 54, 78],
+ 18 => [6, 30, 56, 82],
+ 19 => [6, 30, 58, 86],
+ 20 => [6, 34, 62, 90],
+ 21 => [6, 28, 50, 72, 94],
+ 22 => [6, 26, 50, 74, 98],
+ 23 => [6, 30, 54, 78, 102],
+ 24 => [6, 28, 54, 80, 106],
+ 25 => [6, 32, 58, 84, 110],
+ 26 => [6, 30, 58, 86, 114],
+ 27 => [6, 34, 62, 90, 118],
+ 28 => [6, 26, 50, 74, 98, 122],
+ 29 => [6, 30, 54, 78, 102, 126],
+ 30 => [6, 26, 52, 78, 104, 130],
+ 31 => [6, 30, 56, 82, 108, 134],
+ 32 => [6, 34, 60, 86, 112, 138],
+ 33 => [6, 30, 58, 86, 114, 142],
+ 34 => [6, 34, 62, 90, 118, 146],
+ 35 => [6, 30, 54, 78, 102, 126, 150],
+ 36 => [6, 24, 50, 76, 102, 128, 154],
+ 37 => [6, 28, 54, 80, 106, 132, 158],
+ 38 => [6, 32, 58, 84, 110, 136, 162],
+ 39 => [6, 26, 54, 82, 110, 138, 166],
+ 40 => [6, 30, 58, 86, 114, 142, 170],
+ ];
+
+ /**
+ * @link http://www.thonky.com/qr-code-tutorial/format-version-tables
+ *
+ * no version pattern for QR Codes < 7
+ */
+ protected const versionPattern = [
+ 7 => 0b000111110010010100,
+ 8 => 0b001000010110111100,
+ 9 => 0b001001101010011001,
+ 10 => 0b001010010011010011,
+ 11 => 0b001011101111110110,
+ 12 => 0b001100011101100010,
+ 13 => 0b001101100001000111,
+ 14 => 0b001110011000001101,
+ 15 => 0b001111100100101000,
+ 16 => 0b010000101101111000,
+ 17 => 0b010001010001011101,
+ 18 => 0b010010101000010111,
+ 19 => 0b010011010100110010,
+ 20 => 0b010100100110100110,
+ 21 => 0b010101011010000011,
+ 22 => 0b010110100011001001,
+ 23 => 0b010111011111101100,
+ 24 => 0b011000111011000100,
+ 25 => 0b011001000111100001,
+ 26 => 0b011010111110101011,
+ 27 => 0b011011000010001110,
+ 28 => 0b011100110000011010,
+ 29 => 0b011101001100111111,
+ 30 => 0b011110110101110101,
+ 31 => 0b011111001001010000,
+ 32 => 0b100000100111010101,
+ 33 => 0b100001011011110000,
+ 34 => 0b100010100010111010,
+ 35 => 0b100011011110011111,
+ 36 => 0b100100101100001011,
+ 37 => 0b100101010000101110,
+ 38 => 0b100110101001100100,
+ 39 => 0b100111010101000001,
+ 40 => 0b101000110001101001,
+ ];
+
+ // ECC level -> mask pattern
+ protected const formatPattern = [
+ [ // L
+ 0b111011111000100,
+ 0b111001011110011,
+ 0b111110110101010,
+ 0b111100010011101,
+ 0b110011000101111,
+ 0b110001100011000,
+ 0b110110001000001,
+ 0b110100101110110,
+ ],
+ [ // M
+ 0b101010000010010,
+ 0b101000100100101,
+ 0b101111001111100,
+ 0b101101101001011,
+ 0b100010111111001,
+ 0b100000011001110,
+ 0b100111110010111,
+ 0b100101010100000,
+ ],
+ [ // Q
+ 0b011010101011111,
+ 0b011000001101000,
+ 0b011111100110001,
+ 0b011101000000110,
+ 0b010010010110100,
+ 0b010000110000011,
+ 0b010111011011010,
+ 0b010101111101101,
+ ],
+ [ // H
+ 0b001011010001001,
+ 0b001001110111110,
+ 0b001110011100111,
+ 0b001100111010000,
+ 0b000011101100010,
+ 0b000001001010101,
+ 0b000110100001100,
+ 0b000100000111011,
+ ],
+ ];
+
+ /**
+ * @var int
+ */
+ protected $version;
+
+ /**
+ * @var int
+ */
+ protected $eclevel;
+
+ /**
+ * @var int
+ */
+ protected $maskPattern = QRCode::MASK_PATTERN_AUTO;
+
+ /**
+ * @var int
+ */
+ protected $moduleCount;
+
+ /**
+ * @var mixed[]
+ */
+ protected $matrix;
+
+ /**
+ * QRMatrix constructor.
+ *
+ * @param int $version
+ * @param int $eclevel
+ *
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ public function __construct(int $version, int $eclevel){
+
+ if(!in_array($version, range(1, 40), true)){
+ throw new QRCodeDataException('invalid QR Code version');
+ }
+
+ if(!array_key_exists($eclevel, QRCode::ECC_MODES)){
+ throw new QRCodeDataException('invalid ecc level');
+ }
+
+ $this->version = $version;
+ $this->eclevel = $eclevel;
+ $this->moduleCount = $this->version * 4 + 17;
+ $this->matrix = array_fill(0, $this->moduleCount, array_fill(0, $this->moduleCount, $this::M_NULL));
+ }
+
+ /**
+ * Returns the data matrix, returns a pure boolean representation if $boolean is set to true
+ *
+ * @return int[][]|bool[][]
+ */
+ public function matrix(bool $boolean = false):array{
+
+ if(!$boolean){
+ return $this->matrix;
+ }
+
+ $matrix = [];
+
+ foreach($this->matrix as $y => $row){
+ $matrix[$y] = [];
+
+ foreach($row as $x => $val){
+ $matrix[$y][$x] = ($val >> 8) > 0;
+ }
+ }
+
+ return $matrix;
+ }
+
+ /**
+ * @return int
+ */
+ public function version():int{
+ return $this->version;
+ }
+
+ /**
+ * @return int
+ */
+ public function eccLevel():int{
+ return $this->eclevel;
+ }
+
+ /**
+ * @return int
+ */
+ public function maskPattern():int{
+ return $this->maskPattern;
+ }
+
+ /**
+ * Returns the absoulute size of the matrix, including quiet zone (after setting it).
+ *
+ * size = version * 4 + 17 [ + 2 * quietzone size]
+ *
+ * @return int
+ */
+ public function size():int{
+ return $this->moduleCount;
+ }
+
+ /**
+ * Returns the value of the module at position [$x, $y]
+ *
+ * @param int $x
+ * @param int $y
+ *
+ * @return int
+ */
+ public function get(int $x, int $y):int{
+ return $this->matrix[$y][$x];
+ }
+
+ /**
+ * Sets the $M_TYPE value for the module at position [$x, $y]
+ *
+ * true => $M_TYPE << 8
+ * false => $M_TYPE
+ *
+ * @param int $x
+ * @param int $y
+ * @param int $M_TYPE
+ * @param bool $value
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function set(int $x, int $y, bool $value, int $M_TYPE):QRMatrix{
+ $this->matrix[$y][$x] = $M_TYPE << ($value ? 8 : 0);
+
+ return $this;
+ }
+
+ /**
+ * Checks whether a module is true (dark) or false (light)
+ *
+ * true => $value >> 8 === $M_TYPE
+ * $value >> 8 > 0
+ *
+ * false => $value === $M_TYPE
+ * $value >> 8 === 0
+ *
+ * @param int $x
+ * @param int $y
+ *
+ * @return bool
+ */
+ public function check(int $x, int $y):bool{
+ return $this->matrix[$y][$x] >> 8 > 0;
+ }
+
+
+ /**
+ * Sets the "dark module", that is always on the same position 1x1px away from the bottom left finder
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function setDarkModule():QRMatrix{
+ $this->set(8, 4 * $this->version + 9, true, $this::M_DARKMODULE);
+
+ return $this;
+ }
+
+ /**
+ * Draws the 7x7 finder patterns in the corners top left/right and bottom left
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function setFinderPattern():QRMatrix{
+
+ $pos = [
+ [0, 0], // top left
+ [$this->moduleCount - 7, 0], // bottom left
+ [0, $this->moduleCount - 7], // top right
+ ];
+
+ foreach($pos as $c){
+ for($y = 0; $y < 7; $y++){
+ for($x = 0; $x < 7; $x++){
+ // outer (dark) 7*7 square
+ if($x === 0 || $x === 6 || $y === 0 || $y === 6){
+ $this->set($c[0] + $y, $c[1] + $x, true, $this::M_FINDER);
+ }
+ // inner (light) 5*5 square
+ elseif($x === 1 || $x === 5 || $y === 1 || $y === 5){
+ $this->set($c[0] + $y, $c[1] + $x, false, $this::M_FINDER);
+ }
+ // 3*3 dot
+ else{
+ $this->set($c[0] + $y, $c[1] + $x, true, $this::M_FINDER_DOT);
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Draws the separator lines around the finder patterns
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function setSeparators():QRMatrix{
+
+ $h = [
+ [7, 0],
+ [$this->moduleCount - 8, 0],
+ [7, $this->moduleCount - 8],
+ ];
+
+ $v = [
+ [7, 7],
+ [$this->moduleCount - 1, 7],
+ [7, $this->moduleCount - 8],
+ ];
+
+ for($c = 0; $c < 3; $c++){
+ for($i = 0; $i < 8; $i++){
+ $this->set($h[$c][0] , $h[$c][1] + $i, false, $this::M_SEPARATOR);
+ $this->set($v[$c][0] - $i, $v[$c][1] , false, $this::M_SEPARATOR);
+ }
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Draws the 5x5 alignment patterns
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function setAlignmentPattern():QRMatrix{
+
+ foreach($this::alignmentPattern[$this->version] as $y){
+ foreach($this::alignmentPattern[$this->version] as $x){
+
+ // skip existing patterns
+ if($this->matrix[$y][$x] !== $this::M_NULL){
+ continue;
+ }
+
+ for($ry = -2; $ry <= 2; $ry++){
+ for($rx = -2; $rx <= 2; $rx++){
+ $v = ($ry === 0 && $rx === 0) || $ry === 2 || $ry === -2 || $rx === 2 || $rx === -2;
+
+ $this->set($x + $rx, $y + $ry, $v, $this::M_ALIGNMENT);
+ }
+ }
+
+ }
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Draws the timing pattern (h/v checkered line between the finder patterns)
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function setTimingPattern():QRMatrix{
+
+ foreach(range(8, $this->moduleCount - 8 - 1) as $i){
+
+ if($this->matrix[6][$i] !== $this::M_NULL || $this->matrix[$i][6] !== $this::M_NULL){
+ continue;
+ }
+
+ $v = $i % 2 === 0;
+
+ $this->set($i, 6, $v, $this::M_TIMING); // h
+ $this->set(6, $i, $v, $this::M_TIMING); // v
+ }
+
+ return $this;
+ }
+
+ /**
+ * Draws the version information, 2x 3x6 pixel
+ *
+ * @param bool|null $test
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function setVersionNumber(bool $test = null):QRMatrix{
+ $bits = $this::versionPattern[$this->version] ?? false;
+
+ if($bits !== false){
+
+ for($i = 0; $i < 18; $i++){
+ $a = (int)floor($i / 3);
+ $b = $i % 3 + $this->moduleCount - 8 - 3;
+ $v = !$test && (($bits >> $i) & 1) === 1;
+
+ $this->set($b, $a, $v, $this::M_VERSION); // ne
+ $this->set($a, $b, $v, $this::M_VERSION); // sw
+ }
+
+ }
+
+ return $this;
+ }
+
+ /**
+ * Draws the format info along the finder patterns
+ *
+ * @param int $maskPattern
+ * @param bool|null $test
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function setFormatInfo(int $maskPattern, bool $test = null):QRMatrix{
+ $bits = $this::formatPattern[QRCode::ECC_MODES[$this->eclevel]][$maskPattern] ?? 0;
+
+ for($i = 0; $i < 15; $i++){
+ $v = !$test && (($bits >> $i) & 1) === 1;
+
+ if($i < 6){
+ $this->set(8, $i, $v, $this::M_FORMAT);
+ }
+ elseif($i < 8){
+ $this->set(8, $i + 1, $v, $this::M_FORMAT);
+ }
+ else{
+ $this->set(8, $this->moduleCount - 15 + $i, $v, $this::M_FORMAT);
+ }
+
+ if($i < 8){
+ $this->set($this->moduleCount - $i - 1, 8, $v, $this::M_FORMAT);
+ }
+ elseif($i < 9){
+ $this->set(15 - $i, 8, $v, $this::M_FORMAT);
+ }
+ else{
+ $this->set(15 - $i - 1, 8, $v, $this::M_FORMAT);
+ }
+
+ }
+
+ $this->set(8, $this->moduleCount - 8, !$test, $this::M_FORMAT);
+
+ return $this;
+ }
+
+ /**
+ * Draws the "quiet zone" of $size around the matrix
+ *
+ * @param int|null $size
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ public function setQuietZone(int $size = null):QRMatrix{
+
+ if($this->matrix[$this->moduleCount - 1][$this->moduleCount - 1] === $this::M_NULL){
+ throw new QRCodeDataException('use only after writing data');
+ }
+
+ $size = $size !== null
+ ? max(0, min($size, floor($this->moduleCount / 2)))
+ : 4;
+
+ for($y = 0; $y < $this->moduleCount; $y++){
+ for($i = 0; $i < $size; $i++){
+ array_unshift($this->matrix[$y], $this::M_QUIETZONE);
+ array_push($this->matrix[$y], $this::M_QUIETZONE);
+ }
+ }
+
+ $this->moduleCount += ($size * 2);
+
+ $r = array_fill(0, $this->moduleCount, $this::M_QUIETZONE);
+
+ for($i = 0; $i < $size; $i++){
+ array_unshift($this->matrix, $r);
+ array_push($this->matrix, $r);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Clears a space of $width * $height in order to add a logo or text.
+ *
+ * Additionally, the logo space can be positioned within the QR Code - respecting the main functional patterns -
+ * using $startX and $startY. If either of these are null, the logo space will be centered in that direction.
+ * ECC level "H" (30%) is required.
+ *
+ * Please note that adding a logo space minimizes the error correction capacity of the QR Code and
+ * created images may become unreadable, especially when printed with a chance to receive damage.
+ * Please test thoroughly before using this feature in production.
+ *
+ * This method should be called from within an output module (after the matrix has been filled with data).
+ * Note that there is no restiction on how many times this method could be called on the same matrix instance.
+ *
+ * @link https://github.com/chillerlan/php-qrcode/issues/52
+ *
+ * @param int $width
+ * @param int $height
+ * @param int|null $startX
+ * @param int|null $startY
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ public function setLogoSpace(int $width, int $height, int $startX = null, int $startY = null):QRMatrix{
+
+ // for logos we operate in ECC H (30%) only
+ if($this->eclevel !== 0b10){
+ throw new QRCodeDataException('ECC level "H" required to add logo space');
+ }
+
+ // we need uneven sizes, adjust if needed
+ if(($width % 2) === 0){
+ $width++;
+ }
+
+ if(($height % 2) === 0){
+ $height++;
+ }
+
+ // $this->moduleCount includes the quiet zone (if created), we need the QR size here
+ $length = $this->version * 4 + 17;
+
+ // throw if the logo space exceeds the maximum error correction capacity
+ if($width * $height > floor($length * $length * 0.2)){
+ throw new QRCodeDataException('logo space exceeds the maximum error correction capacity');
+ }
+
+ // quiet zone size
+ $qz = ($this->moduleCount - $length) / 2;
+ // skip quiet zone and the first 9 rows/columns (finder-, mode-, version- and timing patterns)
+ $start = $qz + 9;
+ // skip quiet zone
+ $end = $this->moduleCount - $qz;
+
+ // determine start coordinates
+ $startX = ($startX !== null ? $startX : ($length - $width) / 2) + $qz;
+ $startY = ($startY !== null ? $startY : ($length - $height) / 2) + $qz;
+
+ // clear the space
+ foreach($this->matrix as $y => $row){
+ foreach($row as $x => $val){
+ // out of bounds, skip
+ if($x < $start || $y < $start ||$x >= $end || $y >= $end){
+ continue;
+ }
+ // a match
+ if($x >= $startX && $x < ($startX + $width) && $y >= $startY && $y < ($startY + $height)){
+ $this->set($x, $y, false, $this::M_LOGO);
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Maps the binary $data array from QRDataInterface::maskECC() on the matrix, using $maskPattern
+ *
+ * @see \chillerlan\QRCode\Data\QRDataAbstract::maskECC()
+ *
+ * @param int[] $data
+ * @param int $maskPattern
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ */
+ public function mapData(array $data, int $maskPattern):QRMatrix{
+ $this->maskPattern = $maskPattern;
+ $byteCount = count($data);
+ $size = $this->moduleCount - 1;
+ $mask = $this->getMask($this->maskPattern);
+
+ for($i = $size, $y = $size, $inc = -1, $byteIndex = 0, $bitIndex = 7; $i > 0; $i -= 2){
+
+ if($i === 6){
+ $i--;
+ }
+
+ while(true){
+ for($c = 0; $c < 2; $c++){
+ $x = $i - $c;
+
+ if($this->matrix[$y][$x] === $this::M_NULL){
+ $v = false;
+
+ if($byteIndex < $byteCount){
+ $v = (($data[$byteIndex] >> $bitIndex) & 1) === 1;
+ }
+
+ if($mask($x, $y) === 0){
+ $v = !$v;
+ }
+
+ $this->matrix[$y][$x] = $this::M_DATA << ($v ? 8 : 0);
+ $bitIndex--;
+
+ if($bitIndex === -1){
+ $byteIndex++;
+ $bitIndex = 7;
+ }
+
+ }
+ }
+
+ $y += $inc;
+
+ if($y < 0 || $this->moduleCount <= $y){
+ $y -= $inc;
+ $inc = -$inc;
+
+ break;
+ }
+
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * ISO/IEC 18004:2000 Section 8.8.1
+ *
+ * Note that some versions of the QR code standard have had errors in the section about mask patterns.
+ * The information below has been corrected. (https://www.thonky.com/qr-code-tutorial/mask-patterns)
+ *
+ * @see \chillerlan\QRCode\QRMatrix::mapData()
+ *
+ * @internal
+ *
+ * @param int $maskPattern
+ *
+ * @return \Closure
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ protected function getMask(int $maskPattern):Closure{
+
+ if((0b111 & $maskPattern) !== $maskPattern){
+ throw new QRCodeDataException('invalid mask pattern'); // @codeCoverageIgnore
+ }
+
+ return [
+ 0b000 => function($x, $y):int{ return ($x + $y) % 2; },
+ 0b001 => function($x, $y):int{ return $y % 2; },
+ 0b010 => function($x, $y):int{ return $x % 3; },
+ 0b011 => function($x, $y):int{ return ($x + $y) % 3; },
+ 0b100 => function($x, $y):int{ return ((int)($y / 2) + (int)($x / 3)) % 2; },
+ 0b101 => function($x, $y):int{ return (($x * $y) % 2) + (($x * $y) % 3); },
+ 0b110 => function($x, $y):int{ return ((($x * $y) % 2) + (($x * $y) % 3)) % 2; },
+ 0b111 => function($x, $y):int{ return ((($x * $y) % 3) + (($x + $y) % 2)) % 2; },
+ ][$maskPattern];
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Helpers/BitBuffer.php b/vendor/chillerlan/php-qrcode/src/Helpers/BitBuffer.php
new file mode 100644
index 000000000..0b4ff6a77
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Helpers/BitBuffer.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Class BitBuffer
+ *
+ * @filesource BitBuffer.php
+ * @created 25.11.2015
+ * @package chillerlan\QRCode\Helpers
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Helpers;
+
+use function count, floor;
+
+class BitBuffer{
+
+ /**
+ * @var int[]
+ */
+ public $buffer = [];
+
+ /**
+ * @var int
+ */
+ public $length = 0;
+
+ /**
+ * @return \chillerlan\QRCode\Helpers\BitBuffer
+ */
+ public function clear():BitBuffer{
+ $this->buffer = [];
+ $this->length = 0;
+
+ return $this;
+ }
+
+ /**
+ * @param int $num
+ * @param int $length
+ *
+ * @return \chillerlan\QRCode\Helpers\BitBuffer
+ */
+ public function put(int $num, int $length):BitBuffer{
+
+ for($i = 0; $i < $length; $i++){
+ $this->putBit((($num >> ($length - $i - 1)) & 1) === 1);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param bool $bit
+ *
+ * @return \chillerlan\QRCode\Helpers\BitBuffer
+ */
+ public function putBit(bool $bit):BitBuffer{
+ $bufIndex = floor($this->length / 8);
+
+ if(count($this->buffer) <= $bufIndex){
+ $this->buffer[] = 0;
+ }
+
+ if($bit === true){
+ $this->buffer[(int)$bufIndex] |= (0x80 >> ($this->length % 8));
+ }
+
+ $this->length++;
+
+ return $this;
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Helpers/Polynomial.php b/vendor/chillerlan/php-qrcode/src/Helpers/Polynomial.php
new file mode 100644
index 000000000..abe11d0cc
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Helpers/Polynomial.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ * Class Polynomial
+ *
+ * @filesource Polynomial.php
+ * @created 25.11.2015
+ * @package chillerlan\QRCode\Helpers
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Helpers;
+
+use chillerlan\QRCode\QRCodeException;
+
+use function array_fill, count, sprintf;
+
+/**
+ * @link http://www.thonky.com/qr-code-tutorial/error-correction-coding
+ */
+class Polynomial{
+
+ /**
+ * @link http://www.thonky.com/qr-code-tutorial/log-antilog-table
+ */
+ protected const table = [
+ [ 1, 0], [ 2, 0], [ 4, 1], [ 8, 25], [ 16, 2], [ 32, 50], [ 64, 26], [128, 198],
+ [ 29, 3], [ 58, 223], [116, 51], [232, 238], [205, 27], [135, 104], [ 19, 199], [ 38, 75],
+ [ 76, 4], [152, 100], [ 45, 224], [ 90, 14], [180, 52], [117, 141], [234, 239], [201, 129],
+ [143, 28], [ 3, 193], [ 6, 105], [ 12, 248], [ 24, 200], [ 48, 8], [ 96, 76], [192, 113],
+ [157, 5], [ 39, 138], [ 78, 101], [156, 47], [ 37, 225], [ 74, 36], [148, 15], [ 53, 33],
+ [106, 53], [212, 147], [181, 142], [119, 218], [238, 240], [193, 18], [159, 130], [ 35, 69],
+ [ 70, 29], [140, 181], [ 5, 194], [ 10, 125], [ 20, 106], [ 40, 39], [ 80, 249], [160, 185],
+ [ 93, 201], [186, 154], [105, 9], [210, 120], [185, 77], [111, 228], [222, 114], [161, 166],
+ [ 95, 6], [190, 191], [ 97, 139], [194, 98], [153, 102], [ 47, 221], [ 94, 48], [188, 253],
+ [101, 226], [202, 152], [137, 37], [ 15, 179], [ 30, 16], [ 60, 145], [120, 34], [240, 136],
+ [253, 54], [231, 208], [211, 148], [187, 206], [107, 143], [214, 150], [177, 219], [127, 189],
+ [254, 241], [225, 210], [223, 19], [163, 92], [ 91, 131], [182, 56], [113, 70], [226, 64],
+ [217, 30], [175, 66], [ 67, 182], [134, 163], [ 17, 195], [ 34, 72], [ 68, 126], [136, 110],
+ [ 13, 107], [ 26, 58], [ 52, 40], [104, 84], [208, 250], [189, 133], [103, 186], [206, 61],
+ [129, 202], [ 31, 94], [ 62, 155], [124, 159], [248, 10], [237, 21], [199, 121], [147, 43],
+ [ 59, 78], [118, 212], [236, 229], [197, 172], [151, 115], [ 51, 243], [102, 167], [204, 87],
+ [133, 7], [ 23, 112], [ 46, 192], [ 92, 247], [184, 140], [109, 128], [218, 99], [169, 13],
+ [ 79, 103], [158, 74], [ 33, 222], [ 66, 237], [132, 49], [ 21, 197], [ 42, 254], [ 84, 24],
+ [168, 227], [ 77, 165], [154, 153], [ 41, 119], [ 82, 38], [164, 184], [ 85, 180], [170, 124],
+ [ 73, 17], [146, 68], [ 57, 146], [114, 217], [228, 35], [213, 32], [183, 137], [115, 46],
+ [230, 55], [209, 63], [191, 209], [ 99, 91], [198, 149], [145, 188], [ 63, 207], [126, 205],
+ [252, 144], [229, 135], [215, 151], [179, 178], [123, 220], [246, 252], [241, 190], [255, 97],
+ [227, 242], [219, 86], [171, 211], [ 75, 171], [150, 20], [ 49, 42], [ 98, 93], [196, 158],
+ [149, 132], [ 55, 60], [110, 57], [220, 83], [165, 71], [ 87, 109], [174, 65], [ 65, 162],
+ [130, 31], [ 25, 45], [ 50, 67], [100, 216], [200, 183], [141, 123], [ 7, 164], [ 14, 118],
+ [ 28, 196], [ 56, 23], [112, 73], [224, 236], [221, 127], [167, 12], [ 83, 111], [166, 246],
+ [ 81, 108], [162, 161], [ 89, 59], [178, 82], [121, 41], [242, 157], [249, 85], [239, 170],
+ [195, 251], [155, 96], [ 43, 134], [ 86, 177], [172, 187], [ 69, 204], [138, 62], [ 9, 90],
+ [ 18, 203], [ 36, 89], [ 72, 95], [144, 176], [ 61, 156], [122, 169], [244, 160], [245, 81],
+ [247, 11], [243, 245], [251, 22], [235, 235], [203, 122], [139, 117], [ 11, 44], [ 22, 215],
+ [ 44, 79], [ 88, 174], [176, 213], [125, 233], [250, 230], [233, 231], [207, 173], [131, 232],
+ [ 27, 116], [ 54, 214], [108, 244], [216, 234], [173, 168], [ 71, 80], [142, 88], [ 1, 175],
+ ];
+
+ /**
+ * @var array
+ */
+ protected $num = [];
+
+ /**
+ * Polynomial constructor.
+ *
+ * @param array|null $num
+ * @param int|null $shift
+ */
+ public function __construct(array $num = null, int $shift = null){
+ $this->setNum($num ?? [1], $shift);
+ }
+
+ /**
+ * @return array
+ */
+ public function getNum():array{
+ return $this->num;
+ }
+
+ /**
+ * @param array $num
+ * @param int|null $shift
+ *
+ * @return \chillerlan\QRCode\Helpers\Polynomial
+ */
+ public function setNum(array $num, int $shift = null):Polynomial{
+ $offset = 0;
+ $numCount = count($num);
+
+ while($offset < $numCount && $num[$offset] === 0){
+ $offset++;
+ }
+
+ $this->num = array_fill(0, $numCount - $offset + ($shift ?? 0), 0);
+
+ for($i = 0; $i < $numCount - $offset; $i++){
+ $this->num[$i] = $num[$i + $offset];
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param array $e
+ *
+ * @return \chillerlan\QRCode\Helpers\Polynomial
+ */
+ public function multiply(array $e):Polynomial{
+ $n = array_fill(0, count($this->num) + count($e) - 1, 0);
+
+ foreach($this->num as $i => $vi){
+ $vi = $this->glog($vi);
+
+ foreach($e as $j => $vj){
+ $n[$i + $j] ^= $this->gexp($vi + $this->glog($vj));
+ }
+
+ }
+
+ $this->setNum($n);
+
+ return $this;
+ }
+
+ /**
+ * @param array $e
+ *
+ * @return \chillerlan\QRCode\Helpers\Polynomial
+ */
+ public function mod(array $e):Polynomial{
+ $n = $this->num;
+
+ if(count($n) - count($e) < 0){
+ return $this;
+ }
+
+ $ratio = $this->glog($n[0]) - $this->glog($e[0]);
+
+ foreach($e as $i => $v){
+ $n[$i] ^= $this->gexp($this->glog($v) + $ratio);
+ }
+
+ $this->setNum($n)->mod($e);
+
+ return $this;
+ }
+
+ /**
+ * @param int $n
+ *
+ * @return int
+ * @throws \chillerlan\QRCode\QRCodeException
+ */
+ public function glog(int $n):int{
+
+ if($n < 1){
+ throw new QRCodeException(sprintf('log(%s)', $n));
+ }
+
+ return Polynomial::table[$n][1];
+ }
+
+ /**
+ * @param int $n
+ *
+ * @return int
+ */
+ public function gexp(int $n):int{
+
+ if($n < 0){
+ $n += 255;
+ }
+ elseif($n >= 256){
+ $n -= 255;
+ }
+
+ return Polynomial::table[$n][0];
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QRCodeOutputException.php b/vendor/chillerlan/php-qrcode/src/Output/QRCodeOutputException.php
new file mode 100644
index 000000000..639bdd111
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Output/QRCodeOutputException.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Class QRCodeOutputException
+ *
+ * @filesource QRCodeOutputException.php
+ * @created 09.12.2015
+ * @package chillerlan\QRCode\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\QRCodeException;
+
+class QRCodeOutputException extends QRCodeException{}
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QRFpdf.php b/vendor/chillerlan/php-qrcode/src/Output/QRFpdf.php
new file mode 100644
index 000000000..a706685af
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Output/QRFpdf.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Class QRFpdf
+ *
+ * https://github.com/chillerlan/php-qrcode/pull/49
+ *
+ * @filesource QRFpdf.php
+ * @created 03.06.2020
+ * @package chillerlan\QRCode\Output
+ * @author Maximilian Kresse
+ *
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\Data\QRMatrix;
+use chillerlan\QRCode\QRCodeException;
+use chillerlan\Settings\SettingsContainerInterface;
+use FPDF;
+
+use function array_values, class_exists, count, is_array;
+
+/**
+ * QRFpdf output module (requires fpdf)
+ *
+ * @see https://github.com/Setasign/FPDF
+ * @see http://www.fpdf.org/
+ */
+class QRFpdf extends QROutputAbstract{
+
+ public function __construct(SettingsContainerInterface $options, QRMatrix $matrix){
+
+ if(!class_exists(FPDF::class)){
+ // @codeCoverageIgnoreStart
+ throw new QRCodeException(
+ 'The QRFpdf output requires FPDF as dependency but the class "\FPDF" couldn\'t be found.'
+ );
+ // @codeCoverageIgnoreEnd
+ }
+
+ parent::__construct($options, $matrix);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function setModuleValues():void{
+
+ foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){
+ $v = $this->options->moduleValues[$M_TYPE] ?? null;
+
+ if(!is_array($v) || count($v) < 3){
+ $this->moduleValues[$M_TYPE] = $defaultValue
+ ? [0, 0, 0]
+ : [255, 255, 255];
+ }
+ else{
+ $this->moduleValues[$M_TYPE] = array_values($v);
+ }
+
+ }
+
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @return string|\FPDF
+ */
+ public function dump(string $file = null){
+ $file = $file ?? $this->options->cachefile;
+
+ $fpdf = new FPDF('P', $this->options->fpdfMeasureUnit, [$this->length, $this->length]);
+ $fpdf->AddPage();
+
+ $prevColor = null;
+
+ foreach($this->matrix->matrix() as $y => $row){
+
+ foreach($row as $x => $M_TYPE){
+ /** @var int $M_TYPE */
+ $color = $this->moduleValues[$M_TYPE];
+
+ if($prevColor === null || $prevColor !== $color){
+ $fpdf->SetFillColor(...$color);
+ $prevColor = $color;
+ }
+
+ $fpdf->Rect($x * $this->scale, $y * $this->scale, 1 * $this->scale, 1 * $this->scale, 'F');
+ }
+
+ }
+
+ if($this->options->returnResource){
+ return $fpdf;
+ }
+
+ $pdfData = $fpdf->Output('S');
+
+ if($file !== null){
+ $this->saveToFile($pdfData, $file);
+ }
+
+ if($this->options->imageBase64){
+ $pdfData = sprintf('data:application/pdf;base64,%s', base64_encode($pdfData));
+ }
+
+ return $pdfData;
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QRImage.php b/vendor/chillerlan/php-qrcode/src/Output/QRImage.php
new file mode 100644
index 000000000..598948c94
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Output/QRImage.php
@@ -0,0 +1,208 @@
+<?php
+/**
+ * Class QRImage
+ *
+ * @filesource QRImage.php
+ * @created 05.12.2015
+ * @package chillerlan\QRCode\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ *
+ * @noinspection PhpComposerExtensionStubsInspection
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\Data\QRMatrix;
+use chillerlan\QRCode\{QRCode, QRCodeException};
+use chillerlan\Settings\SettingsContainerInterface;
+use Exception;
+
+use function array_values, base64_encode, call_user_func, count, imagecolorallocate, imagecolortransparent,
+ imagecreatetruecolor, imagedestroy, imagefilledrectangle, imagegif, imagejpeg, imagepng, in_array,
+ is_array, ob_end_clean, ob_get_contents, ob_start, range, sprintf;
+
+/**
+ * Converts the matrix into GD images, raw or base64 output
+ * requires ext-gd
+ * @link http://php.net/manual/book.image.php
+ */
+class QRImage extends QROutputAbstract{
+
+ protected const TRANSPARENCY_TYPES = [
+ QRCode::OUTPUT_IMAGE_PNG,
+ QRCode::OUTPUT_IMAGE_GIF,
+ ];
+
+ /**
+ * @var string
+ */
+ protected $defaultMode = QRCode::OUTPUT_IMAGE_PNG;
+
+ /**
+ * @see imagecreatetruecolor()
+ * @var resource
+ */
+ protected $image;
+
+ /**
+ * @inheritDoc
+ *
+ * @throws \chillerlan\QRCode\QRCodeException
+ */
+ public function __construct(SettingsContainerInterface $options, QRMatrix $matrix){
+
+ if(!extension_loaded('gd')){
+ throw new QRCodeException('ext-gd not loaded'); // @codeCoverageIgnore
+ }
+
+ parent::__construct($options, $matrix);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function setModuleValues():void{
+
+ foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){
+ $v = $this->options->moduleValues[$M_TYPE] ?? null;
+
+ if(!is_array($v) || count($v) < 3){
+ $this->moduleValues[$M_TYPE] = $defaultValue
+ ? [0, 0, 0]
+ : [255, 255, 255];
+ }
+ else{
+ $this->moduleValues[$M_TYPE] = array_values($v);
+ }
+
+ }
+
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @return string|resource
+ */
+ public function dump(string $file = null){
+ $this->image = imagecreatetruecolor($this->length, $this->length);
+
+ // avoid: Indirect modification of overloaded property $imageTransparencyBG has no effect
+ // https://stackoverflow.com/a/10455217
+ $tbg = $this->options->imageTransparencyBG;
+ $background = imagecolorallocate($this->image, ...$tbg);
+
+ if((bool)$this->options->imageTransparent && in_array($this->options->outputType, $this::TRANSPARENCY_TYPES, true)){
+ imagecolortransparent($this->image, $background);
+ }
+
+ imagefilledrectangle($this->image, 0, 0, $this->length, $this->length, $background);
+
+ foreach($this->matrix->matrix() as $y => $row){
+ foreach($row as $x => $M_TYPE){
+ $this->setPixel($x, $y, $this->moduleValues[$M_TYPE]);
+ }
+ }
+
+ if($this->options->returnResource){
+ return $this->image;
+ }
+
+ $imageData = $this->dumpImage($file);
+
+ if($this->options->imageBase64){
+ $imageData = sprintf('data:image/%s;base64,%s', $this->options->outputType, base64_encode($imageData));
+ }
+
+ return $imageData;
+ }
+
+ /**
+ * @param int $x
+ * @param int $y
+ * @param array $rgb
+ *
+ * @return void
+ */
+ protected function setPixel(int $x, int $y, array $rgb):void{
+ imagefilledrectangle(
+ $this->image,
+ $x * $this->scale,
+ $y * $this->scale,
+ ($x + 1) * $this->scale,
+ ($y + 1) * $this->scale,
+ imagecolorallocate($this->image, ...$rgb)
+ );
+ }
+
+ /**
+ * @param string|null $file
+ *
+ * @return string
+
+ * @throws \chillerlan\QRCode\Output\QRCodeOutputException
+ */
+ protected function dumpImage(string $file = null):string{
+ $file = $file ?? $this->options->cachefile;
+
+ ob_start();
+
+ try{
+ call_user_func([$this, $this->outputMode ?? $this->defaultMode]);
+ }
+ // not going to cover edge cases
+ // @codeCoverageIgnoreStart
+ catch(Exception $e){
+ throw new QRCodeOutputException($e->getMessage());
+ }
+ // @codeCoverageIgnoreEnd
+
+ $imageData = ob_get_contents();
+ imagedestroy($this->image);
+
+ ob_end_clean();
+
+ if($file !== null){
+ $this->saveToFile($imageData, $file);
+ }
+
+ return $imageData;
+ }
+
+ /**
+ * @return void
+ */
+ protected function png():void{
+ imagepng(
+ $this->image,
+ null,
+ in_array($this->options->pngCompression, range(-1, 9), true)
+ ? $this->options->pngCompression
+ : -1
+ );
+ }
+
+ /**
+ * Jiff - like... JitHub!
+ * @return void
+ */
+ protected function gif():void{
+ imagegif($this->image);
+ }
+
+ /**
+ * @return void
+ */
+ protected function jpg():void{
+ imagejpeg(
+ $this->image,
+ null,
+ in_array($this->options->jpegQuality, range(0, 100), true)
+ ? $this->options->jpegQuality
+ : 85
+ );
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QRImagick.php b/vendor/chillerlan/php-qrcode/src/Output/QRImagick.php
new file mode 100644
index 000000000..03886cf3b
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Output/QRImagick.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * Class QRImagick
+ *
+ * @filesource QRImagick.php
+ * @created 04.07.2018
+ * @package chillerlan\QRCode\Output
+ * @author smiley <[email protected]>
+ * @copyright 2018 smiley
+ * @license MIT
+ *
+ * @noinspection PhpComposerExtensionStubsInspection
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\Data\QRMatrix;
+use chillerlan\QRCode\QRCodeException;
+use chillerlan\Settings\SettingsContainerInterface;
+use Imagick, ImagickDraw, ImagickPixel;
+
+use function is_string;
+
+/**
+ * ImageMagick output module
+ * requires ext-imagick
+ * @link http://php.net/manual/book.imagick.php
+ * @link http://phpimagick.com
+ */
+class QRImagick extends QROutputAbstract{
+
+ /**
+ * @var \Imagick
+ */
+ protected $imagick;
+
+ /**
+ * @inheritDoc
+ * @throws \chillerlan\QRCode\QRCodeException
+ */
+ public function __construct(SettingsContainerInterface $options, QRMatrix $matrix){
+
+ if(!extension_loaded('imagick')){
+ throw new QRCodeException('ext-imagick not loaded'); // @codeCoverageIgnore
+ }
+
+ parent::__construct($options, $matrix);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function setModuleValues():void{
+
+ foreach($this::DEFAULT_MODULE_VALUES as $type => $defaultValue){
+ $v = $this->options->moduleValues[$type] ?? null;
+
+ if(!is_string($v)){
+ $this->moduleValues[$type] = $defaultValue
+ ? new ImagickPixel($this->options->markupDark)
+ : new ImagickPixel($this->options->markupLight);
+ }
+ else{
+ $this->moduleValues[$type] = new ImagickPixel($v);
+ }
+ }
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @return string|\Imagick
+ */
+ public function dump(string $file = null){
+ $file = $file ?? $this->options->cachefile;
+ $this->imagick = new Imagick;
+
+ $this->imagick->newImage(
+ $this->length,
+ $this->length,
+ new ImagickPixel($this->options->imagickBG ?? 'transparent'),
+ $this->options->imagickFormat
+ );
+
+ $this->drawImage();
+
+ if($this->options->returnResource){
+ return $this->imagick;
+ }
+
+ $imageData = $this->imagick->getImageBlob();
+
+ if($file !== null){
+ $this->saveToFile($imageData, $file);
+ }
+
+ return $imageData;
+ }
+
+ /**
+ * @return void
+ */
+ protected function drawImage():void{
+ $draw = new ImagickDraw;
+
+ foreach($this->matrix->matrix() as $y => $row){
+ foreach($row as $x => $M_TYPE){
+ $draw->setStrokeColor($this->moduleValues[$M_TYPE]);
+ $draw->setFillColor($this->moduleValues[$M_TYPE]);
+ $draw->rectangle(
+ $x * $this->scale,
+ $y * $this->scale,
+ ($x + 1) * $this->scale,
+ ($y + 1) * $this->scale
+ );
+
+ }
+ }
+
+ $this->imagick->drawImage($draw);
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QRMarkup.php b/vendor/chillerlan/php-qrcode/src/Output/QRMarkup.php
new file mode 100644
index 000000000..15559dae0
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Output/QRMarkup.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * Class QRMarkup
+ *
+ * @filesource QRMarkup.php
+ * @created 17.12.2016
+ * @package chillerlan\QRCode\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2016 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\QRCode;
+
+use function is_string, sprintf, strip_tags, trim;
+
+/**
+ * Converts the matrix into markup types: HTML, SVG, ...
+ */
+class QRMarkup extends QROutputAbstract{
+
+ /**
+ * @var string
+ */
+ protected $defaultMode = QRCode::OUTPUT_MARKUP_SVG;
+
+ /**
+ * @see \sprintf()
+ *
+ * @var string
+ */
+ protected $svgHeader = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="qr-svg %1$s" style="width: 100%%; height: auto;" viewBox="0 0 %2$d %2$d">';
+
+ /**
+ * @inheritDoc
+ */
+ protected function setModuleValues():void{
+
+ foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){
+ $v = $this->options->moduleValues[$M_TYPE] ?? null;
+
+ if(!is_string($v)){
+ $this->moduleValues[$M_TYPE] = $defaultValue
+ ? $this->options->markupDark
+ : $this->options->markupLight;
+ }
+ else{
+ $this->moduleValues[$M_TYPE] = trim(strip_tags($v), '\'"');
+ }
+
+ }
+
+ }
+
+ /**
+ * @return string
+ */
+ protected function html():string{
+ $html = '<div class="'.$this->options->cssClass.'">'.$this->options->eol;
+
+ foreach($this->matrix->matrix() as $row){
+ $html .= '<div>';
+
+ foreach($row as $M_TYPE){
+ $html .= '<span style="background: '.$this->moduleValues[$M_TYPE].';"></span>';
+ }
+
+ $html .= '</div>'.$this->options->eol;
+ }
+
+ $html .= '</div>'.$this->options->eol;
+
+ if($this->options->cachefile){
+ return '<!DOCTYPE html><head><meta charset="UTF-8"></head><body>'.$this->options->eol.$html.'</body>';
+ }
+
+ return $html;
+ }
+
+ /**
+ * @link https://github.com/codemasher/php-qrcode/pull/5
+ *
+ * @return string
+ */
+ protected function svg():string{
+ $matrix = $this->matrix->matrix();
+
+ $svg = sprintf($this->svgHeader, $this->options->cssClass, $this->options->svgViewBoxSize ?? $this->moduleCount)
+ .$this->options->eol
+ .'<defs>'.$this->options->svgDefs.'</defs>'
+ .$this->options->eol;
+
+ foreach($this->moduleValues as $M_TYPE => $value){
+ $path = '';
+
+ foreach($matrix as $y => $row){
+ //we'll combine active blocks within a single row as a lightweight compression technique
+ $start = null;
+ $count = 0;
+
+ foreach($row as $x => $module){
+
+ if($module === $M_TYPE){
+ $count++;
+
+ if($start === null){
+ $start = $x;
+ }
+
+ if(isset($row[$x + 1])){
+ continue;
+ }
+ }
+
+ if($count > 0){
+ $len = $count;
+ $path .= sprintf('M%s %s h%s v1 h-%sZ ', $start, $y, $len, $len);
+
+ // reset count
+ $count = 0;
+ $start = null;
+ }
+
+ }
+
+ }
+
+ if(!empty($path)){
+ $svg .= sprintf('<path class="qr-%s %s" stroke="transparent" fill="%s" fill-opacity="%s" d="%s" />', $M_TYPE, $this->options->cssClass, $value, $this->options->svgOpacity, $path);
+ }
+
+ }
+
+ // close svg
+ $svg .= '</svg>'.$this->options->eol;
+
+ // if saving to file, append the correct headers
+ if($this->options->cachefile){
+ return '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'.$this->options->eol.$svg;
+ }
+
+ if($this->options->imageBase64){
+ $svg = sprintf('data:image/svg+xml;base64,%s', base64_encode($svg));
+ }
+
+ return $svg;
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php b/vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php
new file mode 100644
index 000000000..4ec47de24
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Output/QROutputAbstract.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * Class QROutputAbstract
+ *
+ * @filesource QROutputAbstract.php
+ * @created 09.12.2015
+ * @package chillerlan\QRCode\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\{Data\QRMatrix, QRCode};
+use chillerlan\Settings\SettingsContainerInterface;
+
+use function call_user_func, dirname, file_put_contents, get_called_class, in_array, is_writable, sprintf;
+
+/**
+ * common output abstract
+ */
+abstract class QROutputAbstract implements QROutputInterface{
+
+ /**
+ * @var int
+ */
+ protected $moduleCount;
+
+ /**
+ * @param \chillerlan\QRCode\Data\QRMatrix $matrix
+ */
+ protected $matrix;
+
+ /**
+ * @var \chillerlan\QRCode\QROptions
+ */
+ protected $options;
+
+ /**
+ * @var string
+ */
+ protected $outputMode;
+
+ /**
+ * @var string;
+ */
+ protected $defaultMode;
+
+ /**
+ * @var int
+ */
+ protected $scale;
+
+ /**
+ * @var int
+ */
+ protected $length;
+
+ /**
+ * @var array
+ */
+ protected $moduleValues;
+
+ /**
+ * QROutputAbstract constructor.
+ *
+ * @param \chillerlan\Settings\SettingsContainerInterface $options
+ * @param \chillerlan\QRCode\Data\QRMatrix $matrix
+ */
+ public function __construct(SettingsContainerInterface $options, QRMatrix $matrix){
+ $this->options = $options;
+ $this->matrix = $matrix;
+ $this->moduleCount = $this->matrix->size();
+ $this->scale = $this->options->scale;
+ $this->length = $this->moduleCount * $this->scale;
+
+ $class = get_called_class();
+
+ if(isset(QRCode::OUTPUT_MODES[$class]) && in_array($this->options->outputType, QRCode::OUTPUT_MODES[$class])){
+ $this->outputMode = $this->options->outputType;
+ }
+
+ $this->setModuleValues();
+ }
+
+ /**
+ * Sets the initial module values (clean-up & defaults)
+ *
+ * @return void
+ */
+ abstract protected function setModuleValues():void;
+
+ /**
+ * saves the qr data to a file
+ *
+ * @see file_put_contents()
+ * @see \chillerlan\QRCode\QROptions::cachefile
+ *
+ * @param string $data
+ * @param string $file
+ *
+ * @return bool
+ * @throws \chillerlan\QRCode\Output\QRCodeOutputException
+ */
+ protected function saveToFile(string $data, string $file):bool{
+
+ if(!is_writable(dirname($file))){
+ throw new QRCodeOutputException(sprintf('Could not write data to cache file: %s', $file));
+ }
+
+ return (bool)file_put_contents($file, $data);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function dump(string $file = null){
+ // call the built-in output method
+ $data = call_user_func([$this, $this->outputMode ?? $this->defaultMode]);
+ $file = $file ?? $this->options->cachefile;
+
+ if($file !== null){
+ $this->saveToFile($data, $file);
+ }
+
+ return $data;
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QROutputInterface.php b/vendor/chillerlan/php-qrcode/src/Output/QROutputInterface.php
new file mode 100644
index 000000000..d9149b0f7
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Output/QROutputInterface.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Interface QROutputInterface,
+ *
+ * @filesource QROutputInterface.php
+ * @created 02.12.2015
+ * @package chillerlan\QRCode\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\Data\QRMatrix;
+
+/**
+ * Converts the data matrix into readable output
+ */
+interface QROutputInterface{
+
+ const DEFAULT_MODULE_VALUES = [
+ // light
+ QRMatrix::M_DATA => false, // 4
+ QRMatrix::M_FINDER => false, // 6
+ QRMatrix::M_SEPARATOR => false, // 8
+ QRMatrix::M_ALIGNMENT => false, // 10
+ QRMatrix::M_TIMING => false, // 12
+ QRMatrix::M_FORMAT => false, // 14
+ QRMatrix::M_VERSION => false, // 16
+ QRMatrix::M_QUIETZONE => false, // 18
+ QRMatrix::M_LOGO => false, // 20
+ QRMatrix::M_TEST => false, // 255
+ // dark
+ QRMatrix::M_DARKMODULE << 8 => true, // 512
+ QRMatrix::M_DATA << 8 => true, // 1024
+ QRMatrix::M_FINDER << 8 => true, // 1536
+ QRMatrix::M_ALIGNMENT << 8 => true, // 2560
+ QRMatrix::M_TIMING << 8 => true, // 3072
+ QRMatrix::M_FORMAT << 8 => true, // 3584
+ QRMatrix::M_VERSION << 8 => true, // 4096
+ QRMatrix::M_FINDER_DOT << 8 => true, // 5632
+ QRMatrix::M_TEST << 8 => true, // 65280
+ ];
+
+ /**
+ * generates the output, optionally dumps it to a file, and returns it
+ *
+ * @param string|null $file
+ *
+ * @return mixed
+ */
+ public function dump(string $file = null);
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/Output/QRString.php b/vendor/chillerlan/php-qrcode/src/Output/QRString.php
new file mode 100644
index 000000000..ba8d83675
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/Output/QRString.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Class QRString
+ *
+ * @filesource QRString.php
+ * @created 05.12.2015
+ * @package chillerlan\QRCode\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode\Output;
+
+use chillerlan\QRCode\QRCode;
+
+use function implode, is_string, json_encode;
+
+/**
+ * Converts the matrix data into string types
+ */
+class QRString extends QROutputAbstract{
+
+ /**
+ * @var string
+ */
+ protected $defaultMode = QRCode::OUTPUT_STRING_TEXT;
+
+ /**
+ * @inheritDoc
+ */
+ protected function setModuleValues():void{
+
+ foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){
+ $v = $this->options->moduleValues[$M_TYPE] ?? null;
+
+ if(!is_string($v)){
+ $this->moduleValues[$M_TYPE] = $defaultValue
+ ? $this->options->textDark
+ : $this->options->textLight;
+ }
+ else{
+ $this->moduleValues[$M_TYPE] = $v;
+ }
+
+ }
+
+ }
+
+ /**
+ * @return string
+ */
+ protected function text():string{
+ $str = [];
+
+ foreach($this->matrix->matrix() as $row){
+ $r = [];
+
+ foreach($row as $M_TYPE){
+ $r[] = $this->moduleValues[$M_TYPE];
+ }
+
+ $str[] = implode('', $r);
+ }
+
+ return implode($this->options->eol, $str);
+ }
+
+ /**
+ * @return string
+ */
+ protected function json():string{
+ return json_encode($this->matrix->matrix());
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/QRCode.php b/vendor/chillerlan/php-qrcode/src/QRCode.php
new file mode 100644
index 000000000..91f7aa0eb
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/QRCode.php
@@ -0,0 +1,310 @@
+<?php
+/**
+ * Class QRCode
+ *
+ * @filesource QRCode.php
+ * @created 26.11.2015
+ * @package chillerlan\QRCode
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode;
+
+use chillerlan\QRCode\Data\{
+ MaskPatternTester, QRCodeDataException, QRDataInterface, QRMatrix
+};
+use chillerlan\QRCode\Output\{
+ QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString
+};
+use chillerlan\Settings\SettingsContainerInterface;
+
+use function array_search, call_user_func_array, class_exists, in_array, min, ord, strlen;
+
+/**
+ * Turns a text string into a Model 2 QR Code
+ *
+ * @link https://github.com/kazuhikoarase/qrcode-generator/tree/master/php
+ * @link http://www.qrcode.com/en/codes/model12.html
+ * @link http://www.thonky.com/qr-code-tutorial/
+ */
+class QRCode{
+
+ /**
+ * API constants
+ */
+ public const OUTPUT_MARKUP_HTML = 'html';
+ public const OUTPUT_MARKUP_SVG = 'svg';
+ public const OUTPUT_IMAGE_PNG = 'png';
+ public const OUTPUT_IMAGE_JPG = 'jpg';
+ public const OUTPUT_IMAGE_GIF = 'gif';
+ public const OUTPUT_STRING_JSON = 'json';
+ public const OUTPUT_STRING_TEXT = 'text';
+ public const OUTPUT_IMAGICK = 'imagick';
+ public const OUTPUT_FPDF = 'fpdf';
+ public const OUTPUT_CUSTOM = 'custom';
+
+ public const VERSION_AUTO = -1;
+ public const MASK_PATTERN_AUTO = -1;
+
+ public const ECC_L = 0b01; // 7%.
+ public const ECC_M = 0b00; // 15%.
+ public const ECC_Q = 0b11; // 25%.
+ public const ECC_H = 0b10; // 30%.
+
+ public const DATA_NUMBER = 0b0001;
+ public const DATA_ALPHANUM = 0b0010;
+ public const DATA_BYTE = 0b0100;
+ public const DATA_KANJI = 0b1000;
+
+ public const ECC_MODES = [
+ self::ECC_L => 0,
+ self::ECC_M => 1,
+ self::ECC_Q => 2,
+ self::ECC_H => 3,
+ ];
+
+ public const DATA_MODES = [
+ self::DATA_NUMBER => 0,
+ self::DATA_ALPHANUM => 1,
+ self::DATA_BYTE => 2,
+ self::DATA_KANJI => 3,
+ ];
+
+ public const OUTPUT_MODES = [
+ QRMarkup::class => [
+ self::OUTPUT_MARKUP_SVG,
+ self::OUTPUT_MARKUP_HTML,
+ ],
+ QRImage::class => [
+ self::OUTPUT_IMAGE_PNG,
+ self::OUTPUT_IMAGE_GIF,
+ self::OUTPUT_IMAGE_JPG,
+ ],
+ QRString::class => [
+ self::OUTPUT_STRING_JSON,
+ self::OUTPUT_STRING_TEXT,
+ ],
+ QRImagick::class => [
+ self::OUTPUT_IMAGICK,
+ ],
+ QRFpdf::class => [
+ self::OUTPUT_FPDF
+ ]
+ ];
+
+ /**
+ * @var \chillerlan\QRCode\QROptions|\chillerlan\Settings\SettingsContainerInterface
+ */
+ protected $options;
+
+ /**
+ * @var \chillerlan\QRCode\Data\QRDataInterface
+ */
+ protected $dataInterface;
+
+ /**
+ * QRCode constructor.
+ *
+ * @param \chillerlan\Settings\SettingsContainerInterface|null $options
+ */
+ public function __construct(SettingsContainerInterface $options = null){
+ $this->options = $options ?? new QROptions;
+ }
+
+ /**
+ * Renders a QR Code for the given $data and QROptions
+ *
+ * @param string $data
+ * @param string|null $file
+ *
+ * @return mixed
+ */
+ public function render(string $data, string $file = null){
+ return $this->initOutputInterface($data)->dump($file);
+ }
+
+ /**
+ * Returns a QRMatrix object for the given $data and current QROptions
+ *
+ * @param string $data
+ *
+ * @return \chillerlan\QRCode\Data\QRMatrix
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ public function getMatrix(string $data):QRMatrix{
+
+ if(empty($data)){
+ throw new QRCodeDataException('QRCode::getMatrix() No data given.');
+ }
+
+ $this->dataInterface = $this->initDataInterface($data);
+
+ $maskPattern = $this->options->maskPattern === $this::MASK_PATTERN_AUTO
+ ? $this->getBestMaskPattern()
+ : $this->options->maskPattern;
+
+ $matrix = $this->dataInterface->initMatrix($maskPattern);
+
+ if((bool)$this->options->addQuietzone){
+ $matrix->setQuietZone($this->options->quietzoneSize);
+ }
+
+ return $matrix;
+ }
+
+ /**
+ * shoves a QRMatrix through the MaskPatternTester to find the lowest penalty mask pattern
+ *
+ * @see \chillerlan\QRCode\Data\MaskPatternTester
+ *
+ * @return int
+ */
+ protected function getBestMaskPattern():int{
+ $penalties = [];
+
+ for($pattern = 0; $pattern < 8; $pattern++){
+ $tester = new MaskPatternTester($this->dataInterface->initMatrix($pattern, true));
+
+ $penalties[$pattern] = $tester->testPattern();
+ }
+
+ return array_search(min($penalties), $penalties, true);
+ }
+
+ /**
+ * returns a fresh QRDataInterface for the given $data
+ *
+ * @param string $data
+ *
+ * @return \chillerlan\QRCode\Data\QRDataInterface
+ * @throws \chillerlan\QRCode\Data\QRCodeDataException
+ */
+ public function initDataInterface(string $data):QRDataInterface{
+ $dataModes = ['Number', 'AlphaNum', 'Kanji', 'Byte'];
+ $dataNamespace = __NAMESPACE__.'\\Data\\';
+
+ // allow forcing the data mode
+ // see https://github.com/chillerlan/php-qrcode/issues/39
+ if(in_array($this->options->dataMode, $dataModes, true)){
+ $dataInterface = $dataNamespace.$this->options->dataMode;
+
+ return new $dataInterface($this->options, $data);
+ }
+
+ foreach($dataModes as $mode){
+ $dataInterface = $dataNamespace.$mode;
+
+ if(call_user_func_array([$this, 'is'.$mode], [$data]) && class_exists($dataInterface)){
+ return new $dataInterface($this->options, $data);
+ }
+
+ }
+
+ throw new QRCodeDataException('invalid data type'); // @codeCoverageIgnore
+ }
+
+ /**
+ * returns a fresh (built-in) QROutputInterface
+ *
+ * @param string $data
+ *
+ * @return \chillerlan\QRCode\Output\QROutputInterface
+ * @throws \chillerlan\QRCode\Output\QRCodeOutputException
+ */
+ protected function initOutputInterface(string $data):QROutputInterface{
+
+ if($this->options->outputType === $this::OUTPUT_CUSTOM && class_exists($this->options->outputInterface)){
+ return new $this->options->outputInterface($this->options, $this->getMatrix($data));
+ }
+
+ foreach($this::OUTPUT_MODES as $outputInterface => $modes){
+
+ if(in_array($this->options->outputType, $modes, true) && class_exists($outputInterface)){
+ return new $outputInterface($this->options, $this->getMatrix($data));
+ }
+
+ }
+
+ throw new QRCodeOutputException('invalid output type');
+ }
+
+ /**
+ * checks if a string qualifies as numeric
+ *
+ * @param string $string
+ *
+ * @return bool
+ */
+ public function isNumber(string $string):bool{
+ return $this->checkString($string, QRDataInterface::NUMBER_CHAR_MAP);
+ }
+
+ /**
+ * checks if a string qualifies as alphanumeric
+ *
+ * @param string $string
+ *
+ * @return bool
+ */
+ public function isAlphaNum(string $string):bool{
+ return $this->checkString($string, QRDataInterface::ALPHANUM_CHAR_MAP);
+ }
+
+ /**
+ * checks is a given $string matches the characters of a given $charmap, returns false on the first invalid occurence.
+ *
+ * @param string $string
+ * @param array $charmap
+ *
+ * @return bool
+ */
+ protected function checkString(string $string, array $charmap):bool{
+ $len = strlen($string);
+
+ for($i = 0; $i < $len; $i++){
+ if(!in_array($string[$i], $charmap, true)){
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * checks if a string qualifies as Kanji
+ *
+ * @param string $string
+ *
+ * @return bool
+ */
+ public function isKanji(string $string):bool{
+ $i = 0;
+ $len = strlen($string);
+
+ while($i + 1 < $len){
+ $c = ((0xff & ord($string[$i])) << 8) | (0xff & ord($string[$i + 1]));
+
+ if(!($c >= 0x8140 && $c <= 0x9FFC) && !($c >= 0xE040 && $c <= 0xEBBF)){
+ return false;
+ }
+
+ $i += 2;
+ }
+
+ return $i >= $len;
+ }
+
+ /**
+ * a dummy
+ *
+ * @param $data
+ *
+ * @return bool
+ */
+ protected function isByte(string $data):bool{
+ return !empty($data);
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/src/QRCodeException.php b/vendor/chillerlan/php-qrcode/src/QRCodeException.php
new file mode 100644
index 000000000..68af380ff
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/QRCodeException.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Class QRCodeException
+ *
+ * @filesource QRCodeException.php
+ * @created 27.11.2015
+ * @package chillerlan\QRCode
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode;
+
+class QRCodeException extends \Exception{}
diff --git a/vendor/chillerlan/php-qrcode/src/QROptions.php b/vendor/chillerlan/php-qrcode/src/QROptions.php
new file mode 100644
index 000000000..778ae0407
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/QROptions.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Class QROptions
+ *
+ * @filesource QROptions.php
+ * @created 08.12.2015
+ * @package chillerlan\QRCode
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode;
+
+use chillerlan\Settings\SettingsContainerAbstract;
+
+/**
+ * @property int $version
+ * @property int $versionMin
+ * @property int $versionMax
+ * @property int $eccLevel
+ * @property int $maskPattern
+ * @property bool $addQuietzone
+ * @property bool $quietzoneSize
+ *
+ * @property string $dataMode
+ * @property string $outputType
+ * @property string $outputInterface
+ * @property string $cachefile
+ *
+ * @property string $eol
+ * @property int $scale
+ *
+ * @property string $cssClass
+ * @property string $svgOpacity
+ * @property string $svgDefs
+ * @property int $svgViewBoxSize
+ *
+ * @property string $textDark
+ * @property string $textLight
+ *
+ * @property string $markupDark
+ * @property string $markupLight
+ *
+ * @property bool $returnResource
+ * @property bool $imageBase64
+ * @property bool $imageTransparent
+ * @property array $imageTransparencyBG
+ * @property int $pngCompression
+ * @property int $jpegQuality
+ *
+ * @property string $imagickFormat
+ * @property string $imagickBG
+ *
+ * @property string $fpdfMeasureUnit
+ *
+ * @property array $moduleValues
+ */
+class QROptions extends SettingsContainerAbstract{
+ use QROptionsTrait;
+}
diff --git a/vendor/chillerlan/php-qrcode/src/QROptionsTrait.php b/vendor/chillerlan/php-qrcode/src/QROptionsTrait.php
new file mode 100644
index 000000000..45d4cb415
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/src/QROptionsTrait.php
@@ -0,0 +1,408 @@
+<?php
+/**
+ * Trait QROptionsTrait
+ *
+ * @filesource QROptionsTrait.php
+ * @created 10.03.2018
+ * @package chillerlan\QRCode
+ * @author smiley <[email protected]>
+ * @copyright 2018 smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCode;
+
+use function array_values, count, in_array, is_array, is_numeric, max, min, sprintf, strtolower;
+
+trait QROptionsTrait{
+
+ /**
+ * QR Code version number
+ *
+ * [1 ... 40] or QRCode::VERSION_AUTO
+ *
+ * @var int
+ */
+ protected $version = QRCode::VERSION_AUTO;
+
+ /**
+ * Minimum QR version (if $version = QRCode::VERSION_AUTO)
+ *
+ * @var int
+ */
+ protected $versionMin = 1;
+
+ /**
+ * Maximum QR version
+ *
+ * @var int
+ */
+ protected $versionMax = 40;
+
+ /**
+ * Error correct level
+ *
+ * QRCode::ECC_X where X is
+ * L => 7%
+ * M => 15%
+ * Q => 25%
+ * H => 30%
+ *
+ * @var int
+ */
+ protected $eccLevel = QRCode::ECC_L;
+
+ /**
+ * Mask Pattern to use
+ *
+ * [0...7] or QRCode::MASK_PATTERN_AUTO
+ *
+ * @var int
+ */
+ protected $maskPattern = QRCode::MASK_PATTERN_AUTO;
+
+ /**
+ * Add a "quiet zone" (margin) according to the QR code spec
+ *
+ * @var bool
+ */
+ protected $addQuietzone = true;
+
+ /**
+ * Size of the quiet zone
+ *
+ * internally clamped to [0 ... $moduleCount / 2], defaults to 4 modules
+ *
+ * @var int
+ */
+ protected $quietzoneSize = 4;
+
+ /**
+ * Use this to circumvent the data mode detection and force the usage of the given mode.
+ * valid modes are: Number, AlphaNum, Kanji, Byte
+ *
+ * @see https://github.com/chillerlan/php-qrcode/issues/39
+ *
+ * @var string|null
+ */
+ protected $dataMode = null;
+
+ /**
+ * QRCode::OUTPUT_MARKUP_XXXX where XXXX = HTML, SVG
+ * QRCode::OUTPUT_IMAGE_XXX where XXX = PNG, GIF, JPG
+ * QRCode::OUTPUT_STRING_XXXX where XXXX = TEXT, JSON
+ * QRCode::OUTPUT_CUSTOM
+ *
+ * @var string
+ */
+ protected $outputType = QRCode::OUTPUT_IMAGE_PNG;
+
+ /**
+ * the FQCN of the custom QROutputInterface if $outputType is set to QRCode::OUTPUT_CUSTOM
+ *
+ * @var string|null
+ */
+ protected $outputInterface = null;
+
+ /**
+ * /path/to/cache.file
+ *
+ * @var string|null
+ */
+ protected $cachefile = null;
+
+ /**
+ * newline string [HTML, SVG, TEXT]
+ *
+ * @var string
+ */
+ protected $eol = PHP_EOL;
+
+ /**
+ * size of a QR code pixel [SVG, IMAGE_*]
+ * HTML -> via CSS
+ *
+ * @var int
+ */
+ protected $scale = 5;
+
+ /**
+ * a common css class
+ *
+ * @var string
+ */
+ protected $cssClass = '';
+
+ /**
+ * SVG opacity
+ *
+ * @var float
+ */
+ protected $svgOpacity = 1.0;
+
+ /**
+ * anything between <defs>
+ *
+ * @see https://developer.mozilla.org/docs/Web/SVG/Element/defs
+ *
+ * @var string
+ */
+ protected $svgDefs = '<style>rect{shape-rendering:crispEdges}</style>';
+
+ /**
+ * SVG viewBox size. a single integer number which defines width/height of the viewBox attribute.
+ *
+ * viewBox="0 0 x x"
+ *
+ * @see https://css-tricks.com/scale-svg/#article-header-id-3
+ *
+ * @var int|null
+ */
+ protected $svgViewBoxSize = null;
+
+ /**
+ * string substitute for dark
+ *
+ * @var string
+ */
+ protected $textDark = '🔴';
+
+ /**
+ * string substitute for light
+ *
+ * @var string
+ */
+ protected $textLight = '⭕';
+
+ /**
+ * markup substitute for dark (CSS value)
+ *
+ * @var string
+ */
+ protected $markupDark = '#000';
+
+ /**
+ * markup substitute for light (CSS value)
+ *
+ * @var string
+ */
+ protected $markupLight = '#fff';
+
+ /**
+ * Return the image resource instead of a render if applicable.
+ * This option overrides other output options, such as $cachefile and $imageBase64.
+ *
+ * Supported by the following modules:
+ *
+ * - QRImage: resource
+ * - QRImagick: Imagick
+ * - QRFpdf: FPDF
+ *
+ * @see \chillerlan\QRCode\Output\QROutputInterface::dump()
+ *
+ * @var bool
+ */
+ protected $returnResource = false;
+
+ /**
+ * toggle base64 or raw image data
+ *
+ * @var bool
+ */
+ protected $imageBase64 = true;
+
+ /**
+ * toggle transparency, not supported by jpg
+ *
+ * @var bool
+ */
+ protected $imageTransparent = true;
+
+ /**
+ * @see imagecolortransparent()
+ *
+ * @var array [R, G, B]
+ */
+ protected $imageTransparencyBG = [255, 255, 255];
+
+ /**
+ * @see imagepng()
+ *
+ * @var int
+ */
+ protected $pngCompression = -1;
+
+ /**
+ * @see imagejpeg()
+ *
+ * @var int
+ */
+ protected $jpegQuality = 85;
+
+ /**
+ * Imagick output format
+ *
+ * @see Imagick::setType()
+ *
+ * @var string
+ */
+ protected $imagickFormat = 'png';
+
+ /**
+ * Imagick background color (defaults to "transparent")
+ *
+ * @see \ImagickPixel::__construct()
+ *
+ * @var string|null
+ */
+ protected $imagickBG = null;
+
+ /**
+ * Measurement unit for FPDF output: pt, mm, cm, in (defaults to "pt")
+ *
+ * @see \FPDF::__construct()
+ */
+ protected $fpdfMeasureUnit = 'pt';
+
+ /**
+ * Module values map
+ *
+ * HTML, IMAGICK: #ABCDEF, cssname, rgb(), rgba()...
+ * IMAGE: [63, 127, 255] // R, G, B
+ *
+ * @var array|null
+ */
+ protected $moduleValues = null;
+
+ /**
+ * clamp min/max version number
+ *
+ * @param int $versionMin
+ * @param int $versionMax
+ *
+ * @return void
+ */
+ protected function setMinMaxVersion(int $versionMin, int $versionMax):void{
+ $min = max(1, min(40, $versionMin));
+ $max = max(1, min(40, $versionMax));
+
+ $this->versionMin = min($min, $max);
+ $this->versionMax = max($min, $max);
+ }
+
+ /**
+ * sets the minimum version number
+ *
+ * @param int $version
+ *
+ * @return void
+ */
+ protected function set_versionMin(int $version):void{
+ $this->setMinMaxVersion($version, $this->versionMax);
+ }
+
+ /**
+ * sets the maximum version number
+ *
+ * @param int $version
+ *
+ * @return void
+ */
+ protected function set_versionMax(int $version):void{
+ $this->setMinMaxVersion($this->versionMin, $version);
+ }
+
+ /**
+ * sets the error correction level
+ *
+ * @param int $eccLevel
+ *
+ * @return void
+ * @throws \chillerlan\QRCode\QRCodeException
+ */
+ protected function set_eccLevel(int $eccLevel):void{
+
+ if(!isset(QRCode::ECC_MODES[$eccLevel])){
+ throw new QRCodeException(sprintf('Invalid error correct level: %s', $eccLevel));
+ }
+
+ $this->eccLevel = $eccLevel;
+ }
+
+ /**
+ * sets/clamps the mask pattern
+ *
+ * @param int $maskPattern
+ *
+ * @return void
+ */
+ protected function set_maskPattern(int $maskPattern):void{
+
+ if($maskPattern !== QRCode::MASK_PATTERN_AUTO){
+ $this->maskPattern = max(0, min(7, $maskPattern));
+ }
+
+ }
+
+ /**
+ * sets the transparency background color
+ *
+ * @param mixed $imageTransparencyBG
+ *
+ * @return void
+ * @throws \chillerlan\QRCode\QRCodeException
+ */
+ protected function set_imageTransparencyBG($imageTransparencyBG):void{
+
+ // invalid value - set to white as default
+ if(!is_array($imageTransparencyBG) || count($imageTransparencyBG) < 3){
+ $this->imageTransparencyBG = [255, 255, 255];
+
+ return;
+ }
+
+ foreach($imageTransparencyBG as $k => $v){
+
+ if(!is_numeric($v)){
+ throw new QRCodeException('Invalid RGB value.');
+ }
+
+ // clamp the values
+ $this->imageTransparencyBG[$k] = max(0, min(255, (int)$v));
+ }
+
+ // use the array values to not run into errors with the spread operator (...$arr)
+ $this->imageTransparencyBG = array_values($this->imageTransparencyBG);
+ }
+
+ /**
+ * sets/clamps the version number
+ *
+ * @param int $version
+ *
+ * @return void
+ */
+ protected function set_version(int $version):void{
+
+ if($version !== QRCode::VERSION_AUTO){
+ $this->version = max(1, min(40, $version));
+ }
+
+ }
+
+ /**
+ * sets the FPDF measurement unit
+ *
+ * @codeCoverageIgnore
+ */
+ protected function set_fpdfMeasureUnit(string $unit):void{
+ $unit = strtolower($unit);
+
+ if(in_array($unit, ['cm', 'in', 'mm', 'pt'], true)){
+ $this->fpdfMeasureUnit = $unit;
+ }
+
+ // @todo throw or ignore silently?
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Data/AlphaNumTest.php b/vendor/chillerlan/php-qrcode/tests/Data/AlphaNumTest.php
new file mode 100644
index 000000000..c29b1f639
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Data/AlphaNumTest.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Class AlphaNumTest
+ *
+ * @filesource AlphaNumTest.php
+ * @created 24.11.2017
+ * @package chillerlan\QRCodeTest\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Data;
+
+use chillerlan\QRCode\Data\{AlphaNum, QRCodeDataException};
+
+class AlphaNumTest extends DatainterfaceTestAbstract{
+
+ protected $FQCN = AlphaNum::class;
+ protected $testdata = '0 $%*+-./:';
+ protected $expected = [
+ 32, 80, 36, 212, 252, 15, 175, 251,
+ 176, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 112, 43, 9, 248, 200, 194, 75, 25,
+ 205, 173, 154, 68, 191, 16, 128,
+ 92, 112, 20, 198, 27
+ ];
+
+ public function testGetCharCodeException(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('illegal char: "#" [35]');
+
+ $this->dataInterface->setData('#');
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Data/ByteTest.php b/vendor/chillerlan/php-qrcode/tests/Data/ByteTest.php
new file mode 100644
index 000000000..cbfe1fab2
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Data/ByteTest.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Class ByteTest
+ *
+ * @filesource ByteTest.php
+ * @created 24.11.2017
+ * @package chillerlan\QRCodeTest\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Data;
+
+use chillerlan\QRCode\Data\Byte;
+
+class ByteTest extends DatainterfaceTestAbstract{
+
+ protected $FQCN = Byte::class;
+ protected $testdata = '[¯\_(ツ)_/¯]';
+ protected $expected = [
+ 64, 245, 188, 42, 245, 197, 242, 142,
+ 56, 56, 66, 149, 242, 252, 42, 245,
+ 208, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 79, 89, 226, 48, 209, 89, 151, 1,
+ 12, 73, 42, 163, 11, 34, 255, 205,
+ 21, 47, 250, 101
+ ];
+
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Data/DatainterfaceTestAbstract.php b/vendor/chillerlan/php-qrcode/tests/Data/DatainterfaceTestAbstract.php
new file mode 100644
index 000000000..19d74617a
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Data/DatainterfaceTestAbstract.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Class DatainterfaceTestAbstract
+ *
+ * @filesource DatainterfaceTestAbstract.php
+ * @created 24.11.2017
+ * @package chillerlan\QRCodeTest\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Data;
+
+use chillerlan\QRCode\QROptions;
+use chillerlan\QRCode\Data\{QRCodeDataException, QRDataInterface, QRMatrix};
+use chillerlan\QRCodeTest\QRTestAbstract;
+
+abstract class DatainterfaceTestAbstract extends QRTestAbstract{
+
+ /**
+ * @var \chillerlan\QRCode\Data\QRDataAbstract
+ */
+ protected $dataInterface;
+
+ protected $testdata;
+ protected $expected;
+
+ protected function setUp():void{
+ parent::setUp();
+
+ $this->dataInterface = $this->reflection->newInstanceArgs([new QROptions(['version' => 4])]);
+ }
+
+ public function testInstance(){
+ $this->dataInterface = $this->reflection->newInstanceArgs([new QROptions, $this->testdata]);
+
+ $this->assertInstanceOf(QRDataInterface::class, $this->dataInterface);
+ }
+
+ public function testSetData(){
+ $this->dataInterface->setData($this->testdata);
+
+ $this->assertSame($this->expected, $this->getProperty('matrixdata')->getValue($this->dataInterface));
+ }
+
+ public function testInitMatrix(){
+ $m = $this->dataInterface->setData($this->testdata)->initMatrix(0);
+
+ $this->assertInstanceOf(QRMatrix::class, $m);
+ }
+
+ public function testGetMinimumVersion(){
+ $this->assertSame(1, $this->getMethod('getMinimumVersion')->invoke($this->dataInterface));
+ }
+
+ public function testGetMinimumVersionException(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('data exceeds');
+
+ $this->getProperty('strlen')->setValue($this->dataInterface, 13370);
+ $this->getMethod('getMinimumVersion')->invoke($this->dataInterface);
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Data/KanjiTest.php b/vendor/chillerlan/php-qrcode/tests/Data/KanjiTest.php
new file mode 100644
index 000000000..108b8fed7
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Data/KanjiTest.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Class KanjiTest
+ *
+ * @filesource KanjiTest.php
+ * @created 24.11.2017
+ * @package chillerlan\QRCodeTest\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Data;
+
+use chillerlan\QRCode\Data\{Kanji, QRCodeDataException};
+
+class KanjiTest extends DatainterfaceTestAbstract{
+
+ protected $FQCN = Kanji::class;
+ protected $testdata = '茗荷茗荷茗荷茗荷茗荷';
+ protected $expected = [
+ 128, 173, 85, 26, 95, 85, 70, 151,
+ 213, 81, 165, 245, 84, 105, 125, 85,
+ 26, 92, 0, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 195, 11, 221, 91, 141, 220, 163, 46,
+ 165, 37, 163, 176, 79, 0, 64, 68,
+ 96, 113, 54, 191
+ ];
+
+ public function testIllegalCharException1(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('illegal char at 1 [16191]');
+
+ $this->dataInterface->setData('ÃÃ');
+ }
+
+ public function testIllegalCharException2(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('illegal char at 1');
+
+ $this->dataInterface->setData('Ã');
+ }
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Data/MaskPatternTesterTest.php b/vendor/chillerlan/php-qrcode/tests/Data/MaskPatternTesterTest.php
new file mode 100644
index 000000000..ae4af9f29
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Data/MaskPatternTesterTest.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Class MaskPatternTesterTest
+ *
+ * @filesource MaskPatternTesterTest.php
+ * @created 24.11.2017
+ * @package chillerlan\QRCodeTest\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Data;
+
+use chillerlan\QRCode\{QROptions, Data\Byte, Data\MaskPatternTester};
+use chillerlan\QRCodeTest\QRTestAbstract;
+
+class MaskPatternTesterTest extends QRTestAbstract{
+
+ protected $FQCN = MaskPatternTester::class;
+
+ // coverage
+ public function testMaskpattern(){
+ $matrix = (new Byte(new QROptions(['version' => 10]), 'test'))->initMatrix(3, true);
+
+ $this->assertSame(4243, (new MaskPatternTester($matrix))->testPattern());
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Data/NumberTest.php b/vendor/chillerlan/php-qrcode/tests/Data/NumberTest.php
new file mode 100644
index 000000000..983346a34
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Data/NumberTest.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Class NumberTest
+ *
+ * @filesource NumberTest.php
+ * @created 24.11.2017
+ * @package chillerlan\QRCodeTest\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Data;
+
+use chillerlan\QRCode\Data\{Number, QRCodeDataException};
+
+class NumberTest extends DatainterfaceTestAbstract{
+
+ protected $FQCN = Number::class;
+ protected $testdata = '0123456789';
+ protected $expected = [
+ 16, 40, 12, 86, 106, 105, 0, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 17, 236, 17, 236, 17, 236, 17, 236,
+ 201, 141, 102, 116, 238, 162, 239, 230,
+ 222, 37, 79, 192, 42, 109, 188, 72,
+ 89, 63, 168, 151
+ ];
+
+ public function testGetCharCodeException(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('illegal char: "#" [35]');
+
+ $this->dataInterface->setData('#');
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Data/QRMatrixTest.php b/vendor/chillerlan/php-qrcode/tests/Data/QRMatrixTest.php
new file mode 100644
index 000000000..531c82eb2
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Data/QRMatrixTest.php
@@ -0,0 +1,260 @@
+<?php
+/**
+ * Class QRMatrixTest
+ *
+ * @filesource QRMatrixTest.php
+ * @created 17.11.2017
+ * @package chillerlan\QRCodeTest\Data
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Data;
+
+use chillerlan\QRCode\QRCode;
+use chillerlan\QRCode\QROptions;
+use chillerlan\QRCode\Data\{QRCodeDataException, QRMatrix};
+use chillerlan\QRCodeTest\QRTestAbstract;
+use ReflectionClass;
+
+class QRMatrixTest extends QRTestAbstract{
+
+ protected $FQCN = QRMatrix::class;
+
+ protected $version = 7;
+
+ /**
+ * @var \chillerlan\QRCode\Data\QRMatrix
+ */
+ protected $matrix;
+
+ protected function setUp():void{
+ parent::setUp();
+
+ $this->matrix = $this->reflection->newInstanceArgs([$this->version, QRCode::ECC_L]);
+ }
+
+ public function testInvalidVersionException(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('invalid QR Code version');
+
+ $this->reflection->newInstanceArgs([42, 0]);
+ }
+
+ public function testInvalidEccException(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('invalid ecc level');
+
+ $this->reflection->newInstanceArgs([1, 42]);
+ }
+
+ public function testInstance(){
+ $this->assertInstanceOf($this->FQCN, $this->matrix);
+ }
+
+ public function testSize(){
+ $this->assertCount($this->matrix->size(), $this->matrix->matrix());
+ }
+
+ public function testVersion(){
+ $this->assertSame($this->version, $this->matrix->version());
+ }
+
+ public function testECC(){
+ $this->assertSame(QRCode::ECC_L, $this->matrix->eccLevel());
+ }
+
+ public function testMaskPattern(){
+ $this->assertSame(-1, $this->matrix->maskPattern());
+ }
+
+ public function testGetSetCheck(){
+ $this->matrix->set(10, 10, true, QRMatrix::M_TEST);
+ $this->assertSame(65280, $this->matrix->get(10, 10));
+ $this->assertTrue($this->matrix->check(10, 10));
+
+ $this->matrix->set(20, 20, false, QRMatrix::M_TEST);
+ $this->assertSame(255, $this->matrix->get(20, 20));
+ $this->assertFalse($this->matrix->check(20, 20));
+ }
+
+ public function testSetDarkModule(){
+ $this->matrix->setDarkModule();
+
+ $this->assertSame(QRMatrix::M_DARKMODULE << 8, $this->matrix->get(8, $this->matrix->size() - 8));
+ }
+
+ public function testSetFinderPattern(){
+ $this->matrix->setFinderPattern();
+
+ $this->assertSame(QRMatrix::M_FINDER << 8, $this->matrix->get(0, 0));
+ $this->assertSame(QRMatrix::M_FINDER << 8, $this->matrix->get(0, $this->matrix->size() - 1));
+ $this->assertSame(QRMatrix::M_FINDER << 8, $this->matrix->get($this->matrix->size() - 1, 0));
+ }
+
+ public function testSetSeparators(){
+ $this->matrix->setSeparators();
+
+ $this->assertSame(QRMatrix::M_SEPARATOR, $this->matrix->get(7, 0));
+ $this->assertSame(QRMatrix::M_SEPARATOR, $this->matrix->get(0, 7));
+ $this->assertSame(QRMatrix::M_SEPARATOR, $this->matrix->get(0, $this->matrix->size() - 8));
+ $this->assertSame(QRMatrix::M_SEPARATOR, $this->matrix->get($this->matrix->size() - 8, 0));
+ }
+
+ public function testSetAlignmentPattern(){
+ $this->matrix
+ ->setFinderPattern()
+ ->setAlignmentPattern()
+ ;
+
+ $alignmentPattern = (new ReflectionClass(QRMatrix::class))->getConstant('alignmentPattern')[$this->version];
+
+ foreach($alignmentPattern as $py){
+ foreach($alignmentPattern as $px){
+
+ if($this->matrix->get($px, $py) === QRMatrix::M_FINDER << 8){
+ $this->assertSame(QRMatrix::M_FINDER << 8, $this->matrix->get($px, $py), 'skipped finder pattern');
+ continue;
+ }
+
+ $this->assertSame(QRMatrix::M_ALIGNMENT << 8, $this->matrix->get($px, $py));
+ }
+ }
+
+ }
+
+ public function testSetTimingPattern(){
+ $this->matrix
+ ->setAlignmentPattern()
+ ->setTimingPattern()
+ ;
+
+ $size = $this->matrix->size();
+
+ for($i = 7; $i < $size - 7; $i++){
+ if($i % 2 === 0){
+ $p1 = $this->matrix->get(6, $i);
+
+ if($p1 === QRMatrix::M_ALIGNMENT << 8){
+ $this->assertSame(QRMatrix::M_ALIGNMENT << 8, $p1, 'skipped alignment pattern');
+ continue;
+ }
+
+ $this->assertSame(QRMatrix::M_TIMING << 8, $p1);
+ $this->assertSame(QRMatrix::M_TIMING << 8, $this->matrix->get($i, 6));
+ }
+ }
+ }
+
+ public function testSetVersionNumber(){
+ $this->matrix->setVersionNumber(true);
+
+ $this->assertSame(QRMatrix::M_VERSION, $this->matrix->get($this->matrix->size() - 9, 0));
+ $this->assertSame(QRMatrix::M_VERSION, $this->matrix->get($this->matrix->size() - 11, 5));
+ $this->assertSame(QRMatrix::M_VERSION, $this->matrix->get(0, $this->matrix->size() - 9));
+ $this->assertSame(QRMatrix::M_VERSION, $this->matrix->get(5, $this->matrix->size() - 11));
+ }
+
+ public function testSetFormatInfo(){
+ $this->matrix->setFormatInfo(0, true);
+
+ $this->assertSame(QRMatrix::M_FORMAT, $this->matrix->get(8, 0));
+ $this->assertSame(QRMatrix::M_FORMAT, $this->matrix->get(0, 8));
+ $this->assertSame(QRMatrix::M_FORMAT, $this->matrix->get($this->matrix->size() - 1, 8));
+ $this->assertSame(QRMatrix::M_FORMAT, $this->matrix->get($this->matrix->size() - 8, 8));
+ }
+
+ public function testSetQuietZone(){
+ $size = $this->matrix->size();
+ $q = 5;
+
+ $this->matrix->set(0, 0, true, QRMatrix::M_TEST);
+ $this->matrix->set($size - 1, $size - 1, true, QRMatrix::M_TEST);
+
+ $this->matrix->setQuietZone($q);
+
+ $this->assertCount($size + 2 * $q, $this->matrix->matrix());
+ $this->assertCount($size + 2 * $q, $this->matrix->matrix()[$size - 1]);
+
+ $size = $this->matrix->size();
+ $this->assertSame(QRMatrix::M_QUIETZONE, $this->matrix->get(0, 0));
+ $this->assertSame(QRMatrix::M_QUIETZONE, $this->matrix->get($size - 1, $size - 1));
+
+ $this->assertSame(QRMatrix::M_TEST << 8, $this->matrix->get($q, $q));
+ $this->assertSame(QRMatrix::M_TEST << 8, $this->matrix->get($size - 1 - $q, $size - 1 - $q));
+ }
+
+ public function testSetQuietZoneException(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('use only after writing data');
+
+ $this->matrix->setQuietZone();
+ }
+
+ public function testSetLogoSpaceOrientation():void{
+ $o = new QROptions;
+ $o->version = 10;
+ $o->eccLevel = QRCode::ECC_H;
+ $o->addQuietzone = false;
+
+ $matrix = (new QRCode($o))->getMatrix('testdata');
+ // also testing size adjustment to uneven numbers
+ $matrix->setLogoSpace(20, 14);
+
+ // NW corner
+ $this::assertNotSame(QRMatrix::M_LOGO, $matrix->get(17, 20));
+ $this::assertSame(QRMatrix::M_LOGO, $matrix->get(18, 21));
+
+ // SE corner
+ $this::assertSame(QRMatrix::M_LOGO, $matrix->get(38, 35));
+ $this::assertNotSame(QRMatrix::M_LOGO, $matrix->get(39, 36));
+ }
+
+ public function testSetLogoSpacePosition():void{
+ $o = new QROptions;
+ $o->version = 10;
+ $o->eccLevel = QRCode::ECC_H;
+ $o->addQuietzone = true;
+ $o->quietzoneSize = 10;
+
+ $m = (new QRCode($o))->getMatrix('testdata');
+
+ // logo space should not overwrite quiet zone & function patterns
+ $m->setLogoSpace(21, 21, -10, -10);
+ $this::assertSame(QRMatrix::M_QUIETZONE, $m->get(9, 9));
+ $this::assertSame(QRMatrix::M_FINDER << 8, $m->get(10, 10));
+ $this::assertSame(QRMatrix::M_FINDER << 8, $m->get(16, 16));
+ $this::assertSame(QRMatrix::M_SEPARATOR, $m->get(17, 17));
+ $this::assertSame(QRMatrix::M_FORMAT << 8, $m->get(18, 18));
+ $this::assertSame(QRMatrix::M_LOGO, $m->get(19, 19));
+ $this::assertSame(QRMatrix::M_LOGO, $m->get(20, 20));
+ $this::assertNotSame(QRMatrix::M_LOGO, $m->get(21, 21));
+
+ // i just realized that setLogoSpace() could be called multiple times
+ // on the same instance and i'm not going to do anything about it :P
+ $m->setLogoSpace(21, 21, 45, 45);
+ $this::assertNotSame(QRMatrix::M_LOGO, $m->get(54, 54));
+ $this::assertSame(QRMatrix::M_LOGO, $m->get(55, 55));
+ $this::assertSame(QRMatrix::M_QUIETZONE, $m->get(67, 67));
+ }
+
+ public function testSetLogoSpaceInvalidEccException():void{
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('ECC level "H" required to add logo space');
+
+ (new QRCode)->getMatrix('testdata')->setLogoSpace(50, 50);
+ }
+
+ public function testSetLogoSpaceMaxSizeException():void{
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('logo space exceeds the maximum error correction capacity');
+
+ $o = new QROptions;
+ $o->version = 5;
+ $o->eccLevel = QRCode::ECC_H;
+
+ (new QRCode($o))->getMatrix('testdata')->setLogoSpace(50, 50);
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Helpers/BitBufferTest.php b/vendor/chillerlan/php-qrcode/tests/Helpers/BitBufferTest.php
new file mode 100644
index 000000000..25d1c3504
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Helpers/BitBufferTest.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Class BitBufferTest
+ *
+ * @filesource BitBufferTest.php
+ * @created 08.02.2016
+ * @package chillerlan\QRCodeTest\Helpers
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Helpers;
+
+use chillerlan\QRCode\{QRCode, Helpers\BitBuffer};
+use chillerlan\QRCodeTest\QRTestAbstract;
+
+class BitBufferTest extends QRTestAbstract{
+
+ /**
+ * @var \chillerlan\QRCode\Helpers\BitBuffer
+ */
+ protected $bitBuffer;
+
+ protected function setUp():void{
+ $this->bitBuffer = new BitBuffer;
+ }
+
+ public function bitProvider(){
+ return [
+ 'number' => [QRCode::DATA_NUMBER, 16],
+ 'alphanum' => [QRCode::DATA_ALPHANUM, 32],
+ 'byte' => [QRCode::DATA_BYTE, 64],
+ 'kanji' => [QRCode::DATA_KANJI, 128],
+ ];
+ }
+
+ /**
+ * @dataProvider bitProvider
+ */
+ public function testPut($data, $value){
+ $this->bitBuffer->put($data, 4);
+ $this->assertSame($value, $this->bitBuffer->buffer[0]);
+ $this->assertSame(4, $this->bitBuffer->length);
+ }
+
+ public function testClear(){
+ $this->bitBuffer->clear();
+ $this->assertSame([], $this->bitBuffer->buffer);
+ $this->assertSame(0, $this->bitBuffer->length);
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Helpers/PolynomialTest.php b/vendor/chillerlan/php-qrcode/tests/Helpers/PolynomialTest.php
new file mode 100644
index 000000000..7f6da303c
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Helpers/PolynomialTest.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Class PolynomialTest
+ *
+ * @filesource PolynomialTest.php
+ * @created 09.02.2016
+ * @package chillerlan\QRCodeTest\Helpers
+ * @author Smiley <[email protected]>
+ * @copyright 2015 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Helpers;
+
+use chillerlan\QRCode\Helpers\Polynomial;
+use chillerlan\QRCode\QRCodeException;
+use chillerlan\QRCodeTest\QRTestAbstract;
+
+class PolynomialTest extends QRTestAbstract{
+
+ /**
+ * @var \chillerlan\QRCode\Helpers\Polynomial
+ */
+ protected $polynomial;
+
+ protected function setUp():void{
+ $this->polynomial = new Polynomial;
+ }
+
+ public function testGexp(){
+ $this->assertSame(142, $this->polynomial->gexp(-1));
+ $this->assertSame(133, $this->polynomial->gexp(128));
+ $this->assertSame(2, $this->polynomial->gexp(256));
+ }
+
+ public function testGlogException(){
+ $this->expectException(QRCodeException::class);
+ $this->expectExceptionMessage('log(0)');
+
+ $this->polynomial->glog(0);
+ }
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Output/QRFpdfTest.php b/vendor/chillerlan/php-qrcode/tests/Output/QRFpdfTest.php
new file mode 100644
index 000000000..1b49182d2
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Output/QRFpdfTest.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Class QRFpdfTest
+ *
+ * @filesource QRFpdfTest.php
+ * @created 03.06.2020
+ * @package chillerlan\QRCodeTest\Output
+ * @author smiley <[email protected]>
+ * @copyright 2020 smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use FPDF;
+use chillerlan\QRCode\Output\{QRFpdf, QROutputInterface};
+use chillerlan\QRCode\{QRCode, QROptions};
+
+use function class_exists, substr;
+
+/**
+ * Tests the QRFpdf output module
+ */
+class QRFpdfTest extends QROutputTestAbstract{
+
+ protected $FQCN = QRFpdf::class;
+
+ /**
+ * @inheritDoc
+ * @internal
+ */
+ public function setUp():void{
+
+ if(!class_exists(FPDF::class)){
+ $this->markTestSkipped('FPDF not available');
+ return;
+ }
+
+ parent::setUp();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function testSetModuleValues():void{
+
+ $this->options->moduleValues = [
+ // data
+ 1024 => [0, 0, 0],
+ 4 => [255, 255, 255],
+ ];
+
+ $this->outputInterface->dump();
+
+ $this::assertTrue(true); // tricking the code coverage
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function testRenderImage():void{
+ $type = QRCode::OUTPUT_FPDF;
+
+ $this->options->outputType = $type;
+ $this->options->imageBase64 = false;
+ $this->outputInterface->dump($this::cachefile.$type);
+
+ // substr() to avoid CreationDate
+ $expected = substr(file_get_contents($this::cachefile.$type), 0, 2000);
+ $actual = substr($this->outputInterface->dump(), 0, 2000);
+
+ $this::assertSame($expected, $actual);
+ }
+
+ public function testOutputGetResource():void{
+ $this->options->returnResource = true;
+
+ $this->setOutputInterface();
+
+ $this::assertInstanceOf(FPDF::class, $this->outputInterface->dump());
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Output/QRImageTest.php b/vendor/chillerlan/php-qrcode/tests/Output/QRImageTest.php
new file mode 100644
index 000000000..34ecf4f91
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Output/QRImageTest.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Class QRImageTest
+ *
+ * @filesource QRImageTest.php
+ * @created 24.12.2017
+ * @package chillerlan\QRCodeTest\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\{QRCode, Output\QRImage};
+
+class QRImageTest extends QROutputTestAbstract{
+
+ protected $FQCN = QRImage::class;
+
+ public function types(){
+ return [
+ 'png' => [QRCode::OUTPUT_IMAGE_PNG],
+ 'gif' => [QRCode::OUTPUT_IMAGE_GIF],
+ 'jpg' => [QRCode::OUTPUT_IMAGE_JPG],
+ ];
+ }
+
+ /**
+ * @dataProvider types
+ * @param $type
+ */
+ public function testImageOutput($type){
+ $this->options->outputType = $type;
+ $this->options->imageBase64 = false;
+
+ $this->setOutputInterface();
+ $this->outputInterface->dump($this::cachefile.$type);
+ $img = $this->outputInterface->dump();
+
+ if($type === QRCode::OUTPUT_IMAGE_JPG){ // jpeg encoding may cause different results
+ $this->markAsRisky();
+ }
+
+ $this->assertSame($img, file_get_contents($this::cachefile.$type));
+ }
+
+ public function testSetModuleValues(){
+
+ $this->options->moduleValues = [
+ // data
+ 1024 => [0, 0, 0],
+ 4 => [255, 255, 255],
+ ];
+
+ $this->setOutputInterface()->dump();
+
+ $this->assertTrue(true); // tricking the code coverage
+ }
+
+ public function testOutputGetResource():void{
+ $this->options->returnResource = true;
+
+ $this->setOutputInterface();
+
+ $this::assertIsResource($this->outputInterface->dump());
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Output/QRImagickTest.php b/vendor/chillerlan/php-qrcode/tests/Output/QRImagickTest.php
new file mode 100644
index 000000000..c927cc64e
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Output/QRImagickTest.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Class QRImagickTest
+ *
+ * @filesource QRImagickTest.php
+ * @created 04.07.2018
+ * @package chillerlan\QRCodeTest\Output
+ * @author smiley <[email protected]>
+ * @copyright 2018 smiley
+ * @license MIT
+ *
+ * @noinspection PhpComposerExtensionStubsInspection
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use Imagick;
+use chillerlan\QRCode\{QRCode, Output\QRImagick};
+
+class QRImagickTest extends QROutputTestAbstract{
+
+ protected $FQCN = QRImagick::class;
+
+ public function setUp():void{
+
+ if(!extension_loaded('imagick')){
+ $this->markTestSkipped('ext-imagick not loaded');
+ return;
+ }
+
+ parent::setUp();
+ }
+
+ public function testImageOutput(){
+ $type = QRCode::OUTPUT_IMAGICK;
+
+ $this->options->outputType = $type;
+ $this->setOutputInterface();
+ $this->outputInterface->dump($this::cachefile.$type);
+ $img = $this->outputInterface->dump();
+
+ $this->assertSame($img, file_get_contents($this::cachefile.$type));
+ }
+
+ public function testSetModuleValues(){
+
+ $this->options->moduleValues = [
+ // data
+ 1024 => '#4A6000',
+ 4 => '#ECF9BE',
+ ];
+
+ $this->setOutputInterface()->dump();
+
+ $this->assertTrue(true); // tricking the code coverage
+ }
+
+ public function testOutputGetResource():void{
+ $this->options->returnResource = true;
+
+ $this->setOutputInterface();
+
+ $this::assertInstanceOf(Imagick::class, $this->outputInterface->dump());
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Output/QRMarkupTest.php b/vendor/chillerlan/php-qrcode/tests/Output/QRMarkupTest.php
new file mode 100644
index 000000000..24fdc3ce6
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Output/QRMarkupTest.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Class QRMarkupTest
+ *
+ * @filesource QRMarkupTest.php
+ * @created 24.12.2017
+ * @package chillerlan\QRCodeTest\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\{QRCode, Output\QRMarkup};
+
+class QRMarkupTest extends QROutputTestAbstract{
+
+ protected $FQCN = QRMarkup::class;
+
+ public function types(){
+ return [
+ 'html' => [QRCode::OUTPUT_MARKUP_HTML],
+ 'svg' => [QRCode::OUTPUT_MARKUP_SVG],
+ ];
+ }
+
+ /**
+ * @dataProvider types
+ * @param $type
+ */
+ public function testMarkupOutputFile($type){
+ $this->options->outputType = $type;
+ $this->options->cachefile = $this::cachefile.$type;
+ $this->setOutputInterface();
+ $data = $this->outputInterface->dump();
+
+ $this->assertSame($data, file_get_contents($this->options->cachefile));
+ }
+
+ /**
+ * @dataProvider types
+ * @param $type
+ */
+ public function testMarkupOutput($type){
+ $this->options->imageBase64 = false;
+ $this->options->outputType = $type;
+ $this->setOutputInterface();
+
+ $expected = explode($this->options->eol, file_get_contents($this::cachefile.$type));
+ // cut off the doctype & head
+ array_shift($expected);
+
+ if($type === QRCode::OUTPUT_MARKUP_HTML){
+ // cut off the </body> tag
+ array_pop($expected);
+ }
+
+ $expected = implode($this->options->eol, $expected);
+
+ $this->assertSame(trim($expected), trim($this->outputInterface->dump()));
+ }
+
+ public function testSetModuleValues(){
+
+ $this->options->imageBase64 = false;
+ $this->options->moduleValues = [
+ // data
+ 1024 => '#4A6000',
+ 4 => '#ECF9BE',
+ ];
+
+ $this->setOutputInterface();
+ $data = $this->outputInterface->dump();
+ $this->assertStringContainsString('#4A6000', $data);
+ $this->assertStringContainsString('#ECF9BE', $data);
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Output/QROutputTestAbstract.php b/vendor/chillerlan/php-qrcode/tests/Output/QROutputTestAbstract.php
new file mode 100644
index 000000000..6cd95d080
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Output/QROutputTestAbstract.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Class QROutputTestAbstract
+ *
+ * @filesource QROutputTestAbstract.php
+ * @created 24.12.2017
+ * @package chillerlan\QRCodeTest\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\QROptions;
+use chillerlan\QRCode\Data\Byte;
+use chillerlan\QRCode\Output\{QRCodeOutputException, QROutputInterface};
+use chillerlan\QRCodeTest\QRTestAbstract;
+
+use function dirname, file_exists, mkdir;
+
+abstract class QROutputTestAbstract extends QRTestAbstract{
+
+ const cachefile = __DIR__.'/../../.build/output_test/test.';
+
+ /**
+ * @var \chillerlan\QRCode\Output\QROutputInterface
+ */
+ protected $outputInterface;
+
+ /**
+ * @var \chillerlan\QRCode\QROptions
+ */
+ protected $options;
+
+ /**
+ * @var \chillerlan\QRCode\Data\QRMatrix
+ */
+ protected $matrix;
+
+ protected function setUp():void{
+ parent::setUp();
+
+ $buildDir = dirname($this::cachefile);
+ if(!file_exists($buildDir)){
+ mkdir($buildDir, 0777, true);
+ }
+
+ $this->options = new QROptions;
+ $this->setOutputInterface();
+ }
+
+ protected function setOutputInterface(){
+ $this->outputInterface = $this->reflection->newInstanceArgs([$this->options, (new Byte($this->options, 'testdata'))->initMatrix(0)]);
+ return $this->outputInterface;
+ }
+
+ public function testInstance(){
+ $this->assertInstanceOf(QROutputInterface::class, $this->outputInterface);
+ }
+
+ public function testSaveException(){
+ $this->expectException(QRCodeOutputException::class);
+ $this->expectExceptionMessage('Could not write data to cache file: /foo');
+
+ $this->options->cachefile = '/foo';
+ $this->setOutputInterface();
+ $this->outputInterface->dump();
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/Output/QRStringTest.php b/vendor/chillerlan/php-qrcode/tests/Output/QRStringTest.php
new file mode 100644
index 000000000..5dbd34010
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/Output/QRStringTest.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Class QRStringTest
+ *
+ * @filesource QRStringTest.php
+ * @created 24.12.2017
+ * @package chillerlan\QRCodeTest\Output
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest\Output;
+
+use chillerlan\QRCode\{QRCode, Output\QRString};
+
+class QRStringTest extends QROutputTestAbstract{
+
+ protected $FQCN = QRString::class;
+
+ public function types(){
+ return [
+ 'json' => [QRCode::OUTPUT_STRING_JSON],
+ 'text' => [QRCode::OUTPUT_STRING_TEXT],
+ ];
+ }
+
+ /**
+ * @dataProvider types
+ * @param $type
+ */
+ public function testStringOutput($type){
+ $this->options->outputType = $type;
+ $this->options->cachefile = $this::cachefile.$type;
+ $this->setOutputInterface();
+ $data = $this->outputInterface->dump();
+
+ $this->assertSame($data, file_get_contents($this->options->cachefile));
+ }
+
+ public function testSetModuleValues(){
+
+ $this->options->moduleValues = [
+ // data
+ 1024 => 'A',
+ 4 => 'B',
+ ];
+
+ $this->setOutputInterface();
+ $data = $this->outputInterface->dump();
+
+ $this->assertStringContainsString('A', $data);
+ $this->assertStringContainsString('B', $data);
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/QRCodeTest.php b/vendor/chillerlan/php-qrcode/tests/QRCodeTest.php
new file mode 100644
index 000000000..8613c961f
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/QRCodeTest.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Class QRCodeTest
+ *
+ * @filesource QRCodeTest.php
+ * @created 17.11.2017
+ * @package chillerlan\QRCodeTest
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest;
+
+use chillerlan\QRCode\{QROptions, QRCode};
+use chillerlan\QRCode\Data\{AlphaNum, Byte, Number, QRCodeDataException};
+use chillerlan\QRCode\Output\QRCodeOutputException;
+use chillerlan\QRCodeExamples\MyCustomOutput;
+
+use function random_bytes;
+
+class QRCodeTest extends QRTestAbstract{
+
+ protected $FQCN = QRCode::class;
+
+ /**
+ * @var \chillerlan\QRCode\QRCode
+ */
+ protected $qrcode;
+
+ protected function setUp():void{
+ parent::setUp();
+
+ $this->qrcode = $this->reflection->newInstance();
+ }
+
+ public function testIsNumber(){
+ $this->assertTrue($this->qrcode->isNumber('0123456789'));
+ $this->assertFalse($this->qrcode->isNumber('ABC'));
+ }
+
+ public function testIsAlphaNum(){
+ $this->assertTrue($this->qrcode->isAlphaNum('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 $%*+-./:'));
+ $this->assertFalse($this->qrcode->isAlphaNum('abc'));
+ }
+
+ public function testIsKanji(){
+ $this->assertTrue($this->qrcode->isKanji('茗荷'));
+ $this->assertFalse($this->qrcode->isKanji('Ã'));
+ }
+
+ // coverage
+
+ public function typeDataProvider(){
+ return [
+ 'png' => [QRCode::OUTPUT_IMAGE_PNG, 'data:image/png;base64,'],
+ 'gif' => [QRCode::OUTPUT_IMAGE_GIF, 'data:image/gif;base64,'],
+ 'jpg' => [QRCode::OUTPUT_IMAGE_JPG, 'data:image/jpg;base64,'],
+ 'svg' => [QRCode::OUTPUT_MARKUP_SVG, 'data:image/svg+xml;base64,'],
+ 'html' => [QRCode::OUTPUT_MARKUP_HTML, '<div><span style="background:'],
+ 'text' => [QRCode::OUTPUT_STRING_TEXT, '⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕⭕'.PHP_EOL],
+ 'json' => [QRCode::OUTPUT_STRING_JSON, '[[18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18],'],
+ ];
+ }
+
+ /**
+ * @dataProvider typeDataProvider
+ * @param $type
+ */
+ public function testRenderImage($type, $expected){
+ $this->qrcode = $this->reflection->newInstanceArgs([new QROptions(['outputType' => $type])]);
+
+ $this->assertStringContainsString($expected, $this->qrcode->render('test'));
+ }
+
+ public function testInitDataInterfaceException(){
+ $this->expectException(QRCodeOutputException::class);
+ $this->expectExceptionMessage('invalid output type');
+
+ (new QRCode(new QROptions(['outputType' => 'foo'])))->render('test');
+ }
+
+ public function testGetMatrixException(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('QRCode::getMatrix() No data given.');
+
+ $this->qrcode->getMatrix('');
+ }
+
+ public function testTrim() {
+ $m1 = $this->qrcode->getMatrix('hello');
+ $m2 = $this->qrcode->getMatrix('hello '); // added space
+
+ $this->assertNotEquals($m1, $m2);
+ }
+
+ public function testImageTransparencyBGDefault(){
+ $this->qrcode = $this->reflection->newInstanceArgs([new QROptions(['imageTransparencyBG' => 'foo'])]);
+
+ $this->assertSame([255,255,255], $this->getProperty('options')->getValue($this->qrcode)->imageTransparencyBG);
+ }
+
+ public function testCustomOutput(){
+
+ $options = new QROptions([
+ 'version' => 5,
+ 'eccLevel' => QRCode::ECC_L,
+ 'outputType' => QRCode::OUTPUT_CUSTOM,
+ 'outputInterface' => MyCustomOutput::class,
+ ]);
+
+ $expected = '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111110111010000101111010000011111110000000010000010111000001101011000001010000010000000010111010101101011000001101011010111010000000010111010110100111110010100111010111010000000010111010000001101011000001101010111010000000010000010100111110010100111110010000010000000011111110101010101010101010101011111110000000000000000010010100111110010100000000000000000011001110000101111010000101111001011110000000000000000111010000101111010000111100010000000001011010100111110010100111110011001010000000010000101111101011000001101011110011110000000000011010100011000001101011000101110100000000011001100001001101011000001101010011010000000010110111110000001101011000001100110100000000010000100100010100111110010100001100100000000011111110111101111010000101111010100110000000011010000111010000101111010000111100100000000010101111111111110010100111110011001000000000010110001110101011000001101011110011010000000001001111100011000001101011000101110010000000011000100110001101011000001101010011100000000001000011001000001101011000001100110000000000011101001011010100111110010100001100000000000010111010001101111010000101111010100110000000011100000001010000101111010000111100000000000000001110110111110010100111110011001000000000000011001011101011000001101011110011100000000011111110101011000001101011001111110110000000000000000110001101011000001101000111100000000011111110001000001101011000011010110000000000010000010101010100111110010101000100100000000010111010111101111010000101111111100110000000010111010011010000101111010001101100010000000010111010000111110010100111100101101100000000010000010101101011000001101001100111100000000011111110101011000001101011000110010110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
+
+ $this->assertSame($expected, $this->reflection->newInstanceArgs([$options])->render('test'));
+ }
+
+ public function testDataModeOverride(){
+ $this->qrcode = $this->reflection->newInstance();
+
+ $this->assertInstanceOf(Number::class, $this->qrcode->initDataInterface('123'));
+ $this->assertInstanceOf(AlphaNum::class, $this->qrcode->initDataInterface('ABC123'));
+ $this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface(random_bytes(32)));
+
+ $this->qrcode = $this->reflection->newInstanceArgs([new QROptions(['dataMode' => 'Byte'])]);
+
+ $this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface('123'));
+ $this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface('ABC123'));
+ $this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface(random_bytes(32)));
+ }
+
+ public function testDataModeOverrideError(){
+ $this->expectException(QRCodeDataException::class);
+ $this->expectExceptionMessage('illegal char:');
+
+ $this->qrcode = $this->reflection->newInstanceArgs([new QROptions(['dataMode' => 'AlphaNum'])]);
+
+ $this->qrcode->initDataInterface(random_bytes(32));
+ }
+
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/QROptionsTest.php b/vendor/chillerlan/php-qrcode/tests/QROptionsTest.php
new file mode 100644
index 000000000..41bf69ced
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/QROptionsTest.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Class QROptionsTest
+ *
+ * @filesource QROptionsTest.php
+ * @created 08.11.2018
+ * @package chillerlan\QRCodeTest
+ * @author smiley <[email protected]>
+ * @copyright 2018 smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest;
+
+use chillerlan\QRCode\{QRCode, QRCodeException, QROptions};
+use PHPUnit\Framework\TestCase;
+
+class QROptionsTest extends TestCase{
+
+ /**
+ * @var \chillerlan\QRCode\QROptions
+ */
+ protected $options;
+
+ public function testVersionClamp(){
+ $this->assertSame(40, (new QROptions(['version' => 42]))->version);
+ $this->assertSame(1, (new QROptions(['version' => -42]))->version);
+ $this->assertSame(21, (new QROptions(['version' => 21]))->version);
+ $this->assertSame(QRCode::VERSION_AUTO, (new QROptions)->version); // QRCode::VERSION_AUTO = -1, default
+ }
+
+ public function testVersionMinMaxClamp(){
+ // normal clamp
+ $o = new QROptions(['versionMin' => 5, 'versionMax' => 10]);
+ $this->assertSame(5, $o->versionMin);
+ $this->assertSame(10, $o->versionMax);
+
+ // exceeding values
+ $o = new QROptions(['versionMin' => -42, 'versionMax' => 42]);
+ $this->assertSame(1, $o->versionMin);
+ $this->assertSame(40, $o->versionMax);
+
+ // min > max
+ $o = new QROptions(['versionMin' => 10, 'versionMax' => 5]);
+ $this->assertSame(5, $o->versionMin);
+ $this->assertSame(10, $o->versionMax);
+
+ $o = new QROptions(['versionMin' => 42, 'versionMax' => -42]);
+ $this->assertSame(1, $o->versionMin);
+ $this->assertSame(40, $o->versionMax);
+ }
+
+ public function testMaskPatternClamp(){
+ $this->assertSame(7, (new QROptions(['maskPattern' => 42]))->maskPattern);
+ $this->assertSame(0, (new QROptions(['maskPattern' => -42]))->maskPattern);
+ $this->assertSame(QRCode::MASK_PATTERN_AUTO, (new QROptions)->maskPattern); // QRCode::MASK_PATTERN_AUTO = -1, default
+ }
+
+ public function testInvalidEccLevelException(){
+ $this->expectException(QRCodeException::class);
+ $this->expectExceptionMessage('Invalid error correct level: 42');
+
+ new QROptions(['eccLevel' => 42]);
+ }
+
+ public function testClampRGBValues(){
+ $o = new QROptions(['imageTransparencyBG' => [-1, 0, 999]]);
+
+ $this->assertSame(0, $o->imageTransparencyBG[0]);
+ $this->assertSame(0, $o->imageTransparencyBG[1]);
+ $this->assertSame(255, $o->imageTransparencyBG[2]);
+ }
+
+ public function testInvalidRGBValueException(){
+ $this->expectException(QRCodeException::class);
+ $this->expectExceptionMessage('Invalid RGB value.');
+
+ new QROptions(['imageTransparencyBG' => ['r', 'g', 'b']]);
+ }
+}
diff --git a/vendor/chillerlan/php-qrcode/tests/QRTestAbstract.php b/vendor/chillerlan/php-qrcode/tests/QRTestAbstract.php
new file mode 100644
index 000000000..7b9eb8049
--- /dev/null
+++ b/vendor/chillerlan/php-qrcode/tests/QRTestAbstract.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Class QRTestAbstract
+ *
+ * @filesource QRTestAbstract.php
+ * @created 17.11.2017
+ * @package chillerlan\QRCodeTest
+ * @author Smiley <[email protected]>
+ * @copyright 2017 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\QRCodeTest;
+
+use PHPUnit\Framework\TestCase;
+use ReflectionClass, ReflectionMethod, ReflectionProperty;
+
+abstract class QRTestAbstract extends TestCase{
+
+ /**
+ * @var \ReflectionClass
+ */
+ protected $reflection;
+
+ /**
+ * @var string
+ */
+ protected $FQCN;
+
+ protected function setUp():void{
+ $this->reflection = new ReflectionClass($this->FQCN);
+ }
+
+ /**
+ * @param string $method
+ *
+ * @return \ReflectionMethod
+ */
+ protected function getMethod(string $method):ReflectionMethod {
+ $method = $this->reflection->getMethod($method);
+ $method->setAccessible(true);
+
+ return $method;
+ }
+
+ /**
+ * @param string $property
+ *
+ * @return \ReflectionProperty
+ */
+ protected function getProperty(string $property):ReflectionProperty{
+ $property = $this->reflection->getProperty($property);
+ $property->setAccessible(true);
+
+ return $property;
+ }
+
+ /**
+ * @param $object
+ * @param string $property
+ * @param $value
+ *
+ * @return void
+ */
+ protected function setProperty($object, string $property, $value){
+ $property = $this->getProperty($property);
+ $property->setAccessible(true);
+ $property->setValue($object, $value);
+ }
+
+
+}
diff --git a/vendor/chillerlan/php-settings-container/.gitignore b/vendor/chillerlan/php-settings-container/.gitignore
new file mode 100644
index 000000000..e313cba45
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/.gitignore
@@ -0,0 +1,4 @@
+.idea
+.vendor
+composer.lock
+*.phpunit.result.cache
diff --git a/vendor/chillerlan/php-settings-container/.scrutinizer.yml b/vendor/chillerlan/php-settings-container/.scrutinizer.yml
new file mode 100644
index 000000000..7fdd2a4dc
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/.scrutinizer.yml
@@ -0,0 +1,5 @@
+filter:
+ excluded_paths:
+ - examples/*
+ - tests/*
+ - vendor/*
diff --git a/vendor/chillerlan/php-settings-container/.travis.yml b/vendor/chillerlan/php-settings-container/.travis.yml
new file mode 100644
index 000000000..208cdeb6a
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/.travis.yml
@@ -0,0 +1,18 @@
+language: php
+
+matrix:
+ include:
+ - php: 7.2
+ - php: 7.3
+ - php: 7.4snapshot
+ - php: nightly
+ allow_failures:
+ - php: 7.4snapshot
+ - php: nightly
+
+
+before_script: travis_retry composer install --no-interaction --prefer-source
+
+script: vendor/bin/phpunit --configuration phpunit.xml --coverage-clover clover.xml
+
+after_script: bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/chillerlan/php-settings-container/LICENSE b/vendor/chillerlan/php-settings-container/LICENSE
new file mode 100644
index 000000000..25d371fc3
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Smiley <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/chillerlan/php-settings-container/README.md b/vendor/chillerlan/php-settings-container/README.md
new file mode 100644
index 000000000..7d0ccf09d
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/README.md
@@ -0,0 +1,153 @@
+# chillerlan/php-settings-container
+
+A container class for immutable settings objects. Not a DI container. PHP 7.2+
+- [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/master/src/SettingsContainerInterface.php) provides immutable properties with magic getter & setter and some fancy
+
+[![version][packagist-badge]][packagist]
+[![license][license-badge]][license]
+[![Travis][travis-badge]][travis]
+[![Coverage][coverage-badge]][coverage]
+[![Scrunitizer][scrutinizer-badge]][scrutinizer]
+[![Packagist downloads][downloads-badge]][downloads]
+[![PayPal donate][donate-badge]][donate]
+
+[packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-settings-container.svg?style=flat-square
+[packagist]: https://packagist.org/packages/chillerlan/php-settings-container
+[license-badge]: https://img.shields.io/github/license/chillerlan/php-settings-container.svg?style=flat-square
+[license]: https://github.com/chillerlan/php-settings-container/blob/master/LICENSE
+[travis-badge]: https://img.shields.io/travis/chillerlan/php-settings-container.svg?style=flat-square
+[travis]: https://travis-ci.org/chillerlan/php-settings-container
+[coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-settings-container.svg?style=flat-square
+[coverage]: https://codecov.io/github/chillerlan/php-settings-container
+[scrutinizer-badge]: https://img.shields.io/scrutinizer/g/chillerlan/php-settings-container.svg?style=flat-square
+[scrutinizer]: https://scrutinizer-ci.com/g/chillerlan/php-settings-container
+[downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-settings-container.svg?style=flat-square
+[downloads]: https://packagist.org/packages/chillerlan/php-settings-container/stats
+[donate-badge]: https://img.shields.io/badge/donate-paypal-ff33aa.svg?style=flat-square
+[donate]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WLYUNAT9ZTJZ4
+
+## Documentation
+
+### Installation
+**requires [composer](https://getcomposer.org)**
+
+*composer.json* (note: replace `dev-master` with a version boundary)
+```json
+{
+ "require": {
+ "php": "^7.2",
+ "chillerlan/php-settings-container": "^1.0"
+ }
+}
+```
+
+### Manual installation
+Download the desired version of the package from [master](https://github.com/chillerlan/php-settings-container/archive/master.zip) or
+[release](https://github.com/chillerlan/php-settings-container/releases) and extract the contents to your project folder. After that:
+- run `composer install` to install the required dependencies and generate `/vendor/autoload.php`.
+- if you use a custom autoloader, point the namespace `chillerlan\Settings` to the folder `src` of the package
+
+Profit!
+
+## Usage
+
+The `SettingsContainerInterface` (wrapped in`SettingsContainerAbstract` ) provides plug-in functionality for immutable object variables and adds some fancy, like loading/saving JSON, arrays etc.
+It takes iterable as the only constructor argument and calls a method with the trait's name on invocation (`MyTrait::MyTrait()`) for each used trait.
+
+### Simple usage
+```php
+class MyContainer extends SettingsContainerAbstract{
+ protected $foo;
+ protected $bar;
+}
+```
+
+```php
+// use it just like a \stdClass
+$container = new MyContainer;
+$container->foo = 'what';
+$container->bar = 'foo';
+
+// which is equivalent to
+$container = new MyContainer(['bar' => 'foo', 'foo' => 'what']);
+// ...or try
+$container->fromJSON('{"foo": "what", "bar": "foo"}');
+
+
+// fetch all properties as array
+$container->toArray(); // -> ['foo' => 'what', 'bar' => 'foo']
+// or JSON
+$container->toJSON(); // -> {"foo": "what", "bar": "foo"}
+
+//non-existing properties will be ignored:
+$container->nope = 'what';
+
+var_dump($container->nope); // -> null
+```
+
+### Advanced usage
+```php
+trait SomeOptions{
+ protected $foo;
+ protected $what;
+
+ // this method will be called in SettingsContainerAbstract::construct()
+ // after the properties have been set
+ protected function SomeOptions(){
+ // just some constructor stuff...
+ $this->foo = strtoupper($this->foo);
+ }
+
+ // this method will be called from __set() when property $what is set
+ protected function set_what(string $value){
+ $this->what = md5($value);
+ }
+}
+
+trait MoreOptions{
+ protected $bar = 'whatever'; // provide default values
+}
+```
+
+```php
+$commonOptions = [
+ // SomeOptions
+ 'foo' => 'whatever',
+ // MoreOptions
+ 'bar' => 'nothing',
+];
+
+// now plug the several library options together to a single object
+$container = new class ($commonOptions) extends SettingsContainerAbstract{
+ use SomeOptions, MoreOptions;
+};
+
+var_dump($container->foo); // -> WHATEVER (constructor ran strtoupper on the value)
+var_dump($container->bar); // -> nothing
+
+$container->what = 'some value';
+var_dump($container->what); // -> md5 hash of "some value"
+```
+
+### API
+
+#### [`SettingsContainerAbstract`](https://github.com/chillerlan/php-settings-container/blob/master/src/SettingsContainerAbstract.php)
+
+method | return | info
+-------- | ---- | -----------
+`__construct(iterable $properties = null)` | - | calls `construct()` internally after the properties have been set
+(protected) `construct()` | void | calls a method with trait name as replacement constructor for each used trait
+`__get(string $property)` | mixed | calls `$this->{'get_'.$property}()` if such a method exists
+`__set(string $property, $value)` | void | calls `$this->{'set_'.$property}($value)` if such a method exists
+`__isset(string $property)` | bool |
+`__unset(string $property)` | void |
+`__toString()` | string | a JSON string
+`toArray()` | array |
+`fromIterable(iterable $properties)` | `SettingsContainerInterface` |
+`toJSON(int $jsonOptions = null)` | string | accepts [JSON options constants](http://php.net/manual/json.constants.php)
+`fromJSON(string $json)` | `SettingsContainerInterface` |
+`jsonSerialize()` | mixed | implements the [`JsonSerializable`](https://www.php.net/manual/en/jsonserializable.jsonserialize.php) interface
+
+## Disclaimer
+This might be either an utterly genius or completely stupid idea - you decide. However, i like it and it works.
+Also, this is not a dependency injection container. Stop using DI containers FFS.
diff --git a/vendor/chillerlan/php-settings-container/composer.json b/vendor/chillerlan/php-settings-container/composer.json
new file mode 100644
index 000000000..4dc758665
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/composer.json
@@ -0,0 +1,40 @@
+{
+ "name": "chillerlan/php-settings-container",
+ "description": "A container class for immutable settings objects. Not a DI container. PHP 7.2+",
+ "homepage": "https://github.com/chillerlan/php-settings-container",
+ "license": "MIT",
+ "type": "library",
+ "minimum-stability": "stable",
+ "keywords": [
+ "php7", "helper", "container", "settings"
+ ],
+ "authors": [
+ {
+ "name": "Smiley",
+ "email": "[email protected]",
+ "homepage": "https://github.com/codemasher"
+ }
+ ],
+ "support": {
+ "issues": "https://github.com/chillerlan/php-settings-container/issues",
+ "source": "https://github.com/chillerlan/php-settings-container"
+ },
+ "require": {
+ "php": "^7.2",
+ "ext-json": "*"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.3"
+ },
+ "autoload": {
+ "psr-4": {
+ "chillerlan\\Settings\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "chillerlan\\SettingsTest\\": "tests/",
+ "chillerlan\\SettingsExamples\\": "examples/"
+ }
+ }
+}
diff --git a/vendor/chillerlan/php-settings-container/examples/advanced.php b/vendor/chillerlan/php-settings-container/examples/advanced.php
new file mode 100644
index 000000000..1030b0a29
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/examples/advanced.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * @filesource advanced.php
+ * @created 28.08.2018
+ * @author smiley <[email protected]>
+ * @copyright 2018 smiley
+ * @license MIT
+ */
+
+namespace chillerlan\SettingsExamples;
+
+use chillerlan\Settings\SettingsContainerAbstract;
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+// from library #1
+trait SomeOptions{
+ protected $foo;
+
+ // this method will be called in SettingsContainerAbstract::__construct() after the properties have been set
+ protected function SomeOptions(){
+ // just some constructor stuff...
+ $this->foo = strtoupper($this->foo);
+ }
+}
+
+// from library #2
+trait MoreOptions{
+ protected $bar = 'whatever'; // provide default values
+}
+
+$commonOptions = [
+ // SomeOptions
+ 'foo' => 'whatever',
+ // MoreOptions
+ 'bar' => 'nothing',
+];
+
+// now plug the several library options together to a single object
+/** @var \chillerlan\Settings\SettingsContainerInterface $container */
+$container = new class ($commonOptions) extends SettingsContainerAbstract{
+ use SomeOptions, MoreOptions; // ...
+};
+
+var_dump($container->foo); // -> WHATEVER (constructor ran strtoupper on the value)
+var_dump($container->bar); // -> nothing
diff --git a/vendor/chillerlan/php-settings-container/examples/simple.php b/vendor/chillerlan/php-settings-container/examples/simple.php
new file mode 100644
index 000000000..d8d81095b
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/examples/simple.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @filesource simple.php
+ * @created 28.08.2018
+ * @author smiley <[email protected]>
+ * @copyright 2018 smiley
+ * @license MIT
+ */
+
+namespace chillerlan\SettingsExamples;
+
+use chillerlan\Settings\SettingsContainerAbstract;
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+class MyContainer extends SettingsContainerAbstract{
+ protected $foo;
+ protected $bar;
+}
+
+/** @var \chillerlan\Settings\SettingsContainerInterface $container */
+$container = new MyContainer(['foo' => 'what']);
+$container->bar = 'foo';
+
+var_dump($container->toJSON()); // -> {"foo":"what","bar":"foo"}
+
+// non-existing properties will be ignored:
+$container->nope = 'what';
+
+var_dump($container->nope); // -> NULL
diff --git a/vendor/chillerlan/php-settings-container/phpmd.xml b/vendor/chillerlan/php-settings-container/phpmd.xml
new file mode 100644
index 000000000..3ba7e11b7
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/phpmd.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<ruleset name="codemasher/php-settings-container PMD ruleset"
+ xmlns="http://pmd.sf.net/ruleset/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
+ xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
+ <description>codemasher/php-settings-container PMD ruleset</description>
+ <exclude-pattern>*/examples/*</exclude-pattern>
+ <exclude-pattern>*/tests/*</exclude-pattern>
+ <exclude-pattern>*/vendor/*</exclude-pattern>
+ <rule ref="rulesets/cleancode.xml">
+ <exclude name="BooleanArgumentFlag"/>
+ </rule>
+ <rule ref="rulesets/codesize.xml/CyclomaticComplexity">
+ <priority>1</priority>
+ <properties>
+ <property name="maximum" value="150" />
+ </properties>
+ </rule>
+ <rule ref="rulesets/controversial.xml">
+ <exclude name="CamelCaseMethodName"/>
+ <exclude name="CamelCasePropertyName"/>
+ <exclude name="CamelCaseParameterName"/>
+ <exclude name="CamelCaseVariableName"/>
+ </rule>
+ <rule ref="rulesets/design.xml">
+ </rule>
+ <rule ref="rulesets/naming.xml">
+ <exclude name="LongVariable"/>
+ <exclude name="ShortVariable"/>
+ </rule>
+ <rule ref="rulesets/unusedcode.xml">
+ <exclude name="UnusedFormalParameter"/>
+ </rule>
+</ruleset>
diff --git a/vendor/chillerlan/php-settings-container/phpunit.xml b/vendor/chillerlan/php-settings-container/phpunit.xml
new file mode 100644
index 000000000..bb05d1289
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/phpunit.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit backupGlobals="false"
+ backupStaticAttributes="false"
+ bootstrap="vendor/autoload.php"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false"
+>
+ <filter>
+ <whitelist processUncoveredFilesFromWhitelist="true">
+ <directory suffix=".php">./src</directory>
+ </whitelist>
+ </filter>
+ <testsuites>
+ <testsuite name="php-settings-container test suite">
+ <directory suffix=".php">./tests/</directory>
+ </testsuite>
+ </testsuites>
+</phpunit>
diff --git a/vendor/chillerlan/php-settings-container/src/SettingsContainerAbstract.php b/vendor/chillerlan/php-settings-container/src/SettingsContainerAbstract.php
new file mode 100644
index 000000000..1ccc1a0e2
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/src/SettingsContainerAbstract.php
@@ -0,0 +1,172 @@
+<?php
+/**
+ * Class SettingsContainerAbstract
+ *
+ * @filesource SettingsContainerAbstract.php
+ * @created 28.08.2018
+ * @package chillerlan\Settings
+ * @author Smiley <[email protected]>
+ * @copyright 2018 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\Settings;
+
+use Exception, ReflectionClass, ReflectionProperty;
+
+use function call_user_func, call_user_func_array, get_object_vars, json_decode, json_encode, method_exists, property_exists;
+
+abstract class SettingsContainerAbstract implements SettingsContainerInterface{
+
+ /**
+ * SettingsContainerAbstract constructor.
+ *
+ * @param iterable|null $properties
+ */
+ public function __construct(iterable $properties = null){
+
+ if(!empty($properties)){
+ $this->fromIterable($properties);
+ }
+
+ $this->construct();
+ }
+
+ /**
+ * calls a method with trait name as replacement constructor for each used trait
+ * (remember pre-php5 classname constructors? yeah, basically this.)
+ *
+ * @return void
+ */
+ protected function construct():void{
+ $traits = (new ReflectionClass($this))->getTraits();
+
+ foreach($traits as $trait){
+ $method = $trait->getShortName();
+
+ if(method_exists($this, $method)){
+ call_user_func([$this, $method]);
+ }
+ }
+
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function __get(string $property){
+
+ if(property_exists($this, $property) && !$this->isPrivate($property)){
+
+ if(method_exists($this, 'get_'.$property)){
+ return call_user_func([$this, 'get_'.$property]);
+ }
+
+ return $this->{$property};
+ }
+
+ return null;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function __set(string $property, $value):void{
+
+ if(!property_exists($this, $property) || $this->isPrivate($property)){
+ return;
+ }
+
+ if(method_exists($this, 'set_'.$property)){
+ call_user_func_array([$this, 'set_'.$property], [$value]);
+
+ return;
+ }
+
+ $this->{$property} = $value;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function __isset(string $property):bool{
+ return isset($this->{$property}) && !$this->isPrivate($property);
+ }
+
+ /**
+ * @internal Checks if a property is private
+ *
+ * @param string $property
+ *
+ * @return bool
+ */
+ protected function isPrivate(string $property):bool{
+ return (new ReflectionProperty($this, $property))->isPrivate();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function __unset(string $property):void{
+
+ if($this->__isset($property)){
+ unset($this->{$property});
+ }
+
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function __toString():string{
+ return $this->toJSON();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function toArray():array{
+ return get_object_vars($this);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function fromIterable(iterable $properties):SettingsContainerInterface{
+
+ foreach($properties as $key => $value){
+ $this->__set($key, $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function toJSON(int $jsonOptions = null):string{
+ return json_encode($this, $jsonOptions ?? 0);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function fromJSON(string $json):SettingsContainerInterface{
+
+ $data = json_decode($json, true); // as of PHP 7.3: JSON_THROW_ON_ERROR
+
+ if($data === false || $data === null){
+ throw new Exception('error while decoding JSON');
+ }
+
+ return $this->fromIterable($data);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function jsonSerialize(){
+ return $this->toArray();
+ }
+
+}
diff --git a/vendor/chillerlan/php-settings-container/src/SettingsContainerInterface.php b/vendor/chillerlan/php-settings-container/src/SettingsContainerInterface.php
new file mode 100644
index 000000000..59cef6232
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/src/SettingsContainerInterface.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Interface SettingsContainerInterface
+ *
+ * @filesource SettingsContainerInterface.php
+ * @created 28.08.2018
+ * @package chillerlan\Settings
+ * @author Smiley <[email protected]>
+ * @copyright 2018 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\Settings;
+
+use JsonSerializable;
+
+/**
+ * a generic container with magic getter and setter
+ */
+interface SettingsContainerInterface extends JsonSerializable{
+
+ /**
+ * Retrieve the value of $property
+ *
+ * @param string $property
+ *
+ * @return mixed
+ */
+ public function __get(string $property);
+
+ /**
+ * Set $property to $value while avoiding private and non-existing properties
+ *
+ * @param string $property
+ * @param mixed $value
+ *
+ * @return void
+ */
+ public function __set(string $property, $value):void;
+
+ /**
+ * Checks if $property is set (aka. not null), excluding private properties
+ *
+ * @param string $property
+ *
+ * @return bool
+ */
+ public function __isset(string $property):bool;
+
+ /**
+ * Unsets $property while avoiding private and non-existing properties
+ *
+ * @param string $property
+ *
+ * @return void
+ */
+ public function __unset(string $property):void;
+
+ /**
+ * @see SettingsContainerInterface::toJSON()
+ *
+ * @return string
+ */
+ public function __toString():string;
+
+ /**
+ * Returns an array representation of the settings object
+ *
+ * @return array
+ */
+ public function toArray():array;
+
+ /**
+ * Sets properties from a given iterable
+ *
+ * @param iterable $properties
+ *
+ * @return \chillerlan\Settings\SettingsContainerInterface
+ */
+ public function fromIterable(iterable $properties):SettingsContainerInterface;
+
+ /**
+ * Returns a JSON representation of the settings object
+ * @see \json_encode()
+ *
+ * @param int|null $jsonOptions
+ *
+ * @return string
+ */
+ public function toJSON(int $jsonOptions = null):string;
+
+ /**
+ * Sets properties from a given JSON string
+ *
+ * @param string $json
+ *
+ * @return \chillerlan\Settings\SettingsContainerInterface
+ *
+ * @throws \Exception
+ * @throws \JsonException
+ */
+ public function fromJSON(string $json):SettingsContainerInterface;
+
+}
diff --git a/vendor/chillerlan/php-settings-container/tests/ContainerTest.php b/vendor/chillerlan/php-settings-container/tests/ContainerTest.php
new file mode 100644
index 000000000..ddae538f3
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/tests/ContainerTest.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * Class ContainerTraitTest
+ *
+ * @filesource ContainerTraitTest.php
+ * @created 28.08.2018
+ * @package chillerlan\SettingsTest
+ * @author Smiley <[email protected]>
+ * @copyright 2018 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\SettingsTest;
+
+use PHPUnit\Framework\TestCase;
+use Exception, TypeError;
+
+class ContainerTraitTest extends TestCase{
+
+ public function testConstruct(){
+ $container = new TestContainer([
+ 'test1' => 'test1',
+ 'test2' => 'test2',
+ 'test3' => 'test3',
+ 'test4' => 'test4',
+ ]);
+
+ $this->assertSame('test1', $container->test1);
+ $this->assertSame('test2', $container->test2);
+ $this->assertNull($container->test3);
+ $this->assertSame('test4', $container->test4);
+
+ $this->assertSame('success', $container->testConstruct);
+ }
+
+ public function testGet(){
+ $container = new TestContainer;
+
+ $this->assertSame('foo', $container->test1);
+ $this->assertNull($container->test2);
+ $this->assertNull($container->test3);
+ $this->assertNull($container->test4);
+ $this->assertNull($container->foo);
+
+ // isset test
+ $this->assertTrue(isset($container->test1));
+ $this->assertFalse(isset($container->test2));
+ $this->assertFalse(isset($container->test3));
+ $this->assertFalse(isset($container->test4));
+ $this->assertFalse(isset($container->foo));
+
+ // custom getter
+ $container->test6 = 'foo';
+ $this->assertSame(sha1('foo'), $container->test6);
+ // nullable/isset test
+ $container->test6 = null;
+ $this->assertFalse(isset($container->test6));
+ $this->assertSame('null', $container->test6);
+ }
+
+ public function testSet(){
+ $container = new TestContainer;
+ $container->test1 = 'bar';
+ $container->test2 = 'what';
+ $container->test3 = 'nope';
+
+ $this->assertSame('bar', $container->test1);
+ $this->assertSame('what', $container->test2);
+ $this->assertNull($container->test3);
+
+ // unset
+ unset($container->test1);
+ $this->assertFalse(isset($container->test1));
+
+ // custom setter
+ $container->test5 = 'bar';
+ $this->assertSame('bar_test5', $container->test5);
+ }
+
+ public function testToArray(){
+ $container = new TestContainer(['test1' => 'no', 'test2' => true, 'testConstruct' => 'success']);
+
+ $this->assertSame(['test1' => 'no', 'test2' => true, 'testConstruct' => 'success', 'test4' => null, 'test5' => null, 'test6' => null], $container->toArray());
+ }
+
+ public function testToJSON(){
+ $container = (new TestContainer)->fromJSON('{"test1":"no","test2":true,"testConstruct":"success"}');
+
+ $expected = '{"test1":"no","test2":true,"testConstruct":"success","test4":null,"test5":null,"test6":null}';
+
+ $this->assertSame($expected, $container->toJSON());
+ $this->assertSame($expected, (string)$container);
+ }
+
+ public function testFromJsonException(){
+ $this->expectException(Exception::class);
+ (new TestContainer)->fromJSON('-');
+
+ }
+ public function testFromJsonTypeError(){
+ $this->expectException(TypeError::class);
+ (new TestContainer)->fromJSON('2');
+ }
+
+}
diff --git a/vendor/chillerlan/php-settings-container/tests/TestContainer.php b/vendor/chillerlan/php-settings-container/tests/TestContainer.php
new file mode 100644
index 000000000..a35f75277
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/tests/TestContainer.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Class TestContainer
+ *
+ * @filesource TestContainer.php
+ * @created 28.08.2018
+ * @package chillerlan\SettingsTest
+ * @author Smiley <[email protected]>
+ * @copyright 2018 Smiley
+ * @license MIT
+ */
+
+namespace chillerlan\SettingsTest;
+
+use chillerlan\Settings\SettingsContainerAbstract;
+
+/**
+ * @property $test1
+ * @property $test2
+ * @property $test3
+ * @property $test4
+ * @property $test5
+ * @property $test6
+ */
+class TestContainer extends SettingsContainerAbstract{
+ use TestOptionsTrait;
+
+ private $test3 = 'what';
+}
diff --git a/vendor/chillerlan/php-settings-container/tests/TestOptionsTrait.php b/vendor/chillerlan/php-settings-container/tests/TestOptionsTrait.php
new file mode 100644
index 000000000..261f533ac
--- /dev/null
+++ b/vendor/chillerlan/php-settings-container/tests/TestOptionsTrait.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Trait TestOptionsTrait
+ *
+ * @filesource TestOptionsTrait.php
+ * @created 28.08.2018
+ * @package chillerlan\SettingsTest
+ * @author smiley <[email protected]>
+ * @copyright 2018 smiley
+ * @license MIT
+ */
+
+namespace chillerlan\SettingsTest;
+
+trait TestOptionsTrait{
+
+ protected $test1 = 'foo';
+
+ protected $test2;
+
+ protected $testConstruct;
+
+ protected $test4;
+
+ protected $test5;
+
+ protected $test6;
+
+ protected function TestOptionsTrait(){
+ $this->testConstruct = 'success';
+ }
+
+ protected function set_test5($value){
+ $this->test5 = $value.'_test5';
+ }
+
+ protected function get_test6(){
+ return $this->test6 === null
+ ? 'null'
+ : sha1($this->test6);
+ }
+}