# Deciphering XKCD colors

Randall Munroe (author of XKCD) held a survey to give names to colors. The main outcome is a list of names for the 954 most common RGB monitor colors.

For ease of programming, here is the list in plain text: http://xkcd.com/color/rgb.txt. Beware, the first line is not data, but contains the license.

Write a program or function that takes a valid color name from above list as input and outputs the associated RGB color code. Your program does not have to handle invalid inputs in any defined manner.

Standard loopholes apply. Additionally, your answer must not use pre-defined (built-in or external) color code <-> color name maps. (This includes the linked list.) Shortest code in bytes wins. If you read from a file, the file's byte count must be included.

Examples:

dark peach -> #de7e5d
robin's egg blue -> #98eff9
pink/purple -> #ef1de7
• Are we allowed to access that file online? – Leaky Nun Aug 17 '16 at 5:18
• @LeakyNun That's a standard loophole. On top of that it's explicitly disallowed in the 4th paragraph of my challenge. – orlp Aug 17 '16 at 5:19
• shit #7f5f00 – Leaky Nun Aug 17 '16 at 5:48
• bubble gum pink #ff69af, bubblegum pink #fe83cc – Leaky Nun Aug 17 '16 at 6:40
• @LeakyNun The first is the color of really sick swollen gums, the second is the color of a type of candy. – Adám Aug 17 '16 at 7:23

# Perl 5 - 42123956 3930

use IO::Uncompress::Gunzip qw(gunzip);

### Usage

echo -n 'baby shit brown' | perl xkcd-colours.pl
• Try compressing your input file with "zopfli --i100 " instead of gzip. It'll still be readable as a gzipped file. – Glenn Randers-Pehrson Aug 17 '16 at 23:40

# Ruby, 12131 12030 + -p = 12033 bytes

Byte count is after replacing <compressed text> with the raw paste data in http://pastebin.com/xQM6EF9Q. (Make sure you get the raw data because of tabs within the file)

I really could shrink the text further but I've been at it for a few hours now and I need to sleep.

