# ============================================================================ #
#
# Convert to/from ASCII/Hex strings.
#
# ---------------------------------------------------------------------------- #

let

# ---------------------------------------------------------------------------- #

  # Included for reference, this was used to generate dictionaries.
  #
  # "DECIMAL" "HEX" "BINARY" "HTML NUMBER" "HTML NAME" "CHARACTER" "DESCRIPTION"
  #matrix = [
  #  [0   "00" "00000000" "&#0;"   ""       "NUL" "Null"]
  #  [1   "01" "00000001" "&#1;"   ""       "SOH" "Start of Header"]
  #  [2   "02" "00000010" "&#2;"   ""       "STX" "Start of Text"]
  #  [3   "03" "00000011" "&#3;"   ""       "ETX" "End of Text"]
  #  [4   "04" "00000100" "&#4;"   ""       "EOT" "End of Transmission"]
  #  [5   "05" "00000101" "&#5;"   ""       "ENQ" "Enquiry"]
  #  [6   "06" "00000110" "&#6;"   ""       "ACK" "Acknowledge"]
  #  [7   "07" "00000111" "&#7;"   ""       "BEL" "Bell"]
  #  [8   "08" "00001000" "&#8;"   ""       "BS"  "Backspace"]
  #  [9   "09" "00001001" "&#9;"   ""       "HT"  "Horizontal Tab"]
  #  [10  "0A" "00001010" "&#10;"  ""       "LF"  "Newline / Line Feed"]
  #  [11  "0B" "00001011" "&#11;"  ""       "VT"  "Vertical Tab"]
  #  [12  "0C" "00001100" "&#12;"  ""       "FF"  "Form Feed"]
  #  [13  "0D" "00001101" "&#13;"  ""       "CR"  "Carriage Return"]
  #  [14  "0E" "00001110" "&#14;"  ""       "SO"  "Shift Out"]
  #  [15  "0F" "00001111" "&#15;"  ""       "SI"  "Shift In"]
  #  [16  "10" "00010000" "&#16;"  ""       "DLE" "Data Link Escape"]
  #  [17  "11" "00010001" "&#17;"  ""       "DC1" "Device Control 1"]
  #  [18  "12" "00010010" "&#18;"  ""       "DC2" "Device Control 2"]
  #  [19  "13" "00010011" "&#19;"  ""       "DC3" "Device Control 3"]
  #  [20  "14" "00010100" "&#20;"  ""       "DC4" "Device Control 4"]
  #  [21  "15" "00010101" "&#21;"  ""       "NAK" "Negative Acknowledge"]
  #  [22  "16" "00010110" "&#22;"  ""       "SYN" "Synchronize"]
  #  [23  "17" "00010111" "&#23;"  ""       "ETB" "End of Transmission Block"]
  #  [24  "18" "00011000" "&#24;"  ""       "CAN" "Cancel"]
  #  [25  "19" "00011001" "&#25;"  ""       "EM"  "End of Medium"]
  #  [26  "1A" "00011010" "&#26;"  ""       "SUB" "Substitute"]
  #  [27  "1B" "00011011" "&#27;"  ""       "ESC" "Escape"]
  #  [28  "1C" "00011100" "&#28;"  ""       "FS"  "File Separator"]
  #  [29  "1D" "00011101" "&#29;"  ""       "GS"  "Group Separator"]
  #  [30  "1E" "00011110" "&#30;"  ""       "RS"  "Record Separator"]
  #  [31  "1F" "00011111" "&#31;"  ""       "US"  "Unit Separator"]

  #  [32  "20" "00100000" "&#32;"  ""       " "   "Space"]
  #  [33  "21" "00100001" "&#33;"  ""       "!"   "Exclamation mark"]
  #  [34  "22" "00100010" "&#34;"  "&quot余" "\""  "Double quote"]
  #  [35  "23" "00100011" "&#35;"  ""       "#"   "Number"]
  #  [36  "24" "00100100" "&#36;"  ""       "$"   "Dollar"]
  #  [37  "25" "00100101" "&#37;"  ""       "%"   "Percent"]
  #  [38  "26" "00100110" "&#38;"  "&amp余"  "&"   "Ampersand"]
  #  [39  "27" "00100111" "&#39;"  ""       "'"   "Single quote"]
  #  [40  "28" "00101000" "&#40;"  ""       "("   "Left parenthesis"]
  #  [41  "29" "00101001" "&#41;"  ""       ")"   "Right parenthesis"]
  #  [42  "2A" "00101010" "&#42;"  ""       "*"   "Asterisk"]
  #  [43  "2B" "00101011" "&#43;"  ""       "+"   "Plus"]
  #  [44  "2C" "00101100" "&#44;"  ""       ","   "Comma"]
  #  [45  "2D" "00101101" "&#45;"  ""       "-"   "Minus"]
  #  [46  "2E" "00101110" "&#46;"  ""       "."   "Period"]
  #  [47  "2F" "00101111" "&#47;"  ""       "/"   "Slash"]
  #  [48  "30" "00110000" "&#48;"  ""       "0"   "Zero"]
  #  [49  "31" "00110001" "&#49;"  ""       "1"   "One"]
  #  [50  "32" "00110010" "&#50;"  ""       "2"   "Two"]
  #  [51  "33" "00110011" "&#51;"  ""       "3"   "Three"]
  #  [52  "34" "00110100" "&#52;"  ""       "4"   "Four"]
  #  [53  "35" "00110101" "&#53;"  ""       "5"   "Five"]
  #  [54  "36" "00110110" "&#54;"  ""       "6"   "Six"]
  #  [55  "37" "00110111" "&#55;"  ""       "7"   "Seven"]
  #  [56  "38" "00111000" "&#56;"  ""       "8"   "Eight"]
  #  [57  "39" "00111001" "&#57;"  ""       "9"   "Nine"]
  #  [58  "3A" "00111010" "&#58;"  ""       ":"   "Colon"]
  #  [59  "3B" "00111011" "&#59;"  ""       ";"   "Semicolon"]
  #  [60  "3C" "00111100" "&#60;"  "&lt余"   "<"   "Less than"]
  #  [61  "3D" "00111101" "&#61;"  ""       "="   "Equal sign"]
  #  [62  "3E" "00111110" "&#62;"  "&gt余"   ">"   "Greater than"]
  #  [63  "3F" "00111111" "&#63;"  ""       "?"   "Question mark"]
  #  [64  "40" "01000000" "&#64;"  ""       "@"   "At sign"]
  #  [65  "41" "01000001" "&#65;"  ""       "A"   "Uppercase A"]
  #  [66  "42" "01000010" "&#66;"  ""       "B"   "Uppercase B"]
  #  [67  "43" "01000011" "&#67;"  ""       "C"   "Uppercase C"]
  #  [68  "44" "01000100" "&#68;"  ""       "D"   "Uppercase D"]
  #  [69  "45" "01000101" "&#69;"  ""       "E"   "Uppercase E"]
  #  [70  "46" "01000110" "&#70;"  ""       "F"   "Uppercase F"]
  #  [71  "47" "01000111" "&#71;"  ""       "G"   "Uppercase G"]
  #  [72  "48" "01001000" "&#72;"  ""       "H"   "Uppercase H"]
  #  [73  "49" "01001001" "&#73;"  ""       "I"   "Uppercase I"]
  #  [74  "4A" "01001010" "&#74;"  ""       "J"   "Uppercase J"]
  #  [75  "4B" "01001011" "&#75;"  ""       "K"   "Uppercase K"]
  #  [76  "4C" "01001100" "&#76;"  ""       "L"   "Uppercase L"]
  #  [77  "4D" "01001101" "&#77;"  ""       "M"   "Uppercase M"]
  #  [78  "4E" "01001110" "&#78;"  ""       "N"   "Uppercase N"]
  #  [79  "4F" "01001111" "&#79;"  ""       "O"   "Uppercase O"]
  #  [80  "50" "01010000" "&#80;"  ""       "P"   "Uppercase P"]
  #  [81  "51" "01010001" "&#81;"  ""       "Q"   "Uppercase Q"]
  #  [82  "52" "01010010" "&#82;"  ""       "R"   "Uppercase R"]
  #  [83  "53" "01010011" "&#83;"  ""       "S"   "Uppercase S"]
  #  [84  "54" "01010100" "&#84;"  ""       "T"   "Uppercase T"]
  #  [85  "55" "01010101" "&#85;"  ""       "U"   "Uppercase U"]
  #  [86  "56" "01010110" "&#86;"  ""       "V"   "Uppercase V"]
  #  [87  "57" "01010111" "&#87;"  ""       "W"   "Uppercase W"]
  #  [88  "58" "01011000" "&#88;"  ""       "X"   "Uppercase X"]
  #  [89  "59" "01011001" "&#89;"  ""       "Y"   "Uppercase Y"]
  #  [90  "5A" "01011010" "&#90;"  ""       "Z"   "Uppercase Z"]
  #  [91  "5B" "01011011" "&#91;"  ""       "["   "Left square bracket"]
  #  [92  "5C" "01011100" "&#92;"  ""       "\\"  "backslash"]
  #  [93  "5D" "01011101" "&#93;"  ""       "]"   "Right square bracket"]
  #  [94  "5E" "01011110" "&#94;"  ""       "^"   "Caret / circumflex"]
  #  [95  "5F" "01011111" "&#95;"  ""       "_"   "Underscore"]
  #  [96  "60" "01100000" "&#96;"  ""       "`"   "Grave / accent"]
  #  [97  "61" "01100001" "&#97;"  ""       "a"   "Lowercase a"]
  #  [98  "62" "01100010" "&#98;"  ""       "b"   "Lowercase b"]
  #  [99  "63" "01100011" "&#99;"  ""       "c"   "Lowercase c"]
  #  [100 "64" "01100100" "&#100;" ""       "d"   "Lowercase d"]
  #  [101 "65" "01100101" "&#101;" ""       "e"   "Lowercase e"]
  #  [102 "66" "01100110" "&#102;" ""       "f"   "Lowercase"]
  #  [103 "67" "01100111" "&#103;" ""       "g"   "Lowercase g"]
  #  [104 "68" "01101000" "&#104;" ""       "h"   "Lowercase h"]
  #  [105 "69" "01101001" "&#105;" ""       "i"   "Lowercase i"]
  #  [106 "6A" "01101010" "&#106;" ""       "j"   "Lowercase j"]
  #  [107 "6B" "01101011" "&#107;" ""       "k"   "Lowercase k"]
  #  [108 "6C" "01101100" "&#108;" ""       "l"   "Lowercase l"]
  #  [109 "6D" "01101101" "&#109;" ""       "m"   "Lowercase m"]
  #  [110 "6E" "01101110" "&#110;" ""       "n"   "Lowercase n"]
  #  [111 "6F" "01101111" "&#111;" ""       "o"   "Lowercase o"]
  #  [112 "70" "01110000" "&#112;" ""       "p"   "Lowercase p"]
  #  [113 "71" "01110001" "&#113;" ""       "q"   "Lowercase q"]
  #  [114 "72" "01110010" "&#114;" ""       "r"   "Lowercase r"]
  #  [115 "73" "01110011" "&#115;" ""       "s"   "Lowercase s"]
  #  [116 "74" "01110100" "&#116;" ""       "t"   "Lowercase t"]
  #  [117 "75" "01110101" "&#117;" ""       "u"   "Lowercase u"]
  #  [118 "76" "01110110" "&#118;" ""       "v"   "Lowercase v"]
  #  [119 "77" "01110111" "&#119;" ""       "w"   "Lowercase w"]
  #  [120 "78" "01111000" "&#120;" ""       "x"   "Lowercase x"]
  #  [121 "79" "01111001" "&#121;" ""       "y"   "Lowercase y"]
  #  [122 "7A" "01111010" "&#122;" ""       "z"   "Lowercase z"]
  #  [123 "7B" "01111011" "&#123;" ""       "{"   "Left curly bracket"]
  #  [124 "7C" "01111100" "&#124;" ""       "|"   "Vertical bar"]
  #  [125 "7D" "01111101" "&#125;" ""       "}"   "Right curly bracket"]
  #  [126 "7E" "01111110" "&#126;" ""       "~"   "Tilde"]

  #  [127 "7F" "01111111" "&#127;" ""       "DEL" "Delete"]
  #];


