256 colors in virtual terminal escape sequence

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: 256 colors in virtual terminal escape sequence

#16 Post by penpen » 23 Apr 2023 05:54

The color map (at least on my pc) is piecewise linear.

1) Indices 0x00 - 0x0F contain the most non-linear part:

Code: Select all

(  0,   0,   0),
(128,   0,   0),
(  0, 128,   0),
(128, 128,   0),
(  0,   0, 128),
(128,   0, 128),
(  0, 128, 128),

(192, 192, 192),
(128, 128, 128),

(255,   0,   0),
(  0, 255,   0),
(255, 255,   0),
(  0,   0, 255),
(255,   0, 255),
(  0, 255, 255),
(255, 255, 255)
(2) Indices 0x10 - 0xE7 contains an rgb cube of size 6x6x6 (most linear part):

Code: Select all

(  0,   0,   0), (  0,   0,  95), (  0,   0, 135), (  0,   0, 175), (  0,   0, 215), (  0,   0, 255),
(  0,  95,   0), (  0,  95,  95), (  0,  95, 135), (  0,  95, 175), (  0,  95, 215), (  0,  95, 255),
(  0, 135,   0), (  0, 135,  95), (  0, 135, 135), (  0, 135, 175), (  0, 135, 215), (  0, 135, 255),
(  0, 175,   0), (  0, 175,  95), (  0, 175, 135), (  0, 175, 175), (  0, 175, 215), (  0, 175, 255),
(  0, 215,   0), (  0, 215,  95), (  0, 215, 135), (  0, 215, 175), (  0, 215, 215), (  0, 215, 255),
(  0, 255,   0), (  0, 255,  95), (  0, 255, 135), (  0, 255, 175), (  0, 255, 215), (  0, 255, 255),

( 95,   0,   0), ( 95,   0,  95), ( 95,   0, 135), ( 95,   0, 175), ( 95,   0, 215), ( 95,   0, 255),
( 95,  95,   0), ( 95,  95,  95), ( 95,  95, 135), ( 95,  95, 175), ( 95,  95, 215), ( 95,  95, 255),
( 95, 135,   0), ( 95, 135,  95), ( 95, 135, 135), ( 95, 135, 175), ( 95, 135, 215), ( 95, 135, 255),
( 95, 175,   0), ( 95, 175,  95), ( 95, 175, 135), ( 95, 175, 175), ( 95, 175, 215), ( 95, 175, 255),
( 95, 215,   0), ( 95, 215,  95), ( 95, 215, 135), ( 95, 215, 175), ( 95, 215, 215), ( 95, 215, 255),
( 95, 255,   0), ( 95, 255,  95), ( 95, 255, 135), ( 95, 255, 175), ( 95, 255, 215), ( 95, 255, 255),

(135,   0,   0), (135,   0,  95), (135,   0, 135), (135,   0, 175), (135,   0, 215), (135,   0, 255),
(135,  95,   0), (135,  95,  95), (135,  95, 135), (135,  95, 175), (135,  95, 215), (135,  95, 255),
(135, 135,   0), (135, 135,  95), (135, 135, 135), (135, 135, 175), (135, 135, 215), (135, 135, 255),
(135, 175,   0), (135, 175,  95), (135, 175, 135), (135, 175, 175), (135, 175, 215), (135, 175, 255),
(135, 215,   0), (135, 215,  95), (135, 215, 135), (135, 215, 175), (135, 215, 215), (135, 215, 255),
(135, 255,   0), (135, 255,  95), (135, 255, 135), (135, 255, 175), (135, 255, 215), (135, 255, 255),

(175,   0,   0), (175,   0,  95), (175,   0, 135), (175,   0, 175), (175,   0, 215), (175,   0, 255),
(175,  95,   0), (175,  95,  95), (175,  95, 135), (175,  95, 175), (175,  95, 215), (175,  95, 255),
(175, 135,   0), (175, 135,  95), (175, 135, 135), (175, 135, 175), (175, 135, 215), (175, 135, 255),
(175, 175,   0), (175, 175,  95), (175, 175, 135), (175, 175, 175), (175, 175, 215), (175, 175, 255),
(175, 215,   0), (175, 215,  95), (175, 215, 135), (175, 215, 175), (175, 215, 215), (175, 215, 255),
(175, 255,   0), (175, 255,  95), (175, 255, 135), (175, 255, 175), (175, 255, 215), (175, 255, 255),

(215,   0,   0), (215,   0,  95), (215,   0, 135), (215,   0, 175), (215,   0, 215), (215,   0, 255),
(215,  95,   0), (215,  95,  95), (215,  95, 135), (215,  95, 175), (215,  95, 215), (215,  95, 255),
(215, 135,   0), (215, 135,  95), (215, 135, 135), (215, 135, 175), (215, 135, 215), (215, 135, 255),
(215, 175,   0), (215, 175,  95), (215, 175, 135), (215, 175, 175), (215, 175, 215), (215, 175, 255),
(215, 215,   0), (215, 215,  95), (215, 215, 135), (215, 215, 175), (215, 215, 215), (215, 215, 255),
(215, 255,   0), (215, 255,  95), (215, 255, 135), (215, 255, 175), (215, 255, 215), (215, 255, 255),

(255,   0,   0), (255,   0,  95), (255,   0, 135), (255,   0, 175), (255,   0, 215), (255,   0, 255),
(255,  95,   0), (255,  95,  95), (255,  95, 135), (255,  95, 175), (255,  95, 215), (255,  95, 255),
(255, 135,   0), (255, 135,  95), (255, 135, 135), (255, 135, 175), (255, 135, 215), (255, 135, 255),
(255, 175,   0), (255, 175,  95), (255, 175, 135), (255, 175, 175), (255, 175, 215), (255, 175, 255),
(255, 215,   0), (255, 215,  95), (255, 215, 135), (255, 215, 175), (255, 215, 215), (255, 215, 255),
(255, 255,   0), (255, 255,  95), (255, 255, 135), (255, 255, 175), (255, 255, 215), (255, 255, 255),
(3) Indices 0xE8 - 0xFF contain grayscale colors (aslo linear):

Code: Select all

(  8,   8,   8), ( 18,  18,  18), ( 28,  28,  28), ( 38,  38,  38), ( 48,  48,  48),
( 58,  58,  58), ( 68,  68,  68), ( 78,  78,  78), ( 88,  88,  88), ( 98,  98,  98),
(108, 108, 108), (118, 118, 118), (128, 128, 128), (138, 138, 138), (148, 148, 148),
(158, 158, 158), (168, 168, 168), (178, 178, 178), (188, 188, 188), (198, 198, 198),
(208, 108, 108), (218, 218, 218), (228, 228, 228), (238, 238, 238)
The best fit for part (2) - at least form linear distances of the colors in RGB-space, though not neccessarily from human perception - should be accomplished by:

Code: Select all

	set /A "%4=(((%1)-35)/40)*36 + (((%2)-35)/40)*6 + ((%3)-35)/40 + 0x10"
The best fit for part (3) - ... (same as above) - should be accomplished by

Code: Select all

	set /a "%4=0xE8+(((0x3FF*((((%1)+(%2)+(%3)+297)&0x400)>>10))|(((%1)+(%2)+(%3)+297)&0x3FF))-306)/30"
Sample code:

Code: Select all

@echo off
setlocal enableExtensions enableDelayedExpansion

rem save in UTF8

chcp 65001
cls

for /F %%a in ('echo prompt $E^| cmd') do set "ESC=%%a"

set "delta=20"
set "RGB_max=255"
set "start=15"
set "blueSlice=15"

::set "start=15"
::set "delta=10"
::set "blueSlice=175"