Input is a piped-in line from STDIN without a trailing newline. Adding in trailing newline requires +3 bytes by changing ($_+?\t) to (chomp+?\t). i="<compressed text>" %w"Bblu Ddeep_ R*ight_ N*own Yyellow Tdirt Kdark Ldull_ Sdu} Qdusk Ee]ctric_ Ffaded_ G|een Iish A|ey Hlight Oor{g Ppa]_ Upurpl Cred Vvery_ -pink %ros ~sea .pea @egg ^burnt_ &baby ,poo =tea !t{ Mmedium_$pa}el_ ;mud aqua ?s{d >neon_ <lavend :gold +lime |gr ]le [mon }st {an *br".map{|x|i.gsub!x[0],x[1,99]}
$_=i.tr(?_,' ').lines.find{|s|($_+?\t)[/^#{s[/[^#]+/]}/]}[/#.*/]

# BASH + bzip2, 80586809 6797 bytes

bunzip2 -c c|tr -d "\t"|grep -F "$1#"|cut -d "${1: -1}" -f2

Stored the original list to a file after compressing it, not sure if this is allowed.

Call with:

sh ./colors.sh "shit"
#2a0134

# C, 19,566 bytes

A miserable 19,566 bytes.

#include <stdio.h>
int main(int argc,char **argv){int m=0;char *t=argv[1];int c=0;while(c!=EOF){if(m==1){if(c==10||c==13){printf("\n");m=2;}else{if(c>32)putchar(c);}}if(m==0){if(c==*t){t++;if(*t==0){m=1;printf("%s -> ",argv[1]);}}else{t=argv[1];}}c=getchar();}}

Bog-standard C. The rgb.txt file is piped in through stdin. The colour to find is given as the first argument.

So:

./xkcd "bright sea green" < colors.txt

Gives:

bright sea green -> #05ffa6

• Please read the 4th paragraph of my challenge. – orlp Aug 17 '16 at 11:11
• Welcome to code golf! Unfortunately the rules state that if you read from a file (or in this case, pipe it in) you need to include the byte count of the file as well. Kolmogorov Complexity questions are all about shrinking big data. – Value Ink Aug 17 '16 at 11:12
• Oh, I geddit. Hmm... – ncke Aug 17 '16 at 11:20

# Java, 7,978 7,435 bytes

Code is 293 bytes, data is 7,142 bytes

Golfed:

Object f(String k)throws Exception{Map c=new HashMap();ObjectInputStream i=new ObjectInputStream(new GZIPInputStream(new FileInputStream("c")));for(int j=0;++j<950;){c.put(i.readInt(),i.readInt());}String s=Integer.toHexString((int)c.get(k.hashCode()));while(s.length()<6)s="0"+s;return"#"+s;}

Ungolfed:

public class DecipheringXkcdColors {

public static void main(String[] args) {
Map<String, String> testData = new HashMap<>();
testData.put("light moss green", "#a6c875");
testData.put("straw", "#fcf679");
testData.put("dark fuchsia", "#9d0759");
testData.put("custard", "#fffd78");
testData.put("purple", "#7e1e9c");
try {
for (Map.Entry<String, String> data : testData.entrySet()) {
System.out.println("Key -> " + data.getKey());
System.out.println("Expected -> " + data.getValue());
System.out.print("Actual   -> ");
System.out.println(new DecipheringXkcdColors().f(data.getKey()));
System.out.println();
}
}
catch (Exception ex) {
ex.printStackTrace();
}
}

// Begin golf
Object f(String k) throws Exception {
Map c = new HashMap();
ObjectInputStream i = new ObjectInputStream(new GZIPInputStream(new FileInputStream("c")));
for (int j = 0; ++j < 950;) {
}
String s = Integer.toHexString((int) c.get(k.hashCode()));
while (s.length() < 6)
s = "0" + s;
return "#" + s;
}
// End golf

}

The file named "c" in the program is the result of the inverse operation of this program: take the hash code of each key in the input file and store it with the integer representation of the color value. That goes into an object output stream, a GZip output stream, then a file output stream. This program reads it through the inverse input streams.

The default Java hash codes of all the colors are unique across this data set, so it makes a good 32 bit key in the hash map. The value is already an integer, so all that needs to be done is to format it correctly as a hex string, padded to six digits if necessary, with a hash mark in front.

• I tried various compression techniques as well as custom hashes, but nothing I tried could beat the built-in functionality in Java. – user18932 Aug 19 '16 at 1:31
• I'd like to thank you for giving a nice simple example how to use GZIPInputStream :-) – Tschallacka Aug 19 '16 at 10:07

## Java, 4649 bytes

Java code : 497 bytes, data file : 4152 bytes

The file can be found here

import java.io.*;import java.util.*;public class A{static void main(String[] a) throws Exception{byte[]d=new byte[4864];new FileInputStream("d").read(d);long h=a[0].hashCode(),k,l,r=0;h=(h&1023)+(h&14336)/2+(h&491520)/4;BitSet b=BitSet.valueOf(d);for(int i=0,j;i<33216;i+=35){for(l=0,j=16;j>=0;){l<<=1;if(b.get(i+j--))l|=1;}r+=b.get(i+33)?1:0;r+=b.get(i+34)?2:0;if(l==h){for(k=0,j=15;j>=0;){k<<=1;if(b.get(i+17+j--))k|=1;}System.out.println("#"+String.format("%06X",(k<<8)+r).toLowerCase());}}}}

ungolfed:

import java.io.*;
import java.util.*;

public class A{
public static void main(String[] a) throws Exception{
byte[]d=new byte[4864];
// compute word hashcode
long h=a[0].hashCode(),k,l,r=0;
h=(h&1023)+(h&14336)/2+(h&491520)/4;
BitSet b=BitSet.valueOf(d);
// browse data file
for(int i=0,j;i<33216;i+=35){
for(l=0,j=16;j>=0;){
l<<=1;
if(b.get(i+j--))l|=1;
}
// compute color blue component
r+=b.get(i+33)?1:0;
r+=b.get(i+34)?2:0;
// do hashcode match ?
if(l==h){
// compute color value
for(k=0,j=15;j>=0;){
k<<=1;
if(b.get(i+17+j--))k|=1;
}
System.out.println("#"+String.format("%06X",(k<<8)+r).toLowerCase());
}
}
}
}

The program uses an improved version of Java hashcode that uses only 17 bits:

long hash = s.hashCode();
long hash2 = hash & 0b1111111111;
hash2 += (hash & 0b11100000000000) / 2;
hash2 += (hash & 0b1111000000000000000) / 4;

Colors are sorted by blue component increasing. They are stored on 18 bits: 8 for red, 8 for green and 2 for delta blue.

Total file size: 949 colors * (18 + 17) = 33 215 = 4152 bytes

# JavaScript (Node.js), 10785 bytes

q=>${require('zlib').inflateRawSync(new Buffer('<encoded data>','base64'))}.split(';').map(x=>x.split(':')).find(([a])=>a===q)[1] Usage: const f = q=>${require('zlib').inflateRawSync(new Buffer('<encoded data>','base64'))}.split(';').map(x=>x.split(':')).find(([a])=>a===q)[1]

# MATLAB, 94 + 7.243 = 7.337 bytes

Generate the MAT-file "h.mat" with variable "c" containing a sorted list of the CRC32 checksums of the names ( c=java.util.zip.CRC32;c.update(uint8(x));c.getValue();) and the same sorted list of the converted hex codes of the colors ( sscanf(x(:,end),'%x') ) as "e". This should have (R2013b, v7 File format, a size of 7.243 bytes.

The function is as follows

It takes advantage of the builtin compression of the MAT-files and the support of java for the CRC32 function.

# Go, 6709 bytes

Code is 404 bytes, data is 6305 bytes

package main
import ("bytes"
"compress/flate"
"fmt"
"os")
func main(){t:=make([]byte,6643)
i:=os.Args[1]
copy(t,i)
s:=[]byte{byte(len(i))<<4|t[0]>>1&8|t[0]&7,t[1]&6<<5|t[2]&30|t[3]>>2&1,t[3]<<7|t[4]&1<<3|t[5]&20|t[6]&6<<4|t[7]&3,t[8]&3|t[9]&1<<3|t[10]&1<<4|t[11]&1<<5|t[12]&4}
f,_:=os.Open("f")
for i:=0;;i+=7{
if bytes.Equal(s,t[i:i+4]){fmt.Printf("#%X", t[i+4:i+7])
return}}}

The Data is encoded with xxd -p. Extract into a file simply named f with xxd -r paste f. The code can be ran as go run file.go "tree green"

## C#, 6422 bytes

Code is 575 bytes, data is 5847 bytes

The data exists in an adjacent GZipped file which contains a transformed representation of the original data. Color words which appear more than once are extracted and placed in a header table at the top of the file, prefixed by a one-byte length.

Data entries (after the header) consist of a set of:

1. Single byte entries representing a common word from the header table (value equals array offset + 16)
2. Inline string data prefixed by a single-byte length field (max length 15)

Each entry is terminated with either 0xFF, 0xFE, 0xFD which indicates that the next one, two, or three bytes following represent the color value offset, respectively.

The table is parsed in-order and color value is accumulated until a matching string to the input is found.

Minified Decompression / Lookup Code:

using System;using System.IO;using System.IO.Compression;namespace G{partial class P{static void Main(string[]a){var f=new GZipStream(File.OpenRead("m"),CompressionMode.Decompress);var b=new BinaryReader(f,S.Encoding.GetEncoding(1252));Func<int>r=()=>f.ReadByte();var d=new string[256];int t,v=0;while(""!=(d[v++]=new string(b.ReadChars(r()))));var k="";v=0;while(0<(t=r())){if(t<0xFD)k+=(t<16?new string(b.ReadChars(t)):d[t-16])+" ";else{v+=t==0xFF?r():t==0xFE?b.ReadUInt16():(r())+(b.ReadUInt16()<<8);if(k.Trim()==a[0]){Console.WriteLine($"#{v:x6}");return;}k="";}}}}} Data Compression Code public static void Compress(string path) { var lines = File.ReadAllLines(path); var grams = new Dictionary<string, int>(); var data = new Dictionary<string, string>(); foreach (var line in lines) { var tokens = line.Split('\t'); data[tokens[0]] = tokens[1]; foreach (var gram in tokens[0].Split(' ')) { int count; if (grams.TryGetValue(gram, out count)) { grams[gram] = count + 1; } else { grams[gram] = 1; } } } var dict = new Dictionary<string, byte>(); byte codeValue = 0; foreach (var result in grams.OrderBy(kvp => -kvp.Value)) { if (result.Value == 1) break; dict[result.Key] = codeValue; codeValue++; } using (var outputData = new BinaryWriter(File.OpenWrite("m.dat"), Encoding.GetEncoding(1252))) { foreach(var dictValue in dict.OrderBy(kvp => kvp.Value)) { outputData.Write((byte)dictValue.Key.Length); outputData.Write(dictValue.Key.ToCharArray()); } outputData.Write('\0'); int currentColor = 0; foreach (var entry in data.OrderBy(kvp => kvp.Value)) { foreach (var gram in entry.Key.Split(' ')) { if (dict.ContainsKey(gram)) { outputData.Write((byte)(dict[gram] + 16)); } else { outputData.Write((byte)gram.Length); outputData.Write(gram.ToCharArray()); } } var colorValueString = entry.Value.TrimStart('#'); var colorValueInt = int.Parse(colorValueString, System.Globalization.NumberStyles.AllowHexSpecifier); var colorValueDiff = colorValueInt - currentColor; if(colorValueDiff <= byte.MaxValue) { outputData.Write((byte)0xFF); outputData.Write((byte)colorValueDiff); } else if(colorValueDiff <= ushort.MaxValue) { outputData.Write((byte)0xFE); outputData.Write((ushort)colorValueDiff); } else { outputData.Write((byte)0xFD); outputData.Write(colorValueDiff); outputData.BaseStream.Seek(-1, SeekOrigin.Current); } currentColor = colorValueInt; } } var d = File.ReadAllBytes("m.dat"); var g = new GZipStream(File.OpenWrite("m"), CompressionLevel.Optimal); g.Write(d, 0, d.Length); g.Dispose(); } # C# 7,209 bytes: 6,643 bytes data + 566 bytes code (878 bytes unminimized) Github repo is here: https://github.com/nbcarey/color-map Color names are compressed in the data file using the FNV-32-1a hash as this hash algorithm is conventiently collision-free for this set of color names. So each color name is stored as 4 bytes. Each color is stored as 3 bytes (1 each for red, green and blue). No magic there. Consequently, each mapping of color name to RGV value occupies 7 bytes in the compressed file. This is a one-line version of the FNV-32-1a hash (assuming a string containing only simple ASCII characters: uint hash = Encoding.ASCII.GetBytes("royal blue") .Aggregate(0x811c9dc5u, (h,b)=> h=(h^b)*0x01000193u ) ; This compressed data file is in the github repo at https://github.com/nbcarey/color-map/blob/master/color-map/hashed-color-map.dat Here's the minimized code: using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Text;namespace A{class B{static void Main(string[]C){var D = new Dictionary<uint,uint>();var E=File.ReadAllBytes("hashed-color-map.dat");for(int i=0;i<E.Length;i+=7){uint F=BitConverter.ToUInt32(E,i);uint G =(uint)(E[i+4]<<16|E[i+5]<<8|E[i+6]);D.Add(F,G);}foreach(var H in C){uint I;var J=D.TryGetValue(Encoding.ASCII.GetBytes(H).Aggregate(0x811c9dc5u,(h,b)=>h=(h^b)*0x01000193u),out I);var c=J?String.Format("#{0:X6}",I):"NOT FOUND";Console.WriteLine("{0}: {1}",c,H);}}}} And here's human-readable code: using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace color_map { class Program { static void Main( string[] args ) { var map = new Dictionary<uint,uint>(); var data = File.ReadAllBytes("hashed-color-map.dat"); for ( int i = 0 ; i < data.Length ; i += 7 ) { uint hash = BitConverter.ToUInt32(data,i); uint rgb = (uint)( data[i+4] << 16 | data[i+5] << 8 | data[i+6] << 0 ); map.Add(hash,rgb); } foreach (var cn in args ) { uint rgb; var hit = map.TryGetValue(Encoding.ASCII.GetBytes(cn).Aggregate(0x811c9dc5u, (h,b)=> h=(h^b)*0x01000193u ), out rgb); var c = hit ? String.Format("#{0:X6}",rgb) : "NOT FOUND"; Console.WriteLine("{0}: {1}", c , cn); } } } } # PHP, 5014 bytes Not the best there is but it's late and I need to get some sleep. :-) The beauty of PHP is that you can inline payload data into your script and read the file itself, so the script is self-sufficient. Just download it, run it and it will prompt for the color name. <?$f=fopen(__FILE__,r);fseek($f,269);$m=stream_get_contents($f);while($l<4745){$d.=str_pad(dechex(ord($m{$l++})),2,0);}$h=sha1(trim(fgets(STDIN)));$k=substr($h,0,3).$h{16};for($i=0;$i<9490;$i+=10){if($k==substr($d,$i,4)){echo'#'.substr($d,$i+4,6);}};__HALT_COMPILER();$¥¬ÂÙóûV®W}a²™nÂÀ¨ÿÄ°iØOûO‰E…&@p²? xÔÿÿuAe«|Šü•.¤üüÁÿ¥£‘F²8€?šL…8^›Šlï´5m‘Ù›‚´
[...MORE BINARY DATA...]

The basic trick here is to hash the color names and generate minimally identifying substrings of that hash. I found that 4 chars of a SHA1 hash are enough, the first 3 and the 17th to uniquely identify all those colors. The key is in binary as well as the color code, which is conveniently one byte per color channel. So every entry takes up 5 bytes, which makes for 5 x 949 = 4745 bytes payload (the magic number you see in the code).

Compression didn't help very much, bzip2, LZMA all created bigger files so without any further tricks, this is as compressed as it goes for this approach.

# Bash + (coreutils,gzip,xxd,openssl,sed,grep), 4946 bytes

data: 4482 bytes, code: 464 bytes

s=$(echo$1|openssl dgst -md5 -binary|base64|cut -c3,10,19)
f=$(gzip -cd g) a='' function p { q=$(grep -Eo "[$1]{[A-Za-z0-9/+]+}"<<<$f|sed -r "s/([$1]\{|\})//g") for i in seq 1 6${#q};do
n="$1$(cut -c$i-$((i+1))<<<$q)" c="$(echo -n $(echo$q|cut -c$((i+2))-$((i+5)))|base64 -d|xxd -p)"
a="$n#$c,$a" done } p$(echo $s|cut -c1) s=$(sed -r 's~([+/])~[\1]~g'<<<$s) r=$(echo $a|grep -Eo ",?$s#[a-z0-9]+")
if [ ${#r} -gt 0 ];then echo -n '#' echo$r|cut -d\# -f 2
fi

Data can be found in base64 here. I know that code may be more golfed. Too sleepy now :/ Any suggestions are welcome :-)

## Explanation

Here are the actions I made on the original file after removing the license comment.

1. Calculate the binary md5 of the color names and turned it in base64: openssl dgst -md5 -binary|base64
2. Found that the characters 3, 10 and 19 may be used to represent uniquely all the entries. base64 uses a set of 64 characters to represent the data, A-Za-z0-9+/. So, I was hoping to find 2 bytes because all the entries were 494 and 64*64=4096 but I couldn't find any. I also tried to find 2-char unique entries by using sha512 in step one but without any luck. So, I stayed with these 3 bytes for the color names.
3. I represented in base64 the color names instead of hex: (echo '0:';echo -n "$line"|cut -d '#' -f 2)|xxd -rp -l 16|base64 4. I grouped the results by the first byte from step 2. 5. I used zopfli -i1000 to compress the file. So the result file before the compression would look like that: +{wf/7FtHhPAAIgWXKwtrpFbAaS6/i9KYk7cj//bpvuy9zvOysmxxvz//6vBP+m2sZFuXG+EgcIhZY1tsTAYif5s1f//xCFS7/}/{61snE90JK69qWKBIJDy83YXXE4df1jNx+XMGQA/60B1Msf9lKaAAEzLs+1WB}0{uiBWlrhIdJVRGSMr+ERZ78D+m2Tv1USQpL5cS3wcb8Hmj/+fZMa6NTEUwrcJqRvv1z+k2VRNvy/7GavV/5qKCTlFaMk5/3lsisUWVy2lraWH3nuaKBdb/+Nu}... I tried other compression utilities also but with worst results except from zopfli -i0000 --zlib with 4470 bytes and zopfli -i10000 --defalte with 4464 but I was not sure how to uncompress there formats. In order to find the color code I do the reverse actions. I create the 3 character code from the given name and I reconstruct partially the original color codes. For example for adobe I create all that start with X: Xqy#bd6c48 XL7#7ea07a XI4#3a18b1 ... Then I grep the Xqy line and return the second part which is the color hex. I really enjoyed this puzzle and there are many great answers here. Thanks and good job everyone! # Bash + coreutils/xxd, 4064 bytes Data 3796 bytes (hex dump of data file) Bash 268 bytes h=md5sum<<<$1|xxd -r -p|xxd -b -g0 -l128 -c128|cut -c18,20,26,41,46,49,65,85,88,90,94,95,118,135;case $1 in mud|aqua?blue)h=0${h%0};;esac;xxd -b -g4 -c4 d|while read -r x;do let b+=2#${x:23:2};case${x:9:14} in $h)printf '#%04x%02x\n'$((2#${x:25:16}))$b;;esac;done

Ungolfed

# Set h to select 14 bits from the md5sum in base 2
h=md5sum<<<$1 | \ xxd -r -p|xxd -b -g0 -l128 -c128|cut -c18,20,26,41,46,49,65,85,88,90,94,95,118,135 # Disambiguate hash collisions case$1 in
mud|aqua?blue)
h=0${h%0} ;; esac # process each 32-bit record: # First 14 bits are hash # Next 2 bits are blue deltas # Final 16 bits rg xxd -b -g4 -c4 d | \ while read -r x; do let b+=2#${x:23:2};
case ${x:9:14} in$h)
printf '#%04x%02x\n' $((2#${x:25:16})) $b ;; esac; done The overall idea is to scan through 32-bit fields, find the matching unique 14-bit hash, and print the color code at that location. The 18-bit color encoding leverages Super Chafouin's approach. The unique 14-bit hash starts with a subset of 14 of the bits from the 128-bit md5sum. To find those bits I used a genetic algorithm coded in C++ here. The code pre-loads a fixed file called "data", which is just the md5sum's, one per line, in binary. If you need that in recipe form, this will create the data file: (cut -f1 rgb.txt|while read x; do md5sum<<<$x | xxd -r -p | xxd -b -g16 -c16| cut -d' ' -f 2;done) > data

I find the best candidate 14 bits (that I've seen so far) from this code in generation 2, but this set has two collisions. Specifically: "mud" and "pale purple" map to the same value, and "aqua blue" and "light green" map to the same value. Since there are only two collisions and I haven't found anything better, I just disambiguate them; turns out half of each of these bucket values is unused.

I already tried compression on d; but neither bzip2, nor gzip, nor xz appears to shrink d's size.

# Groovy, 153 + 10,697 = 10,850 253 + 9870 = 10,123 bytes

I decided I wanted a solution which involved only one file, so (at the obvious cost of space) I encoded a GZIPped CSV version of the data to Unicode characters 0x0020-0x007E (which I guess would be a base 95 encoding?). The code is 253 characters, the content of the String is 10123 characters.

import java.util.zip.*
t=0
'''^/3"O:<]NULAydP{|dgMn0T4;4&Y!~0=(BsILP$#KxAoQ<C6Z-.Psh/}k3&uOEa[S}R+u4=X*K?X&zTKSQT>xdA-_XEy2/e{N$Ue:DSF- *Df1E3x)i=cq;FFq]|p,!sbQpE5F}$qr]zu'jK&A^\\Vd9"sKPgF_^uv>q)6#/"b1#gR"yvZ#<p9{T+__!fl\\\\=7P{zO0('G R+5QKuX}( ,r$V]" ;G)\\3Yooo}<)%HrxnFWLtG1Dwe!N Nz*u;TiTI}ly@T.zA!Lx{w#e0[:Y@feo,=^M|D7qwZLHz2Hss&:z!%W2s|1S%TK]MaH]$KzQGR=*uue5O{d~J{%hU+[0_2z&|iiw )\\aq?(5:~l_u%6U^,&V&N$1YoYUX]E%}TMN=/#KA?@['=]c|l?=!S9v,S|1]2do8cx>QWA]+ nMK_YDa~TdM+Ot4v[Ty\\){}zl0FG2cF**j'tN<g@>^ s='jDcXj|j],2P:p>3_V4$ybMXP?|7D4+W{Mmtsbs#S\\eZH!BUj.1_{@k/YPKe"D2yJ7!~T8A*o3z1e_hvsd[,^k8>~{>/EUQo#:v>=dO$mkyyl+E[*@C1Adym8-cMYRjY IVxTzu@@Z^ V,&9zO_?P*j~F~t&XPj*pQyH4[b0ob1JB@?X&_vGPx$Y.\\h6.!d+CY-=w~IJ*)8&Q;HW"cv#]@tw0A\\uX@+{a"?PjvOF.{l])Z5&pV&]r*4f|Fr &fcnW)6|==t7"TqXeEK6vfyGU)$xqP6c#snqwBYt}0|ayy~o]CUd',>fva~1OC1p5@,k0aJy,!BkF1yGe@qVF-T12bdE~6m420Zc [v|:w~l_[ZPq<*G?DA}~H<lJ 7y"c@Yq8JtFz#uur*E]dxbt:%mXdc}>%Mvg^^qL603|~@DdqWp]e6R9J?\\4Il/"v|tZXo\\8EtW^t.+~TcSK9T{ymny=KOD[,coYoh5eg~Uge(_N08w5HxP-BV\\E%Rajr\\K3RE{eP^c#QYEU6%|].W&_-nX=d| _i:S,CAlaCquAjtKfCNV~$r7sU)4BN*@'3=MoM&kxWzQvOeW$\\gM(\\&d=1y(D'cF=;O!Q.noW'k1u(Kmalk:xNFl,H)o3rlcS\\VcYMIcB.08,*3kQi~g9Y!>'<#KtJp]c5J|~U8j!\\>!0L<=0W(Xg<QF\\EA[~N-t/k 07 ]YPyYT(u|tJ3(=Wle~o3i6Z{pg)qWiMh=K1Ny]IJN^%O -.%L?>:fkbo7bLj +Xr{L|B*hq\\,$3m(nz+:U:fq5BpQz9Qznlu2h6\\9#>00Z%gb?AmJ]9$XTSM|]ZeKRXIE$Xd2MGDqzZ M9m7K8*ZlX1W"A"H+H9h3 YZscB.<l-YNe;NbuvGlq3@:xrA#:o@.6IqM+#b.eg|k/CDiW[JPU~7E$o5O1Q.7F:8sF7!~:$Mh1:sm%_#Q@>86;*-kZs1PdLb^,>zh\\[,>n7Ve;6+#yvTcJEm,RUnZ4pP7*PED\\AMX9$m}K>-x&faPz[=ho?|%rrF@>!RYH)F(#L"v$?g:[19\\"M[O8vGOXP>4k CLt^$2,rf<gd?dw~K6w;|+u'Z6W+<qfq%ShD?.Q(ya<wXc:PdrP4c7R%=%#7#s^v"Pe^:AVTgt\\)O^J%ZWXGZcZ(5ay@\\SXFE.7a/p/?8^6Iu]{-=kTNQ[~uTru~}[]&hka2nt)~CwaCfhG~[:=>}OZ?TA)dP*CDC7C|VVUX@b5SW#7RNy~7i63>={*U3=@qz*+=R$4?[3yTTM0;i=u%#wSOZe87w*.{5m>q1ZmV1$DuBUJD_R7B>H)*o2b(_|%JHT.+8d1fdc yG(BaG8!]*:7_@&u#goQ^K0P%Jp!hbFk}!jaYpa(:e%k[ r&sm~Dn-S@V[ZH9U=b#,Ur04-Da;9JnUslwvf3CqmD9O5LTd5q4,K8*CjzjA/|/D9L\\|#[\\Z)gUhi](S=VaU*FBu4m{N\\'CcUw!Qf+#Y8^0v=gf2F1\\i2kb=kv{*'7Yf%\\Pi4)+;3v'^#F}S-Dr)x9?UB<m7KOn<rjU30")%4{p_<fCb!D=0# Q-rhI\\^~Rx+2CUXB/:CpYWwwk}*u<J/h-\\V^!EgfjKt<z8Ra*3{Oe0;:-+'$Z0(_nP|8Z]Gm4zJO!bu9[znH_05V1*1\\7"Q#S.ZtV\\FCS|'OJ#qHRQP>P4$<(E6W%zE&+LCqFe8%pBy6+jrk<VfFVu5WZA}vK_{n>:f]Rg}@}yT89CS1J\\xgvl:+>mCac+V@fnTXY,6pg/Vk$N WXsq]U{Y:A01pTx6$W8+fqn,XAS[i{F:7~uX5Z-\\C-u/zDa1,A-\\?#SQ@(I{poNrX~/7Dm+Fp0A4uPS\\#+!ex+\\K0A/N*jAJJP~C_B(.+CIx=!'@'|n.w5T3KcD;(*O)#@YJA$<;K*G-k?PW?{tIF8GUJjWtF|GVAp/3V'k&ehk~ibSVg'SSB}eVxRbSS=3;'o/=1@OY<s"6Y;'&6"J]Dtq}UM_<xN1dD$k~),^~Wb003~QFep1L @_pL<vp6_pNIaHQ*PO&5!-EEkFyt&;Hd"uBULxUY+xY:F}>zTH( YYzQh+Qi0x9~'.i,47@2Ar kVL{$[);#2+_9L[ooa=.QtBPO-T3H@M[\\k^E"qS0/~f2@q}B>.r|B{DnXkcj5Bl}'q4%w<J)q=-?g5N0 r(z8CWe:ssf}PO&gd4F$~w5'LbIiXH:f4}0/0+#n@js#0+qhApQ\\&{rK@F8=K6xqgETEL(G{Iu+?)kWMWjSZp}pP6TnF$[&~0caL.HM5cm+mJ;"<ld<'m2@.~j_[pQ6PaVK^XZ/,|.z,XXBwt;\\Ug%bHv8K-5#)#?"4-u]58SBXM@j^wv- EH!bz8Xnq@3309@:5|jd6{jff$e$nM0JW%A~a+?tMb~'a\\5<V=f$l-6Rqa4.4LnK;sjQ"^w?}gWl%G$nir3S7YO ysDwTfOHOF:_*A-gF4{)qL:hNUXW6Z<Ohxqf<)rJ|8X{#rCn:r8yN+xv5}<<[mM<<,N2+4~r,Y #s&o>-*03z'\\+:CA4%/HQVTH-!;e{UUMgtm!)"si-)W2$~~S+*W0ws QP_5U<W{"IceL?FQn[b(FjkRD0EBc,y>$5(C.C?xKX5Qdr"mwoH\\gTX[yuOk"M.b6<O|HOClKKOS *5jkJH&riCIGRc=$NP}#4kUUs3<'x)D[.u-%{) Hx7Oj(c;qzosHGk,$n[pRw[<b8D>|50XT@}h^Bn 9SRR}GsL1@K=F!%H&f!ENNQ1)U;0j9iJoJ%n&Sb5w3@ehvdCpk([ yM(t34_a9Z}{WUoRTEfE!bG!"QTURfSZHh~l<k*1cX\\,\\_ {dA.VdD{sMj,M18-{Jswd"jr4/721>g8J,q!883SQ6p3]LYDrJoF'{:g1TS4m%b5!b6i[fbAQQbbu3{J's&rt)N>.WkpH3I}UFwd~~[}Xi;-hl))0rRw~|:Gcc#+HXdA}o[="E$CKEF'/VD_L4ipRF'@S@3vS&Zk6[v~s/-=Qsli-2C893?>?]p)=:&-EAbrhLx~x<T&y5BwSu(_p@!\\NSKdX70U<-t*}K-<)g>)A s?x9}t<:RWHQT2aU[(M}pWY\\:<s>*+9L_2XR~9-$Py)>}&qbQ5ZV%!5[QQpLNiV^}F]J3<BAIJ6E+/Of$_B)q7X)>u}W^:b(>?_|iG ZnBNVe[eGapt t!qROz'M6Os(.led}wtz1wDi}^TM6yC+y~Se8^#@, @ZNB^jEY<dI;".UhkVZfeVJB4J+Fg1t6Qgcio7@fvng:s_W&*D/rP SsYErf6;xlF&}&:5[RMv7=+;|!n>gsLq,A<LkK/R7*#cnpRb:Oq(iM7Z}:#|TzD{6:Q\\[y;zA.tO=NX9X=veF"Hvg["oAItX7exbJ_D@5@QY4)s9*TK!3Umkk>T)Wuu~p[!j1j"'"gN.6_Uslo(Z>#m<Wr%Gg>>/+xA- 8NQBeYLd{#}pk"+Ll[=W":)c^3:WV)>3mS1!v]/XytHGG:v<V0rIm7]Gb>H,m'D3A<xV+8YB?4k@L(n$WV\\>P5%Ur!|CcYJ3O^x!*)btz-T+oLO{e{tjKD==rG"6fI_nF1n~a>nqqf1WQRvR+8]QIOIMjY=TJ9dK:7[bf:E%h1d}h<Nj[(;olGs)Z>'nJEqNh4p|<yXlYr%'CrF8JWTo)d2HklsDkOv/($ y~UOTta?4k2U^]a\\6IK'dm'#3XHY ]V0)iJNV^3<]*4)pw/Mns_/WuGnRsKSvZjgZDX<lg/u:fli{2k$%qt*nP6v? I~tdyN>@7,D@m$vIH2dr-pLp[}]<nmS(//Y0IMi>{"3F-XmnN92L \\ZY}1;y% ac^(Kz$PVK+#-@1*;]~;l)VvHGC?1IbvqXe4K7(ZY;^)~S&5{L\\bQRs}Fmi6h@s0^b7"zof?IAi.iXOud9IxsCb}zGX/s3HUg?;1e.a\\/jCqP~K8Y#7v6+"6S ?e.pF<B,LO,~"]Y;(LL G}Y@H/k4F6hcuk8LjOOh6kJZ[Sd uo#U>j[i<\\;uR3B1*"JJ"kD(8a9l!}CQ|L'8oVP>{<jfw+'[m'pR.6%aF!>LcqMC$I,l7w~y,8BM<e=iB|(pDDJVei'zOPrSTI]ditp}Zl<\\Nn\\y9r$jA;I?l[/"u\\2\\v]"0rU7wwQ!62}f}? MWt|#HNP1((]]Lz!pBY[MG{0lN H5[v3T)RT6eGfRL_auwOWhgW2[Fca_K/ qz0Xryc=!, bGLI9:t#-] -nEDf0#MULimVVwKVn~{RH6f$97E3*L?0n^tQnt.uKOVO9/iQ#oN3%"HNIT/QN~jtt7HH-!f2<|3O4[|f8Pj_/,V7':O5i0>f%!X[nR*+^6GO=6.y@x'MllbrmIiQlKBIErOv4Mp!<;Bxv,l:DslO>IbZNfB<*/[R9F\\A@u1 _"e8%54cM,dejpP%Q<Kf#;<hfrD;*&wl)KNbt0z5h~6*dwl-eo.x/"gn3zwE<peP1iL77U+FSD!P~D3$ElPS%x,Rfnh&=&n5a27ok@8&I29#(M drb\\d"EiFyNw*ZQ9M@w96iq7Zu*JClp=S$Br5Rr+%n_J/(\\8"87Sa}JTFN&<d=(:KIN\\hW<t]UD>m1 mA3eW&iH<8GL]pN3av|.Z5@@IQdsklji%gLSqzcm5FFM$Lg:\\ib#I&b2:ZJj3w1#B3Ovjtqj<S*R5duR]z@TTGYUKnP)/N<P;Z.R_s,.X,.n~PIV7([sirqhg7B5Vuw8}G3tMq\\gAsvh5R:gybQba'bLW^sbxN/M,BAA,)if/BvPyU_MGNvS^(]k3KQbJk|%H7=B".MlQIP4'2K"^v _'|V!+RWtX+<(sRr~p}/J~Zyxf+kBieZB~(B!/Epp@h6!:|U9Ak}LG6=9xoD'TuiP *M$Mr6w}Q;q~ >MZ(N^YqllEQM$Q,: dc==/YKJ#qDdHNO^zu%?'7BEo*xa%S*X!vcLKc$/W KZ@2C?~Dblf\\?C?t@"S5LAQ[5)b3>q{T}'_OOhb+iH$!>HhFgtYJijK@C'Z&g4QVx2\\O>X@,=J#P~2])&|-[M|.qZ5%ya3{,rx%K,Ipvs"jv}0? e_H*CpZwm7}CpcR4/xVz}3/1>5\\p+_>-|aH=Y<k#0+8eMa,JziJ>r qDLJie1nC&}g84{(wH^TL:'\\ + Z<gt1s ^}WxMTRe2.*djV{B}5npS{F'B:k181bV?!]&XkTi%lvZB<S- ?C<EEHO|2Ri,BP(cC[F:x#e,$*D*ZPmuhTk\\G+aFfMV~pT-FKz=fj\\o>-9UY%"|wi4,1DN:Yo80T*D6QL/q(Wu$U,1IfqtGY&iMP)=P,$xaT*2+@V4"PnU$L^t]?,@<}:Jfh?hL}MUa9U1]vVuIUl2'z%l|?Y@u>84e39Z:oH)OxNhnLK&9+"/Q7&$>TR%I';gZ9G-'&F?M}*fy8tiU*ZU=[>K#)Re$GQXju2s1q}l00&U=DvT-s"a+n*TPrx)Bz5})r"Il4^.2U:g|g}&>q4u$WS:]yhEZzt.M%~WYI_,0Sa(Rwe''Mh1ut06[^q,L<\\x[!IS&(~j!xvTAW{DwKhPlUy!$ki]W'tYbO;a\\o>X9%L|gQjX[z0VJz['-GSybY+}3XtxF_%\\q:ufFfQ,SK8FabUCR63}at@.8{G3RAO-%A.?zjxaDnXs!w]--?{Cwi4NX"=,dyLwRf-lO[e8<Uovbd@t$DI*WKO$?c]gDdmB,D6kC@9]I6l fTpk0{=x[6'riqTXL:2~\\iG*]C)%Jx9.vJ{aQ_7>:>)akb),L[-~}!1bcBsh)kz>j"hIM~"(A.S\\/K'uDTMPgX5p wqk<?r;[)2[.vCAV~H$lUS6Gs{KOE.SD<OSD;j^S%yNw4Sku.iKBzIR*c0X|oI3\\)6Xe%&N6?Ex6Y*TW;WSwi DhhqA}:,}kX}~kY}qz}t&,(Lb1[<=4Ha-,91J1+l{"^WQL'0qvY]TdM/h^A"|27N;>5i#Ka"aYpwk|,kV2XS*JP[}zB.iRD_O'>"-DKx6h0 %}qWN)vc#K%WUQ5vTzX7Hq1sE7hg%kAYod~RVM<}&.Ub@ebo6jo>{(y'^R!|^;n!*>h8<P.Q6Zu9?%:Yz&1C>C2mT<U_BN=8=#ds><G>V'W1]C*#zkrp=c/6Z=rMU{dRtU$8]P(2brytf!I Y=c_jh@c8jj>p<lF/Xvh(mKeW P>-qO4KWZbR1o;2M qzPrvAF(Av,dMRpcno#%C_]W9rMrjBCu',glHbB"X.jRbTeu+,Bu/+ R=3e)SYv+bS"3vD2!5;&lgC.3w Q4:IDmY*cyqc$SYee&zl44b<"Uxloy,*XGuZ;]#yMLp;Rp/>2}n||c+Xt,r<T'Nn[Obqjf5B[5Vm()$$qW)ZQzeXa6,N}/=!6klFhRG%>BvhGFcS2]GO8+>k/xp+MHwO!#rDg!KvVWC.!Q:FjC3UTtUt+>yWd#HIEDR>?Qr@V5,_Ts-m;&<cn+q<g^LU'v7?a.c*EM{,9*#re#}9NWqw]|:0ZAjt+^vE50H^Jzi_2"D5Ab\\=gG&f.iuo_RCxcYn%Vs>=pdRp-88D^j}yC^[kT|7v_CrbW&pa_wEWM9de!y(MfL9E1!CNGcXpJqJBXR]OZm6e^XS[cBeK3wvXfAa6eT{+TGq8#Wqp}"L[LHNc>0V0.,rR:2ij{P'/K*Mn^nab%1qXopwh^Nq2LL8}Wx]QV|3'r'M:c/r@aG7_/t/yB=o,++YjUYO+r6Ot~51]+*D"{B9atCfTX'gwT/Men\\.VE}]DtnWFc)P ^2|2l[/leo.{wbme+p7[VK.b'p1A3hkZ@_G^,G*vMAJJ5tKZT nOm(yy&Xoduos0<?^Q8ht&/sXE>{EXcTr.sxH4yrc%553u1/rcm:W^:v;8+g&o1%&c2BVG>X'vdY6lnS;o_T& DIHt]z^vrH>"#).nK/'6n(9TOue~tXcXt)sW57?6>h@jX!VFt16CP3)Sf4~@/kWn>R^-@]8;eW0!3/*bw\\Ao]jsU&2^%ylL@8s+;"+&prh_')Y+{XrgslTC=|mb%|Sk{Lb.uCxW+e8%~=*0KnVyAj;kf)<QSvwoD^"4~ql.7e\\j0k>"\\Zgv%>T3ie{cdd*70 @_~^D].q%=but)A[Q!o1pX&nO+/F{Ks)5[zU8_%iY>r+t@BMy04qwZ8r@j f:j,WIWlx:l*SRbuWBRD_Ep?h*i/Td*>u+XZ~2]!=[}^J)T8F(+%{%#K\\ue|+DNHg!PNZ/8C0V@QH2KF^.nFW26;\\H5-Hg|t-i:z9F@8@{EJ%^og%19;?#~Q_7ZVpQ|]1?,wg?HM)DNr4H]h3qmjZ3(06r+<}0%,B[(3siMPakb90q2(cwqeye9NDfXXFrd#_dh=I]:TaUEo(ItV\\t+NUpygO#|/7l0kx)vND:dhkH)gu;lbn4n(:8'FxY,(CCheT)sm!3k]F4_j1"zXMHd0/0Efuo#yF:i.LjvW^EWU-).]ns"j^u_jB}LF9y9c%MF.:Oai]>_s<KUZaD&k*aNLj}ZUe:@'>O\\7w%VbO|oQ?D?}L"8Y(V*9i\\<A[(3UX/09~+%o7^F'6af78"V^sORba6qiu+yG{2RZ[q7glFA=q1(gFP =8;gkoBZN?{?wx/l!H5w;<*G'+6l=gT8":[LuZ4=Op^X<*0{}7XK>!W_y%y{+dp*S/o.jU\\|z3j+6*y7?yfe<'qTy2NJ%k]ueXBDtA)BLcif;>LF36/TwpMzlGj@7XL/:x3:[DU&x1~"3eRdU[%7|/4rjG#iIBDm"5:x]m 11lp./q5J>-y}Tx.|7B8"g=q\\r)Wa<xsdn3Bm[<y1Wget:SzC9&9A-gU@FT&Or>*Y(8).2<}?-j}gx;+ZTVk.:XVrW*T"N0{S3Y7Ttx6Z]%*3EMG~Wv*Y0tY6pAU161/?u+*t~JyFQzV+|EJe l;H~=-7P-k{t%'jsORGatzeO>FR@V|gnviL,mK Nu6"pR1V.;#q]^Q0 &:lmjhWY<4/?<h4-d^^VQ5SQhh1G~%:9(ws.K*M.F^(XTdq^Y6Jw[0)aA-_3r32lCSz&1)xI<+3R_{I}];:Ldz!=>mI?:Bg)t_>~3J?bV,Wsx(#;t<f?bsf<Uy,>3i6q<q|iZLEVj#F*j-E1 +? FkBC g\\f.Jo7F)=c";crn!p>H:F1*Q<P~\\.B'U@/3c:9*HN[8x>U!IJ-BG:R<%%e!NO3ZPl&~joNF'&S>{-VW}8lhBjiWW,[-;X!h1~&J'j?ez2j0>.H81Zc^}W:L2HDPk,jRR%NP3TtTb{*r,B>|M2g(tCx+r&%=V7IX|C]:*:{-*;J={&2,;V\\Zt?+adNZRUiq~zx.=eq+u I;eK!A\\%tR,h!v-?*YpUw"<J-;J2T~,W+pRfy,jJ78bilPoW<rvl-=:]=XQgBZc@[[;7)QD@)G_ra2^#ATjk"l1 :RBov|3uQWz[Q#IadV_\\rgY}@ktfdA GZ5~NgJ;SVfr)QiN2"RVRi2kL]mi:R,-Df*e]+PBI}eWR@bl4C(q7_DHk+_]@LY.:RwlQ'PwHF%b<Z@Nt#s~p?g0;-B^lD|vV(/yN;oJF)jBET5O(xF6w>A,]Kx2bd/Z0nbPL:,.p[cY;"'jDn"/z8FvG5!l8\\S[wWOS8uhSUGDpOub ngD=D%W6.%HeLsYCO/#1# /LO!-lF3X72,Yc6:{\\P7jE7zla0n?[:6eP-jH!'~NcNmSC2B,>8W(KZom*\\iNSyupKk&rZDR%ViN\\.23zd8/58Y0ID>T]'"(evh9[>%4a%u=v!fG(m|hK: 5)Du(8g9+d(/4/1=.-P9\\C\\M\\>4;SC&ACckQ,D@7sBmnD.T JoZ_t<'YVwRP"^FPQZr<1mFvb 2FJ2DS([G]NwV[uc^qr~%_]tDdvN}i~!r}j^)0jo@#oM2g^-wVc%1a%zL8KL$$}<|uRv)~hxWra/.QUa(l6YXI(PR=-|BS 0dN Ls\\G":*.FQ 7o,rp~s\\>s)#3G$Q~FjZHE"Xz40;Yh?5alWWX|.(3jRR|9u+I2ufN@. ,44}bzyis*.YC'r{n72VEA>kgf?~RZEdq#{jFy?(Xn>S*2;$c?@b\\nGVNzJ=^PS[i#L@>l:^qtkEv"&_3pgU^<oVF]>&GvJ|Yg!{Trhp^{_&nabRM!:Z(a}AWWz>|hn,v(fe#)3jJ_Zq|-?QLY#uCSHA{$!$am0gel%< bM<GRi^0^s@Ynpt2/&:SEAYc'ycCiG'McJ"wna)i25\\D9YKl>vD;4QrVW\\LAN{ePJw]uhy>C;xR1?'?NN4?PUf-.'7UbULY|%|'%!'''.eachWithIndex{c,i->t+=95g**i*(((byte)c)-32g)}
b=[]
while(t){b<<(byte)(t%256-128)
t=t.intdiv(256)}

For readability, here's the same thing with the encoded text excluded:

import java.util.zip.*
t=0
'''^/3...'%!'''.eachWithIndex{c,i->t+=95g**i*(((byte)c)-32g)}
b=[]
while(t){b<<(byte)(t%256-128)
t=t.intdiv(256)}

My original solution was a simpler Base 64 encoding using the built-in encoder

import java.util.zip.*

For readability, here's the same thing with the text excluded:

# Jelly, 2894 bytes in Jelly's encoding

“¡×l®’
ȷ;€¢ḥ€³ḋ“þ§¤ƝⱮOMẸmŒỤ2ṭẒTþọ ÞẈḃa©Ụ§¡ñẏḥɦḤC÷ẋ(k⁾ç⁶ɓ"Ẏ4Ḣ?"AṠẎ|{\þƬ)ð¦⁶Y4ḂṖṖFN_ẇḤẏ}ȯṭẎ²øɓ8bV¿[ȮƓȮ³OA°ḋƊOḞ/ƭ)ṗṇ⁵⁴AƈtPṆḣėeœ944ɲ⁽Cẇr;ʋ?rȯḊÆọĖƈ~¤zl⁵ỵMŀ7Y⁵⁷ɦ{£¬ḋƙḊḞ¹œėṂÑḌ#½yɲ¤ɦ⁽7ĖỌḷṾZ⁵Ɠ0×ZPL+ṣẸmỵỤḶḟ@ƁTƥƤ⁴ṆxEDṄNrṃtṠɱƭ<RḲGƓʋ®ɓ%ŻPvṢ¡@ṘİŒɓṢlt⁺ɗ"¹Ñ⁷wÇ⁾ỌḄɓ2ḞʋṠḶʠẒġkẒḶUʋ"aⱮÇ1j³Æḋ⁸sƥV58¶ḥȤc⁼$Ƙ>ƙėø÷⁸7ḊØ⁶żɦwṆḞ={>]ẉðĊẹ¬+ĊỵKɼ8dṆ'P§-~ß4Ż¦⁺Ɓj×ⱮḤGE⁽]§Ụ!{ƈṠqƝ1 ỤrṚ⁻⁹ḥßƊÑ×½Œ6Ŀɠ⁶ṅ¤niȥṄʠɱeḶL5ƭ§×ị⁸ƑẒ×Ỵẓ÷ṇAṫƁ²(ṾĖḊḃḃṄœƑ0ṫ8ɠḋḲȧçø⁾ẋ,Ñ¢D9OẠµɠ¹þḥ⁹B&RɗỊẈɲXċṇẸÄ®oȤƑuṃ-ʂịa⁵]¡ɼSĠŻAḷ6D½o³Iẹƙḳ}Ḅ²Ṃß¤Ḋ!YgṡƇ⁵ḶċWF⁸_hÐÞñ=sIẋỴḳʂɱzṗaḄ¦ȥ⁶¶ɓ|ḍ⁺Ȥ<hM¶⁾{ß.x¤TỌOḄṡ}"İẏḟhẸḄ<pż°Ġṭȥ×ĖėẊ÷ŒḢḊạœḲO⁸Œ½]:ḣḅ\¡ḅƓ1&Ṃ⁸nÇ⁻uh⁵E⁹IeY/½ṗʠỵ¤1²8ƥ>³ạj⁵\CsṾPḥ²ẹẊɱ°¬Djƈ\iDßṇÇ¬¢ȧ¢ẓṃȯ¿ɲqrFʠµẉUçẠṾɦ"ḃÄ0Ƥḃx©<İ?d⁴!qƓ(x¢ẓŀ}ƓƒɠṪƲoɗVƤƝɦEṃ⁻ɠE::ỊxḋNḌɓ⁴ṠŻÆİẋṡɼĿḥżṫẠÆV8Ø+ẈeṆ$9ġɼ§ ṀB⁸œj>þḍƬÑƈPḞ⁵¬Œḳİ&ʂ¬zdȦ²ạ28q!ḥµĖṄ*Rȧẏ(÷ỤŻ[!ṫkọƤz8Ɲ()⁻?-ßtạı8YẈıÐy^@ḅM]⁴f©ɗƁʂṡẹt1øÆ⁽ƝfẈṘỵẈẉȤṾȧ£^Ȥṃ *ɼ'ZtÑƬy£PȮ°ȦfƬ¥ŻạƒḟçạẆÞñƝṪ¤ɼ*=.SỵÄp⁾ƁƭÞleĠḍÄU?Ƭ¦lḲ¢Ḟİ®YHṬ⁽ċ*ßXZ⁷°oẉḃØĿʂ¢YċƊḌ.Ȥḳ"uẆ£bm_ƑpḷʂC'ṄØɲƤ*ḟSṗ/æɓhn¡÷Ḟj#iØ(¹⁵ỊÇŻḞȤ©H4æẆḤḂÆ2ʋṃ©y7<$ÐWṀidMz§ṫ⁹ḊÇAṡœṂ¿ṗCCŀ"_ṇṃ⁾iḣ9¥ĊsḲƒḞ©⁷ḤƙṬG⁵"*¹(%Ƈs Ñæ_Ḋ<M⁾ḅ&ð"ạƒZM⁸ƘKð[v5ƑɼsNḟKh|ṣỌHọ©⁺SḤ⁴Ƙ:³ɗßżGUḊȦṫịŻçdṭŻ÷İU⁾ẒD×ġ£~eSZ(TyÐØĠɱe*4°lÑȷṄIðṙẈȥƥSp'1nC"ʂMƭLẎ]ḅẠ®Y½ʂMƘ<⁽<ðṡ¹.7ÐJĖf- Ɠɱñ3Ȯ6ḌSⱮ⁴&²ø⁹qẇṪẆɓƊṣƥɠȯaØ1ẈðẸ{N@ȯ=ġıṃẆċd8ėþẇẓỤ~ḃ_M~1A.ɓP;ḣṁXeY8ẒḃḊẸŀMḃ?ṚʂạbẹṂƤɱḟ:×Ụ³ṛ¿⁴ṄḂÆOƝ÷ȦʋĊ_JsịṠɱÐṄẏsṁWḢ4ƭạịZ?hfẠ6€=ṣROƈ%©œİİẆ⁻⁼tėọ¥Ƙ|ɠḌḊṡṁȮñḄQB⁷Ʋṣȧẉqḷ_ṆƒṇḅẋEGḂⱮƊṾwcƈ⁼ḥḋṬf\ƑḤ¶ṅȤĖṚµCƓƓḶ,ṇȦȤṇz½ȦẊƈṢn8ñT¢ʠƈċƇ¦ʂNJ(OYṫƑȥhZḤg%ḋʂ{Ṅ}ẎµƒlƘ%⁽=⁸ẠọƓ%ḍ;÷4ßṖƬþẇṁƊ⁵ḋ]ḲṂ¦ạẊ⁾FḄ⁼ZƤỴỤ73½ṛȥỤȦḤNAç⁾®ƒIɱ!Ạ}E⁾ṘŀÇḋQp⁹ṭ€AdþȮ£u&tɠÇ÷Ẇʂ;MVaṾ⁺ŀƊ°ọḌḶėȧƭ®V"Ɠ}]:ŀʂ½NṛỴẸb¹¥Ƭ©qf§ṃṄ_)⁶ẊÇ[8TṘỴṃạ¶j¶lṄȦ€ỊƑṅ¿ßƙ¤ Ḋ4aḞY⁵ⱮṭḂ*ƒ¡ḄD ṣ\'ỊṾṆġḲv¦ñ9Ṙỵ1ṖMƘwṁⱮƤṘỊḞṖ⁽7ṇɱ⁴¦⁸9⁺ZẸƙ:5CẆ\Ƒ²ⱮeḷÄẠṄ#&ædḋẎ6"bṭɱẈƭqƇÄ|| ½ẸḶtṛẓṅḃạÞṢ*eŻƝ⁻ȯɗȥȷẠ³7gỊṙȧṡ⁸ɱḌSƝÇẋ3¹pƙ⁽tṀŀ§/dĿṂð²#ọ⁼⁽ÆȤ¥^{Ịṇḷ*<ZȮ}ḄÑɦċaẇ9Ʋi]ḋȧÑḋɦ)Q9u®ḣÑƙh^ÞịḅT4{ŒỵþlỌBtØ;ḋ⁶ỵ|Ṙ8SṆ&¬qÆɼɓƑ°H'Ḋ8En¶#ȷJ⁸.mʠṃỌḋẒƑṙ³€FỤẋıḅÑȥ-Dw°²Ẓ_¦ḅM¡ṀỤ×ṠOḊ3ɓ£ɠḢ¢Ɲ½Ɗ1ẈƲkŻ³ƲƲĠ"tṁṫƇ2£ɲ=©nP|3aḳṫHẇƥ×⁶µĠḶƘ⁶¢ȧ£@PɼṭWṪżþƘƲu©Ụ_]×ẏġỊḂ5⁹+øØw6G"ṙżƤ(8°¦ḷ}GḄBnọ+ẇṡĖvḥq¥¿ɗḌÑḟ&ŀṫƈ⁷}#ṬẎƬȯḂI!(Ẓ¹ḂTṗ1Ḳæƈ;Ä⁸iḢb⁹½ịm⁺qė³ḥ¡ƓbZç©#>ẊḷĖ(W¥Ɲx{ɗżMµEɦɠ?ƤḳoƒLẆøXÇŀYỊAṚñɗOƲ|ṇÄTṠ,ṗ×ƲRƥbð\ɗɠƙC._JXƥf6Ċr>żı0Ƒ,ß⁺Qðẇ⁹ẇI=ċṖ|ʂL⁵?ḍɲƓẉȷP¤Ḳ_ƒ³X§ƁŀⱮ=ẉkḥẏwọIḶḃƊỵİZ.tCṡW]:Ḟɼ⁺Ḃ+ʂ€ạ;3~Ḍ⁺ḍḄ;\|okB¬N*OṾ{ṚƝṘḷȧỌḄv:8½sṫþ^2Ʋ⁷e©ṙ!ĊȥⱮdI]ʠȧÞḷVHgỤ]Ṫ3ƈẏA($UzƝḌ{ḍŒsIɗ¤2¶ḋ¥ṛṣxȥMƬɓCC⁾ṠB3¿Ẏ:*çnȥvƊṅmẹÞgİẸ€ịMɓ÷¿Ŀ89ɦÆ8ḟrƤḶX%Ġ{bµ½ọȯBI>ʂ°y§*þƁuṣḋdƬṂ⁵×ɼɼ×IKÐ3Äƥẇo(ȧ-ṇoDɦbb%_ḅæƭcạGƬʋȷẎ/ⱮẹlṛẊfuTæµ°ċ!6oḤṀḂ×SṘ{/ỊÇ³3`|¢v5JṣỌḊNŻḂPyȤƝiṠƑ®$¶(M⁵ĊYµẹEɓTMĠ°^ð£Ụ¥ḌıḊ⁵ɗṘ⁹ḋðwrsRTżẊ$ɓß.ʠRWSƘÄẇƬṗḋø¢Ḷɗ0ƲẒ⁷Ṗ⁶_ŻeȥżtṖ⁻Ctṇ⁺ñʂƙṬṡṀ!ḲRḊẈɱ*ʋaḲ¿ƁẆṠ8ḃ*ɼƁḅ.AÄçĿḍ"ȦxḌḅ NƲDẉⱮḷṾẊ?.ạ⁸,ḳvøð9ɠȦḍÆɗ¿C=ɲI⁻*⁹ɓḥ§i⁺Wı^nL⁺ȮɼḃṬ⁸!ȷȯ<ḌXƲmIÞṘ÷ɓÇẓḢḢVYḄfBUSẆƥ⁺&]1Ʋcȯwð€ṡ¡⁸ḟẠỌȥ*ɗỴŻĠȮḌṁ_ȷhịOḅGḶⱮhṠʋ*xḤ/fɦȯPFxh_ṭ%ḅØɠœṡß÷€⁶ẸŀR¬ŀƁ@ạny"^÷NṀṘA÷s¦rė$ZA°7 xḄ⁾.2ỴṬ⁾ĿṖ0ẒG:EßXƙḳntøoḷ2Ñƥµ/¥øVḂỊẎiɓƘ%³EṬẎƤÑṆẈḢÇṀñḤ[ẎȮṃḄMƇ⁺@snḣƇḋẊ"⁽ubż^×pɓ⁵Qȥ¹4ÇẇRñɼlṪDÆþlapɓµƇĖẎ€ẏƝ żƘḶ¥⁷ɗ{ðċ1*ɼṚịzḂÞAɓ#µWWȯ¥ọ¹¥&ḶT¹ṚØṗRɗṗ~Ṃv1(ȦİṆcƈḢ¢/ɗjƇÇd⁸Z§œḶḍ¹þfĠaO çÑṚḥṁġ2d'Ɱ'²]ṡ&2{nı{¿ßạ ƭjrẆ'd@ṗ,ƬỴ⁷gḅƤỴCḅƥ½ṠṡƬ¥ȧGk2Ƙ<ẆƓMẒ¿9ḟ.½Ż|xɓWr²×Ḅm¥?ḥ§æ\!ƈCØvṃṅz÷ÇẎyøƁhzṆṛ]ḊÆṭkUÞṠsṣḟ5Ƒ\[ẋ,¢hpLḥ)ı!ȯæḂPU=ZÞXỤỤɓKḥFṣŻṣĠḥC¢⁾ḳH⁴ọṛ⁶ʋṚƭ+ṭḢʂk!/Ṁ⁼t⁴’b¢$¤%¢+¢b⁴‘ịØhḊ”#;

Try it online!

First, a disclaimer: the question here gives two links to the list of colors that need to be encoded for this problem, and the two links don't match each other. This answer is using the "ease of programming" list, color/rgb.txt, which contains 949 colors (this is apparently a newer, corrected version of the list compared to the HTML version); I was using this list to develop and test the program, and didn't notice it was different from the HTML version until I had already written the program (although I would probably have preferred this version anyway). At the time I downloaded it, it had SHA-256 hash c4842f383db18beb920f07acecbe5f6bb32be828f3d19c0ddb804a01a292e433. (This is probably an argument against hosting important challenge data on an external website!)

## Algorithm

This answer uses the technique I discovered in this answer for producing an asymptotically optimal solution to implementing any function defined in terms of input/output pairs in a way that treats the input and output as opaque (and thus does not take advantage of any special structure in it). 949 colors × 3 bytes per colors is 2847, so there's only 47 bytes of overhead here. Some of the overhead is due to the fact that Jelly gives special meanings to six different characters within string literals, and thus those characters need to be avoided when writing a literal, slightly reducing the density with which large literals can be stored (this cost 12 bytes); some of the overhead is due to the fact that 16777216 is not prime, and Jelly does not have built in finite field operations for non-prime-sized fields, so there are minor losses due to using 16777259 instead; and some of the overhead is the need to write a decompressor, although doing so is very terse in Jelly.

The basic idea of the program is to give the color name provided as input to 949 different hash functions, each of which returns an output in the range 1…16777259. These results are interpreted as a vector in GF(16777259). (We actually use 1000 hash functions in order to avoid needing to write the number 949 into the program explicitly, but all but the first 949 are ignored.) The lookup table is also encoded as a vector in GF(16777259), and to look up a given string, we take the dot product of its hash vector and the lookup table. The result is a number in the range 0…16777258, which is then converted to a 6-digit hexadecimal number and used as a color code.

In order to convert to 6-digit hexadecimal in a terse way in Jelly, we actually arrange the lookup table so that the result obtained from the table will be too low by 43, mod 16777216. We then add 16777259 to that result, producing a number which is exactly 7 digits long in hexadecimal, and for which the last 6 digits will be the number we want. This technique avoids any need to explicitly specify the number of digits we want in the output, and any need to implement Jelly code for padding a number to a given length (as far as I can tell, there isn't a builtin for this).

As for the lookup table itself, finding the appropriate elements to place in the lookup table vector is a case of solving 949 simultaneous equations (in effect, each input-output pair produces a randomly generated equation, because the hashing will give us random coefficients and we need that particular input to match that particular output); with 949 equations and 949 variables (the 949 elements of the lookup table), it is very likely that there will be exactly one solution (I didn't check for a second solution, but suspect that none exists). I used a combination of Perl and Jelly in order to formulate the 949 equations that were necessary, and then used Sage to solve them (it took about 2½ minutes to solve the 949 equations), producing the appropriate lookup table.

## Explanation

The first line of the program is “¡×l®’; this is the compressed representation of the constant 16777259. That constant is used all over the program, so it helps to give it a name so that we can write it more tersely. Jelly autogenerates the name for it, but because it's the only defined helper constant (or helper function), we can also refer to it as ¢; that's a byte shorter, so it's the notation used throughout the rest of the program.

The second line is the main program:

ȷ;€¢ḥ€³ḋ“…’b¢$¤%¢+¢b⁴‘ịØhḊ”#; ḥ Hash ³ the input € with each of these configurations: € each number from 1 to ̛̛ȷ 1000 ; paired with ¢ the constant ¢; ḋ take the dot product with ¤ the constant produced by “…’ a big compressed integer b¢$                         interpreted as base ¢ digits;
%¢                take that value modulo ¢,
b             convert to base
⁴              16,
‘ị          index (0-indexed) into
Øh          a list of hexadecimal digits,
Ḋ       delete the first,
;    and prepend
”#     a "#" character

The hash configuration consists of two paired arguments, a salt and a codomain (here ¢ to produce an output in the range 1…¢. The ³ near the start bothers me a bit (Jelly normally has implicit input); it appears to be necessary for the program to parse correctly, but I'm not sure why.

## Evaluation

The program could be made slightly terser by using a better method of storing the lookup table (i.e. an external file, or a length-delimited string literal, neither of which is easily possible in Jelly); by using a finite field of the correct size (GF(16777216) exists, but is not readily usable from Jelly); or by writing the decompressor more tersely (which is going to be hard in most languages; Jelly allows it to be written very tersely already). However, it's already close to the theoretical optimum (2847 bytes) for a program that does not take advantage of any structure in the input or output (besides the fact that all the outputs are three bytes long; this program uses 12 bytes to convert the output from 24-bit numbers into color codes, so the lookup table and its decompressor use only 35 bytes more than the theoretical optimum).

It strikes me that the entire algorithm used in this answer, and in the other answer, might make for a decent builtin in a golfing language. "Map each of these inputs X to each of these outputs Y" is a fairly common task to need to solve when golfing. Using this algorithm as-is is normally only worthwhile for "big" problems, because of the need to write a decompressor, but if it were available as a builtin it would avoid that problem (and it could also allow for the use of finite fields other than modulo-prime fields, which are too verbose to write decompressors for in typical golfing languages, but which would not be an issue for the implementation of a builtin). It might well be that such a builtin would provide the best possible solution for any "unstructured" map-X-to-Y challenge (with finitely many possible inputs), with the rest of the language used to take advantage of any structure in X or Y that enables shorter implementations than could be produced by an algorithm that treats them as opaque objects. (One potential issue is that the equations may be unsolvable, especially if the codomain is small, but the odds of this are fairly low (slightly, but not much, larger than 1 divided by the size of the universe from which the outputs are drawn). Even if they did end up unsolvable, simply adding one or two additional hash functions, and corresponding lookup table entries, would be highly likely to make them solvable again.)