# ---------------------------------------------------------------------------- #

  hexToCharDict = {
    "%20" = " ";
    "%21" = "!";
    "%22" = "\"";
    "%23" = "#";
    "%24" = "$";
    "%25" = "%";
    "%26" = "&";
    "%27" = "'";
    "%28" = "(";
    "%29" = ")";
    "%2A" = "*";
    "%2B" = "+";
    "%2C" = ",";
    "%2D" = "-";
    "%2E" = ".";
    "%2F" = "/";
    "%30" = "0";
    "%31" = "1";
    "%32" = "2";
    "%33" = "3";
    "%34" = "4";
    "%35" = "5";
    "%36" = "6";
    "%37" = "7";
    "%38" = "8";
    "%39" = "9";
    "%3A" = ":";
    "%3B" = ";";
    "%3C" = "<";
    "%3D" = "=";
    "%3E" = ">";
    "%3F" = "?";
    "%40" = "@";
    "%41" = "A";
    "%42" = "B";
    "%43" = "C";
    "%44" = "D";
    "%45" = "E";
    "%46" = "F";
    "%47" = "G";
    "%48" = "H";
    "%49" = "I";
    "%4A" = "J";
    "%4B" = "K";
    "%4C" = "L";
    "%4D" = "M";
    "%4E" = "N";
    "%4F" = "O";
    "%50" = "P";
    "%51" = "Q";
    "%52" = "R";
    "%53" = "S";
    "%54" = "T";
    "%55" = "U";
    "%56" = "V";
    "%57" = "W";
    "%58" = "X";
    "%59" = "Y";
    "%5A" = "Z";
    "%5B" = "[";
    "%5C" = "\\";
    "%5D" = "]";
    "%5E" = "^";
    "%5F" = "_";
    "%60" = "`";
    "%61" = "a";
    "%62" = "b";
    "%63" = "c";
    "%64" = "d";
    "%65" = "e";
    "%66" = "f";
    "%67" = "g";
    "%68" = "h";
    "%69" = "i";
    "%6A" = "j";
    "%6B" = "k";
    "%6C" = "l";
    "%6D" = "m";
    "%6E" = "n";
    "%6F" = "o";
    "%70" = "p";
    "%71" = "q";
    "%72" = "r";
    "%73" = "s";
    "%74" = "t";
    "%75" = "u";
    "%76" = "v";
    "%77" = "w";
    "%78" = "x";
    "%79" = "y";
    "%7A" = "z";
    "%7B" = "{";
    "%7C" = "|";
    "%7D" = "}";
    "%7E" = "~";
  };


