Skip to content

Instantly share code, notes, and snippets.

@mathmul
Last active December 2, 2021 10:36
Show Gist options
  • Save mathmul/5f668eae8700618458357714df1d5160 to your computer and use it in GitHub Desktop.
Save mathmul/5f668eae8700618458357714df1d5160 to your computer and use it in GitHub Desktop.
[PHP] Display text on a bus LED display
<?php
/**
* @author S3C_MM
* @license Free to use in anyway you wish.
* @phpversion 8.x
*
* NOTES:
* - For earlier PHP versions replace match expression in map_to_instructions function to switch statement.
* - If mbstring not compiled with PHP, replace mb_str_split with str_split
* - To read the output more easily zoom out or really squint. :)
* - I randomly chose the size of character to be 5×7 and you may change the code to fit your needs, but as
* it happens this was a good choice.
* [quote source="https://en.wikipedia.org/wiki/Dot-matrix_display"]
* A common size for a character is 5×7 pixels, either separated with blank lines with no dots (in most
* text-only displays), or with lines of blank pixels (making the real size 6×8). This is seen on most
* graphic calculators, such as Casio calculators or TI-82 and superior.
* [/quote]
*/
define('BREAK_LINE', PHP_EOL);
define('OUTPUT_CHARACTER', '#');
define('DARK_MODE', false);
$text = 'OK, what do we have here? Let\'s see...\n\nI get it!! This prints out: "monospaced uppercased characters" to a display with a fixed width.\n\nExit;';
/**
* Break text in array of lines, depending on the display width, respecting character size 5×7 and space size 1×7
*/
function generate_lines(string $text, int $displayWidth): array
{
$lettersPerRow = intval(($displayWidth + 1) / 6);
$wordsArr = explode(' ', $text);
$linesArr = [];
$currentLine = '';
$lineLength = 0;
foreach ($wordsArr as $word) {
$isCurrentLineStored = false;
if ($lineLength === 0) {
/* Break word if longer than line */
while (strlen($word) > $lettersPerRow) {
$linesArr[] = substr($word, 0, $lettersPerRow - 1) . '-';
$word = substr($word, $lettersPerRow - 1);
}
$currentLine = $word;
$lineLength = strlen($currentLine);
} elseif (strlen($word) > $lettersPerRow - $lineLength - 1) {
/* Add " wordPart-" to current line if room */
if ($lettersPerRow - $lineLength - 2 > 0) {
$currentLine .= ' ' . substr($word, 0, $lettersPerRow - $lineLength - 2) . '-';
$word = substr($word, $lettersPerRow - $lineLength - 2);
}
/* Store current line and reset it */
$linesArr[] = $currentLine;
$currentLine = '';
$lineLength = 0;
/* Break word if longer than line */
while (strlen($word) > $lettersPerRow) {
$linesArr[] = substr($word, 0, $lettersPerRow - 1) . '-';
$word = substr($word, $lettersPerRow - 1);
}
$currentLine = $word;
$lineLength = strlen($currentLine);
} else {
$currentLine .= ' ' . $word;
$lineLength = strlen($currentLine);
/* Store current line and reset it if no room for another */
if ($lineLength >= $lettersPerRow - 1) {
$linesArr[] = $currentLine;
$currentLine = '';
$lineLength = 0;
$isCurrentLineStored = true;
}
}
}
if (!$isCurrentLineStored)
$linesArr[] = $currentLine;
/* Fill line to fit width (needed for dark mode) */
foreach ($linesArr as $key => $line)
$linesArr[$key] = str_pad($line, $lettersPerRow);
return $linesArr;
}
/**
* Map characters to string[] array, where each element is a string of integers summing to 5 (character width). Integers
* are alternating instructions on how many space/OUTPUT_CHARACTER characters to print out consecutively, starting with
* OUTPUT_CHARACTER in dark mode, and space otherwise.
*/
function map_to_instructions(string $character): array
{
return match ($character) {
'A' => ['212', '11111', '0131', '0131', '05', '0131', '0131'],
'B' => ['041', '0131', '0131', '041', '0131', '0131', '041'],
'C' => ['131', '0131', '014', '014', '014', '0131', '131'],
'D' => ['041', '0131', '0131', '0131', '0131', '0131', '041'],
'E' => ['05', '014', '014', '032', '014', '014', '05'],
'F' => ['05', '014', '014', '032', '014', '014', '014'],
'G' => ['131', '0131', '014', '0122', '0131', '0131', '131'],
'H' => ['0131', '0131', '0131', '05', '0131', '0131', '0131'],
'I' => ['05', '212', '212', '212', '212', '212', '05'],
'J' => ['41', '41', '41', '41', '41', '0131', '131'],
'K' => ['0131', '01211', '01112', '023', '01112', '01211', '0131'],
'L' => ['014', '014', '014', '014', '014', '014', '05'],
'M' => ['0131', '0212', '011111', '0131', '0131', '0131', '0131'],
'N' => ['0131', '0131', '0221', '011111', '0122', '0131', '0131'],
'O' => ['131', '0131', '0131', '0131', '0131', '0131', '131'],
'P' => ['041', '0131', '0131', '041', '014', '014', '014'],
'Q' => ['131', '0131', '0131', '0131', '0131', '01211', '1211'],
'R' => ['041', '0131', '0131', '041', '01112', '01211', '0131'],
'S' => ['131', '0131', '014', '131', '41', '0131', '131'],
'T' => ['05', '212', '212', '212', '212', '212', '212'],
'U' => ['0131', '0131', '0131', '0131', '0131', '0131', '131'],
'V' => ['0131', '0131', '0131', '0131', '0131', '11111', '212'],
'W' => ['0131', '0131', '0131', '0131', '011111', '0212', '0131'],
'X' => ['0131', '0131', '11111', '212', '11111', '0131', '0131'],
'Y' => ['0131', '0131', '11111', '212', '212', '212', '212'],
'Z' => ['05', '41', '311', '212', '113', '014', '05'],
'-' => ['5', '5', '5', '05', '5', '5', '5'],
'.' => ['5', '5', '5', '5', '5', '122', '122'],
',' => ['5', '5', '5', '5', '122', '212', '113'],
'!' => ['122', '122', '122', '122', '122', '5', '122'],
'?' => ['131', '0221', '32', '221', '122', '5', '122'],
':' => ['5', '122', '122', '5', '122', '122', '5'],
';' => ['5', '122', '5', '5', '122', '212', '113'],
'\'' => ['122', '212', '113', '5', '5', '5', '5'],
'"' => ['11111', '11111', '11111', '5', '5', '5', '5'],
default => array_fill(0, 7, '5'),
};
}
/**
* Returns a single of line of an output character given string $instruction eg. '0122' => DARK_MODE ? ' ## ' : '# ##'.
*/
function generate_line(string $instruction): string
{
$isSpace = !DARK_MODE;
$output = '';
$instructions = mb_str_split($instruction);
$instructions = array_map('intval', $instructions);
foreach ($instructions as $count) {
$output .= str_repeat(
$isSpace ? ' ' : OUTPUT_CHARACTER,
$count
);
$isSpace = !$isSpace;
}
return $output;
}
/**
* Returns the final output from a single paragraph of text.
* @use map_to_instructions()
* @use generate_line
*/
function generate_display_text(string $text): string
{
$charactersArr = mb_str_split($text);
if (empty($charactersArr))
return '';
$charactersArr = array_map('strtoupper', $charactersArr);
$output = '';
$preparedArray = [];
foreach ($charactersArr as $character) {
$instructionsArr = map_to_instructions($character);
$preparedArray[] = array_map('generate_line', $instructionsArr);
}
for ($i = 0; $i < 7; ++$i) {
$rowArray = [];
foreach ($preparedArray as $hashArray)
$rowArray[] = $hashArray[$i];
$output .= implode(DARK_MODE ? OUTPUT_CHARACTER : ' ', $rowArray) . BREAK_LINE;
}
return $output;
}
/**
* Outputs the final string including new lines (\n)
*/
function display(string $text, int $displayWidth = 92): string
{
$charactersInLine = intval(($displayWidth + 1) / 6) * 6 - 1;
$emptyLine = str_repeat(DARK_MODE ? OUTPUT_CHARACTER : ' ', $charactersInLine);
$paragraphs = explode('\n', $text);
foreach ($paragraphs as $paragraph) {
echo $emptyLine . BREAK_LINE;
$lines = generate_lines($paragraph, $displayWidth);
foreach ($lines as $line) {
echo generate_display_text($line);
echo $emptyLine . BREAK_LINE;
}
}
}
display($text);
/*
### # # # # # # # ##### #### ### # # #####
# # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # #
# # ## # # ##### # # # # # # # # # ###
# # # # ## # # # # # ##### # # # # # # # # #
# # # # # ## ## # # # # # # # # # ## ## #
### # # # # # # # # # # #### ### # # #####
# # # # # ##### # # ##### #### ##### ### # ##### #####
# # # # # # # # # # # # # ## # # # #
# # # # # # # # # # # # # ## # # #
##### # # # # ### ##### ### #### ### ## # ### # #####
# # ##### # # # # # # # # # ## # # #
# # # # # # # # # # # # # # # #
# # # # # ##### # # ##### # # ##### ## ##### ##### #
## ### ### ##### #####
# # # # # # #
# # # # #
### ### ### ###
# # # #
# # # # # # ## ## ##
### ### ##### ##### ## ## ##
##### ### ##### ##### ##### ##### ## ## ##### # # ##### ###
# # # # # # # ## ## # # # # # #
# # # # # # ## ## # # # # #
# # ## ### # # # ## ## # ##### # ###
# # # # # # # ## ## # # # # #
# # # # # # # # # # # # #
##### ### ##### # ##### # ## ## # # # ##### ###
#### #### ##### # # ##### ### ### # # ##### # # # #
# # # # # # # # # # # # # # # ## # # ## ##
# # # # # ## # # # # # # # # ## # # # # #
#### #### # # # # # ### # # # # # # # #####
# # # # # ## # # # # # # # ## # #
# # # # # # # # # # # # # # ## # #
# # # ##### # # # ### ### ### # # #
### # # ### ### #### # ### ##### #### # # #### #### #####
# # # # # # # # # # # # # # # # # # # # # # # #
# # ## # # # # # # # # # # # # # # # # # # #
# # # # # # # ### #### # # # ### # # # # #### #### ### #####
# # # ## # # # # ##### # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # #
### # # ### ### # # # ### ##### #### ### # # #####
#### ### # ### ##### #### ### # # # #### # ### #####
# # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # #
#### # # # ### ### # # # ##### # # #### # # # # #####
# # # ##### # # # # # # # ##### # # ##### # #
# # # # # # # # # # # # # # # # # # # # # # # #
# # ### # # ### ##### #### ### # # # # # # # # ### #
##### #### ### # # ##### ### # #### ##### ### ####
# # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # #
### #### ### # # # # # # # # ### #### #####
# # # # # # # ##### # # # # #
# # # # # # # # # # # # # # # #
##### # # ### # ### # # #### ##### ### #
# # # # # # ##### ##### # # # ##### ##### # #
# # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # #
# # # # # # # # ##### # # ### # # #####
# ##### # # # # # # # # ##### # # # #
# # # # ## ## # # # # # # # # # #
##### # # # # # ##### # # # # # # ##### # #
##### #### # # ##### #### ##### # #
# # # # # # # # # # #
# # # # # # # # # # #
### # # # # # # # # #####
# # # # # # # # # # # #
# # # ## ## # # # # # # ##
##### #### # # ##### #### # # # ##
##### # # ##### #####
# # # # # ##
# # # # #
### # # #
# # # # # ##
# # # # # #
##### # # ##### # #
*/
define('OUTPUT_CHARACTER', 'X');
define('DARK_MODE', true);
display($text);
/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X XX XXX XXXXXXXXXXXXX XXX X XXX XXX XXX XXXXXXX XXX XXXXXXXX XXX X XXXXXX
XXX X XX XXXXXXXXXXXXXX XXX X XXX XX X XXXX XXXXXXXXX XXX X XXX XXXXXXX XXX X XXXXXXXXXX
XXX X X XXXXXXXXXXXXXXX XXX X XXX X XXX XXX XXXXXXXXX XXX X XXX XXXXXXX XXX X XXXXXXXXXX
XXX X XXXXXXXXXXXXXXXX XXX X X XXX XXX XXXXXXXXX XXX X XXX XXXXXXX XXX X XXXXXXXX
XXX X X XXXX XXXXXXXXX X X X XXX X XXX XXXXXXXXX XXX X XXX XXXXXXX X X X XXXXXXXXXX
XXX X XX XXXX XXXXXXXXX X X XXX X XXX XXX XXXXXXXXX XXX X XXX XXXXXXX X X XXXXXXXXXX
X XX XXX XX XXXXXXXXXX XXX X XXX X XXX XXX XXXXXXXXX XXX XXXXXXXX XXX X XXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXX XXX XXX XXX X XXXXXXX XXX X X XX XX XXXXXXXX XXXXX X XXXXXX
XXX XX X XX XXX X XXXXXXXXXXX XXX X XXXXX XXX X XXXXX XX XXXXXXX XXXXX XXXXXXX XXXXXXXX
XXX X XXX X XXX X XXXXXXXXXXX XXX X XXXXX XXX X XXXXXXXX XXXXXXX XXXXX XXXXXXX XXXXXXXX
X XXX X XXX X XXXXXXXXX X XXX XX XXXXX XXXXXXXX XXXXX XXXXX XXX
XXX X X XXX X XXXXXXXXXXX XXX X XXXXX X XXX XXXXXX XXXXXXXXX XXXXX XXXXXXX XXXXXXXX
XXX X XXX XX X XX XXXXXXXXXXX XXX X XXXXX XX XX XXXXXXXXXXXXXXXXX XXXXX XXXXXXX XXXXXXXX
XXX X XXX XXX XXX XXXXXXX XXX X X XXX X XX XXXXXXXXX X XXX XXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X XXXX XXXXXXXXX XX X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XX XXX XXX XXXXXXX XXX X XXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X XXXX XXXXXXXXXXX XXXXX XXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXX XXXXXXXXX XX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXX XXXXXXXXXXX X XXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX XXX XXXXXXX XXX X XXXXX XXXXXX XXXX XXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXX XXXXXXXXX XX X XX XXXX XXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXX XX X XXXXXXX X XX XXXX XXXXXXXXX X XXX X XX X
XX XXXXXXXXX XXX X XXXXXXX XXXXXXXXXXX XXXXX XXXX XXXX XXXXXXXXXXX XXX XXX XXX XXX XXX
XX XXXXXXXXX XXXXX XXXXXXX XXXXXXXXXXX XXXXX XXXX XXXX XXXXXXXXXXX XXX XXX XXX XXX XXXX
XX XXXXXXXXX XX X XXXXX XXXXXXXXXXX XXXXX XXXX XXXX XXXXXXXXXXX XXX XXX XXXX X
XX XXXXXXXXX XXX X XXXXXXX XXXXXXXXXXX XXXXX XXXX XXXX XXXXXXXXXXX XXX XXX XXX XXXXXXX
XX XXXXXXXXX XXX X XXXXXXX XXXXXXXXXXX XXXXX XXXXXXXXXXXXXXXXXXXXXXX XXX XXX XXX XXX XXX
XXXXXXXX XX XXX XXXXXXXXX XXX XXXX XXXX XXXXXXXXXXX XXX XXX X XX X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XX XX X XXX X XX XXXXXXXXX XX XXX X XXXXXXXXXXXXXX X XX XXX XXXXXX
XXX X XXX XXX XXX XXX XXX XXX XXX XXXXXXX XXX X XXX XXX XXXX XXXXXXXXXX X XX X XXXXXX
XXX X XXX XXX XXX XX XXX XXX XXXXXXXXXXX XXX X XXX XXX XXXX XXXXXXXXXX X XX X X XXXXXX
XX XXXX XXX X X XXX XXXX XXXXXXXX XXX X XXX XXX XXXXXXXXXXXXXXXXXXXXX XXX X
XXXXX X XXXXX XXX XX XXX XXXXXXX XXXXXXX XXX X XXX XXX XXXX XXXXXXXXXXXXXXX XXX XXXXXX
XXXXX XX XXXX XXX XXX XXX XXX XXX XXXXXXX XXX X XXX XXX XXXX XXXXXXXXXXXXXXX XXX XXXXXX
XXXXX XXX X X XXX XXX XXXX XXXXXXXXX XXX XXXX XXXXXXXXXXXXXXXXXXXXX XXX XXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X XX XXX XX XXX XX XXXX XXXX XX X XXXXXXXX XXX X XX XX XXXXXX
XXX X XXX X XXX X XXX X XXX XX X XX XXX X XXXXX XXX XXXXXXX XXX X XXX X XXX X XXXXXXXXXX
XXX X XX X XXX X XXXXX XXX X XXX X XXXXX XXXXX XXX XXXXXXX XXX X XXX X XXX X XXXXXXXXXX
XXX X X X X XXX XX XX XX XXX X XXXXX XXX XXX XXXXXXX XXX X XX XX XXX
XXX X XX X XXX XXXXX X XXXXX X XXXXX XXXXX XXX XXXXXXX XXX X XXXXX XXXXX XXXXXXXXXX
XXX X XXX X XXX X XXX X XXXXX XXX X XXX X XXXXX XXX XXXXXXX XXX X XXXXX XXXXX XXXXXXXXXX
X XX XXX XX XXX XX XXXXX XXX XX XX X XXXXXXXXX XX XXXXX XXXXX XXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXX XXXX XXXX XX X XXXXXXXXX XX XXX XXX XXX XXXX XXXX XX XXXXXX
XXX X XXX XX X XX XXX X XXXXX XXX XXXXXXX XXX X XXX XX X XX XXX XX X XX XXX XXX XXXXXXXX
XXX X XXXXX XXX X XXXXX XXXXX XXX XXXXXXX XXXXX XXX X XXX X XXX X XXX X XXXXXXX XXXXXXXX
XX XXXXX XXX XX XX XXX XXX XXXXXXX XXXXX X XXX X XX XXX X XXXXXXX XXX
X XXX XXXXX XXXXX X XXXXX XXX XXXXXXX XXXXX XXX X X X XXX X XXXXXXX XXXXXXXX
XX XX XXX X XXX X XXX X XXXXX XXX XXXXXXX XXX X XXX X XXX X XX XX XXX X XXX XXX XXXXXXXX
XXX XX XX XXX XX XX X XXXXXXXXX XX XXX X XXX X XXX X XXX XX XXXX XXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X XXX XXX X XXXXXXXX XX XXXXXXXXXX XXXXXXXXX XX XX XX XXXXXXX
XXXXX XXX X XXX XX X XXXXXXXXXX XXX XXX XXXXXXXX X XXXXXXXX XXX XXX XXX XXX X XXX XXXXXX
XXXXX XXX X XXXXXX X XXXXXXXXXX XXX XXX XXXXXXX XXX XXXXXXX XXX XXX XXX XXXXX XXX XXXXXX
XXX XXX XXXXXXXXXXXXXXXX XXX XXX XXXXXXX XXX XXXXXXX XXX XXX XXXX XX XX
XXXXX X XXXXXXX XXXXXXXXXXXXXXX XXX XXX XXXXXXX XXXXXXX XXX XXX XXXXXXX X XXXXXXXXXX
XXXXX XX XX XXX XXXXXXXXXXXXXXX XXX XXX XXXXXXX XXX XXXXXXX XXX XXX XXX XXX X XXXXXXXXXX
X XXX XX XXXXXXXXXXXXXXXX XXXX XXXXXXXX XXX XXXXXXX XX XX XX XXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXX XXX XXX XXXXXXX XXX X X X XXX XXXXXXXXX XXXXXXXXX X X XXX XXXXXX
XXXXXX X XX XXX XXXXXXX XXX XXX XXXXX XXX XXX XXXXXXXX X XXXXXXXX XXXXXXX XXX XXX XXXXXX
XXXXX XXX XX X XXXXXXXX XXX XXX XXXXX XXX XXX XXXXXXX XXX XXXXXXX XXXXXXX XXXX X XXXXXXX
XXXXX XXX XXX XXXXXXXXX XXX XXX XXXXX XXX XXXXXXX XXX XXXXXXX XXXXX XXXXX XXX
XXXXX XXX XXXXXXXXX X X XXX XXXXX XXX XXX XXXXXXX XXXXXXX XXXXXXX XXXX X XXXXXXX
XXXXX XXX XXX XXXXXXXXX X XXX XXXXX XXX XXX XXXXXXX XXX XXXXXXX XXXXXXX XXX XXX XXXXXX
X XXX XXX XXXXXXXXX XXX X XXX XXX XXX XXXXXXX XXX XXXXXXX XXXXX X XXX XXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X XXXXXXXX XXX X X XX X XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXX XXX XXXXXXX XXX XXX XXX XXX XXX XXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXX XXX XXXXXXX XXX XXX XXX XXX XXX XXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXX XXX XXXXXXX XXX XXX XXX XXX XXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXX XXX XXXXXXX X X XXX XXX XXX XXX XXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXX XXX XXXXXXX X XXX XXX XXX XXX XXX XXX XX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X XXXXXXXX XXX X X XXXX XXX XXX XX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X XXX X X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXX XXX XXX XXXXX XXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX X XXXX XXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXX XXXXX XXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX X XXXX XXXXX XXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXX XXX XXX XXXXX XXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X XXX X XXX XXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment