Magento2 Less Compiler Problem
• Magento2
Preface
Actually, Magento2 is not to blame here. This issue is combination of PHP7 + less compiler + preg_match + JIT compiler + long base64 encoded strings. But read on, if you are interested.
The issue
This one caused a lot of headache today. Suddenly my locally installed Magento2 Shop had no styles anymore. Well not exactly suddenly, I were trying to port my dev environment to new docker containers and used php:7.0.14-apache
as a base image. Diving into this problem was really weird because css files were not correctly built. The less compiler ran into a compilation error. Even using bin/magento setup:static-content:deploy
did not help. I got an error like this and couldn’t really figure out what was wrong here.
Compilation from source:
frontend/theme/folder/de_DE/css/styles-m.less
in _theme.less on line 129, column 1
127 | url("http://php.net/images/logo.php") format("svg");
128 | }
129 | @font-face {
I tracked this issue down to less statements which where using base64 encoded images like this:
.test {
background-image: url("data:image/png;base64,iVBB44EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAEGABQZZvNBNcEa4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAQAAORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N0FGOTc0Rjg3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N0FGOTc0Rjk3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3QUY5NzRGNjczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3QUY5NzRGNzczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PrKqgLMAAAIASURBVHja7JnLSsNAFIabNl5aQbG6Ebpy4calO5euBJ9AH0DUlbhwIZjWKoIrL2vfwZ0gCK5dCb6AuhXUei9qjf/ACQwhaabpJJOROfDRSXM7/8ycMyeJ5bpuTmfL5zQ3XsAm+ARuxmE+bnhOW9wUYjv6Nen4Jij6BegWDNa/iwEjwAgwAtpbD0U+TwGMgCmwDu7anN8XcH4YA8KpqIM0ygT8CBxzCJYD9vWCb0G/SuBdJI3aMfNvndpv4BpcgkdycAUMgYU211gT6IjERoBNu5Zv3xOYB2e0PQhuQDlkBGQsmlIXsmFwCiZp+wUc65aF8hTInp2kUk9ImkKefXAZhE2ZV/pNbArZkjukRGn1AXyBe1CJEcRLYELkhnYCo1ohAV5wBwnYj7jGrEoBBYF0aIlMD1UCGly7HHLMb1ZrIRbEt9QuUjxoVcxdcL077ZtOWgg44NpzOi1kLXpTcE7bo2AxDQFxgtjl0mCLUiarga64DHIUURI7Avepqyin2Wq7B1a7LKdF/JG2ErMLjYEZsAXG03wi60TAc8j/RcGFp6G6mMuamRdbRoAR4BPQ1MjvZpCAXU1EMB+3g9JonJIiythXnx1dY8BJ2vkkBTj8MOsmIDXnkxBQTdN52QKqojV8FgUocV6WgJoq52UIqNFDjJa1kHLnu12JTTUqw/4EGABQZZvNBNcEaQAAAABJRU5E4EGABQZZvNBNcEaQAArkJggB44EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAEGABQZZvNBNcEa4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAQAAORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N0FGOTc0Rjg3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N0FGOTc0Rjk3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3QUY5NzRGNjczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3QUY5NzRGNzczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PrKqgLMAAAIASURBVHja7JnLSsNAFIabNl5aQbG6Ebpy4calO5euBJ9AH0DUlbhwIZjWKoIrL2vfwZ0gCK5dCb6AuhXUei9qjf/ACQwhaabpJJOROfDRSXM7/8ycMyeJ5bpuTmfL5zQ3XsAm+ARuxmE+bnhOW9wUYjv6Nen4Jij6BegWDNa/iwEjwAgwAtpbD0U+TwGMgCmwDu7anN8XcH4YA8KpqIM0ygT8CBxzCJYD9vWCb0G/SuBdJI3aMfNvndpv4BpcgkdycAUMgYU211gT6IjERoBNu5Zv3xOYB2e0PQ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TUqw/4EGABQZZvNBNcEaQAAAABJRU5E4EGABQZZvNBNcEaQAArkJgg44EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAEGABQZZvNBNcEa4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAQAAORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N0FGOTc0Rjg3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N0FGOTc0Rjk3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3QUY5NzRGNjczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3QUY5NzRGNzczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PrKqgLMAAAIASURBVHja7JnLSsNAFIabNl5aQbG6Ebpy4calO5euBJ9AH0DUlbhwIZjWKoIrL2vfwZ0gCK5dCb6AuhXUei9qjf/ACQwhaabpJJOROfDRSXM7/8ycMyeJ5bpuTmfL5zQ3XsAm+ARuxmE+bnhOW9wUYjv6Nen4Jij6BegWDNa/iwEjwAgwAtpbD0U+TwGMgCmwDu7anN8XcH4YA8KpqIM0ygT8CBxzCJYD9vWCb0G/SuBdJI3aMfNvndpv4BpcgkdycAUMgYU211gT6IjERoBNu5Zv3xOYB2e0PQhuQDlkBGQsmlIXsmFwCiZp+wUc65aF8hTInp2kUk9ImkKefXAZhE2ZV/pNbArZkjukRGn1AXyBe1CJEcRLYELkhnYCo1ohAV5wBwnYj7jGrEoBBYF0aIlMD1UCGly7HHLMb1ZrIRbEt9QuUjxoVcxdcL077ZtOWgg44NpzOi1kLXpTcE7bo2AxDQFxgtjl0mCLUiarga64DHIUURI7Avepqyin2Wq7B1a7LKdF/JG2ErMLjYEZsAXG03wi60TAc8j/RcGFp6G6mMuamRdbRoAR4BPQ1MjvZpCAXU1EMB+3g9JonJIiythXnx1dY8BJ2vkkBTj8MOsmIDXnkxBQTdN52QKqojV8FgUocV6WgJoq52UIqNFDjJa1kHLnu12JTTUqw/4EGABQZZvNBNcEaQAAAABJRU5E4EGABQZZvNBNcEaQAArkJggg==");
}
Removing them, made the error go away.
Tracking the issue down
It turns out that I was running into an issue with oyejorge/less.php
. A similar issue has been reported here. The PHP-based less compiler uses preg_match
for parsing. It turns out that PHP7 is using a newly introduced JIT compiler for regular expressions. A similar issue has been reported here.
This is a really, really bad edge case where several conditions need to be met:
- PHP7
- PCRE JIT Support enabled
- Magento2 with server side less compilation
- very long base64-encoded images in less file
It seems, we did not stumble upon this earlier, because we were using ppa:ondrej/php
as a package source for PHP7 where JIT Support seems to be disabled. I compared my config with one of my colleagues like this:
root@c481853da64a:/var/www/html# php -i | grep pcr -B 5
pcre
--
PCRE (Perl Compatible Regular Expressions) Support => enabled
PCRE Library Version => 8.38 2015-11-23
PCRE JIT Support => enabled
Directive => Local Value => Master Value
pcre.backtrack_limit => 1000000 => 1000000
pcre.jit => 1 => 1
pcre.recursion_limit => 100000 => 100000
It turned out, that in his configuration PCRE JIT Support => disabled
was set.
Reproducing the issue
I used following script inside root directory of Magento2 to check for the error:
As you can see, with enabled JIT Support, the less parser runs into an exception:
root@c481853da64a:/var/www/html# php proof.php
php proof.php
Fatal error: Uncaught Less_Exception_Parser: in anonymous-file-0.less in /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php:2616
Stack trace:
#0 /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php(803): Less_Parser->Error(NULL)
#1 /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php(1107): Less_Parser->expectChar(')')
#2 /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php(720): Less_Parser->parseEntitiesUrl()
#3 /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php(1565): Less_Parser->MatchFuncs(Array)
#4 /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php(720): Less_Parser->parseEntity()
#5 /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php(2388): Less_Parser->MatchFuncs(Array)
#6 /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php(2185): Less_Parser->parseExpression()
#7 /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php(720): Less_Parser->parseValue()
#8 /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php(1887): Less_Parser->MatchFuncs(Array)
#9 /va in /var/www/html/vendor/oyejorge/less.php/lib/Less/Parser.php on line 2616
Again, when JIT Support is disabled, everything works as expected. What a nightmare.
root@c481853da64a:/var/www/html# php -d pcre.jit=Off proof.php
php -d pcre.jit=Off proof.php
.test {
background-image: url("data:image/png;base64,iVBB44EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAEGABQZZvNBNcEa4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAQAAORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N0FGOTc0Rjg3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N0FGOTc0Rjk3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3QUY5NzRGNjczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3QUY5NzRGNzczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PrKqgLMAAAIASURBVHja7JnLSsNAFIabNl5aQbG6Ebpy4calO5euBJ9AH0DUlbhwIZjWKoIrL2vfwZ0gCK5dCb6AuhXUei9qjf/ACQwhaabpJJOROfDRSXM7/8ycMyeJ5bpuTmfL5zQ3XsAm+ARuxmE+bnhOW9wUYjv6Nen4Jij6BegWDNa/iwEjwAgwAtpbD0U+TwGMgCmwDu7anN8XcH4YA8KpqIM0ygT8CBxzCJYD9vWCb0G/SuBdJI3aMfNvndpv4BpcgkdycAUMgYU211gT6IjERoBNu5Zv3xOYB2e0PQhuQDlkBGQsmlIXsmFwCiZp+wUc65aF8hTInp2kUk9ImkKefXAZhE2ZV/pNbArZkjukRGn1AXyBe1CJEcRLYELkhnYCo1ohAV5wBwnYj7jGrEoBBYF0aIlMD1UCGly7HHLMb1ZrIRbEt9QuUjxoVcxdcL077ZtOWgg44NpzOi1kLXpTcE7bo2AxDQFxgtjl0mCLUiarga64DHIUURI7Avepqyin2Wq7B1a7LKdF/JG2ErMLjYEZsAXG03wi60TAc8j/RcGFp6G6mMuamRdbRoAR4BPQ1MjvZpCAXU1EMB+3g9JonJIiythXnx1dY8BJ2vkkBTj8MOsmIDXnkxBQTdN52QKqojV8FgUocV6WgJoq52UIqNFDjJa1kHLnu12JTTUqw/4EGABQZZvNBNcEaQAAAABJRU5E4EGABQZZvNBNcEaQAArkJggB44EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAEGABQZZvNBNcEa4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAQAAORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N0FGOTc0Rjg3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N0FGOTc0Rjk3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3QUY5NzRGNjczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3QUY5NzRGNzczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PrKqgLMAAAIASURBVHja7JnLSsNAFIabNl5aQbG6Ebpy4calO5euBJ9AH0DUlbhwIZjWKoIrL2vfwZ0gCK5dCb6AuhXUei9qjf/ACQwhaabpJJOROfDRSXM7/8ycMyeJ5bpuTmfL5zQ3XsAm+ARuxmE+bnhOW9wUYjv6Nen4Jij6BegWDNa/iwEjwAgwAtpbD0U+TwGMgCmwDu7anN8XcH4YA8KpqIM0ygT8CBxzCJYD9vWCb0G/SuBdJI3aMfNvndpv4BpcgkdycAUMgYU211gT6IjERoBNu5Zv3xOYB2e0PQ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TUqw/4EGABQZZvNBNcEaQAAAABJRU5E4EGABQZZvNBNcEaQAArkJgg44EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAEGABQZZvNBNcEa4EGABQZZvNBNcEaQAA4EGABQZZvNBNcEaQAAQAAORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N0FGOTc0Rjg3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N0FGOTc0Rjk3MzY5MTFFNkI2MEI5RDlDMjg0NEYxRTkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3QUY5NzRGNjczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3QUY5NzRGNzczNjkxMUU2QjYwQjlEOUMyODQ0RjFFOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PrKqgLMAAAIASURBVHja7JnLSsNAFIabNl5aQbG6Ebpy4calO5euBJ9AH0DUlbhwIZjWKoIrL2vfwZ0gCK5dCb6AuhXUei9qjf/ACQwhaabpJJOROfDRSXM7/8ycMyeJ5bpuTmfL5zQ3XsAm+ARuxmE+bnhOW9wUYjv6Nen4Jij6BegWDNa/iwEjwAgwAtpbD0U+TwGMgCmwDu7anN8XcH4YA8KpqIM0ygT8CBxzCJYD9vWCb0G/SuBdJI3aMfNvndpv4BpcgkdycAUMgYU211gT6IjERoBNu5Zv3xOYB2e0PQhuQDlkBGQsmlIXsmFwCiZp+wUc65aF8hTInp2kUk9ImkKefXAZhE2ZV/pNbArZkjukRGn1AXyBe1CJEcRLYELkhnYCo1ohAV5wBwnYj7jGrEoBBYF0aIlMD1UCGly7HHLMb1ZrIRbEt9QuUjxoVcxdcL077ZtOWgg44NpzOi1kLXpTcE7bo2AxDQFxgtjl0mCLUiarga64DHIUURI7Avepqyin2Wq7B1a7LKdF/JG2ErMLjYEZsAXG03wi60TAc8j/RcGFp6G6mMuamRdbRoAR4BPQ1MjvZpCAXU1EMB+3g9JonJIiythXnx1dY8BJ2vkkBTj8MOsmIDXnkxBQTdN52QKqojV8FgUocV6WgJoq52UIqNFDjJa1kHLnu12JTTUqw/4EGABQZZvNBNcEaQAAAABJRU5E4EGABQZZvNBNcEaQAArkJggg==");
}