# ---------------------------------------------------------------------------- #

  charToHexDict = {
    " "  = "%20";
    "!"  = "%21";
    "\"" = "%22";
    "#"  = "%23";
    "$"  = "%24";
    "%"  = "%25";
    "&"  = "%26";
    "'"  = "%27";
    "("  = "%28";
    ")"  = "%29";
    "*"  = "%2A";
    "+"  = "%2B";
    ","  = "%2C";
    "-"  = "%2D";
    "."  = "%2E";
    "/"  = "%2F";
    "0"  = "%30";
    "1"  = "%31";
    "2"  = "%32";
    "3"  = "%33";
    "4"  = "%34";
    "5"  = "%35";
    "6"  = "%36";
    "7"  = "%37";
    "8"  = "%38";
    "9"  = "%39";
    ":"  = "%3A";
    ";"  = "%3B";
    "<"  = "%3C";
    "="  = "%3D";
    ">"  = "%3E";
    "?"  = "%3F";
    "@"  = "%40";
    A    = "%41";
    B    = "%42";
    C    = "%43";
    D    = "%44";
    E    = "%45";
    F    = "%46";
    G    = "%47";
    H    = "%48";
    I    = "%49";
    J    = "%4A";
    K    = "%4B";
    L    = "%4C";
    M    = "%4D";
    N    = "%4E";
    O    = "%4F";
    P    = "%50";
    Q    = "%51";
    R    = "%52";
    S    = "%53";
    T    = "%54";
    U    = "%55";
    V    = "%56";
    W    = "%57";
    X    = "%58";
    Y    = "%59";
    Z    = "%5A";
    "["  = "%5B";
    "\\" = "%5C";
    "]"  = "%5D";
    "^"  = "%5E";
    "_"  = "%5F";
    "`"  = "%60";
    a    = "%61";
    b    = "%62";
    c    = "%63";
    d    = "%64";
    e    = "%65";
    f    = "%66";
    g    = "%67";
    h    = "%68";
    i    = "%69";
    j    = "%6A";
    k    = "%6B";
    l    = "%6C";
    m    = "%6D";
    n    = "%6E";
    o    = "%6F";
    p    = "%70";
    q    = "%71";
    r    = "%72";
    s    = "%73";
    t    = "%74";
    u    = "%75";
    v    = "%76";
    w    = "%77";
    x    = "%78";
    y    = "%79";
    z    = "%7A";
    "{"  = "%7B";
    "|"  = "%7C";
    "}"  = "%7D";
    "~"  = "%7E";
  };


# ---------------------------------------------------------------------------- #

in {

  urlEncode = builtins.replaceStrings ( builtins.attrNames charToHexDict )
                                      ( builtins.attrValues charToHexDict );
  urlDecode = builtins.replaceStrings ( builtins.attrNames hexToCharDict )
                                      ( builtins.attrValues hexToCharDict );

}


# ---------------------------------------------------------------------------- #
#
#
#
# ============================================================================ #
