From 307b6462f65ae9d1cb63db77d6876ff0fcd748c7 Mon Sep 17 00:00:00 2001 From: codemasher Date: Tue, 19 Jan 2021 00:24:16 +0100 Subject: [PATCH] :octocat: QRMatrix::M_*TYPE rework, separate masking --- examples/fpdf.php | 31 +++++----- examples/html.php | 49 ++++++---------- examples/image.php | 39 +++++++------ examples/imagick.php | 34 +++++------ examples/svg.php | 34 +++++------ examples/text.php | 32 ++++++----- src/Data/QRData.php | 3 +- src/Data/QRMatrix.php | 99 +++++++++++++++++++++----------- src/Output/QROutputInterface.php | 40 ++++++------- tests/Data/QRMatrixTest.php | 59 +++++++++++++------ tests/Output/QRMarkupTest.php | 6 +- tests/Output/QRStringTest.php | 10 ++-- tests/Output/samples/json | 2 +- tests/Output/samples/svg | 2 +- 14 files changed, 246 insertions(+), 194 deletions(-) diff --git a/examples/fpdf.php b/examples/fpdf.php index b231e49e0..a693df725 100644 --- a/examples/fpdf.php +++ b/examples/fpdf.php @@ -3,6 +3,7 @@ namespace chillerlan\QRCodeExamples; use chillerlan\QRCode\{QRCode, QROptions}; +use chillerlan\QRCode\Data\QRMatrix; use chillerlan\QRCode\Common\EccLevel; require_once __DIR__ . '/../vendor/autoload.php'; @@ -17,29 +18,29 @@ $options = new QROptions([ '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 + QRMatrix::M_FINDER | QRMatrix::IS_DARK => [0, 63, 255], // dark (true) + QRMatrix::M_FINDER => [255, 255, 255], // light (false), white is the transparency color and is enabled by default // alignment - 2560 => [255, 0, 255], - 10 => [255, 255, 255], + QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK => [255, 0, 255], + QRMatrix::M_ALIGNMENT => [255, 255, 255], // timing - 3072 => [255, 0, 0], - 12 => [255, 255, 255], + QRMatrix::M_TIMING | QRMatrix::IS_DARK => [255, 0, 0], + QRMatrix::M_TIMING => [255, 255, 255], // format - 3584 => [67, 191, 84], - 14 => [255, 255, 255], + QRMatrix::M_FORMAT | QRMatrix::IS_DARK => [67, 191, 84], + QRMatrix::M_FORMAT => [255, 255, 255], // version - 4096 => [62, 174, 190], - 16 => [255, 255, 255], + QRMatrix::M_VERSION | QRMatrix::IS_DARK => [62, 174, 190], + QRMatrix::M_VERSION => [255, 255, 255], // data - 1024 => [0, 0, 0], - 4 => [255, 255, 255], + QRMatrix::M_DATA | QRMatrix::IS_DARK => [0, 0, 0], + QRMatrix::M_DATA => [255, 255, 255], // darkmodule - 512 => [0, 0, 0], + QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK => [0, 0, 0], // separator - 8 => [255, 255, 255], + QRMatrix::M_SEPARATOR => [255, 255, 255], // quietzone - 18 => [255, 255, 255], + QRMatrix::M_QUIETZONE => [255, 255, 255], ], ]); diff --git a/examples/html.php b/examples/html.php index 34140671c..e7d658961 100644 --- a/examples/html.php +++ b/examples/html.php @@ -11,6 +11,7 @@ namespace chillerlan\QRCodeExamples; use chillerlan\QRCode\{QRCode, QROptions}; +use chillerlan\QRCode\Data\QRMatrix; use chillerlan\QRCode\Common\EccLevel; require_once '../vendor/autoload.php'; @@ -25,20 +26,12 @@ header('Content-Type: text/html; charset=utf-8'); QRCode test -
5, 'outputType' => QRCode::OUTPUT_MARKUP_HTML, 'eccLevel' => EccLevel::L, + 'cssClass' => 'qrcode', 'moduleValues' => [ // finder - 1536 => '#A71111', // dark (true) - 6 => '#FFBFBF', // light (false) + QRMatrix::M_FINDER | QRMatrix::IS_DARK => '#A71111', // dark (true) + QRMatrix::M_FINDER => '#FFBFBF', // light (false) + QRMatrix::M_FINDER_DOT | QRMatrix::IS_DARK => '#A71111', // finder dot, dark (true) // alignment - 2560 => '#A70364', - 10 => '#FFC9C9', + QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK => '#A70364', + QRMatrix::M_ALIGNMENT => '#FFC9C9', // timing - 3072 => '#98005D', - 12 => '#FFB8E9', + QRMatrix::M_TIMING | QRMatrix::IS_DARK => '#98005D', + QRMatrix::M_TIMING => '#FFB8E9', // format - 3584 => '#003804', - 14 => '#00FB12', + QRMatrix::M_FORMAT | QRMatrix::IS_DARK => '#003804', + QRMatrix::M_FORMAT => '#00FB12', // version - 4096 => '#650098', - 16 => '#E0B8FF', + QRMatrix::M_VERSION | QRMatrix::IS_DARK => '#650098', + QRMatrix::M_VERSION => '#E0B8FF', // data - 1024 => '#4A6000', - 4 => '#ECF9BE', + QRMatrix::M_DATA | QRMatrix::IS_DARK => '#4A6000', + QRMatrix::M_DATA => '#ECF9BE', // darkmodule - 512 => '#080063', + QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK => '#080063', // separator - 8 => '#AFBFBF', + QRMatrix::M_SEPARATOR => '#AFBFBF', // quietzone - 18 => '#FFFFFF', + QRMatrix::M_QUIETZONE => '#DDDDDD', ], ]); echo (new QRCode($options))->render($data); ?> -
diff --git a/examples/image.php b/examples/image.php index 99d3ceab8..6d9069f33 100644 --- a/examples/image.php +++ b/examples/image.php @@ -11,6 +11,7 @@ namespace chillerlan\QRCodeExamples; use chillerlan\QRCode\{QRCode, QROptions}; +use chillerlan\QRCode\Data\QRMatrix; use chillerlan\QRCode\Common\EccLevel; require_once __DIR__.'/../vendor/autoload.php'; @@ -18,39 +19,39 @@ require_once __DIR__.'/../vendor/autoload.php'; $data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s'; $options = new QROptions([ - 'version' => 10, + 'version' => 5, 'outputType' => QRCode::OUTPUT_IMAGE_PNG, 'eccLevel' => EccLevel::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 - 5632 => [241, 28, 163], // finder dot, dark (true) + QRMatrix::M_FINDER | QRMatrix::IS_DARK => [0, 63, 255], // dark (true) + QRMatrix::M_FINDER => [255, 255, 255], // light (false), white is the transparency color and is enabled by default + QRMatrix::M_FINDER_DOT | QRMatrix::IS_DARK => [241, 28, 163], // finder dot, dark (true) // alignment - 2560 => [255, 0, 255], - 10 => [255, 255, 255], + QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK => [255, 0, 255], + QRMatrix::M_ALIGNMENT => [255, 255, 255], // timing - 3072 => [255, 0, 0], - 12 => [255, 255, 255], + QRMatrix::M_TIMING | QRMatrix::IS_DARK => [255, 0, 0], + QRMatrix::M_TIMING => [255, 255, 255], // format - 3584 => [67, 99, 84], - 14 => [255, 255, 255], + QRMatrix::M_FORMAT | QRMatrix::IS_DARK => [67, 99, 84], + QRMatrix::M_FORMAT => [255, 255, 255], // version - 4096 => [62, 174, 190], - 16 => [255, 255, 255], + QRMatrix::M_VERSION | QRMatrix::IS_DARK => [62, 174, 190], + QRMatrix::M_VERSION => [255, 255, 255], // data - 1024 => [0, 0, 0], - 4 => [255, 255, 255], + QRMatrix::M_DATA | QRMatrix::IS_DARK => [0, 0, 0], + QRMatrix::M_DATA => [255, 255, 255], // darkmodule - 512 => [0, 0, 0], + QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK => [0, 0, 0], // separator - 8 => [255, 255, 255], + QRMatrix::M_SEPARATOR => [255, 255, 255], // quietzone - 18 => [255, 255, 255], - // logo (requires a call to QRMatrix::setLogoSpace()) - 20 => [255, 255, 255], + QRMatrix::M_QUIETZONE => [255, 255, 255], + // logo (requires a call to QRMatrix::setLogoSpace()), see QRImageWithLogo + QRMatrix::M_LOGO => [255, 255, 255], ], ]); diff --git a/examples/imagick.php b/examples/imagick.php index 38162972f..fb0561f06 100644 --- a/examples/imagick.php +++ b/examples/imagick.php @@ -1,7 +1,7 @@ * @copyright 2017 Smiley @@ -11,6 +11,7 @@ namespace chillerlan\QRCodeExamples; use chillerlan\QRCode\{QRCode, QROptions}; +use chillerlan\QRCode\Data\QRMatrix; use chillerlan\QRCode\Common\EccLevel; require_once __DIR__.'/../vendor/autoload.php'; @@ -24,29 +25,30 @@ $options = new QROptions([ 'scale' => 5, 'moduleValues' => [ // finder - 1536 => '#A71111', // dark (true) - 6 => '#FFBFBF', // light (false) + QRMatrix::M_FINDER | QRMatrix::IS_DARK => '#A71111', // dark (true) + QRMatrix::M_FINDER => '#FFBFBF', // light (false) + QRMatrix::M_FINDER_DOT | QRMatrix::IS_DARK => '#A71111', // finder dot, dark (true) // alignment - 2560 => '#A70364', - 10 => '#FFC9C9', + QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK => '#A70364', + QRMatrix::M_ALIGNMENT => '#FFC9C9', // timing - 3072 => '#98005D', - 12 => '#FFB8E9', + QRMatrix::M_TIMING | QRMatrix::IS_DARK => '#98005D', + QRMatrix::M_TIMING => '#FFB8E9', // format - 3584 => '#003804', - 14 => '#00FB12', + QRMatrix::M_FORMAT | QRMatrix::IS_DARK => '#003804', + QRMatrix::M_FORMAT => '#00FB12', // version - 4096 => '#650098', - 16 => '#E0B8FF', + QRMatrix::M_VERSION | QRMatrix::IS_DARK => '#650098', + QRMatrix::M_VERSION => '#E0B8FF', // data - 1024 => '#4A6000', - 4 => '#ECF9BE', + QRMatrix::M_DATA | QRMatrix::IS_DARK => '#4A6000', + QRMatrix::M_DATA => '#ECF9BE', // darkmodule - 512 => '#080063', + QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK => '#080063', // separator - 8 => '#DDDDDD', + QRMatrix::M_SEPARATOR => '#DDDDDD', // quietzone - 18 => '#DDDDDD', + QRMatrix::M_QUIETZONE => '#DDDDDD', ], ]); diff --git a/examples/svg.php b/examples/svg.php index 517e393ed..b02040dda 100644 --- a/examples/svg.php +++ b/examples/svg.php @@ -11,6 +11,7 @@ namespace chillerlan\QRCodeExamples; use chillerlan\QRCode\{QRCode, QROptions}; +use chillerlan\QRCode\Data\QRMatrix; use chillerlan\QRCode\Common\EccLevel; require_once __DIR__.'/../vendor/autoload.php'; @@ -39,29 +40,30 @@ $options = new QROptions([ ', 'moduleValues' => [ // finder - 1536 => 'url(#g1)', // dark (true) - 6 => '#fff', // light (false) + QRMatrix::M_FINDER | QRMatrix::IS_DARK => 'url(#g1)', // dark (true) + QRMatrix::M_FINDER => '#fff', // light (false) + QRMatrix::M_FINDER_DOT | QRMatrix::IS_DARK => 'url(#g2)', // finder dot, dark (true) // alignment - 2560 => 'url(#g1)', - 10 => '#fff', + QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK => 'url(#g1)', + QRMatrix::M_ALIGNMENT => '#fff', // timing - 3072 => 'url(#g1)', - 12 => '#fff', + QRMatrix::M_TIMING | QRMatrix::IS_DARK => 'url(#g1)', + QRMatrix::M_TIMING => '#fff', // format - 3584 => 'url(#g1)', - 14 => '#fff', + QRMatrix::M_FORMAT | QRMatrix::IS_DARK => 'url(#g1)', + QRMatrix::M_FORMAT => '#fff', // version - 4096 => 'url(#g1)', - 16 => '#fff', + QRMatrix::M_VERSION | QRMatrix::IS_DARK => 'url(#g1)', + QRMatrix::M_VERSION => '#fff', // data - 1024 => 'url(#g2)', - 4 => '#fff', + QRMatrix::M_DATA | QRMatrix::IS_DARK => 'url(#g2)', + QRMatrix::M_DATA => '#fff', // darkmodule - 512 => 'url(#g1)', + QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK => 'url(#g1)', // separator - 8 => '#fff', + QRMatrix::M_SEPARATOR => '#fff', // quietzone - 18 => '#fff', + QRMatrix::M_QUIETZONE => '#fff', ], ]); @@ -72,7 +74,7 @@ header('Content-type: image/svg+xml'); if($gzip === true){ header('Vary: Accept-Encoding'); header('Content-Encoding: gzip'); - $qrcode = gzencode($qrcode ,9); + $qrcode = gzencode($qrcode, 9); } echo $qrcode; diff --git a/examples/text.php b/examples/text.php index d0a6ec2bc..89854db6a 100644 --- a/examples/text.php +++ b/examples/text.php @@ -11,6 +11,7 @@ namespace chillerlan\QRCodeExamples; use chillerlan\QRCode\{QRCode, QROptions}; +use chillerlan\QRCode\Data\QRMatrix; use chillerlan\QRCode\Common\EccLevel; require_once __DIR__.'/../vendor/autoload.php'; @@ -34,29 +35,30 @@ $options = new QROptions([ 'eccLevel' => EccLevel::L, 'moduleValues' => [ // finder - 1536 => 'A', // dark (true) - 6 => 'a', // light (false) + QRMatrix::M_FINDER | QRMatrix::IS_DARK => 'A', // dark (true) + QRMatrix::M_FINDER => 'a', // light (false) + QRMatrix::M_FINDER_DOT | QRMatrix::IS_DARK => 'รค', // finder dot, dark (true) // alignment - 2560 => 'B', - 10 => 'b', + QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK => 'B', + QRMatrix::M_ALIGNMENT => 'b', // timing - 3072 => 'C', - 12 => 'c', + QRMatrix::M_TIMING | QRMatrix::IS_DARK => 'C', + QRMatrix::M_TIMING => 'c', // format - 3584 => 'D', - 14 => 'd', + QRMatrix::M_FORMAT | QRMatrix::IS_DARK => 'D', + QRMatrix::M_FORMAT => 'd', // version - 4096 => 'E', - 16 => 'e', + QRMatrix::M_VERSION | QRMatrix::IS_DARK => 'E', + QRMatrix::M_VERSION => 'e', // data - 1024 => 'F', - 4 => 'f', + QRMatrix::M_DATA | QRMatrix::IS_DARK => 'F', + QRMatrix::M_DATA => 'f', // darkmodule - 512 => 'G', + QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK => 'G', // separator - 8 => 'h', + QRMatrix::M_SEPARATOR => 'h', // quietzone - 18 => 'i', + QRMatrix::M_QUIETZONE => 'i', ], ]); diff --git a/src/Data/QRData.php b/src/Data/QRData.php index c02d50812..6f62cdb4e 100644 --- a/src/Data/QRData.php +++ b/src/Data/QRData.php @@ -105,7 +105,8 @@ final class QRData{ return (new QRMatrix($this->version, $this->eccLevel)) ->init($maskPattern, $test) - ->mapData($data, $maskPattern) + ->mapData($data) + ->mask($maskPattern) ; } diff --git a/src/Data/QRMatrix.php b/src/Data/QRMatrix.php index 2d9f74b28..d06aa36bc 100755 --- a/src/Data/QRMatrix.php +++ b/src/Data/QRMatrix.php @@ -28,31 +28,33 @@ use function array_fill, array_push, array_unshift, floor, max, min, range; final class QRMatrix{ /** @var int */ - public const M_NULL = 0x00; + public const M_NULL = 0b000000000000; /** @var int */ - public const M_DARKMODULE = 0x02; + public const M_DARKMODULE = 0b000000000001; /** @var int */ - public const M_DATA = 0x04; + public const M_DATA = 0b000000000010; /** @var int */ - public const M_FINDER = 0x06; + public const M_FINDER = 0b000000000100; /** @var int */ - public const M_SEPARATOR = 0x08; + public const M_SEPARATOR = 0b000000001000; /** @var int */ - public const M_ALIGNMENT = 0x0a; + public const M_ALIGNMENT = 0b000000010000; /** @var int */ - public const M_TIMING = 0x0c; + public const M_TIMING = 0b000000100000; /** @var int */ - public const M_FORMAT = 0x0e; + public const M_FORMAT = 0b000001000000; /** @var int */ - public const M_VERSION = 0x10; + public const M_VERSION = 0b000010000000; /** @var int */ - public const M_QUIETZONE = 0x12; + public const M_QUIETZONE = 0b000100000000; /** @var int */ - public const M_LOGO = 0x14; + public const M_LOGO = 0b001000000000; /** @var int */ - public const M_FINDER_DOT = 0x16; + public const M_FINDER_DOT = 0b010000000000; /** @var int */ - public const M_TEST = 0xff; + public const M_TEST = 0b011111111111; + /** @var int */ + public const IS_DARK = 0b100000000000; /** * the used mask pattern, set via QRMatrix::mapData() @@ -123,7 +125,7 @@ final class QRMatrix{ $matrix[$y] = []; foreach($row as $x => $val){ - $matrix[$y][$x] = ($val >> 8) > 0; + $matrix[$y][$x] = ($val & $this::IS_DARK) === $this::IS_DARK; } } @@ -170,28 +172,42 @@ final class QRMatrix{ /** * Sets the $M_TYPE value for the module at position [$x, $y] * - * true => $M_TYPE << 8 + * true => $M_TYPE | 0x800 * false => $M_TYPE */ public function set(int $x, int $y, bool $value, int $M_TYPE):QRMatrix{ - $this->matrix[$y][$x] = $M_TYPE << ($value ? 8 : 0); + $this->matrix[$y][$x] = $M_TYPE | ($value ? $this::IS_DARK : 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 + * Flips the value of the module */ - public function check(int $x, int $y):bool{ - return ($this->matrix[$y][$x] >> 8) > 0; + public function flip(int $x, int $y):QRMatrix{ + $this->matrix[$y][$x] ^= $this::IS_DARK; + + return $this; } + /** + * Checks whether a module is of the given $M_TYPE + * + * true => $value & $M_TYPE === $M_TYPE + */ + public function checkType(int $x, int $y, int $M_TYPE):bool{ + return ($this->matrix[$y][$x] & $M_TYPE) === $M_TYPE; + } + + /** + * Checks whether a module is true (dark) or false (light) + * + * true => $value & 0x800 === 0x800 + * false => $value & 0x800 === 0 + */ + public function check(int $x, int $y):bool{ + return $this->checkType($x, $y, $this::IS_DARK); + } /** * Sets the "dark module", that is always on the same position 1x1px away from the bottom left finder @@ -331,7 +347,7 @@ final class QRMatrix{ if($bits !== null){ for($i = 0; $i < 18; $i++){ - $a = (int)floor($i / 3); + $a = (int)($i / 3); $b = $i % 3 + $this->moduleCount - 8 - 3; $v = !$test && (($bits >> $i) & 1) === 1; @@ -495,18 +511,15 @@ final class QRMatrix{ * @see \chillerlan\QRCode\Data\QRData::maskECC() * * @param \SplFixedArray $data - * @param int $maskPattern * * @return \chillerlan\QRCode\Data\QRMatrix */ - public function mapData(SplFixedArray $data, int $maskPattern):QRMatrix{ - $this->maskPattern = $maskPattern; + public function mapData(SplFixedArray $data):QRMatrix{ $byteCount = $data->count(); $y = $this->moduleCount - 1; $inc = -1; $byteIndex = 0; $bitIndex = 7; - $mask = $this->getMask($this->maskPattern); for($i = $y; $i > 0; $i -= 2){ @@ -525,11 +538,7 @@ final class QRMatrix{ $v = (($data[$byteIndex] >> $bitIndex) & 1) === 1; } - if($mask($x, $y) === 0){ - $v = !$v; - } - - $this->matrix[$y][$x] = $this::M_DATA << ($v ? 8 : 0); + $this->matrix[$y][$x] = $this::M_DATA | ($v ? $this::IS_DARK : 0); $bitIndex--; if($bitIndex === -1){ @@ -555,6 +564,26 @@ final class QRMatrix{ return $this; } + /** + * Applies the mask pattern + * + * ISO/IEC 18004:2000 Section 8.8.1 + */ + public function mask(int $maskPattern):QRMatrix{ + $this->maskPattern = $maskPattern; + $mask = $this->getMask($this->maskPattern); + + foreach($this->matrix as $y => &$row){ + foreach($row as $x => &$val){ + if($mask($x, $y) === 0 && ($val & $this::M_DATA) === $this::M_DATA){ + $val ^= $this::IS_DARK; + } + } + } + + return $this; + } + /** * ISO/IEC 18004:2000 Section 8.8.1 * diff --git a/src/Output/QROutputInterface.php b/src/Output/QROutputInterface.php index b07b8e7a5..847b2b754 100644 --- a/src/Output/QROutputInterface.php +++ b/src/Output/QROutputInterface.php @@ -21,27 +21,27 @@ interface QROutputInterface{ const DEFAULT_MODULE_VALUES = [ // light - QRMatrix::M_NULL => false, // 0 - 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 + QRMatrix::M_NULL => false, + QRMatrix::M_DATA => false, + QRMatrix::M_FINDER => false, + QRMatrix::M_SEPARATOR => false, + QRMatrix::M_ALIGNMENT => false, + QRMatrix::M_TIMING => false, + QRMatrix::M_FORMAT => false, + QRMatrix::M_VERSION => false, + QRMatrix::M_QUIETZONE => false, + QRMatrix::M_LOGO => false, + QRMatrix::M_TEST => false, // 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 + QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK => true, + QRMatrix::M_DATA | QRMatrix::IS_DARK => true, + QRMatrix::M_FINDER | QRMatrix::IS_DARK => true, + QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK => true, + QRMatrix::M_TIMING | QRMatrix::IS_DARK => true, + QRMatrix::M_FORMAT | QRMatrix::IS_DARK => true, + QRMatrix::M_VERSION | QRMatrix::IS_DARK => true, + QRMatrix::M_FINDER_DOT | QRMatrix::IS_DARK => true, + QRMatrix::M_TEST | QRMatrix::IS_DARK => true, ]; /** diff --git a/tests/Data/QRMatrixTest.php b/tests/Data/QRMatrixTest.php index 3b94b974d..53ec8ea3c 100755 --- a/tests/Data/QRMatrixTest.php +++ b/tests/Data/QRMatrixTest.php @@ -87,11 +87,11 @@ final class QRMatrixTest extends TestCase{ */ public function testGetSetCheck():void{ $this->matrix->set(10, 10, true, QRMatrix::M_TEST); - $this::assertSame(65280, $this->matrix->get(10, 10)); + $this::assertSame(QRMatrix::M_TEST | QRMatrix::IS_DARK, $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::assertSame(QRMatrix::M_TEST, $this->matrix->get(20, 20)); $this::assertFalse($this->matrix->check(20, 20)); } @@ -119,7 +119,7 @@ final class QRMatrixTest extends TestCase{ public function testSetDarkModule(int $version):void{ $matrix = $this->getMatrix($version)->setDarkModule(); - $this::assertSame(QRMatrix::M_DARKMODULE << 8, $matrix->get(8, $matrix->size() - 8)); + $this::assertSame(QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK, $matrix->get(8, $matrix->size() - 8)); } /** @@ -130,9 +130,9 @@ final class QRMatrixTest extends TestCase{ public function testSetFinderPattern(int $version):void{ $matrix = $this->getMatrix($version)->setFinderPattern(); - $this::assertSame(QRMatrix::M_FINDER << 8, $matrix->get(0, 0)); - $this::assertSame(QRMatrix::M_FINDER << 8, $matrix->get(0, $matrix->size() - 1)); - $this::assertSame(QRMatrix::M_FINDER << 8, $matrix->get($matrix->size() - 1, 0)); + $this::assertSame(QRMatrix::M_FINDER | QRMatrix::IS_DARK, $matrix->get(0, 0)); + $this::assertSame(QRMatrix::M_FINDER | QRMatrix::IS_DARK, $matrix->get(0, $matrix->size() - 1)); + $this::assertSame(QRMatrix::M_FINDER | QRMatrix::IS_DARK, $matrix->get($matrix->size() - 1, 0)); } /** @@ -174,12 +174,12 @@ final class QRMatrixTest extends TestCase{ foreach($alignmentPattern as $py){ foreach($alignmentPattern as $px){ - if($matrix->get($px, $py) === QRMatrix::M_FINDER << 8){ - $this::assertSame(QRMatrix::M_FINDER << 8, $matrix->get($px, $py), 'skipped finder pattern'); + if($matrix->get($px, $py) === (QRMatrix::M_FINDER | QRMatrix::IS_DARK)){ + $this::assertSame(QRMatrix::M_FINDER | QRMatrix::IS_DARK, $matrix->get($px, $py), 'skipped finder pattern'); continue; } - $this::assertSame(QRMatrix::M_ALIGNMENT << 8, $matrix->get($px, $py)); + $this::assertSame(QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK, $matrix->get($px, $py)); } } @@ -204,13 +204,13 @@ final class QRMatrixTest extends TestCase{ if($i % 2 === 0){ $p1 = $matrix->get(6, $i); - if($p1 === QRMatrix::M_ALIGNMENT << 8){ - $this::assertSame(QRMatrix::M_ALIGNMENT << 8, $p1, 'skipped alignment pattern'); + if($p1 === (QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK)){ + $this::assertSame(QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK, $p1, 'skipped alignment pattern'); continue; } - $this::assertSame(QRMatrix::M_TIMING << 8, $p1); - $this::assertSame(QRMatrix::M_TIMING << 8, $matrix->get($i, 6)); + $this::assertSame(QRMatrix::M_TIMING | QRMatrix::IS_DARK, $p1); + $this::assertSame(QRMatrix::M_TIMING | QRMatrix::IS_DARK, $matrix->get($i, 6)); } } } @@ -274,8 +274,8 @@ final class QRMatrixTest extends TestCase{ $this::assertSame(QRMatrix::M_QUIETZONE, $matrix->get(0, 0)); $this::assertSame(QRMatrix::M_QUIETZONE, $matrix->get($size - 1, $size - 1)); - $this::assertSame(QRMatrix::M_TEST << 8, $matrix->get($q, $q)); - $this::assertSame(QRMatrix::M_TEST << 8, $matrix->get($size - 1 - $q, $size - 1 - $q)); + $this::assertSame(QRMatrix::M_TEST | QRMatrix::IS_DARK, $matrix->get($q, $q)); + $this::assertSame(QRMatrix::M_TEST | QRMatrix::IS_DARK, $matrix->get($size - 1 - $q, $size - 1 - $q)); } /** @@ -319,10 +319,10 @@ final class QRMatrixTest extends TestCase{ // 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_FINDER | QRMatrix::IS_DARK, $m->get(10, 10)); + $this::assertSame(QRMatrix::M_FINDER | QRMatrix::IS_DARK, $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_FORMAT | QRMatrix::IS_DARK, $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)); @@ -353,4 +353,27 @@ final class QRMatrixTest extends TestCase{ (new QRCode($o))->addByteSegment('testdata')->getMatrix()->setLogoSpace(50, 50); } + /** + * Tests flipping the value of a module + */ + public function testFlip():void{ + // using the dark module here because i'm lazy + $matrix = $this->getMatrix(10)->setDarkModule(); + $x = 8; + $y = $matrix->size() - 8; + + // cover checkType() + $this::assertTrue($matrix->checkType($x, $y, QRMatrix::M_DARKMODULE)); + // verify the current state (dark) + $this::assertSame(QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK, $matrix->get($x, $y)); + // flip + $matrix->flip($x, $y); + // verify flip + $this::assertSame(QRMatrix::M_DARKMODULE, $matrix->get($x, $y)); + // flip again + $matrix->flip($x, $y); + // verify flip + $this::assertSame(QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK, $matrix->get($x, $y)); + } + } diff --git a/tests/Output/QRMarkupTest.php b/tests/Output/QRMarkupTest.php index cc18077d5..b928c5062 100644 --- a/tests/Output/QRMarkupTest.php +++ b/tests/Output/QRMarkupTest.php @@ -12,7 +12,7 @@ namespace chillerlan\QRCodeTest\Output; -use chillerlan\QRCode\{QRCode, QROptions}; +use chillerlan\QRCode\{Data\QRMatrix, QRCode, QROptions}; use chillerlan\QRCode\Output\{QROutputInterface, QRMarkup}; /** @@ -46,8 +46,8 @@ class QRMarkupTest extends QROutputTestAbstract{ $this->options->imageBase64 = false; $this->options->moduleValues = [ // data - 1024 => '#4A6000', - 4 => '#ECF9BE', + QRMatrix::M_DATA | QRMatrix::IS_DARK => '#4A6000', + QRMatrix::M_DATA => '#ECF9BE', ]; $this->outputInterface = $this->getOutputInterface($this->options); diff --git a/tests/Output/QRStringTest.php b/tests/Output/QRStringTest.php index 9206c8f10..c40694ec8 100644 --- a/tests/Output/QRStringTest.php +++ b/tests/Output/QRStringTest.php @@ -12,9 +12,11 @@ namespace chillerlan\QRCodeTest\Output; -use chillerlan\QRCodeExamples\MyCustomOutput; -use chillerlan\QRCode\{Common\EccLevel, QRCode, QROptions}; +use chillerlan\QRCode\{QRCode, QROptions}; +use chillerlan\QRCode\Common\EccLevel; +use chillerlan\QRCode\Data\QRMatrix; use chillerlan\QRCode\Output\{QROutputInterface, QRString}; +use chillerlan\QRCodeExamples\MyCustomOutput; /** * Tests the QRString output module @@ -47,8 +49,8 @@ class QRStringTest extends QROutputTestAbstract{ $this->options->moduleValues = [ // data - 1024 => 'A', - 4 => 'B', + QRMatrix::M_DATA | QRMatrix::IS_DARK => 'A', + QRMatrix::M_DATA => 'B', ]; $this->outputInterface = $this->getOutputInterface($this->options); diff --git a/tests/Output/samples/json b/tests/Output/samples/json index f8423f75b..56837ea1b 100644 --- a/tests/Output/samples/json +++ b/tests/Output/samples/json @@ -1 +1 @@ -[[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],[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],[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],[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],[18,18,18,18,1536,1536,1536,1536,1536,1536,1536,8,3584,1024,4,4,1024,8,1536,1536,1536,1536,1536,1536,1536,18,18,18,18],[18,18,18,18,1536,6,6,6,6,6,1536,8,14,1024,4,4,1024,8,1536,6,6,6,6,6,1536,18,18,18,18],[18,18,18,18,1536,6,5632,5632,5632,6,1536,8,3584,4,1024,4,1024,8,1536,6,5632,5632,5632,6,1536,18,18,18,18],[18,18,18,18,1536,6,5632,5632,5632,6,1536,8,3584,4,4,1024,4,8,1536,6,5632,5632,5632,6,1536,18,18,18,18],[18,18,18,18,1536,6,5632,5632,5632,6,1536,8,3584,1024,1024,4,4,8,1536,6,5632,5632,5632,6,1536,18,18,18,18],[18,18,18,18,1536,6,6,6,6,6,1536,8,14,4,4,4,4,8,1536,6,6,6,6,6,1536,18,18,18,18],[18,18,18,18,1536,1536,1536,1536,1536,1536,1536,8,3072,12,3072,12,3072,8,1536,1536,1536,1536,1536,1536,1536,18,18,18,18],[18,18,18,18,8,8,8,8,8,8,8,8,14,1024,1024,4,4,8,8,8,8,8,8,8,8,18,18,18,18],[18,18,18,18,3584,3584,3584,3584,14,14,3072,14,3584,4,1024,4,4,3584,14,14,3584,3584,3584,14,3584,18,18,18,18],[18,18,18,18,1024,4,4,1024,1024,1024,12,1024,4,4,1024,4,1024,4,4,1024,4,1024,1024,4,1024,18,18,18,18],[18,18,18,18,1024,4,1024,4,1024,1024,3072,4,4,4,1024,4,1024,1024,1024,1024,1024,4,4,1024,1024,18,18,18,18],[18,18,18,18,1024,4,1024,1024,4,4,12,1024,1024,4,1024,4,1024,1024,4,4,4,1024,4,1024,4,18,18,18,18],[18,18,18,18,4,1024,1024,4,1024,4,3072,4,4,1024,1024,1024,4,1024,4,4,1024,1024,4,1024,4,18,18,18,18],[18,18,18,18,8,8,8,8,8,8,8,8,512,4,1024,4,4,1024,4,1024,4,1024,4,1024,4,18,18,18,18],[18,18,18,18,1536,1536,1536,1536,1536,1536,1536,8,14,4,1024,4,4,1024,1024,4,1024,1024,1024,4,4,18,18,18,18],[18,18,18,18,1536,6,6,6,6,6,1536,8,14,1024,4,1024,1024,1024,1024,4,4,1024,1024,4,4,18,18,18,18],[18,18,18,18,1536,6,5632,5632,5632,6,1536,8,14,1024,1024,1024,4,4,1024,4,4,4,1024,1024,1024,18,18,18,18],[18,18,18,18,1536,6,5632,5632,5632,6,1536,8,3584,1024,4,4,4,1024,4,4,1024,1024,4,1024,4,18,18,18,18],[18,18,18,18,1536,6,5632,5632,5632,6,1536,8,3584,4,1024,1024,4,1024,4,4,1024,4,1024,4,4,18,18,18,18],[18,18,18,18,1536,6,6,6,6,6,1536,8,3584,1024,1024,1024,1024,4,1024,4,1024,1024,4,4,1024,18,18,18,18],[18,18,18,18,1536,1536,1536,1536,1536,1536,1536,8,3584,1024,4,1024,1024,4,4,1024,4,4,4,4,4,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,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,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,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,18,18,18,18]] +[[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256],[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256],[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256],[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256],[256,256,256,256,2052,2052,2052,2052,2052,2052,2052,8,2112,2050,2,2,2050,8,2052,2052,2052,2052,2052,2052,2052,256,256,256,256],[256,256,256,256,2052,4,4,4,4,4,2052,8,64,2050,2,2,2050,8,2052,4,4,4,4,4,2052,256,256,256,256],[256,256,256,256,2052,4,3072,3072,3072,4,2052,8,2112,2,2050,2,2050,8,2052,4,3072,3072,3072,4,2052,256,256,256,256],[256,256,256,256,2052,4,3072,3072,3072,4,2052,8,2112,2,2,2050,2,8,2052,4,3072,3072,3072,4,2052,256,256,256,256],[256,256,256,256,2052,4,3072,3072,3072,4,2052,8,2112,2050,2050,2,2,8,2052,4,3072,3072,3072,4,2052,256,256,256,256],[256,256,256,256,2052,4,4,4,4,4,2052,8,64,2,2,2,2,8,2052,4,4,4,4,4,2052,256,256,256,256],[256,256,256,256,2052,2052,2052,2052,2052,2052,2052,8,2080,32,2080,32,2080,8,2052,2052,2052,2052,2052,2052,2052,256,256,256,256],[256,256,256,256,8,8,8,8,8,8,8,8,64,2050,2050,2,2,8,8,8,8,8,8,8,8,256,256,256,256],[256,256,256,256,2112,2112,2112,2112,64,64,2080,64,2112,2,2050,2,2,2112,64,64,2112,2112,2112,64,2112,256,256,256,256],[256,256,256,256,2050,2,2,2050,2050,2050,32,2050,2,2,2050,2,2050,2,2,2050,2,2050,2050,2,2050,256,256,256,256],[256,256,256,256,2050,2,2050,2,2050,2050,2080,2,2,2,2050,2,2050,2050,2050,2050,2050,2,2,2050,2050,256,256,256,256],[256,256,256,256,2050,2,2050,2050,2,2,32,2050,2050,2,2050,2,2050,2050,2,2,2,2050,2,2050,2,256,256,256,256],[256,256,256,256,2,2050,2050,2,2050,2,2080,2,2,2050,2050,2050,2,2050,2,2,2050,2050,2,2050,2,256,256,256,256],[256,256,256,256,8,8,8,8,8,8,8,8,2049,2,2050,2,2,2050,2,2050,2,2050,2,2050,2,256,256,256,256],[256,256,256,256,2052,2052,2052,2052,2052,2052,2052,8,64,2,2050,2,2,2050,2050,2,2050,2050,2050,2,2,256,256,256,256],[256,256,256,256,2052,4,4,4,4,4,2052,8,64,2050,2,2050,2050,2050,2050,2,2,2050,2050,2,2,256,256,256,256],[256,256,256,256,2052,4,3072,3072,3072,4,2052,8,64,2050,2050,2050,2,2,2050,2,2,2,2050,2050,2050,256,256,256,256],[256,256,256,256,2052,4,3072,3072,3072,4,2052,8,2112,2050,2,2,2,2050,2,2,2050,2050,2,2050,2,256,256,256,256],[256,256,256,256,2052,4,3072,3072,3072,4,2052,8,2112,2,2050,2050,2,2050,2,2,2050,2,2050,2,2,256,256,256,256],[256,256,256,256,2052,4,4,4,4,4,2052,8,2112,2050,2050,2050,2050,2,2050,2,2050,2050,2,2,2050,256,256,256,256],[256,256,256,256,2052,2052,2052,2052,2052,2052,2052,8,2112,2050,2,2050,2050,2,2,2050,2,2,2,2,2,256,256,256,256],[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256],[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256],[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256],[256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256]] diff --git a/tests/Output/samples/svg b/tests/Output/samples/svg index 54aceb9ec..10d895a93 100644 --- a/tests/Output/samples/svg +++ b/tests/Output/samples/svg @@ -1 +1 @@ -data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGNsYXNzPSJxci1zdmcgIiBzdHlsZT0id2lkdGg6IDEwMCU7IGhlaWdodDogYXV0bzsiIHZpZXdCb3g9IjAgMCAyOSAyOSI+DQo8ZGVmcz48c3R5bGU+cmVjdHtzaGFwZS1yZW5kZXJpbmc6Y3Jpc3BFZGdlc308L3N0eWxlPjwvZGVmcz4NCjxwYXRoIGNsYXNzPSJxci00ICIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0iI2ZmZiIgZmlsbC1vcGFjaXR5PSIxIiBkPSJNMTQgNCBoMiB2MSBoLTJaIE0xNCA1IGgyIHYxIGgtMlogTTEzIDYgaDEgdjEgaC0xWiBNMTUgNiBoMSB2MSBoLTFaIE0xMyA3IGgyIHYxIGgtMlogTTE2IDcgaDEgdjEgaC0xWiBNMTUgOCBoMiB2MSBoLTJaIE0xMyA5IGg0IHYxIGgtNFogTTE1IDExIGgyIHYxIGgtMlogTTEzIDEyIGgxIHYxIGgtMVogTTE1IDEyIGgyIHYxIGgtMlogTTUgMTMgaDIgdjEgaC0yWiBNMTIgMTMgaDIgdjEgaC0yWiBNMTUgMTMgaDEgdjEgaC0xWiBNMTcgMTMgaDIgdjEgaC0yWiBNMjAgMTMgaDEgdjEgaC0xWiBNMjMgMTMgaDEgdjEgaC0xWiBNNSAxNCBoMSB2MSBoLTFaIE03IDE0IGgxIHYxIGgtMVogTTExIDE0IGgzIHYxIGgtM1ogTTE1IDE0IGgxIHYxIGgtMVogTTIxIDE0IGgyIHYxIGgtMlogTTUgMTUgaDEgdjEgaC0xWiBNOCAxNSBoMiB2MSBoLTJaIE0xMyAxNSBoMSB2MSBoLTFaIE0xNSAxNSBoMSB2MSBoLTFaIE0xOCAxNSBoMyB2MSBoLTNaIE0yMiAxNSBoMSB2MSBoLTFaIE0yNCAxNSBoMSB2MSBoLTFaIE00IDE2IGgxIHYxIGgtMVogTTcgMTYgaDEgdjEgaC0xWiBNOSAxNiBoMSB2MSBoLTFaIE0xMSAxNiBoMiB2MSBoLTJaIE0xNiAxNiBoMSB2MSBoLTFaIE0xOCAxNiBoMiB2MSBoLTJaIE0yMiAxNiBoMSB2MSBoLTFaIE0yNCAxNiBoMSB2MSBoLTFaIE0xMyAxNyBoMSB2MSBoLTFaIE0xNSAxNyBoMiB2MSBoLTJaIE0xOCAxNyBoMSB2MSBoLTFaIE0yMCAxNyBoMSB2MSBoLTFaIE0yMiAxNyBoMSB2MSBoLTFaIE0yNCAxNyBoMSB2MSBoLTFaIE0xMyAxOCBoMSB2MSBoLTFaIE0xNSAxOCBoMiB2MSBoLTJaIE0xOSAxOCBoMSB2MSBoLTFaIE0yMyAxOCBoMiB2MSBoLTJaIE0xNCAxOSBoMSB2MSBoLTFaIE0xOSAxOSBoMiB2MSBoLTJaIE0yMyAxOSBoMiB2MSBoLTJaIE0xNiAyMCBoMiB2MSBoLTJaIE0xOSAyMCBoMyB2MSBoLTNaIE0xNCAyMSBoMyB2MSBoLTNaIE0xOCAyMSBoMiB2MSBoLTJaIE0yMiAyMSBoMSB2MSBoLTFaIE0yNCAyMSBoMSB2MSBoLTFaIE0xMyAyMiBoMSB2MSBoLTFaIE0xNiAyMiBoMSB2MSBoLTFaIE0xOCAyMiBoMiB2MSBoLTJaIE0yMSAyMiBoMSB2MSBoLTFaIE0yMyAyMiBoMiB2MSBoLTJaIE0xNyAyMyBoMSB2MSBoLTFaIE0xOSAyMyBoMSB2MSBoLTFaIE0yMiAyMyBoMiB2MSBoLTJaIE0xNCAyNCBoMSB2MSBoLTFaIE0xNyAyNCBoMiB2MSBoLTJaIE0yMCAyNCBoNSB2MSBoLTVaICIgLz48cGF0aCBjbGFzcz0icXItNiAiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGZpbGw9IiNmZmYiIGZpbGwtb3BhY2l0eT0iMSIgZD0iTTUgNSBoNSB2MSBoLTVaIE0xOSA1IGg1IHYxIGgtNVogTTUgNiBoMSB2MSBoLTFaIE05IDYgaDEgdjEgaC0xWiBNMTkgNiBoMSB2MSBoLTFaIE0yMyA2IGgxIHYxIGgtMVogTTUgNyBoMSB2MSBoLTFaIE05IDcgaDEgdjEgaC0xWiBNMTkgNyBoMSB2MSBoLTFaIE0yMyA3IGgxIHYxIGgtMVogTTUgOCBoMSB2MSBoLTFaIE05IDggaDEgdjEgaC0xWiBNMTkgOCBoMSB2MSBoLTFaIE0yMyA4IGgxIHYxIGgtMVogTTUgOSBoNSB2MSBoLTVaIE0xOSA5IGg1IHYxIGgtNVogTTUgMTkgaDUgdjEgaC01WiBNNSAyMCBoMSB2MSBoLTFaIE05IDIwIGgxIHYxIGgtMVogTTUgMjEgaDEgdjEgaC0xWiBNOSAyMSBoMSB2MSBoLTFaIE01IDIyIGgxIHYxIGgtMVogTTkgMjIgaDEgdjEgaC0xWiBNNSAyMyBoNSB2MSBoLTVaICIgLz48cGF0aCBjbGFzcz0icXItOCAiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGZpbGw9IiNmZmYiIGZpbGwtb3BhY2l0eT0iMSIgZD0iTTExIDQgaDEgdjEgaC0xWiBNMTcgNCBoMSB2MSBoLTFaIE0xMSA1IGgxIHYxIGgtMVogTTE3IDUgaDEgdjEgaC0xWiBNMTEgNiBoMSB2MSBoLTFaIE0xNyA2IGgxIHYxIGgtMVogTTExIDcgaDEgdjEgaC0xWiBNMTcgNyBoMSB2MSBoLTFaIE0xMSA4IGgxIHYxIGgtMVogTTE3IDggaDEgdjEgaC0xWiBNMTEgOSBoMSB2MSBoLTFaIE0xNyA5IGgxIHYxIGgtMVogTTExIDEwIGgxIHYxIGgtMVogTTE3IDEwIGgxIHYxIGgtMVogTTQgMTEgaDggdjEgaC04WiBNMTcgMTEgaDggdjEgaC04WiBNNCAxNyBoOCB2MSBoLThaIE0xMSAxOCBoMSB2MSBoLTFaIE0xMSAxOSBoMSB2MSBoLTFaIE0xMSAyMCBoMSB2MSBoLTFaIE0xMSAyMSBoMSB2MSBoLTFaIE0xMSAyMiBoMSB2MSBoLTFaIE0xMSAyMyBoMSB2MSBoLTFaIE0xMSAyNCBoMSB2MSBoLTFaICIgLz48cGF0aCBjbGFzcz0icXItMTIgIiBzdHJva2U9InRyYW5zcGFyZW50IiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9IjEiIGQ9Ik0xMyAxMCBoMSB2MSBoLTFaIE0xNSAxMCBoMSB2MSBoLTFaIE0xMCAxMyBoMSB2MSBoLTFaIE0xMCAxNSBoMSB2MSBoLTFaICIgLz48cGF0aCBjbGFzcz0icXItMTQgIiBzdHJva2U9InRyYW5zcGFyZW50IiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9IjEiIGQ9Ik0xMiA1IGgxIHYxIGgtMVogTTEyIDkgaDEgdjEgaC0xWiBNMTIgMTEgaDEgdjEgaC0xWiBNOCAxMiBoMiB2MSBoLTJaIE0xMSAxMiBoMSB2MSBoLTFaIE0xOCAxMiBoMiB2MSBoLTJaIE0yMyAxMiBoMSB2MSBoLTFaIE0xMiAxOCBoMSB2MSBoLTFaIE0xMiAxOSBoMSB2MSBoLTFaIE0xMiAyMCBoMSB2MSBoLTFaICIgLz48cGF0aCBjbGFzcz0icXItMTggIiBzdHJva2U9InRyYW5zcGFyZW50IiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9IjEiIGQ9Ik0wIDAgaDI5IHYxIGgtMjlaIE0wIDEgaDI5IHYxIGgtMjlaIE0wIDIgaDI5IHYxIGgtMjlaIE0wIDMgaDI5IHYxIGgtMjlaIE0wIDQgaDQgdjEgaC00WiBNMjUgNCBoNCB2MSBoLTRaIE0wIDUgaDQgdjEgaC00WiBNMjUgNSBoNCB2MSBoLTRaIE0wIDYgaDQgdjEgaC00WiBNMjUgNiBoNCB2MSBoLTRaIE0wIDcgaDQgdjEgaC00WiBNMjUgNyBoNCB2MSBoLTRaIE0wIDggaDQgdjEgaC00WiBNMjUgOCBoNCB2MSBoLTRaIE0wIDkgaDQgdjEgaC00WiBNMjUgOSBoNCB2MSBoLTRaIE0wIDEwIGg0IHYxIGgtNFogTTI1IDEwIGg0IHYxIGgtNFogTTAgMTEgaDQgdjEgaC00WiBNMjUgMTEgaDQgdjEgaC00WiBNMCAxMiBoNCB2MSBoLTRaIE0yNSAxMiBoNCB2MSBoLTRaIE0wIDEzIGg0IHYxIGgtNFogTTI1IDEzIGg0IHYxIGgtNFogTTAgMTQgaDQgdjEgaC00WiBNMjUgMTQgaDQgdjEgaC00WiBNMCAxNSBoNCB2MSBoLTRaIE0yNSAxNSBoNCB2MSBoLTRaIE0wIDE2IGg0IHYxIGgtNFogTTI1IDE2IGg0IHYxIGgtNFogTTAgMTcgaDQgdjEgaC00WiBNMjUgMTcgaDQgdjEgaC00WiBNMCAxOCBoNCB2MSBoLTRaIE0yNSAxOCBoNCB2MSBoLTRaIE0wIDE5IGg0IHYxIGgtNFogTTI1IDE5IGg0IHYxIGgtNFogTTAgMjAgaDQgdjEgaC00WiBNMjUgMjAgaDQgdjEgaC00WiBNMCAyMSBoNCB2MSBoLTRaIE0yNSAyMSBoNCB2MSBoLTRaIE0wIDIyIGg0IHYxIGgtNFogTTI1IDIyIGg0IHYxIGgtNFogTTAgMjMgaDQgdjEgaC00WiBNMjUgMjMgaDQgdjEgaC00WiBNMCAyNCBoNCB2MSBoLTRaIE0yNSAyNCBoNCB2MSBoLTRaIE0wIDI1IGgyOSB2MSBoLTI5WiBNMCAyNiBoMjkgdjEgaC0yOVogTTAgMjcgaDI5IHYxIGgtMjlaIE0wIDI4IGgyOSB2MSBoLTI5WiAiIC8+PHBhdGggY2xhc3M9InFyLTUxMiAiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGZpbGw9IiMwMDAiIGZpbGwtb3BhY2l0eT0iMSIgZD0iTTEyIDE3IGgxIHYxIGgtMVogIiAvPjxwYXRoIGNsYXNzPSJxci0xMDI0ICIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIxIiBkPSJNMTMgNCBoMSB2MSBoLTFaIE0xNiA0IGgxIHYxIGgtMVogTTEzIDUgaDEgdjEgaC0xWiBNMTYgNSBoMSB2MSBoLTFaIE0xNCA2IGgxIHYxIGgtMVogTTE2IDYgaDEgdjEgaC0xWiBNMTUgNyBoMSB2MSBoLTFaIE0xMyA4IGgyIHYxIGgtMlogTTEzIDExIGgyIHYxIGgtMlogTTE0IDEyIGgxIHYxIGgtMVogTTQgMTMgaDEgdjEgaC0xWiBNNyAxMyBoMyB2MSBoLTNaIE0xMSAxMyBoMSB2MSBoLTFaIE0xNCAxMyBoMSB2MSBoLTFaIE0xNiAxMyBoMSB2MSBoLTFaIE0xOSAxMyBoMSB2MSBoLTFaIE0yMSAxMyBoMiB2MSBoLTJaIE0yNCAxMyBoMSB2MSBoLTFaIE00IDE0IGgxIHYxIGgtMVogTTYgMTQgaDEgdjEgaC0xWiBNOCAxNCBoMiB2MSBoLTJaIE0xNCAxNCBoMSB2MSBoLTFaIE0xNiAxNCBoNSB2MSBoLTVaIE0yMyAxNCBoMiB2MSBoLTJaIE00IDE1IGgxIHYxIGgtMVogTTYgMTUgaDIgdjEgaC0yWiBNMTEgMTUgaDIgdjEgaC0yWiBNMTQgMTUgaDEgdjEgaC0xWiBNMTYgMTUgaDIgdjEgaC0yWiBNMjEgMTUgaDEgdjEgaC0xWiBNMjMgMTUgaDEgdjEgaC0xWiBNNSAxNiBoMiB2MSBoLTJaIE04IDE2IGgxIHYxIGgtMVogTTEzIDE2IGgzIHYxIGgtM1ogTTE3IDE2IGgxIHYxIGgtMVogTTIwIDE2IGgyIHYxIGgtMlogTTIzIDE2IGgxIHYxIGgtMVogTTE0IDE3IGgxIHYxIGgtMVogTTE3IDE3IGgxIHYxIGgtMVogTTE5IDE3IGgxIHYxIGgtMVogTTIxIDE3IGgxIHYxIGgtMVogTTIzIDE3IGgxIHYxIGgtMVogTTE0IDE4IGgxIHYxIGgtMVogTTE3IDE4IGgyIHYxIGgtMlogTTIwIDE4IGgzIHYxIGgtM1ogTTEzIDE5IGgxIHYxIGgtMVogTTE1IDE5IGg0IHYxIGgtNFogTTIxIDE5IGgyIHYxIGgtMlogTTEzIDIwIGgzIHYxIGgtM1ogTTE4IDIwIGgxIHYxIGgtMVogTTIyIDIwIGgzIHYxIGgtM1ogTTEzIDIxIGgxIHYxIGgtMVogTTE3IDIxIGgxIHYxIGgtMVogTTIwIDIxIGgyIHYxIGgtMlogTTIzIDIxIGgxIHYxIGgtMVogTTE0IDIyIGgyIHYxIGgtMlogTTE3IDIyIGgxIHYxIGgtMVogTTIwIDIyIGgxIHYxIGgtMVogTTIyIDIyIGgxIHYxIGgtMVogTTEzIDIzIGg0IHYxIGgtNFogTTE4IDIzIGgxIHYxIGgtMVogTTIwIDIzIGgyIHYxIGgtMlogTTI0IDIzIGgxIHYxIGgtMVogTTEzIDI0IGgxIHYxIGgtMVogTTE1IDI0IGgyIHYxIGgtMlogTTE5IDI0IGgxIHYxIGgtMVogIiAvPjxwYXRoIGNsYXNzPSJxci0xNTM2ICIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIxIiBkPSJNNCA0IGg3IHYxIGgtN1ogTTE4IDQgaDcgdjEgaC03WiBNNCA1IGgxIHYxIGgtMVogTTEwIDUgaDEgdjEgaC0xWiBNMTggNSBoMSB2MSBoLTFaIE0yNCA1IGgxIHYxIGgtMVogTTQgNiBoMSB2MSBoLTFaIE0xMCA2IGgxIHYxIGgtMVogTTE4IDYgaDEgdjEgaC0xWiBNMjQgNiBoMSB2MSBoLTFaIE00IDcgaDEgdjEgaC0xWiBNMTAgNyBoMSB2MSBoLTFaIE0xOCA3IGgxIHYxIGgtMVogTTI0IDcgaDEgdjEgaC0xWiBNNCA4IGgxIHYxIGgtMVogTTEwIDggaDEgdjEgaC0xWiBNMTggOCBoMSB2MSBoLTFaIE0yNCA4IGgxIHYxIGgtMVogTTQgOSBoMSB2MSBoLTFaIE0xMCA5IGgxIHYxIGgtMVogTTE4IDkgaDEgdjEgaC0xWiBNMjQgOSBoMSB2MSBoLTFaIE00IDEwIGg3IHYxIGgtN1ogTTE4IDEwIGg3IHYxIGgtN1ogTTQgMTggaDcgdjEgaC03WiBNNCAxOSBoMSB2MSBoLTFaIE0xMCAxOSBoMSB2MSBoLTFaIE00IDIwIGgxIHYxIGgtMVogTTEwIDIwIGgxIHYxIGgtMVogTTQgMjEgaDEgdjEgaC0xWiBNMTAgMjEgaDEgdjEgaC0xWiBNNCAyMiBoMSB2MSBoLTFaIE0xMCAyMiBoMSB2MSBoLTFaIE00IDIzIGgxIHYxIGgtMVogTTEwIDIzIGgxIHYxIGgtMVogTTQgMjQgaDcgdjEgaC03WiAiIC8+PHBhdGggY2xhc3M9InFyLTMwNzIgIiBzdHJva2U9InRyYW5zcGFyZW50IiBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9IjEiIGQ9Ik0xMiAxMCBoMSB2MSBoLTFaIE0xNCAxMCBoMSB2MSBoLTFaIE0xNiAxMCBoMSB2MSBoLTFaIE0xMCAxMiBoMSB2MSBoLTFaIE0xMCAxNCBoMSB2MSBoLTFaIE0xMCAxNiBoMSB2MSBoLTFaICIgLz48cGF0aCBjbGFzcz0icXItMzU4NCAiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGZpbGw9IiMwMDAiIGZpbGwtb3BhY2l0eT0iMSIgZD0iTTEyIDQgaDEgdjEgaC0xWiBNMTIgNiBoMSB2MSBoLTFaIE0xMiA3IGgxIHYxIGgtMVogTTEyIDggaDEgdjEgaC0xWiBNNCAxMiBoNCB2MSBoLTRaIE0xMiAxMiBoMSB2MSBoLTFaIE0xNyAxMiBoMSB2MSBoLTFaIE0yMCAxMiBoMyB2MSBoLTNaIE0yNCAxMiBoMSB2MSBoLTFaIE0xMiAyMSBoMSB2MSBoLTFaIE0xMiAyMiBoMSB2MSBoLTFaIE0xMiAyMyBoMSB2MSBoLTFaIE0xMiAyNCBoMSB2MSBoLTFaICIgLz48cGF0aCBjbGFzcz0icXItNTYzMiAiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGZpbGw9IiMwMDAiIGZpbGwtb3BhY2l0eT0iMSIgZD0iTTYgNiBoMyB2MSBoLTNaIE0yMCA2IGgzIHYxIGgtM1ogTTYgNyBoMyB2MSBoLTNaIE0yMCA3IGgzIHYxIGgtM1ogTTYgOCBoMyB2MSBoLTNaIE0yMCA4IGgzIHYxIGgtM1ogTTYgMjAgaDMgdjEgaC0zWiBNNiAyMSBoMyB2MSBoLTNaIE02IDIyIGgzIHYxIGgtM1ogIiAvPjwvc3ZnPg0K +data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGNsYXNzPSJxci1zdmcgIiBzdHlsZT0id2lkdGg6IDEwMCU7IGhlaWdodDogYXV0bzsiIHZpZXdCb3g9IjAgMCAyOSAyOSI+DQo8ZGVmcz48c3R5bGU+cmVjdHtzaGFwZS1yZW5kZXJpbmc6Y3Jpc3BFZGdlc308L3N0eWxlPjwvZGVmcz4NCjxwYXRoIGNsYXNzPSJxci0yICIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0iI2ZmZiIgZmlsbC1vcGFjaXR5PSIxIiBkPSJNMTQgNCBoMiB2MSBoLTJaIE0xNCA1IGgyIHYxIGgtMlogTTEzIDYgaDEgdjEgaC0xWiBNMTUgNiBoMSB2MSBoLTFaIE0xMyA3IGgyIHYxIGgtMlogTTE2IDcgaDEgdjEgaC0xWiBNMTUgOCBoMiB2MSBoLTJaIE0xMyA5IGg0IHYxIGgtNFogTTE1IDExIGgyIHYxIGgtMlogTTEzIDEyIGgxIHYxIGgtMVogTTE1IDEyIGgyIHYxIGgtMlogTTUgMTMgaDIgdjEgaC0yWiBNMTIgMTMgaDIgdjEgaC0yWiBNMTUgMTMgaDEgdjEgaC0xWiBNMTcgMTMgaDIgdjEgaC0yWiBNMjAgMTMgaDEgdjEgaC0xWiBNMjMgMTMgaDEgdjEgaC0xWiBNNSAxNCBoMSB2MSBoLTFaIE03IDE0IGgxIHYxIGgtMVogTTExIDE0IGgzIHYxIGgtM1ogTTE1IDE0IGgxIHYxIGgtMVogTTIxIDE0IGgyIHYxIGgtMlogTTUgMTUgaDEgdjEgaC0xWiBNOCAxNSBoMiB2MSBoLTJaIE0xMyAxNSBoMSB2MSBoLTFaIE0xNSAxNSBoMSB2MSBoLTFaIE0xOCAxNSBoMyB2MSBoLTNaIE0yMiAxNSBoMSB2MSBoLTFaIE0yNCAxNSBoMSB2MSBoLTFaIE00IDE2IGgxIHYxIGgtMVogTTcgMTYgaDEgdjEgaC0xWiBNOSAxNiBoMSB2MSBoLTFaIE0xMSAxNiBoMiB2MSBoLTJaIE0xNiAxNiBoMSB2MSBoLTFaIE0xOCAxNiBoMiB2MSBoLTJaIE0yMiAxNiBoMSB2MSBoLTFaIE0yNCAxNiBoMSB2MSBoLTFaIE0xMyAxNyBoMSB2MSBoLTFaIE0xNSAxNyBoMiB2MSBoLTJaIE0xOCAxNyBoMSB2MSBoLTFaIE0yMCAxNyBoMSB2MSBoLTFaIE0yMiAxNyBoMSB2MSBoLTFaIE0yNCAxNyBoMSB2MSBoLTFaIE0xMyAxOCBoMSB2MSBoLTFaIE0xNSAxOCBoMiB2MSBoLTJaIE0xOSAxOCBoMSB2MSBoLTFaIE0yMyAxOCBoMiB2MSBoLTJaIE0xNCAxOSBoMSB2MSBoLTFaIE0xOSAxOSBoMiB2MSBoLTJaIE0yMyAxOSBoMiB2MSBoLTJaIE0xNiAyMCBoMiB2MSBoLTJaIE0xOSAyMCBoMyB2MSBoLTNaIE0xNCAyMSBoMyB2MSBoLTNaIE0xOCAyMSBoMiB2MSBoLTJaIE0yMiAyMSBoMSB2MSBoLTFaIE0yNCAyMSBoMSB2MSBoLTFaIE0xMyAyMiBoMSB2MSBoLTFaIE0xNiAyMiBoMSB2MSBoLTFaIE0xOCAyMiBoMiB2MSBoLTJaIE0yMSAyMiBoMSB2MSBoLTFaIE0yMyAyMiBoMiB2MSBoLTJaIE0xNyAyMyBoMSB2MSBoLTFaIE0xOSAyMyBoMSB2MSBoLTFaIE0yMiAyMyBoMiB2MSBoLTJaIE0xNCAyNCBoMSB2MSBoLTFaIE0xNyAyNCBoMiB2MSBoLTJaIE0yMCAyNCBoNSB2MSBoLTVaICIgLz48cGF0aCBjbGFzcz0icXItNCAiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGZpbGw9IiNmZmYiIGZpbGwtb3BhY2l0eT0iMSIgZD0iTTUgNSBoNSB2MSBoLTVaIE0xOSA1IGg1IHYxIGgtNVogTTUgNiBoMSB2MSBoLTFaIE05IDYgaDEgdjEgaC0xWiBNMTkgNiBoMSB2MSBoLTFaIE0yMyA2IGgxIHYxIGgtMVogTTUgNyBoMSB2MSBoLTFaIE05IDcgaDEgdjEgaC0xWiBNMTkgNyBoMSB2MSBoLTFaIE0yMyA3IGgxIHYxIGgtMVogTTUgOCBoMSB2MSBoLTFaIE05IDggaDEgdjEgaC0xWiBNMTkgOCBoMSB2MSBoLTFaIE0yMyA4IGgxIHYxIGgtMVogTTUgOSBoNSB2MSBoLTVaIE0xOSA5IGg1IHYxIGgtNVogTTUgMTkgaDUgdjEgaC01WiBNNSAyMCBoMSB2MSBoLTFaIE05IDIwIGgxIHYxIGgtMVogTTUgMjEgaDEgdjEgaC0xWiBNOSAyMSBoMSB2MSBoLTFaIE01IDIyIGgxIHYxIGgtMVogTTkgMjIgaDEgdjEgaC0xWiBNNSAyMyBoNSB2MSBoLTVaICIgLz48cGF0aCBjbGFzcz0icXItOCAiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGZpbGw9IiNmZmYiIGZpbGwtb3BhY2l0eT0iMSIgZD0iTTExIDQgaDEgdjEgaC0xWiBNMTcgNCBoMSB2MSBoLTFaIE0xMSA1IGgxIHYxIGgtMVogTTE3IDUgaDEgdjEgaC0xWiBNMTEgNiBoMSB2MSBoLTFaIE0xNyA2IGgxIHYxIGgtMVogTTExIDcgaDEgdjEgaC0xWiBNMTcgNyBoMSB2MSBoLTFaIE0xMSA4IGgxIHYxIGgtMVogTTE3IDggaDEgdjEgaC0xWiBNMTEgOSBoMSB2MSBoLTFaIE0xNyA5IGgxIHYxIGgtMVogTTExIDEwIGgxIHYxIGgtMVogTTE3IDEwIGgxIHYxIGgtMVogTTQgMTEgaDggdjEgaC04WiBNMTcgMTEgaDggdjEgaC04WiBNNCAxNyBoOCB2MSBoLThaIE0xMSAxOCBoMSB2MSBoLTFaIE0xMSAxOSBoMSB2MSBoLTFaIE0xMSAyMCBoMSB2MSBoLTFaIE0xMSAyMSBoMSB2MSBoLTFaIE0xMSAyMiBoMSB2MSBoLTFaIE0xMSAyMyBoMSB2MSBoLTFaIE0xMSAyNCBoMSB2MSBoLTFaICIgLz48cGF0aCBjbGFzcz0icXItMzIgIiBzdHJva2U9InRyYW5zcGFyZW50IiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9IjEiIGQ9Ik0xMyAxMCBoMSB2MSBoLTFaIE0xNSAxMCBoMSB2MSBoLTFaIE0xMCAxMyBoMSB2MSBoLTFaIE0xMCAxNSBoMSB2MSBoLTFaICIgLz48cGF0aCBjbGFzcz0icXItNjQgIiBzdHJva2U9InRyYW5zcGFyZW50IiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9IjEiIGQ9Ik0xMiA1IGgxIHYxIGgtMVogTTEyIDkgaDEgdjEgaC0xWiBNMTIgMTEgaDEgdjEgaC0xWiBNOCAxMiBoMiB2MSBoLTJaIE0xMSAxMiBoMSB2MSBoLTFaIE0xOCAxMiBoMiB2MSBoLTJaIE0yMyAxMiBoMSB2MSBoLTFaIE0xMiAxOCBoMSB2MSBoLTFaIE0xMiAxOSBoMSB2MSBoLTFaIE0xMiAyMCBoMSB2MSBoLTFaICIgLz48cGF0aCBjbGFzcz0icXItMjU2ICIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0iI2ZmZiIgZmlsbC1vcGFjaXR5PSIxIiBkPSJNMCAwIGgyOSB2MSBoLTI5WiBNMCAxIGgyOSB2MSBoLTI5WiBNMCAyIGgyOSB2MSBoLTI5WiBNMCAzIGgyOSB2MSBoLTI5WiBNMCA0IGg0IHYxIGgtNFogTTI1IDQgaDQgdjEgaC00WiBNMCA1IGg0IHYxIGgtNFogTTI1IDUgaDQgdjEgaC00WiBNMCA2IGg0IHYxIGgtNFogTTI1IDYgaDQgdjEgaC00WiBNMCA3IGg0IHYxIGgtNFogTTI1IDcgaDQgdjEgaC00WiBNMCA4IGg0IHYxIGgtNFogTTI1IDggaDQgdjEgaC00WiBNMCA5IGg0IHYxIGgtNFogTTI1IDkgaDQgdjEgaC00WiBNMCAxMCBoNCB2MSBoLTRaIE0yNSAxMCBoNCB2MSBoLTRaIE0wIDExIGg0IHYxIGgtNFogTTI1IDExIGg0IHYxIGgtNFogTTAgMTIgaDQgdjEgaC00WiBNMjUgMTIgaDQgdjEgaC00WiBNMCAxMyBoNCB2MSBoLTRaIE0yNSAxMyBoNCB2MSBoLTRaIE0wIDE0IGg0IHYxIGgtNFogTTI1IDE0IGg0IHYxIGgtNFogTTAgMTUgaDQgdjEgaC00WiBNMjUgMTUgaDQgdjEgaC00WiBNMCAxNiBoNCB2MSBoLTRaIE0yNSAxNiBoNCB2MSBoLTRaIE0wIDE3IGg0IHYxIGgtNFogTTI1IDE3IGg0IHYxIGgtNFogTTAgMTggaDQgdjEgaC00WiBNMjUgMTggaDQgdjEgaC00WiBNMCAxOSBoNCB2MSBoLTRaIE0yNSAxOSBoNCB2MSBoLTRaIE0wIDIwIGg0IHYxIGgtNFogTTI1IDIwIGg0IHYxIGgtNFogTTAgMjEgaDQgdjEgaC00WiBNMjUgMjEgaDQgdjEgaC00WiBNMCAyMiBoNCB2MSBoLTRaIE0yNSAyMiBoNCB2MSBoLTRaIE0wIDIzIGg0IHYxIGgtNFogTTI1IDIzIGg0IHYxIGgtNFogTTAgMjQgaDQgdjEgaC00WiBNMjUgMjQgaDQgdjEgaC00WiBNMCAyNSBoMjkgdjEgaC0yOVogTTAgMjYgaDI5IHYxIGgtMjlaIE0wIDI3IGgyOSB2MSBoLTI5WiBNMCAyOCBoMjkgdjEgaC0yOVogIiAvPjxwYXRoIGNsYXNzPSJxci0yMDQ5ICIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIxIiBkPSJNMTIgMTcgaDEgdjEgaC0xWiAiIC8+PHBhdGggY2xhc3M9InFyLTIwNTAgIiBzdHJva2U9InRyYW5zcGFyZW50IiBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9IjEiIGQ9Ik0xMyA0IGgxIHYxIGgtMVogTTE2IDQgaDEgdjEgaC0xWiBNMTMgNSBoMSB2MSBoLTFaIE0xNiA1IGgxIHYxIGgtMVogTTE0IDYgaDEgdjEgaC0xWiBNMTYgNiBoMSB2MSBoLTFaIE0xNSA3IGgxIHYxIGgtMVogTTEzIDggaDIgdjEgaC0yWiBNMTMgMTEgaDIgdjEgaC0yWiBNMTQgMTIgaDEgdjEgaC0xWiBNNCAxMyBoMSB2MSBoLTFaIE03IDEzIGgzIHYxIGgtM1ogTTExIDEzIGgxIHYxIGgtMVogTTE0IDEzIGgxIHYxIGgtMVogTTE2IDEzIGgxIHYxIGgtMVogTTE5IDEzIGgxIHYxIGgtMVogTTIxIDEzIGgyIHYxIGgtMlogTTI0IDEzIGgxIHYxIGgtMVogTTQgMTQgaDEgdjEgaC0xWiBNNiAxNCBoMSB2MSBoLTFaIE04IDE0IGgyIHYxIGgtMlogTTE0IDE0IGgxIHYxIGgtMVogTTE2IDE0IGg1IHYxIGgtNVogTTIzIDE0IGgyIHYxIGgtMlogTTQgMTUgaDEgdjEgaC0xWiBNNiAxNSBoMiB2MSBoLTJaIE0xMSAxNSBoMiB2MSBoLTJaIE0xNCAxNSBoMSB2MSBoLTFaIE0xNiAxNSBoMiB2MSBoLTJaIE0yMSAxNSBoMSB2MSBoLTFaIE0yMyAxNSBoMSB2MSBoLTFaIE01IDE2IGgyIHYxIGgtMlogTTggMTYgaDEgdjEgaC0xWiBNMTMgMTYgaDMgdjEgaC0zWiBNMTcgMTYgaDEgdjEgaC0xWiBNMjAgMTYgaDIgdjEgaC0yWiBNMjMgMTYgaDEgdjEgaC0xWiBNMTQgMTcgaDEgdjEgaC0xWiBNMTcgMTcgaDEgdjEgaC0xWiBNMTkgMTcgaDEgdjEgaC0xWiBNMjEgMTcgaDEgdjEgaC0xWiBNMjMgMTcgaDEgdjEgaC0xWiBNMTQgMTggaDEgdjEgaC0xWiBNMTcgMTggaDIgdjEgaC0yWiBNMjAgMTggaDMgdjEgaC0zWiBNMTMgMTkgaDEgdjEgaC0xWiBNMTUgMTkgaDQgdjEgaC00WiBNMjEgMTkgaDIgdjEgaC0yWiBNMTMgMjAgaDMgdjEgaC0zWiBNMTggMjAgaDEgdjEgaC0xWiBNMjIgMjAgaDMgdjEgaC0zWiBNMTMgMjEgaDEgdjEgaC0xWiBNMTcgMjEgaDEgdjEgaC0xWiBNMjAgMjEgaDIgdjEgaC0yWiBNMjMgMjEgaDEgdjEgaC0xWiBNMTQgMjIgaDIgdjEgaC0yWiBNMTcgMjIgaDEgdjEgaC0xWiBNMjAgMjIgaDEgdjEgaC0xWiBNMjIgMjIgaDEgdjEgaC0xWiBNMTMgMjMgaDQgdjEgaC00WiBNMTggMjMgaDEgdjEgaC0xWiBNMjAgMjMgaDIgdjEgaC0yWiBNMjQgMjMgaDEgdjEgaC0xWiBNMTMgMjQgaDEgdjEgaC0xWiBNMTUgMjQgaDIgdjEgaC0yWiBNMTkgMjQgaDEgdjEgaC0xWiAiIC8+PHBhdGggY2xhc3M9InFyLTIwNTIgIiBzdHJva2U9InRyYW5zcGFyZW50IiBmaWxsPSIjMDAwIiBmaWxsLW9wYWNpdHk9IjEiIGQ9Ik00IDQgaDcgdjEgaC03WiBNMTggNCBoNyB2MSBoLTdaIE00IDUgaDEgdjEgaC0xWiBNMTAgNSBoMSB2MSBoLTFaIE0xOCA1IGgxIHYxIGgtMVogTTI0IDUgaDEgdjEgaC0xWiBNNCA2IGgxIHYxIGgtMVogTTEwIDYgaDEgdjEgaC0xWiBNMTggNiBoMSB2MSBoLTFaIE0yNCA2IGgxIHYxIGgtMVogTTQgNyBoMSB2MSBoLTFaIE0xMCA3IGgxIHYxIGgtMVogTTE4IDcgaDEgdjEgaC0xWiBNMjQgNyBoMSB2MSBoLTFaIE00IDggaDEgdjEgaC0xWiBNMTAgOCBoMSB2MSBoLTFaIE0xOCA4IGgxIHYxIGgtMVogTTI0IDggaDEgdjEgaC0xWiBNNCA5IGgxIHYxIGgtMVogTTEwIDkgaDEgdjEgaC0xWiBNMTggOSBoMSB2MSBoLTFaIE0yNCA5IGgxIHYxIGgtMVogTTQgMTAgaDcgdjEgaC03WiBNMTggMTAgaDcgdjEgaC03WiBNNCAxOCBoNyB2MSBoLTdaIE00IDE5IGgxIHYxIGgtMVogTTEwIDE5IGgxIHYxIGgtMVogTTQgMjAgaDEgdjEgaC0xWiBNMTAgMjAgaDEgdjEgaC0xWiBNNCAyMSBoMSB2MSBoLTFaIE0xMCAyMSBoMSB2MSBoLTFaIE00IDIyIGgxIHYxIGgtMVogTTEwIDIyIGgxIHYxIGgtMVogTTQgMjMgaDEgdjEgaC0xWiBNMTAgMjMgaDEgdjEgaC0xWiBNNCAyNCBoNyB2MSBoLTdaICIgLz48cGF0aCBjbGFzcz0icXItMjA4MCAiIHN0cm9rZT0idHJhbnNwYXJlbnQiIGZpbGw9IiMwMDAiIGZpbGwtb3BhY2l0eT0iMSIgZD0iTTEyIDEwIGgxIHYxIGgtMVogTTE0IDEwIGgxIHYxIGgtMVogTTE2IDEwIGgxIHYxIGgtMVogTTEwIDEyIGgxIHYxIGgtMVogTTEwIDE0IGgxIHYxIGgtMVogTTEwIDE2IGgxIHYxIGgtMVogIiAvPjxwYXRoIGNsYXNzPSJxci0yMTEyICIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIxIiBkPSJNMTIgNCBoMSB2MSBoLTFaIE0xMiA2IGgxIHYxIGgtMVogTTEyIDcgaDEgdjEgaC0xWiBNMTIgOCBoMSB2MSBoLTFaIE00IDEyIGg0IHYxIGgtNFogTTEyIDEyIGgxIHYxIGgtMVogTTE3IDEyIGgxIHYxIGgtMVogTTIwIDEyIGgzIHYxIGgtM1ogTTI0IDEyIGgxIHYxIGgtMVogTTEyIDIxIGgxIHYxIGgtMVogTTEyIDIyIGgxIHYxIGgtMVogTTEyIDIzIGgxIHYxIGgtMVogTTEyIDI0IGgxIHYxIGgtMVogIiAvPjxwYXRoIGNsYXNzPSJxci0zMDcyICIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIxIiBkPSJNNiA2IGgzIHYxIGgtM1ogTTIwIDYgaDMgdjEgaC0zWiBNNiA3IGgzIHYxIGgtM1ogTTIwIDcgaDMgdjEgaC0zWiBNNiA4IGgzIHYxIGgtM1ogTTIwIDggaDMgdjEgaC0zWiBNNiAyMCBoMyB2MSBoLTNaIE02IDIxIGgzIHYxIGgtM1ogTTYgMjIgaDMgdjEgaC0zWiAiIC8+PC9zdmc+DQo=