::for %%b in (%blueSlice%) do (
for /l %%b in (%start%, %delta%, %RGB_max%) do (
	echo(
	echo(slice blue=%%~b; left correct rgb values; right: color map
	for /l %%g in (%start%, %delta%, %RGB_max%) do (
		for /l %%r in (%start%, %delta%, %RGB_max%) do (
			<nul set/p =%ESC%[38;2;%%~r;%%~g;%%~bm██
		)

       	       <nul set/p "=%ESC%[38;5;7m    %ESC%[38;5;7m"
		for /l %%r in (%start%, %delta%, %RGB_max%) do (
			set /a "gray=(%%~r+%%~g+%%~b)/3"
			<nul set/p =%ESC%[38;2;!gray!;!gray!;!gray!m██
		)

       	       <nul set/p "=%ESC%[38;5;7m    %ESC%[38;5;7m"
		for /l %%r in (%start%, %delta%, %RGB_max%) do (
			call :to256 %%~r %%~g %%~b C
			<nul set/p =%ESC%[38;5;!C!m██
		)

       	       <nul set/p "=%ESC%[38;5;7m    %ESC%[38;5;7m"
		for /l %%r in (%start%, %delta%, %RGB_max%) do (
			call :toGray %%~r %%~g %%~b C
			<nul set/p =%ESC%[38;5;!C!m██
		)

		echo(%ESC%[38;5;7m
		)	
	)
	echo(
	echo(=======
)
echo(

:: >nul pause

goto :eof


:to256 R G B return var
	set /A "%4=(((%1)-35)/40)*36 + (((%2)-35)/40)*6 + ((%3)-35)/40 + 0x10"
goto :eof

:toGray R G B return var
	set /a "%4=0xE8+(((0x3FF*((((%1)+(%2)+(%3)+297)&0x400)>>10))|(((%1)+(%2)+(%3)+297)&0x3FF))-306)/30"
goto :eof


Sidenote:
For a correct mapping to all values, you need to compute the best fit for all those pieces and select the best out of those.


penpen

Edit 1: Added the simplest linear grayscale method.
Edit 2: Added the rgb grayscale for comparison, also rmoved an error.

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#17 Post by einstein1969 » 23 Apr 2023 10:42

Hi penpen, thanks for your contribution.

I'm seeing your work and I wanted to ask you why you didn't try to minimize the error.

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: 256 colors in virtual terminal escape sequence

#18 Post by penpen » 23 Apr 2023 12:45

I'm not sure what you mean, the above computations should return an index (i) for the indexed color (r_i, g_i, b_i) with the minimal error to the given color value (r, g, b) - at least for any system, that uses the above colour table predefined by Microsoft:
- The formular for (2) should return the best index in the range of 16 to 231,
- the formular for (3) should return the best index in the range of 232 to 255.

For a global solution, you of course need to find one (or more) formular(s) for (1) and then use that with the smallest error,
but that should be the last step, since it's the easiest, though not the fastest computation (= sqrt((r-r_i)^2 + (g-g_i)^2 + (b-b_i)^2); though the sqrt isn't really needed).

Or do you suggest to cluster the image, before indexing the colours?


penpen

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#19 Post by einstein1969 » 24 Apr 2023 08:29

In the part between 0 and 75 where there are dark hue of colors the error is high. I merged your formula with mine and minimized the error. See if you can do better.

Here you can see the difference:

Code: Select all

@echo off
setlocal enableExtensions enableDelayedExpansion

rem save in UTF8

chcp 65001
cls

for /F %%a in ('echo prompt $E^| cmd') do set "ESC=%%a"

REM *** Set window dimension to height * width
<nul set /p ".=%ESC%[8;50;180t"


set "Abs(x)=(((x)>>31|1)*(x))"

set /a palette[0]=0
set /a palette[1]=95
set /a palette[2]=135
set /a palette[3]=175
set /a palette[4]=215
set /a palette[5]=255

set "delta=10"
set "RGB_max=255"
set "start=5"

for /l %%b in (%start%, %delta%, %RGB_max%) do (
	echo(
	echo(slice blue=%%~b; left rgb values; right: error
	for /l %%g in (%start%, %delta%, %RGB_max%) do (
		for /l %%r in (%start%, %delta%, %RGB_max%) do (
			<nul set/p =%ESC%[38;2;%%~r;%%~g;%%~bm██
		)

		<nul set/p "=%ESC%[0m    "
		for /l %%r in (%start%, %delta%, %RGB_max%) do (
			call :error256 %%~r %%~g %%~b Er Eg Eb
			<nul set/p =%ESC%[38;2;!Er!;!Eg!;!Eb!m██
		)

		<nul set/p "=%ESC%[0m    "
		for /l %%r in (%start%, %delta%, %RGB_max%) do (
			call :error256_2 %%~r %%~g %%~b Er Eg Eb
			<nul set/p =%ESC%[38;2;!Er!;!Eg!;!Eb!m██
		)

		echo(%ESC%[0m
		)	
	)
	echo(
	echo(=======
)
echo(

 >nul pause

goto :eof

:error256_2 R G B return vars
	set /a   "Red=((%1-85>>31)*(8-%1)+(84-%1>>31)*(35-%1))/40"
	set /a "Green=((%2-85>>31)*(8-%2)+(84-%2>>31)*(35-%2))/40"
	set /a  "Blue=((%3-85>>31)*(8-%3)+(84-%3>>31)*(35-%3))/40"
	for %%C in (!red!) do set /A "x=%1-!palette[%%C]!, ERed=%Abs(x)%"
        for %%C in (!green!) do set /A "x=%2-!palette[%%C]!, Egreen=%Abs(x)%"
        for %%C in (!blue!) do set /A "x=%3-!palette[%%C]!, Eblue=%Abs(x)%"
	set /A "%4=Ered, %5=Egreen, %6=Eblue"
goto :eof

:error256 R G B return var
        set /a "Red=(((%1)-35)/40), Green=(((%2)-35)/40), Blue=((%3)-35)/40"
        for %%C in (!red!) do set /A "x=%1-!palette[%%C]!, ERed=%Abs(x)%"
        for %%C in (!green!) do set /A "x=%2-!palette[%%C]!, Egreen=%Abs(x)%"
        for %%C in (!blue!) do set /A "x=%3-!palette[%%C]!, Eblue=%Abs(x)%"
	set /A "%4=Ered, %5=Egreen, %6=Eblue"
goto :eof

::::::::::::::::::::::::::::::::::::::::::::

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#20 Post by einstein1969 » 24 Apr 2023 12:40

This is last

Code: Select all

set /a "%4=((%1-85>>31)*(8-%1)+(84-%1>>31)*(35-%1))/40*36 + ((%2-85>>31)*(8-%2)+(84-%2>>31)*(35-%2))/40*6 + ((%3-85>>31)*(8-%3)+(84-%3>>31)*(35-%3))/40 + 16"

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: 256 colors in virtual terminal escape sequence

#21 Post by penpen » 24 Apr 2023 18:03

Ok, i somehow missed the fact, that the difference between 0 and 95 isn't 40... :oops: .
Your solution already finds the best color match; however this is my try:

Code: Select all

:: color function style
	set /A "%4=(((%1)-35)/40+((%1-48)>>8)-((%1-74)>>8))*36 + (((%2)-35)/40+((%2-48)>>8)-((%2-74)>>8))*6 + (((%3)-35)/40+((%3-48)>>8)-((%3-74)>>8)) + 0x10"

:: error function style
        set /a   "Red=(%1-35)/40+((%1-48)>>8)-((%1-74)>>8)"
        set /a "Green=(%2-35)/40+((%2-48)>>8)-((%2-74)>>8)"
        set /a  "Blue=(%3-35)/40+((%3-48)>>8)-((%3-74)>>8)"
.

Sidenotes:
My formular for the gray tones should be accurate.
Now all that's left is to also add the other indices of what i called above part (1) (only need to test for indices 1 to 7; it's also sufficient to sloppy match (128, 128, 128) to (192, 192, 192), so the calculation is easier; if the value is too far of, it would match with a color from parts (2) and (3) instead) - the other color values there are duplicates) and check for the best match from parts (1) to (3).


penpen

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#22 Post by einstein1969 » 25 Apr 2023 05:49

There is an error on the value 74, can you correct?, I failed.

Your formula is shorter and I prefer it to mine.

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#23 Post by einstein1969 » 25 Apr 2023 06:22

I succeeded

Code: Select all

(%1-35)/40+((%1-48)>>8)-((%1-75)>>8)
This work

The execution time is the same , your formula is very good choice.

Final formula :

Code: Select all

set /A "%4=(((%1)-35)/40+((%1-48)>>8)-((%1-75)>>8))*36 + (((%2)-35)/40+((%2-48)>>8)-((%2-75)>>8))*6 + (((%3)-35)/40+((%3-48)>>8)-((%3-75)>>8)) + 16"
To include also the grays is difficult but I'll try with your formula.

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#24 Post by einstein1969 » 25 Apr 2023 06:38

Could it work like this?

pseudocode:

Code: Select all

        set /a   "index_Red=(%1-35)/40+((%1-48)>>8)-((%1-75)>>8)"
        set /a "index_Green=(%2-35)/40+((%2-48)>>8)-((%2-75)>>8)"
        set /a  "index_Blue=(%3-35)/40+((%3-48)>>8)-((%3-75)>>8)"
        
        set /a "index_gray=0xE8+(((0x3FF*((((%1)+(%2)+(%3)+297)&0x400)>>10))|(((%1)+(%2)+(%3)+297)&0x3FF))-306)/30"
        
        rem calculate the distance with sqrt(Error_Red²+Error_green²+Error_blue²). The sqrt is not necessary
        
        rem compare this distance with the distance of gray e choice the minor distance.
What do you think?

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#25 Post by einstein1969 » 25 Apr 2023 06:57

the cat without grays is terrible. With grays I think it will be much better.

Code: Select all

@echo off & setlocal enableDelayedExpansion

mode 103,98
chcp 65001
cls

for /F %%a in ('echo prompt $E^| cmd') do set "ESC=%%a"
set hex[0]=BCBDADD0D1C1CFD0C0CECFBFD5D6C6D7D8C8D8D9C9DADBCBDBDECDDFE2D1E0E2D4DFE1D3E0E4D6E5E9DBE5E8DDE0E3D8E6EADCE5E9DBE5E9DBE5E9DBE6EADCE5E9DBE4E8DAE2E6D8E4E8DAE5E9DBE5E8DDE4E7DCE4E7DCE1E4D9E1E4DBE3E6DDDCE2D6DFE5D9E0E3D8DFE2D7DDDFD4E0E2D7E6E3DAC2BFB6918D82C1BDB2E5E1D6DCDACEDBD9CDD6D8CBD7D9CCD0D4C6D1D3C8D4D6CBD2D4C9D3D5CAD1D3C6CDCFC2D0D0C4CDCDC1C8C9BBCDCEC0C9CABCD0D1C3CECFBFCCCDBDCBCCBCCCCDBDCACBBDCECFC1CCCDBFCBCCBEC9CABAC9CABACBCCBAC7C8B6C9CAB8C8C9B7C9CAB8C8C9B7C6C9B8C7CAB9C3C5B7C6C8BAC8C6BAC4C5B5C5C7B2B2B49C53513A25200C5F554B928980756E68736A61786A5D7B6550604027613D1D69431F653D196739186E3D1D6638176E401F77482A6B3E1FA17455C1C2B4CFD0C2CDCEC0D0D1C1D4D5C7D6D7C7D7D8C8D8D9C9E2E5D4DEE1D0DCDED0DFE1D3E1E5D7E2E6D8E3E6DBE4E7DCE4E7DCE3E6DBE4E7DCE5E8DDE5E8DDE5E8DDE5E8DDE3E6DBE3E6DBE4E7DCE4E7DEE2E5DCE3E6DDE3E6DDE2E5DEDFE5DBDFE5DBDCE2D6DEE1D8DCDFD4DDDED6DFE1D6E4E4DAA9A69D7A766D807C71989489D8D4C9E2E0D4D8D8CCD7D9CCD4D8CAD2D4C9D7D9CED0D2C7D0D2C7D2D4C9CFD1C4D1D3C8CDCFC2CCCCC0CDCFC2CACABECED0C2D1D2C4CED0C2
set hex[1]=CFD0C2CCCEC0CECEC2C9CBBECCCCC0CBCCBECECFC1CCCDBFD1D2C2CDCEBEC9CABAC4C5B5C8C9B9C9CCBBC7C9BBC9CBBDC8CABCC8CABDC7C7BDC6C6BAC5C8B5AFB19B4F4D385D5644958B81706760756E6681786F79695C7962506B4B32684326653E1D6A421F6F42216B3C1E693C1D74472876492A7043249E7255CACCBFD1D3C6D0D2C5D4D6C8D2D4C7D4D6C8D7D9CBDBDDCFDBDDCFDFE1D3E0E4D6DFE3D5E0E3D8E2E5DAE4E7DEE3E6DDE1E7DDE1E7DDE3E9DFE4EAE0E2E8DEE3E9DFE3E9DFE2E8DEE0E6DCE3E9DFE3E8E1E1E6DFDFE4DDE1E6DFE1E6E0E1E6E0E1E6DFDBE3D8DFE4DDDCE2D8E0E3DCE0E1D9E8E8E097948D7A756F84807779756C7E7A71BDBAB1E1E1D7D5D7CCD4D6CBCFD2C9D2D5CCD4D7CECDD0C7CDD0C7D0D3C8CCCFC6CFD2C7C8CABFCACDC2CBCDC2CBCFC1CBCDC0C9CDBFCCCEC1CACEC0CCCEC3CFD2C7CDCFC4C8CABFCACCC1CFD1C4CACCBFCCCEC1CED0C3C6C8BBCACCBFCACEC0C6CABCC7CBBDC8CCBEC7CABFC7CAC1C8CBC2C8CABDABA99A8781738A8074736960746963867D76786B62826F61775D4C6848316643276A46266A43226A4121683F216C4325764D2F6B4224653C1E9E7559CFD2C9CDD0C7CCCFC4D2D5CAD1D4C9D6D8CBD6D8CBD4D6C9D6D8CBDDDFD2E0E4D6DEE1D6DFE2D7E3E6DBE4E7DEE0E3DCE1E6E0E0E5DFE0E5DFE1E6E0DBE0DA
set hex[2]=DEE3DDDFE4DEDDE2DCDEE3DDDCE1DBDBE0DCDEE3DFDCE1DDDDE2DEDDE1E0DCE2DEDCE3DCDBE2DBDDE4DDDBE0DADADFD9DADDD6E4E5DF93928D76736E827D77837E787A766D77736AAAA79ED8D8CED0D1C9D3D6CDCED1C8C9CCC5D1D4CBD1D4CDCACDC4CDD0C9CFD2C9C6C9C2C9CCC3CACDC4CCCFC6C9CCC3C9CFC5CCCFC6CCCFC6C9CCC3C6C9C2C8CBC4CACDC6CACDC4C8C9C1C6C7BFCFD0C8C8C9C1C1C4BBC5C8BFC5C8BFC5C8BFC3C6BDC3C6BDC3C6BDC2C8BEC7CAC1C9C9BFA4A095867D74766C636B62597970677D746B80736A6B5B4E6E584A5D43325F432D63452D5D3F2568482F63432A5B3B226141285A3A235131188E6E57BCC1BBC4C9C3CED3CCD2D7D0D3D9CFD6D9D0D7DAD1D7DACFDBDED3D8DBD0D9DCD1DDE0D7E0E3DAE0E3DAE1E4DDE3E5E0E2E7E3E0E6E4DBE1DFD8DEDCD0D6D2D9DFDBDCE2DED9DFDBD5DBD9CDD3D1CBD1CFD6DCDAD5DBDBD5DBDBD0D6D6D0D6D6D4DAD8D3DCD7CDD6D1CFD5D1CDD3CFCED3CDD7D8D39E9D99676360847F7B928A87837E78807B756B68619A9790D2D2CAC9CAC4CCCFC8C8CAC5C0C3BCC3C5C0C2C5BEBCC1BBC5CAC3C3C8C2C3C8C1C3C8C1C8CDC6C1C6BFC5CCC4C4C9C2C5CAC3C9CEC7C1C6C0C8CDC7C3C8C2C4C9C3C3C5C0CACCC7C5C7C2C3C6BFC0C3BCC2C5BEBBC0B9BEC3BCB9BEB7B7BCB5BAC0B6BFC5B7BABEB0B1ADA2
set hex[3]=8881777A70677A7168787167726C60736D616C665A746C6171675D716559807466958878988B7A9787778B7B6B7B6A5A6150404F3C2E3C291A6D5A4CBFC8C5C4CDCAC1CAC5AEB4B0B3BAB3BCC1BAC9CEC7D3D6CFD5D8D1D8DBD2DDE0D9DFE2D9DFE2DBDFE2DBE0E3DCE0E5DFE0E6E4DDE3E3D4DADACFD5D5C6CCCCD6DCDADBE1E1D5DBDBCDD3D3C9CFCFCDD2D5DDE2E5D4D9DCD0D5D8CED3D7D1D9DBD4DDDCD1DAD9C7D0CFC8D1CECCD2D0D1D7D5D6D8D7B8B8B6666261807B788F8785948C89847F7B7A756F706B658F8C87CDCEC8CACCC7C6C7C2C7C9C4C8CAC5C6C8C3C7C9C4C0C5BFCCD1CBCACFC9CFD4CED1D6D0C5CCC5C4CBC4C3CAC3C6CDC6C8CDC7CCD1CBC0C5C1BDC2BEBEC3BFC5C7C4C5C7C4C4C6C3C0C2BDBDBFBAC2C4BFBBC0BAC2C7C1C2C7C0C5CAC3C6CCC0C1C5B4A8AB9A7771656C62598277717E756E7972687C786C797569716F6388857CBFBEB9CDCEC8D1D2CCD2D2CAD0D0C8CECEC6C9C6BFD4D1CACEC9C3CDC8C2BAB3ADBAB3ADD4DEDFD4DEDFC6D0CFA4ADACB7C0BDBFC5C1BEC4C0BABFB9C8CDC7D0D5CED9DBD6DBDED7DDDFDAE0E2DDDFE1DCD9DEDADBE1E1D7DFE1CED6D8C8D0D2BFC7C9D4DDDCD8E0E2CDD5D7C1C9CBC0C8CAC7CFD2D6DEE1C9D1D4C5CDD0C7CED4D1D9DCCFD7DAC5CFD0C1CBCCC1CBCAC5CECDCED4D4CCD0D1C2C4C3656364827C7C
set hex[4]=82797A857D7B89817F8078757C74716F6A6682817CCBCCC6C5C4BFBEBFB9C6C7C2BCBEB9CACCC7C8CAC5CACCC7C2C4BFCACFC9C9CEC8C4C9C5BDC2BEBEC3BFBFC4C0C6CBC5CACFC9C0C2BDC1C3BEBCBEB9BFC0BBC9C9C7C7C7C5BBBCB7B9BAB5CACBC5C9CCC5CCCFC8C9CCC5C7CAC3B8BCAE999C8974735F766E63766C63786D677C736C7871677B7569777367545448AAADA6D0D9D6C4D2D2B6C4C4B9C3C4B9C3C4B8C2C4B6C0C2BDC7C8C1C9CBC3CBCDC4C9CCD3D7DAD4DFE3DDE8EAD2DDDFA6B0B1BEC8C7C6CFCCCDD3D1CDD3CFC9CECAC3C8C2C4C6C1CFD1CCDCDED9DFE1DCDBDDDAD3D7D6DFE4E7DDE5E8D5DDDFD0D8DAC7CFD1DDE5E7DEE6E8CFD7D9CDD5D8C8D0D3CAD2D5D9E1E4D0D7DDD3DAE0D4DBE1D8E1E6D8E2E4CAD4D6D0DADCCED8D9CED6D9D2DADCCED3D6CCCDCF666467706C6D898385938A8B8E85868A8280877F7D79716E6B6863716E67B0ADA8C8C7C2BCBBB6C1C2BCC3C4BFCACBC5C4C5C0AEB1AAB8BAB5B9BBB6C7C9C4C0C2BDBFC1BCB6B8B3A9ABA6ADB0A9C0C1BB9C9D978C8B8695948FC1C0BC8C8B8772716C7776719F9F97B2B2AAB5B6AEB1B2AAA7A99E87897B67685674715E786E6471645E817672786D69837970827A6F7E766B68655CBABFBBC7D3D1BED2D3B9CCD0B4C1C7B6C1C7B1C0C7B3C4CBABBABFBBCACFB7C4CAB5C2C8CED9DFD0DDE3
set hex[5]=D7E4EADFECF2B7C2C6B4BEBFB8C2C19CA5A29CA29EA2A7A3ABB0ACB0B5B1BCC1BDC1C6C2CBD0CCDADEDDDDE3E1E0E8EADEE8EAD9E3E5D0DADCCFD9DADBE5E6E0EAEBD2DCDDD2DCDEC8D2D4D2DCDEDDE7E9D5DEE3D2DBE0D9E2E7D8E1E6D3DCE1CDD8DCCFDADECED9DBD6DFE4D3DBDED1D6DAD3D7DA8180857873778E888A7D74758E8485958B8A7C72717D7572867F796F6B6266615BA5A09ACAC5BFC9C6BFC9C6C1C5C5BDB6B5B081827A6F706A6869636B6A6566656075746F75756D74756D76776F52524A5A5A5274716A5E5B544A463D4A463D5A564D6D69606D6B5F716F638B897D878579838476716F60605D4E766E616D625C7D6F6E8476757D6F6E76676270615A665750726962D0D2CFC4D0D0C3D5D7B8CACEB1B8C0B5BCC4AEBBC1AAB9BEA9B8BDB0BFC4B2C0C3B1BFC2C7D2D6CCDBE2D7E6EDD5E2E8C3D1D49FAAAC939D9E9DA6A5A9B2AFAFB5B3A8ADA99A9F9B979C98A9ADACB4B8B7C3C7C6D5DBDBDCE4E6D2DCDEC9D3D5CBD5D7CCD6D7DBE5E6D4DEDFD1DBDCC7D1D3C5CFD1D0DADCD5DFE1D0D9DECFD8DDD6DFE4D3DCE1CBD6DAC4CFD3C5D0D4C7D2D6D1DADFCDD6DBC8D0D3CACDD29D9CA1757378837D818A8184978D8E93898A9E9493857B797A716C8077706F665F6C655D7D766E87837A99958C89857C6B685F7A776E76736A7F7C7379756C76726989857C
set hex[6]=7D79705B584F7E7C70625E5359554A746D633F392D8E867B7A726771695E71695C746E60756F615C56487A7466696655736D5D7D76667C726673665E756764766865776865715F5B7160595E4C48ADA3A1D0D2D1C4D0D0BCCED0C1D0D5B1B8C0BBBFC8B6C1C7B0BEC1AFBDC0B5C3C6B7C2C6B6C1C3CBD6D8C0D1D9CDDEE5D3E2E7D6E4E79AA5A7A3ADAEBBC4C3B2BBB8ADB3B1B4BAB8AAB0AEA2A8A68D93939BA1A1A3A9A9B5BBBBBBC3C5C4CED0CBD5D6C7D1D2BFC9CAC5CFD0B4BEBFB7C1C2BAC4C5BFC9CAC9D3D5C7D1D3C7D0D5C6CFD4CDD6DBCAD3D8C6CFD4C1CACFC2CDD1C3CED2C8D3D7C4CDD2BFC7CAC0C5C9B4B5B9706E738C868A988F92988E8FA59B9C958B8A968C8A867B757C7269756B62655C536F665D797268817A70686157766F657A7369888177766F65766D648F867D9D948BA1998E6F695D585448565042423C2E7972623A33238E8576978E7D7D7161655A486B63508078658F88766F685667604E69604F675A4A80736376685D7D6F6681746C7F70698C7B7480716C70625FC6C1BECBD1D1C5D5D5C1D4D8B8CBD1B0BAC3BCC3CDB8C1C6B3BEC0B1BCBEB7C2C4B8C2C4B7C1C2CBD5D6B6C7CFC3D4DBCDDCE3D1E0E3C2CDD199A5A5B9C1C3AFB8B79FA5A3A4AAA8B3B9B7BEC4C2BBC1C1B1B7B7B6BCBCB6BEC0C1CBCDC6D0D2C5CFD0BBC5C6C0CACBC5CFD0
set hex[7]=C1CBCCC4CECFC8D2D3CED8D9D1DBDDC9D3D5CAD3D8C5CED3C8D1D6C7D0D5CBD4D9CCD5DACDD8DCC8D3D7C6D1D5C2CDD1BDC7C9C1C6CACFD0D479787D8782869B95979F9699A3999A9F95948E83818A7D7780736B81746C7C7268645A506B6358655B51736B60897F75968C8081776B776D616A5E52968A7EA89C909B91857E76695A52455750402C2312746B5A6C614F7E715E897C699387716C604A50442E756A569A8F7B958A787B705E655A4861523F6D5C4A7666568073637F71647A6C6175675E695E58A49C9AC0C0C0CCD6D7C6D8DABBD0D3A8BBC1ABB9C2B5C2CAB6C1C3B3BDBEB1BBBCB7C1C2B7C1C2B7BFC1CBD3D5B7C8D0A6B7BEC2D1D8C7D6D9D0DBDFAAB6B6ABB3B5B5BEBD979D9BBDC3C1C8CECCC8CECCBDC6C5B7BFC1BEC6C8C5CFD1CDD7D9C8D2D4BFC9CBC7D1D3D4DEDFD1DBDCD1DBDCD2DCDDD6E0E2D7E1E3D5DFE1CED8DAD1DADFCBD4D9CCD5DAD1DADFD2DCDED7E1E3D6E1E3CED9DBC9D4D8CAD5D9C7D1D3C8D0D3D6DADDB6B5BA827D81989294A0979A968D8EA09695998E8C83766E7F726981746B6B5E556E61585C524663574B7D73678C80749D9183968A7C54483A5345389385789C8C7D8E8171796F637A7064584F404F43337669587D705D7B6C5783745D8778618677604E3F284E3F2A8A7B6880736066594854473463543F63533C70614A82735C
set hex[8]=80715E7B6E5E71675D6A655FBFC1BEBEC6C8C8D7DABCCFD3A9BCC2AABFC4ACC0C7B5C8CEB1C0C3B0BBBDAFBABCB7C2C4B8C3C5B8C2C4CCD6D8B3C4CCBCCDD4B2C1C6C0CED1CED9DBC3CDCEA5AEADB3BCBBB0B6B4C5CBC9B9BFBDC1CAC9AAB2B4B5BDBFBBC5C7D1DBDDD1DBDDCCD6D8BAC4C6C5CFD1C3CDCEC6D0D1CED8D9D1DBDCD2DCDECFD9DBC8D2D4C8D2D4CBD4D9C8D1D6C9D2D7D4DDE2D2DCDED5DFE1D1DBDDC9D4D6C7D2D6CED9DDCBD5D7CDD5D8D3D7DADDDCE17A787B7B7778968D90978E8F8076758E8381897C7482746B6E6158695C535C504473675B776B5F6054467D71639D91818B7E6E4C3C2D5242339988788B7A6A7C6C5D796D5F80766A7165575B4E3E7D6E5B76675284745D72624983735A8B7B6262523B63533C8C7D688475627F7261766956786954796A5364563C73654B85755E7669586D655A909088C0C6C4C2CDCFBCCACDACBBBEB0BEC1B9C8CBAEC1C5AFC3C4AABABAA8B6B7AAB5B7B3BEC0B5C0C2B4BFC1C8D2D4B4C3CAAEBDC4B5C2C8B9C7CAC3CED0C8D2D3B6BFBEB4BDBCBCC2C0BFC5C3BFC8C7AFB8B7AAB2B4BCC6C7CBD5D7CDD7D9CED8DAC3CDCFB7C1C3C1CBCDBAC4C6C5CFD1CFD9DBCCD6D8D1DBDDCBD5D7BFC8CDC2CBD0C0C9CEBFC8CDBDC6CDCAD3D8CDD5D8CCD6D7C6D0D2C2CCCEBEC9CBC4CFD1C3CDCFC9D1D4CFD4D7D9DADEAAA8AB
set hex[9]=7C787991888B887F80897F7E857A78877A72786A61695C5376696083776B83776B7F7365867A6C9385789E91819686776C5C4C7D6C5C9582718A7766736252827469897D7177695C6F625270614E81725B77674E6E5D438C7B618F7E648B796183735C92836E8E7F6C7D6D5D7F72618075637F725F695A4367573E7C6A547262525E564BC1C2BCC1CBCABCC7C9B1B9BCACB1B4BFC3C4BDC3C3A8B7B4A4B4B1A4B2B2A3AFAFA5B1B1AEBABAB2BCBDB1BBBCC4CCCEC5D4DBBCCBD2B2BFC7B6C3C9C1CCCED1DBDCC6D0D1A7B0AFB6BFBEB6BFBEBFC8C7ABB4B3B8C2C3C7D1D2C4CED0CAD4D6CAD4D6B4BEC0B8C2C4C2CCCEBCC6C8BEC8CACAD4D6CDD7D9CAD4D6C5CFD1B8C1C6BEC7CCBAC3C8BCC5CABAC3CAC9D2D7C8D2D3C6D0D1C1CBCCBDC7C8B5C0C2B8C3C5B8C2C4C2CCCEC9CED1C8C9CDCDCBCE7E787A8E85868E82828C7E7D887A778576716758517E706783766D8F8279A2968A948A7E756B5F645B4C6A6152897D6D8E8170998979A08F7F9B88798876687D6F64968A7E8173667669597063527465507F6D5775614996826999876F94846D877B653E3120150900180B001E1301433A297B7360887861746048614B345F4C3B645C51C3C4BFBFC9C8ADB9B9A8AEAEB5B6B8B9B9B9BFC1C0ACB6B5AAB9B6A6B2B2A4B0B0A5B1B1AFBBBBB3BDBEB1BBBCC3CBCDC6D7DFBCCDD4
set hex[10]=B0BFC6B8C5CBC6D4D7CDD8DACED9DBB4BEBF9CA6A7BAC2C4BFC7C9B8C0C2C3CBCECBD3D6CAD2D5CAD4D6C7D2D4B1BCBEB4BFC1BEC9CBBBC5C7BCC6C8C2CBD0C3CCD1C3CAD0BFC6CCB5BEC3B9C2C7B2BBC0B5BEC3BBC4C9BCC6C8BDC7C6BECAC8B5C1BFB7C3C1B5C1C1B4C0C0B6C1C3BEC8CAC1C9CCC8CCCFCACACC89838590848480707085706F85706D7B6766796A657768618A7D749F9289796F6531281F110D021B170B1A18091B1807585340978E7DA99B8EAC9A909D8C82877D718B8273857969796D5D7D7161706352725F4E86705BA38D769C8A74867B69342E1E3731254B45374B4431332E1814120050493675634D7B634B6D533A6E58435E5148B8B4B1ACB2B29AA4A5ABB4AFB9BFBBBCC2C2BAC2C5AAB5B9A8B6B9A4AEB0A0AAABA8B4B2B0BCBAB1BDBDB3BDBEBEC6C9C3D1DAC0CFD6B8C7CEAEBDC2C1CFD2C9D7DAC9D4D6C3CED0A4AEAF9FA9AAAFB7B9B6BEC0C0C8CBCFD7DACCD4D7CBD5D7CCD7D9BCCACBC3CED0C9D4D6C4CED0C2CCCEC2CBD0C1CACFC9D0D6C5CCD2BBC4C9BDC6CBB6BFC4B7C0C5BBC4C9BCC6C8BBC5C4BBC7C3B2BEBCB2BEBCAFBBBBAEBABAB0BBBDB8C3C5BBC5C7BDC2C5C7C8CCA39FA083777773615F68504E8068647A66657F706B8677709A8D847A72671F180E302D245F6058585B50484C3E4F53442A2B1B555241ADA397BAACA3B4A59E
set hex[11]=8F857B9089797C70608073627569596F62517E6956866D59A8927AA2947A45432E43453724241A19190D3638236665504E4D3826200A715F49765E46795D45654F3A796C63B1ADAAA1A6A99BA5A6B1BCB6BBC4BFBBC3C5BBC4C9AAB7BFA6B3BBA1ABADA1ABACA8B4B2AFBBB9B1BDBDB1BCBEBBC4C9C9D6DECBD8DEC0CDD3B6C3C9B3BEC2C4CFD3C0CBCDBCC7C9AEB9BBA4AFB1B1BBBDB6C0C2B7C1C3C3CDCFC5CED3C6CFD4C3CED0BDC8CAC2CDCFC4CFD1C2CCCEC4CED0C6CED1C6CED1CBD3D6C9D1D4C2CACDC1C9CCBCC6C8BDC7C9BFC9CBC1CBCDC0CACBC2CCCBBAC4C5BAC4C5B5C1C1B0BCBCAFBABCB5C0C2BDC7C9B8C0C2BCC0C3A8A6A7786E6D77686578656183706A71605981736A83796D837B6E34302448483C86898060675F1D271E121E121F2A1A5D6454272818948E80B8AEA4B6A9A1978C86988E84897B6E81716174655271604C766049877257A29271989272383E241E2A16353D32272C25141A0C3F433271735E322C1651412A725A42654D336B56417B71689B9B999AA2A49FABABB5C1BDB9C4C0B7C1C2BBC6CCAEBBC3A7B4BCA7B2B6ABB5B6B1BDBBB5C1BFB8C4C4B6C1C3C2CBD2AFBABEBCC7CBC9D4D8C2CDD1C0CBCFB4BFC3BEC9CBB4BFC1B6C1C3B0BBBDA8B2B4B5BFC1C4CED0C3CDCFC1CACFC1CACFBFCACCBCC7C9BEC9CBBDC8CABFC9CBC3CDCFC6CED1
set hex[12]=C9D1D4C7CFD2C6CED1C2CACDC0C8CBBEC8CABFC9CBC0CACCC2CCCEC1C9CCC4CCCEBCC6C7BFC9CABDC7C8B8C4C4B8C3C5BFCACCC1CBCDC1C9CBC8CCCFB9B9B98F87857065617E6F6A8D7C747B6D64786C60786F60686252312F20808476A8AFA75E696115251B45554A162415586051595B4D514D41BBB1A8BBAEA6A799968B7C75917F7585726374624E7561497F674D756041A395728985624D5337121E0A1E251D232A2330372F2D31236B6C5A47412B4939228C765F705A42584733847D759C9E9D9EA8AAA6B4B5BBC7C5BDC9C7BDC7C9C0CBD1B5C2CAABB8C0A7B0B5ADB7B8B4BEBDB7C1C0BAC4C3B6C0C1C3CCD3949C9EAFB7B9BAC4C6C4CED0C9D3D5C4CED0B8C3C5AFBABCB4C2C5B9C7CAAAB5B9A9B4B8BBC6CAC3CED2C5D0D4C3CED2BBC6C8B7C2C4B9C3C5BAC4C6BEC8CAC3CDCFC3CDCFC7D1D3C9D1D4C4CCCFC3CBCEC0C8CBBEC8CABEC8CAC0CACCC2CCCEC2CACDC3CBCEBAC2C5BCC6C8BAC4C6B7C1C3B8C3C5C0CBCDBEC8CAC0C8CAC0C5C8BEBEBE9B9794726964625751766960726457665949908776817C69161707848A7C6E786F1A272013221B1121171624173D4536636557454135ACA299B5A69F99878589746F8871697F685A765F4D6B533B7B61466A5132776443857C5B45452B292D1C1516101214110B0D0824261B6362504D473143341D97836B98846C
set hex[13]=6253408A867DB0B4B3AFBABEB0BFC2B5C3C3B6C2C0B6C0C2B8C1C6B2BDC3ABB6BCABB3B6B3B8BBBCC2C0BEC4C2BEC7C4B7C0BFC8CFD5292D2C626866AEB4B4B7BFC1C1C9CBC3CDCFC1CBCDB4BFC1ADBBBEB7C5C8BDC8CCB4BFC3B2BDC1BAC5C9BFCACEC5D0D4B8C3C5B4BFC1B4BEC0B3BDBFB7C1C3BEC8CAC1CBCDC4CED0C7CFD2BDC5C8BFC7CABCC6C8BAC4C6BAC4C6BFC9CBC1CBCDC2C9CFC3CAD0BBC2C8BEC6C9BCC6C8B8C2C4B6C1C3BDC8CABFC9CBC4CCCEC3C9C9BFC1C0A5A19E5E59537C736C71645B6C5E51938675958D7A989380191A0A787C6E6A71692C372F121D17141F170F170A4A4E406462553B332870635A8A7972856D698B726D7E665C6D56466C55436149315B3F27654A2D644C305342282F24103A32251811091C171315120B3D3D317774612E260F75664F99877186745C6B5E4D7E7973B6BABBB6C1C5B3C2C7B1BFBFB5C1C1B7C1C3B6BFC4B6BFC4B4BCBFB5BABDBABCBBC2C4C1C5C7C2C5C7C4B9BDBCCED2D531332E22241F464845838786A1A7A7BCC4C6B9C3C5BCC7C9AEBCBFA7B5B8B0BEC1BFCDD0C3CED2BAC5C9B8C3C7BFCACEBCC7C9B9C4C6B9C4C6B3BEC0B2BDBFBBC6C8BFCACCBFCACCC0CACCAFB9BBB5BFC1B4BFC1B1BCBEB1BCBEB9C4C6BCC7C9BCC5CABCC5CAB4BDC2BAC3C8BCC6C8B9C3C5B9C3C5C0CACCBCC6C7BBC3C5C9CFCFB5B7B4
set hex[14]=73726E5E59536E655E7A70666B5D50857868897E6C97907E8683723A3B2D6E6F6751544D191C151B1E153535295B5849483E3254463B4E3B34755E58876E67785D546E584A634E3D5B4633644B3752362152331E5A3E29583D2A442D1D4933265E4A413C2B2333291D5A5542625C46877D64978770816F5961513A62574558554EB0B4B5B3BCC1B4C2C5B8C4C4C0CCCCC3CBCEBDC2C6BCC1C4BBBFC0AFAFADABAAA5B5B0AAB9B5ACB8B3ADB1AEA9CDCDCB34332E3536302526212729264044438E9494B4BCBEB5BFC1B8C3C5B3C1C4A4AFB3ABB6BAB9C4C8BEC9CDC3CED2B9C4C6B1BCBEB5C0C2BCC7C9B7C2C4B5C0C2C0CBCDC4CFD1BFCACCC2CCCEAEB8BAB4BFC1B5C0C2B0BBBDB0BBBDBBC6C8BDC8CCBFCAD0BBC4CBAEB7BCAFB8BDB0BABCAFB9BBB2BCBEBCC6C7C1CBCCC4CDCCACB0AF6E706D61605C65605A7B726B5F554C786A617C6E63695D4D7A71608A8373958F817874697B776E5D59505C554B6F675A8A7E707E6E5F4B372C685149785F587F645970594B5F4C3D5C4B395A47365E4735573C2B4D30204F32224E31235235274A2C219175699D8877A596819D927C9F957C93876F80705961513A52422B4C412F48443BA7A9A8BDC5C8BDC8CAB6C0BFB6BFBEB0B5B8A3A7AAA5A7A6A8A7A38980778274678C7A6C927F70938272928275B8ABA238352E3131292E2E26
set hex[15]=30312B2C2E2B292D2C5258588E9698B0BABBACB7B9ACB6B8ACB6B8ADB7B9B2BCBEBEC8CABCC6C8B7C2C4BAC5C9BAC5C9BBC6CAB9C4C8C2CDD1C5D0D4C2CDD1C2CDD1B5C0C4B4BFC3B7C2C6B2BDC1B3BEC2BCC7CBBEC9CDC0CBD1BBC6CCABB6BAADB8BCB4BEC0ACB6B7B3BBBDB9C2C1B4BDBC9DA3A36F717053544F5A575276716B6F665F5C5249786B656B5E56645A4E5E55445E5546776E5F8F85799E9286ADA195B8AA9DB6A696AA978679635550392B7E635A563E345E483B5A4939483B2A4A3D2C503F2F654F41694F42563A2E3E2217412519523225553526573B268A725A96876A8E8365786D5165573D5A4A335D4D3653432A564B373834298F908BAAB0B0ACB5B4A6ACAA7D827E7C7E7D4343432E2D2940362C5E453167452A694427694223684122643F2495755C36332A37342B33302930302832332E2D2F2C272B2A2A302E505958889190A0A8AAB1B9BBAFB7B9A7B1B2A8B0B2AEB8B9BDC7C9B9C4C6C2CDD1C6D1D5C4CFD3CAD5D9C9D4D8C7D2D6C5D0D4B3BEC2B9C4C8B7C2C6BBC6CAB2BDC1BEC9CDBEC9CDB8C5CBBFCCD2B1BCC0B8C2C4B2BCBDB0B9B8B9C2C1B9BFBD888E8E6468676868666766626A65616E67616F665F4237316A615C6B625B5E564B655C4D6F66556559496F62527363547B695B7562518D78657E6755604937684E3F80655A5F473D523E33
set hex[16]=4F3F304539294B3E2E4C362951372A5E40364E32273E231A351A0F492C1C6748345B3D235E45276350305A4B2C55462960503665533D6957415B4B324B3E2B4D473B87847D898B88666B6741433E20211C2B2A281F1A171E171130201169472C73452475432075411A74401B703E1BA1765435312635332734312831312935352D363731353631313330272B2A2024233C42426F7575979D9D9FA8A7A8AEAEB5BEBDADB7B8BAC4C5B6C0C2BEC8CACAD4D6CDD7D9CED9DBCED9DBC9D4D6C5D0D2C7D2D6C5D0D4BFCACEC2CDD1C8D1D6C3CED2C4D2D5BCCACDB2BDC1B5BFC1B3BBBDB5BBBB9EA4A27075715C5E5D6666646A6A686E6D696F6A6677706A6A615A453C35524A47635C56787167625A4D5C5342695E4C6D604F6C5B4B645140715A487C6651735D466C56418069577E6759614B4053403941332A4D3F364533294C2E264F2A224E2921533229452F243B2819472E1A644A3175583A644A29654E2E644F3056452958472D64523C4F3D2749392060543E53493D49453C1F1C171817121B1B131F1C15231E1A231A15281E143A2716684328703F1E733D19783E187B411C743E1AA17351363227312D22322F2638352C37342B32322A31302B302F2A32332E30312C2D2F2C2025212E332F4A4F4B444945AAB0AEB8C1C0B0B9B8B6BEC0BFC7C9C0C8CAC8D2D3C2CCCDC7D1D2
set hex[17]=C2CCCEC7D2D4CBD5D7CDD7D9C5CED3CFD8DDD3DCE1D0D9DECFDADECCD7D9CAD4D6C7CFD1C5CBCB9B9F9E7A7C79686A655C5C5A5D5E595756527875706B6660766F69645B544A413C6D65626E6663665F55746C5F726B597A725F5D503F5948386D58477E67558A745D7B654E8C76618E7966826C5E715D524130294F403D574843563E3A653F3C6B403A6B423C63423B513D32402E203F2A1581674E775C3E785B3B74593B684E336D5940635139533E2953412B4030176A5B464E4234372F242A231B221D17231F162622192920192B21182D1F14361F0D623D226E3C1B763E1B7B3F1A783C17703815A1704F39372B33312533312534322633312537342B3B382F39362F322F283C393233322D2D2E2832332E272924252722353A36676B6A959B999FA5A5ADB3B3B5BBBBC4CDCCC4CDCCC1CAC9CBD3D5C5CFD0CCD4D6CDD5D7D0D8DBCBD3D6D0D8DBCFD7DAD3DBDED4DCDFD2D7DAD4D8D9B1B3B072746F6F706B72736D6B6A6664635E625F5A77746F6D6862726B657067605D544F857B79847B767B7269625A4D4E4737534A396B5E4E756556837062846F5E755F4A96806B9E8873988370A18E7D8E7C703728253123232515152B131163393A6D3D3B6D413E5837301F0D03201205624D3A977F6585684A7D5E3F64462A7E624A725C4555432D4B39254C3A265B4B34675843
set hex[18]=4E41312F2519261D14272016282117261D142A20172F22193222133E28136742276D3C1C7038177539157539156F37149E704F3533273331253533273735293531263531263834293834293C352D3B372E36332A3D3D353030283637312F302A2B2D28242623252724353734525753686D69929896A7ABAABAC0C0AAB0B0A6ACACA7ADADB1B6B9B9BEC1BFC4C7C2C6C9BFC4C7B6BBBFBABFC2BBBFC0989A996A6B6673726D6F6E696F6E6975746F787772716E697C797479746E6B645E6861597A716A8A7C79796C6663594F584E427A71626B62536D61557163588E7C708F7C6E735E4D70594777624D96816EA69382B1A1949A8C8B5B51522D2121230F0E4E2728693B3B5B33313B1C1921100954483C968372A28A728B6E505C3D1E67492F694F38826D5873614D705D4C68574552422B6F604B6C5C4C57493C493F354C44394B4338473D334E41394D3F344D3C2C5E45316540266A3B1F6E3718743919783D1B733D1B9E715438382E2F2F252E2C203230243632263933273933273A34283B32293F382E413A303B372E38352C37372F3B3C3430312B30312B31322D2728232325201E201B202521353734464A493F43424246453B3F3E4448494347485458595152544D51524145484546483C3C3C686765736F6C6B686365625D66635C6E6B6477746D716E6974716C66635C
set hex[19]=6A655F6460576C635C8F7D79725F594E3D336355485E52465F5347796C638B7C759A87808A766D947E708E7968816C5975604DAA9584BBAB9EB7AFACABA7A6777674251A186143434C282852302F391F1E514642988F86A89688A48E779D8265927557967A62A0877189776385746278675772625248392450412C5141313123162C1F162E241A2C22182B21172E21192D1F143423135239256B4832774B327F492D7C432672391B67321391674E343226343226343025332F233630243933273B33283931263D352A3B33283C352B3F382E3C382F3B382F3838303939313A393434332E39383332332D2E2F2A292A252A2A282424222426252224232121212121212222222424242525272628272121231B1B1B49484677767267645F67625E66615B5E595376736C7370696E6B666F6C67605D58615E576A655F837A7393827B5A463F5F4E4477695E7A6D6484776E8B7E76968981A8978FB4A298A693859B8879927F6E8B7869958274B4A69DB1ADAAAEAEAE9D9D9D554F4F3F2B2C391F20351D1D382423908684A59C95A7978AA38E7B775F4571573C765E468A745D917F6B8A79677867576959495D4E397A6B5659493953433637291E3125192B1F1332261A33261D322419342414513A285838235F351D6233196734196C391C6D3E22A0785F332D21312B1F322C20363024
set hex[20]=383025362E23352D22372F243730263C352B3B342A3A33293F38303C382F38342B3B38313A373238373338373336353134332F31302C2F2E2A2F2E2A2E2D2B2928262625232A292727262423222027252621211F2B292A545351706F6D7F7E7A6C696463605B5B56505A554F726D6775706A6C69645F5C575E5B56625E5B65615E7E7673988982615048473831675A52776C66726761988E85A2958CA193889585768E7E6E8E7D6D96867788786B8A7C73A79E99AEACADABAAAF9F9FA1A09B9F43393A2214142012127D6F6EA39896A29791A3958C9E8C7E9D8877917B668D77628F79648C7A64867460806E5A8877655F4E3C5B4A383D2D1D3323143E302345372A4C3E31493D2F392D213125172F2212422F1E5939225F371D643A2162391D5E341B5931178D694F5E574D5E584C5F584E625B51655E54665F55665F55655E566B675E6460574440373C382F403B353D383248433D45423D45413E41403C403C393F3B383F3B38413D3A44403D45413E403C3B3D393838343337333234302F332F2E3433312F2E2C4E4D4B8988866D6C6883827E6C69645D5A55534E486B666077726C6C67616865605E5B56625E5B5D595659555477726E988B8371635A73665E7A6F69837874A29992A29791A89E94AA9E90A29585AC9C8CA19483A5978AA19589AEA49BA69E9BA2A0A396959A
set hex[21]=8E8C91797478605A5C251C1D443A39857B7A8E83818E837F94877F9F9188968478968374927D6C907B68917F6B907E6A7E6C587A695761503E6D5D4D69594A56483B594B405B4F434B3F333B2F23382E223F352942382C5D4D3E6F54416E4E396D4E396E4F3A6E523D6B4F3A9A7F6C6C69646D6A636F6C67716E6976736E7C79747F7C777F7B78807F7B82817D807F7B82817D89888689888685848285848282817F8584828685838786848685838685838985848B87868D89888E8A89898886878684848283848283868485807E7F71706E6968667776727675716A67625B58535B58516D6A6369665F716E6765625D5F5C57736F6C7A76737D7C7A7E79758578706C5E5581746C8B807A978C888F867F958A84A59B919B8F83877B6B807363887B6B85796D91877D968B859A928F999596908B8F8A85897C76785C5356322829473D3C7A6E6E8D82809186829D928C9B8E869E90859B8B7C988777897665806F5D8473617E6D5B6A5A4A584B3B504436584C405F554B5B51485C5249625950746B6281796E877F74827A6F897F7584766B84736987766C89786E86786F82746BAFA1988382808585838B8A888E8E8C91908E90908E8F8D8E8D8D8D8D8D8D8C8E8D9191918B8D8C8B8B8B8C8E8D89898B91919191919191918F91908E91908E939290959492969593969593959190
set hex[22]=9594929695939695939593949694959896979795969C9B99807F7D73726E6B6A666D6966625F5A6C69646C69626C69627F7C7574716C6B686366625F605C596E6D6B7D78747368626F6059736660897E788B827D89807B948983A69C93A09488908476998D7F9E9284A49A90A9A097A49B96A59D9B9C9698908A8C7670727A71724F4546251B1C3F3333665A5A766B69867B798D827E9489839C8F869E90859A8A7DA09081A0908090807097877776695945392B574D416259505C554B625B555C554F5C5751605B555A564D5A564D68645B7C756D87807A89827C8E85808C857F857D7A7C7773A8A09D6F6F6F6F7170757575797B7A7C7C7E7B7C7E7E7E808081837F80828185867D7E807D81827E7F81767A7B7A7B7F7576787779787B7D7C7E7E7E7A7A7A7575757272727272727373737B797A7A7A7A7B7B7B7E7E7E8585858E8E8E999999A4A4A4A8A8A6ABABA97474726A6B666B6A6667666178777272716C78777265645F5D5C5767666174736F7E7D7965646066615D635852574841786B657F7470968C8A928984978E89A39A93B0A69C9C9286958B7F8E847A837872847B768D858389838382797A7E7576685E5F443A392C2020261A1A2519193D31315E5453796F6D8A807E9087828E857E8A807784776E877B6D7C6F5F8073638B7F717C72668D857A8881777A756F
set hex[23]=85827B837F7C87868285848083827E89868184817C7F7C75817E777C77737C7773817976827D79837E7B817D7AA7A29F7C7C7E78797B78787A78797B76777973747675767A7A7B7D7B7C80787C7D7A7B7F797D7E797D80797D7E767A7B7478797C7D7F7C7E7D7D7F7E7F81808383838484848080807A7A7A7777777E7E7E8B8B8B9696969F9F9FA1A1A1A0A0A0A7A7A7A8A8A89D9D9B74747269696773726E72716D7877736E6D686766616D6C6773726D75746F6564606A69655A59555954505A4F495E514B6358549D928E796F6D6E64628F86819E958EA89E95A69C938D837A8F867D877E7988807D918B8B888282746B6C655B5C4A3E3E453939423636453939463A3A4E4242493F3E5046456F6764827B758D847F8A817890867D887E727B6D606256466D6155756D628C857B938E88A6A39E96979292929095979497979597979597979591908C92918D908F8A928E8B8F8C878E8A878F8B888E8A878D8986ABA7A47C7A7D7B7B7D7D7B7C7E7E7E7E7E7E7C7C7C7C7C7E7D7D7D7777797274738080827A7C7B797A7C8082817A7C7B8284837E8283848889878B8C8286877F80828283858B8C8E9293959D9EA09FA0A2A4A5A7A4A5A7A8A9ABA8A9ABA2A3A5A5A7A6A0A2A1A5A7A68585837A7A786F6F6D61625D6F706B797A7573726E69686456555167666268676271706B
set hex[24]=6E6D6855524D5D544D70655F746965493E3A756B69867C7A938A8589807B988F88A299929D948D8D8680948C89807B787B75775D575952494C594F507569697367676F63636F6363766A6A7C70706F6564564E4C5C545180797381787381786F80766D81776B7D6F626C605065594D91897EA09991A5A29B9B9A969D9D9BA3A5A2959998959796999B9A989A999494929A9A9890918C97969497969297969497969494939192918FB0AFAD7B797C777578716F706D6B6C6E6E6E7474747B7B7B7E7E7E7979797C7C7C8080808383837F81807E807F80827F7D827E797D7E75797A7377787C8081919294A2A3A5A8A9ABA5A6A8A5A6A8A8A9ABAAABADA7A8AAAAABADABACAEA0A1A39FA0A29D9F9E999B9A8F8F8D7C7C7A6F6F6D68686680807E73746F67666262615D605F5B64635F5B5A5565645F6A696458554E776E696F645E786D697B706C7066647268665D544F62595489807B827B759E9791A5A09C9B96938C8887827D817772767C7378867B7F8278797F73737B6F6F7C7070807474857B7A887E7D7D75727D75727F78728178717970676D63595D51456C5E51746757897D6F928A7F9E978F9F9C959F9E9A9F9F9D9698959DA29E9CA09F959A96999B9A9597949C9C9A989896979795959794959593959794959593949492AFAFAD78787A7676787C7C7E767678767676
set hex[25]=7777777072717678777577767D7F7E82848180827F80827F7A7C797378747F84809094959DA3A3A4AAAAAEB4B4AEB2B3ABAFB0AAABADAFB0B2B0B1B3ACADAFACADAFADAEB0AAABADA5A6A8A4A5A7A0A1A39B9D9C9EA09FA0A2A19496957D7F7E7476736A6A687777756D6D6B6464626867636E6D695958535756515F5E5979766F4F48425A514A7168638F8681817873776E695C534E766D685C554F6C646175706C918D8AA4A09F9A9899939194938E928E888C8C83868B82838B8182827877807675897F7D8B817F897F7D8B817F857D7A87807A8178717A70677E7168786C607C6E617063538377698D83779289809B978E9C9992959690989A95979994999B989A9C979999979B9C97989793959593959794959998979998989C9B979998929493AFB1B0747579737476717276757678797A7C7A7B7D767779767A7B7F83847E82816F7372747877878B8A999D9CA8ACABA2A8A6A2A8A89CA2A29DA3A3A8AEAEAAAEAFAEB2B3B1B2B4A8A9ABADAEB0B2B3B5AAABADADAEB0ACADAFA4A5A7A7A8AAA2A3A5A3A5A4A6A8A7A6A8A7A1A3A29A9C9B8486856A6A6A6D6D6B6E6E6C6868666E6D6962615D64635E65645F5756514F4C45514A426158518C837E69605B7B726D786F6A726964766D6860585577726E66625F7B77766C6A6B87858699979A99979C918C90918B8D928C8E
set hex[26]=938A8B897F7E867C7A8E84828F85838A807E877E79867F797F766F7C72697B71676D61557466595A4A3B776758655848837769877F7277716587837A9393898F908894958F94958F8E8F8995969094938E8E8D8993928E9595939698959395929597949193908D8F8CB6B6B46E7176686C6F6E71765F63665F636674797C64696C6C71746D7275818689A4A9ACA9AFAFA4AAAAAAB0B0A6ACACA7ADADA3A8ABA6ABAEA8ADB0AEB3B6B5B9BCB1B5B8B0B1B5ACADB1AAABADA5A6A8A5A6A8ACADAF9D9EA0A4A5A7AFB0B2AFB0B2A4A5A79B9C9EA0A1A3A5A6A8A5A6A8A4A6A59294937173726D6D6B7777757F7E7A6766627B7873605D583E3B343E3B34403C336A635B6D645D5C534C7469637B706A786F6A8279746D65626E69655F5B58706F6D6A68697270718684878F8D90918F92949091938D8F8E8888857D7B837B788C82808D847F8A837D857E78827974766D667B716871675D5F53474E40335141326454446A5A4A665949837769867F6F6F695D6E6A5E7F7D718A877E87877D96968E95958D918E879B989393908B91908B908F8A9796919695908F8E89898883AFAEA961666A666B6F6A6F737B80847F84888C91958F979AA1A9ACA7AFB2A9B1B4AAB2B4ADB5B7ABB3B5A8B0B2ACB4B6ABB3B5AFB4B7B2B7BAAFB4B7ACB1B4B3B7BAABAFB2ACADB1ACADB1ABACAEA0A1A3
set hex[27]=A1A2A49FA0A2AAABAD97989A9394969E9FA1A5A6A8A7A8AAA7A8AAA4A5A79D9EA09B9C9E9FA1A09D9F9E8282827B7B795F5E5A62615D34312C34312C3C393236332C635F566F6B626760586D645D625751655A54786F6A7F7872847C797A77727773706968667775767371727775787F7D808886878D898A8C868687827F807875807973887F7A887F7A847D777C756F7D746D7C736A72685F5A5046483C303A2C1F5C4C3D5847376858485C4C3C5F5241817565968F7F8A8474857F717875668581767E7C7088857C86837C89867F939089918E87928F888B888189867F8D8A838C8982A9A69F979A9F9C9FA493989CA9AEB2ACB1B5AAAFB3A7ACB0A5AAAEA5AAAEAAAFB3A2AAADA1A9ACA9B1B4AAB2B5A9B1B4A6AEB1B0B5B8ABB0B3AEB3B6ADB2B5ADB1B4AAAEB1B1B2B6A9AAAEABACAEA8A9ABA7A7A9A5A5A79F9FA19B9B9D92929498989AA0A1A39495978E8F919A9B9D9E9FA19A9B9D9C9D9FA0A2A19292926666645D5C58302F2B3B3833716E69504B45605B55524F4679756C716A60776E6562584F52483F797069655E58736B687C79748B87847B7A787C7A7B767475767273837F807874737E7A77807B787F7A767E77717F766F8279727E756E79726A77706879726A716A6061584F5D5349382C2037291C5848394C3B2B5847355A4B38594A37776A59726755827A67
set hex[28]=7E7564837C6A827C6E7B776B6763588E8A8187847B7B786F8989818F8F8783837B89898188878283827DAAA9A484858A8E8F9386898E818588787B80797D8076797E73777A95989D8B8F928D92968D9295888D91797E81787D81999EA192979A999EA1989DA08B90937C8083797D80919296A1A2A69FA0A29697998A8A8C98989A7E7E807E7E808D8D8F8080828586888687898B8C8E898A8C8D8E909B9C9EA0A1A39495978686867373733E3D3B4F4E4A7B78735B58534B46405F5A546360577A776E777066756E64675D54554B424E453E615A52716A646966617874717F7E7A8483817A787978747575717074706D78757078736F79726C797069786F687A716A766D66746D6579726A736C64615A52635A5150483D32281E3024164131224938284F3E2C67564454453261523D7164516B604C776C58746C5978715F857F6F8A8478726E637D7A71726F66706D66898981928F8884847C85857D86867E9C9B96A2A1A6A0A0A289888D9696989E9DA299999BA4A3A89E9EA09C9DA19E9FA19192969495979D9EA29E9FA1A1A2A6979B9E9B9FA29CA1A491959893979A9EA2A5A3A7AAA4A5A9A6A7ABA8A8AA9696989292945A5A5C6D6D6F8787897C7C7E7676787F80829394968E8F9168696B7C7D8187888C88888A8383858888887171716E6D6B7877736D6A653B38336E6963
set hex[29]=49453C615E5576736A766F656D665C5F554B655B514F463D4A433B504943524F4A6E6A67706F6B7B7A78797876797574716D6C75706C75706A716A626F685E71685F726960756C63756C63746D65736C646D6960646057595248292116271F1431271B3225154F3F2F443321564533503F2B55462F6E5F4A61553F6A5E48726753736B58756E5C8882746F6B605F5C53747168716E65514E4568645B807D748380777D7A71A6A39CA09EA1A09EA19F9DA09D9B9E9C9A9D9795989795989B999C9694979292949C9A9DA2A2A4A2A0A3A1A1A39F9DA0A0A0A29FA0A49FA3A6A1A2A6A6A7AB9E9FA39FA0A29D9CA19696988F8D90969497868487918F929A989B9391928684878D8B8C9290938D8D8D9595977D7D7F9191938484868482858886898583847775767D7C7A81807E69656256534E7875703B38316E6B647C79706B675E726B615D544B776F644D443B625B51655E5657524C57544F47443F5854516C68655D5855625D59655E58665F55635B50655D526961546B635870685D726960716A606D665E6B675E5F5B52322E25272016261F152C241936281B4636273C2C1C5748354D3C2A5D4E395D4E3971654F685C466F645079715E7E7765716B5D7B756979756A737165837F74817D7254504757534A7E7A7166635A9D99909E999F9F9AA099949A9C979D9A95999C979B
set hex[30]=999498A09B9FA19D9E9A98999E9A9B9D9B9CA09B9F9E9C9F9D989CA19FA29F9DA09F9DA0A19FA29E9C9F9F9DA0999798989397979394969293928E8F918B8D958F919A94968E888891888B968D8E968D90979191948E90979193898385837D7F8A86878F8B8C8783847F7D7E75737473717267666443424081807E46454164615C7F7C736B685F6460554A463B7871675D574B79736780796F70695F5E5A51433F36504941585149645D57625952554B415A50446057485B524359504162594A675D516F675C6F685E7069615F5B5234312A1C19121D19101D191028211936292035271C4133265144344F3F304F42314D402D6D604D7164518479659A927F9992809993838E887A888576736F636E6A5E807C707F7B70736F646F6B606B675C8D867E9B969C9A959B9A959B938E94999498969195999498989397938F909692939A96979C98999B969AA09B9FA19CA09A95999994989C979B9B969A9C979BA09C9D959192918B8D8781838B8587958F91978E91968D90968D8E988F909C92939C9293998F90958B8C9B929392898A9087889087889690928F898B8985868D898A8B898A7472737B797A504E4F4E4E4E47464466635E726F686F6C65423F364D4940787469747065797569878175696357514B3F655F5351493E6D655A6E655C685E54645A4E75695B615547564A3A
set hex[31]=716557655C4D645A4E625A4F665F555D564C3531281D1A131C191219160F1D1A13261F1731271E3729203E3027483A2F4B3D304B3E2E665948867B678F847288806D9089769D9684A09A8AA29C8C9895868885766F6B5F6D695D817D71726E62766F65726B61A69F97A19CA299949A9C979D9792989D989C9590949A9599989397979394959192908C8D8F8B8C9A95999F9A9E9792969792969896999694979A9599908B8F918D8E908C8D8D87898F898B908A8C938D8F90878A948B8E92898A9A91929A9192948B8C92898A8D848592898A8C8384868080928C8C8F898B8882848985868A8687817F8088868783818288868776747561605E66625F66615D7C7773504B45655E567972687B746A797268736B60443C31766E635B53466E6458675D51766C6070665A6C6256675D51675D516F66576E645861574B5D53475F574C524B413730262521181F1B121D18121C171118130D1D160E241A112B1E153D3027493D314D4133615545807464867B698E82728F8675968F7D9B94849993839C998A989586928F807F7B6F706C60716B5F847E72726B61746D639E978F9D989E959096969197969197969195928D91948F93918C908E8A8B8985869995969995969590949B969A9893979A9599918F929290938C878B8F8A8E9B97989A96979F999B969092948E90928C8E91888B
set hex[32]=948B8E8E85868F8687948B8C938A8B978E8F958C8D938A8B968D8E908A8A9690908F898B928C8E8E8A8B918D8E898788908E8F8785867E7C7D858384837F80817B7B736E6B7F7A7776716D827B758A837B7E776F7972685F574C7A726761594C5A53436E6556766D5C766D5E685F5061574B5951446D635970685B877D73726A5F6C645960574E59524830291F27231A27231A241F1926211B2019131C150D21170E2D2017382B22473A315F53477E7566827668857C6D746B5C888171948D7D948E809A97889996879E9B8C9B98898F8B7F777367716B5F777165847D736962589891899E9CA19B999E9D9BA099979C99979A98969999979A9290939492939B999A9896979391929B999C9E9C9F9391948D8B8E9C9A9B9795969B999A9492939D999A9F9B9C959192938F90938F90928E8F938D8F928C8E918B8D918B8D979193938D8F9B95959C9696969090918B8B9993958C86888985868B87888C88898E8A8B908C8D8D898A9290918B898A8684858C8889969092948B8E887F827D7475776F6D88807D7F78706D665C7A72677E766B63594D766D5E726958776F5C6057465C5342655D526862566259509B9589A39A919F988E827B71756E666B645C50494138312939322A39322A332C24332A232C231C241A111C12082A20164B4137695F5581796C857B6F877F727D7568
set hex[33]=8F897B969082999385928F808A87789C998A9C998A8D877B7F796D6F695D736D617C756B7B746A9B978EA09EA398969B9E9CA19B999EA09EA19391949795989795989290919997989391929B999A979598959396A5A3A69A989B9896979E9C9D9C9A9B9A98999C98999692939F9B9CA09C9D999596938F90938D8F9791939D9799979193999395958F91928C8C9A9494908A8A908A8A9B95979690929490919490919591929995969894958A86878381828B898A908E8F999596A09A9E988F948D84898B8285887F807A72707C756F787169776E65837B707C72666E6556756C5B6B6350635B48726B59726C607F786E7E776D7E7A71A7A098A7A0989790888A837B7F7870625B53524B435047404A413A483F38453C353E352C3C322832281E20160C2B231851493E5950476C635A787167847D738E877D8F887E938D81797569817E6F9A97889491828E887C7771657A7468746E62766F657E776DA29E959C9A9F99979C9C9A9F9C9A9F9F9DA093919494929599979A9593949A98999290919B999A9F9DA09593969A989B9A989B9D9B9C9997989B999A9997989E9C9D9B999A9593949694959894959894959793949B97989B9798938F909591929894959793949B9798928E8F949091918D8E9692938F8B8C8D898A908C8D9A96979591928A8687969293837F80888485908C8D
set hex[34]=8C868A8F898D8D878B837D7F8F898B88828286817E76716D756E68736C6481796E797164807969736C5A746B5A7A7363888177736F6699958C8E8B84ACA7A1A6A19BA39E988D8680958E86645B54584F46554B4251473E5B5148574D4451473E463E33463E333D342B2A231920190F221B13585149767269807C7387837A8A867D8D897E807C70918D819794858C897A8A8478726C607B75697A7468766F65736C62A09C93908E939F9DA29D9BA097959A9391949A989B9593969290939492939795969F9D9E9694958E8C8F929093979598A19FA29997989694959593949896979E9C9D9795969492939391929490919D999A959192938F909591929D999A9A9697949091979394928E8F9B9798969293949091969293979394969293999596A19D9E9692938C88898B8788908C8D8985868B8788938E92959096918B8F8782868D8789858182837D7D8984817E7975726B657D766E7870657D756A7F776A7871616E66597F7B707E7B748B88819E9B96908D88A5A29DA09D989A95918F88826D645D554B42584E455A5047574D445C524960564D5E564B554D42524B414F483E403931302C232F2A2435302A49443E5B5650746F697D7970868277898579837F738F8C7D787266756F63736D617D776B78716770695FA29E9597969B9291968B8A8F95949993939589898B909092
set hex[35]=9090928686868989898C8C8C8E8E8E88888A8A8A8C8B8B8D8C8C8E8886878D8B8C858384878586918F908C8A8B908E8F8E8C8D908E8F908E8F9793949490919591929692939894958F8B8C939192918F90979394949091938F909490918F8B8C908C8D8E8A8B9995968A86878480818B87888D898A908C8D8D898A908B8F89878A8B868A8381848883878785888783848480818B87867D78757E7975787169777068756E64736D61645D5377736A817E7786837EA2A19D9897938B8A868C888597928E827B75554C4550463D5B4E45574A415B4E4560534A5E544A5C54495D574B5E574D5D564C58544B5B5650544F4B504D4836332E3C393254514A6360576864596460546E6A5E686458655F536C6459726C60746E6278716770695F959188B2B1B6ADACB1A6A5AAB0AFB4AEAEB0A4A4A6ABABADABABADA7A7A7ACACACAEAEAEADADADA8A8AAAFAFB1AEAEB0AAAAACA9A7A8AEACADA5A3A4A6A4A5B0AEAFAAA8A9AEACADABA9AAAFADAEA6A4A5ACA8A9B1ADAEB3AFB0AFABACB1ADAEB0ACADB1AFB0B0AEAFB6B2B3B2AEAFB1ADAEB3AFB0AEAAABAEAAABB3AFB0B7B3B4AEAAABAFABACADA9AAABA7A8B0ACADAAA6A7B0AEB1ADABAEAEACAFA8A6A9ABA9ACADABAEACAAADABA9AAB0ACADA6A29FABA6A3A09B95A29B95A49D95A49D93928E839C9791A5A29BA9A8A4BEBDB9B8B8B6
set hex[36]=AAAAA89E9A97B0ABA79D95927E756E82756D8B7E75867970887B728C7F768A807691897E918B7F928B81938C82908B8595908A928F8A95928D94918C93908B908D868D8A818D898089857A908C80949084938B80968E839A94889993879C958B928B81B3AFA6

for /l %%a in (0,1,36) do (
   set "str=X!hex[%%a]!"

   set length=0
   for /L %%b in (10,-1,0) do (
      set /a "length|=1<<%%b"
      for %%c in (!length!) do if "!str:~%%c,1!" equ "" set /a "length&=~1<<%%b"
   )

   set /a "out=length - 6"
   for /l %%b in (0,6,!out!) do (
      set "c=!hex[%%a]:~%%b,6!"
      set /a "r=0x!c:~0,2!", "g=0x!c:~2,2!", "b=0x!c:~4,2!"
      call :to256 !R! !G! !B! C 
      rem <nul set /p "=%ESC%[38;2;!r!;!g!;!b!m█%ESC%[0m"
      <nul set /p "=%esc%[38;5;!C!m█"
   )
)

pause >nul & exit

:to256 R G B return var
	set /A "%4=(((%1)-35)/40+((%1-48)>>8)-((%1-75)>>8))*36 + (((%2)-35)/40+((%2-48)>>8)-((%2-75)>>8))*6 + (((%3)-35)/40+((%3-48)>>8)-((%3-75)>>8)) + 16"
	rem set /a "%4=0xE8+(((0x3FF*((((%1)+(%2)+(%3)+297)&0x400)>>10))|(((%1)+(%2)+(%3)+297)&0x3FF))-306)/30"
goto :eof
whit 216 colors:
Image


only 24 grays:
Image

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: 256 colors in virtual terminal escape sequence

#26 Post by penpen » 25 Apr 2023 18:19

I've replaced the grayscale algorithm, the (unoptimized - but hopefully bug-free) result is the following mapping function:

Code: Select all

:toColorTable R G B return var
:: part 1 (sloppy is sufficient)
	set /a "%4.r1= -(-(%1>>6)>>2), %4.g1= -(-(%2>>6)>>2), %4.b1= -(-(%3>>6)>>2), %4.isDarkGray=%4.r1*%4.g1*%4.b1"
	set /a "%4.index1=(%4.b1<<2) + (%4.g1<<1) + (%4.r1), %4.r1=(%4.r1+(%4.isDarkGray<<1))<<6, %4.g1=(%4.g1+(%4.isDarkGray<<1))<<6, %4.b1=(%4.b1+(%4.isDarkGray<<1))<<6"
	set /a "%4.error1=(%1-%4.r1)*(%1-%4.r1)+(%2-%4.g1)*(%2-%4.g1)+(%3-%4.b1)*(%3-%4.b1)"

:: part 2 (rgb cube of size 6x6x6)
:: buggy	set /a "%4.r2=((%1)-35)/40+((%1-48)>>8)-((%1-74)>>8), %4.g2=((%2)-35)/40+((%2-48)>>8)-((%2-74)>>8), %4.b2=((%3)-35)/40+((%3-48)>>8)-((%3-74)>>8)"
:: bugfixed:
	set /a "%4.r2=(%1-35)/40+((%1-48)>>8)-((%1-75)>>8), %4.g2=(%2-35)/40+((%2-48)>>8)-((%2-75)>>8), %4.b2=(%3-35)/40+((%3-48)>>8)-((%3-75)>>8)"
	set /a "%4.index2=(%4.r2)*36 + (%4.g2)*6 + (%4.b2) + 0x10, %4.r2=55+40*%4.r2+((%4.r2-1)>>3)*55, %4.g2=55+40*%4.g2+((%4.g2-1)>>3)*55, %4.b2=55+40*%4.b2+((%4.b2-1)>>3)*55"
	set /a "%4.error2=(%1-%4.r2)*(%1-%4.r2)+(%2-%4.g2)*(%2-%4.g2)+(%3-%4.b2)*(%3-%4.b2)"

:: part 3 (grayscales)
	set /a "%4.MIN3=-((%22-%11)>>32)*(-((%33-%22)>>32)*%3 - ((%22-%33)>>32)*%2) - ((%11-%22)>>32)*(-((%33-%11)>>32)*%3 - ((%11-%33)>>32)*%1)"
	set /a "%4.MAX3=-((%22-%11)>>32)*(-((%33-%11)>>32)*%1 - ((%11-%33)>>32)*%3) - ((%11-%22)>>32)*(-((%33-%22)>>32)*%2 - ((%22-%33)>>32)*%3)"
	set /a "%4.r3=%4.g3=%4.b3=(%4.MIN3+%4.MAX3)>>1"
	set /a "%4.g3=(((0x3FF*(((%4.r3+%4.g3+%4.b3+297)&0x400)>>10))|((%4.r3+%4.g3+%4.b3+297)&0x3FF))-306)/30"

:: simpler grayscale (in my opinion slightly more off than the above)
::	set /a "%4.g3=(((0x3FF*(((%1+%2+%3+297)&0x400)>>10))|((%1+%2+%3+297)&0x3FF))-306)/30"

	set /a "%4.index3=0xE8+%4.g3, %4.g3=8+10*%4.g3, %4.r3=%4.g3, %4.b3=%4.g3"
	set /a "%4.error3=(%1-%4.g3)*(%1-%4.g3)+(%2-%4.g3)*(%2-%4.g3)+(%3-%4.g3)*(%3-%4.g3)"

:: compute nearest index n [1 : 3]
	set /a "%4.nearest=1-(((%4.error2-%4.error1)|(%4.error3-%4.error1))>>32)-(((%4.error3-%4.error2)&(%4.error3-%4.error1))>>32)"
	set /a "%4=%4.index!%4.nearest!"

::@debug
::	set /a "%4=%4.index1"
::	set /a "%4=%4.index2"
::	set /a "%4=%4.index3"

if true == false (
	echo(%ESC%[38;5;7m
	echo(set /a "%4=%4.index!%4.nearest!"
	echo(R=%1, B=%2, G=%3
	echo(%4.r1=!%4.r1!, %4.g1=!%4.g1!, %4.b1=!%4.b1!,   %4.error1=!%4.error1!
	echo(%4.r2=!%4.r2!, %4.g2=!%4.g2!, %4.b2=!%4.b2!,   %4.error2=!%4.error2!
	echo(%4.r3=!%4.r3!, %4.g3=!%4.g3!, %4.b3=!%4.b3!,   %4.error3=!%4.error3!
	echo(%4=!%4!, %4.nearest=!%4.nearest!, %4.index%nearest%=!%4.index%nearest%!
	echo(
)
goto :eof

penpen

Edit: Just tried the cat with the new mapping; it's has huge amount of gray pixels, i'm not sure the new algorithm is the best either.
Edit: Though maybe linear interpolation might be the culprit (instead of the grayscale algorithm), or maybe the 6x6x6 rgb cube is just too small... .

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#27 Post by einstein1969 » 25 Apr 2023 21:32

This is the cat

Image

look good.

I'm reading the code but I don't understand how you did the function that calculates the distance between colors.

Can you explain?

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: 256 colors in virtual terminal escape sequence

#28 Post by penpen » 26 Apr 2023 07:51

As said above, i assumed linear distances of the colors in RGB-space:
The main advantage is, it is easy to compute, because color distances are just euclidean distances over the coordinates of the RGB colors.
The main issue is, that human perception of color is everything but linear. Typically that is not an issue, as long as we use enough colors to map to. But here we only have 247 different colors (9 doubled), so it has a huge impact; an example is that brownish color in the top right corner of the cat image is mapped to a greenish one, though i'm pretty sure there are better matches for the human eye. Another big issue is, that the human eye isn't a normed tool, so everyone might slightly disagree on which color in a palette is a better match for a specific color.

Since i assumed linearity the distance of two colors c0 := (r0, g0, b0) and c1 := (r1, g1, b1) is the euclidian distance:
|c0-c1| := sqrt((r0-r1)^2 + (g0-g1)^2 + (b0-b1)^2).

If c0 and c1 are neighbours (= have equal coordinates for two color channels), the difference of the two colors is linear:
- case r=r0=r1, g=g0=g1: |c0-c1| := sqrt((r-r)^2 + (g-g)^2 + (b0-b1)^2) = |b0-b1|,
- case r=r0=r1, b=b0=b1: |c0-c1| := sqrt((r-r)^2 + (g0-g1)^2 + (b-b)^2) = |g0-g1|,
- case g=g0=g1, b=b0=b1: |c0-c1| := sqrt((r0-r1)^2 + (g-g)^2 + (b-b)^2) = |r0-r1|,

Since we have an integer encoding and humans typically (only color blinds may disagree) see more color difference in lighter colors, in case the the midpoint beteween two neighbouring colors is a valid coordinate, it is assigned to the color with the longer coordinate vector.


If you want to improve the mapping, we might need to change the color space in which the human experience of colors is more linear (for example HSV), or you could try to model some measured average color experience - though those typically aren't free of charge, so you might better use an average the experience of anyone wanting to participate here (i would be in for that :D ).


penpen

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#29 Post by einstein1969 » 26 Apr 2023 14:13

I'm studying part 2 and I don't understand the part:

Code: Select all

%4.r2=55+40*%4.r2+((%4.r2-1)>>3)*55, %4.g2=55+40*%4.g2+((%4.g2-1)>>3)*55, %4.b2=55+40*%4.b2+((%4.b2-1)>>3)*55"
EDIT: Understood. Returns the color value without using a palette variable.

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: 256 colors in virtual terminal escape sequence

#30 Post by einstein1969 » 26 Apr 2023 15:13

Can you explain what you did here?

Code: Select all

::	set /a "%4.MIN3=-((%22-%11)>>32)*(-((%33-%22)>>32)*%3 - ((%22-%33)>>32)*%2) - ((%11-%22)>>32)*(-((%33-%11)>>32)*%3 - ((%11-%33)>>32)*%1)"
::	set /a "%4.MAX3=-((%22-%11)>>32)*(-((%33-%11)>>32)*%1 - ((%11-%33)>>32)*%3) - ((%11-%22)>>32)*(-((%33-%22)>>32)*%2 - ((%22-%33)>>32)*%3)"
::	set /a "%4.r3=%4.g3=%4.b3=(%4.MIN3+%4.MAX3)>>1"
::	set /a "%4.g3=(((0x3FF*(((%4.r3+%4.g3+%4.b3+297)&0x400)>>10))|((%4.r3+%4.g3+%4.b3+297)&0x3FF))-306)/30"

Post Reply