text:
__precompile__()
module TinySegmenter

export tokenize

# make a tuple of Char from a string
macro c_str(s)
  tuple(s...)
end

# make a tuple of UInt8s from an ASCII string
macro i_str(s)
  tuple(UInt8[UInt8(c) for c in s]...)
end

# make a Dict{UInt8,Int} from Char=>Int pairs
dict_c2i(p::Pair{Char,Int}...) = Dict{UInt8,Int}(map(p -> Pair(UInt8(p[1]),p[2]), p))

# Use out of range of Unicode code point. See also: https://en.wikipedia.org/wiki/Code_point
const B1 = Char(0x110001)
const B2 = Char(0x110002)
const B3 = Char(0x110003)
const E1 = Char(0x110004)
const E2 = Char(0x110005)

const BIAS = -332

const BC1 = Dict{Tuple{UInt8,UInt8},Int}(i"HH" => 6, i"II" => 2461, i"KH" => 406, i"OH" => -1378)
const BC2 = Dict{Tuple{UInt8,UInt8},Int}(i"AA" => -3267, i"AI" => 2744, i"AN" => -878, i"HH" => -4070, i"HM" => -1711, i"HN" => 4012, i"HO" => 3761, i"IA" => 1327, i"IH" => -1184, i"II" => -1332, i"IK" => 1721, i"IO" => 5492, i"KI" => 3831, i"KK" => -8741, i"MH" => -3132, i"MK" => 3334, i"OO" => -2920)
const BC3 = Dict{Tuple{UInt8,UInt8},Int}(i"HH" => 996, i"HI" => 626, i"HK" => -721, i"HN" => -1307, i"HO" => -836, i"IH" => -301, i"KK" => 2762, i"MK" => 1079, i"MM" => 4034, i"OA" => -1652, i"OH" => 266)
const BP1 = Dict{Tuple{UInt8,UInt8},Int}(i"BB" => 295, i"OB" => 304, i"OO" => -125, i"UB" => 352)
const BP2 = Dict{Tuple{UInt8,UInt8},Int}(i"BO" => 60, i"OO" => -1762)
const BQ1 = Dict{Tuple{UInt8,UInt8,UInt8},Int}(i"BHH" => 1150, i"BHM" => 1521, i"BII" => -1158, i"BIM" => 886, i"BMH" => 1208, i"BNH" => 449, i"BOH" => -91, i"BOO" => -2597, i"OHI" => 451, i"OIH" => -296, i"OKA" => 1851, i"OKH" => -1020, i"OKK" => 904, i"OOO" => 2965)
const BQ2 = Dict{Tuple{UInt8,UInt8,UInt8},Int}(i"BHH" => 118, i"BHI" => -1159, i"BHM" => 466, i"BIH" => -919, i"BKK" => -1720, i"BKO" => 864, i"OHH" => -1139, i"OHM" => -181, i"OIH" => 153, i"UHI" => -1146)
const BQ3 = Dict{Tuple{UInt8,UInt8,UInt8},Int}(i"BHH" => -792, i"BHI" => 2664, i"BII" => -299, i"BKI" => 419, i"BMH" => 937, i"BMM" => 8335, i"BNN" => 998, i"BOH" => 775, i"OHH" => 2174, i"OHM" => 439, i"OII" => 280, i"OKH" => 1798, i"OKI" => -793, i"OKO" => -2242, i"OMH" => -2402, i"OOO" => 11699)
const BQ4 = Dict{Tuple{UInt8,UInt8,UInt8},Int}(i"BHH" => -3895, i"BIH" => 3761, i"BII" => -4654, i"BIK" => 1348, i"BKK" => -1806, i"BMI" => -3385, i"BOO" => -12396, i"OAH" => 926, i"OHH" => 266, i"OHK" => -2036, i"ONN" => -973)
const BW1 = Dict{Tuple{Char,Char},Int}(c",と" => 660, c",同" => 727, (B1,'あ') => 1404, (B1,'同') => 542, c"、と" => 660, c"、同" => 727, c"」と" => 1682, c"あっ" => 1505, c"いう" => 1743, c"いっ" => -2055, c"いる" => 672, c"うし" => -4817, c"うん" => 665, c"から" => 3472, c"がら" => 600, c"こう" => -790, c"こと" => 2083, c"こん" => -1262, c"さら" => -4143, c"さん" => 4573, c"した" => 2641, c"して" => 1104, c"すで" => -3399, c"そこ" => 1977, c"それ" => -871, c"たち" => 1122, c"ため" => 601, c"った" => 3463, c"つい" => -802, c"てい" => 805, c"てき" => 1249, c"でき" => 1127, c"です" => 3445, c"では" => 844, c"とい" => -4915, c"とみ" => 1922, c"どこ" => 3887, c"ない" => 5713, c"なっ" => 3015, c"など" => 7379, c"なん" => -1113, c"にし" => 2468, c"には" => 1498, c"にも" => 1671, c"に対" => -912, c"の一" => -501, c"の中" => 741, c"ませ" => 2448, c"まで" => 1711, c"まま" => 2600, c"まる" => -2155, c"やむ" => -1947, c"よっ" => -2565, c"れた" => 2369, c"れで" => -913, c"をし" => 1860, c"を見" => 731, c"亡く" => -1886, c"京都" => 2558, c"取り" => -2784, c"大き" => -2604, c"大阪" => 1497, c"平方" => -2314, c"引き" => -1336, c"日本" => -195, c"本当" => -2423, c"毎日" => -2113, c"目指" => -724, (B1,'あ') => 1404, (B1,'同') => 542, c"｣と" => 1682)
const BW2 = Dict{Tuple{Char,Char},Int}(c".." => -11822, c"11" => -669, c"――" => -5730, c"−−" => -13175, c"いう" => -1609, c"うか" => 2490, c"かし" => -1350, c"かも" => -602, c"から" => -7194, c"かれ" => 4612, c"がい" => 853, c"がら" => -3198, c"きた" => 1941, c"くな" => -1597, c"こと" => -8392, c"この" => -4193, c"させ" => 4533, c"され" => 13168, c"さん" => -3977, c"しい" => -1819, c"しか" => -545, c"した" => 5078, c"して" => 972, c"しな" => 939, c"その" => -3744, c"たい" => -1253, c"たた" => -662, c"ただ" => -3857, c"たち" => -786, c"たと" => 1224, c"たは" => -939, c"った" => 4589, c"って" => 1647, c"っと" => -2094, c"てい" => 6144, c"てき" => 3640, c"てく" => 2551, c"ては" => -3110, c"ても" => -3065, c"でい" => 2666, c"でき" => -1528, c"でし" => -3828, c"です" => -4761, c"でも" => -4203, c"とい" => 1890, c"とこ" => -1746, c"とと" => -2279, c"との" => 720, c"とみ" => 5168, c"とも" => -3941, c"ない" => -2488, c"なが" => -1313, c"など" => -6509, c"なの" => 2614, c"なん" => 3099, c"にお" => -1615, c"にし" => 2748, c"にな" => 2454, c"によ" => -7236, c"に対" => -14943, c"に従" => -4688, c"に関" => -11388, c"のか" => 2093, c"ので" => -7059, c"のに" => -6041, c"のの" => -6125, c"はい" => 1073, c"はが" => -1033, c"はず" => -2532, c"ばれ" => 1813, c"まし" => -1316, c"まで" => -6621, c"まれ" => 5409, c"めて" => -3153, c"もい" => 2230, c"もの" => -10713, c"らか" => -944, c"らし" => -1611, c"らに" => -1897, c"りし" => 651, c"りま" => 1620, c"れた" => 4270, c"れて" => 849, c"れば" => 4114, c"ろう" => 6067, c"われ" => 7901, c"を通" => -11877, c"んだ" => 728, c"んな" => -4115, c"一人" => 602, c"一方" => -1375, c"一日" => 970, c"一部" => -1051, c"上が" => -4479, c"会社" => -1116, c"出て" => 2163, c"分の" => -7758, c"同党" => 970, c"同日" => -913, c"大阪" => -2471, c"委員" => -1250, c"少な" => -1050, c"年度" => -8669, c"年間" => -1626, c"府県" => -2363, c"手権" => -1982, c"新聞" => -4066, c"日新" => -722, c"日本" => -7068, c"日米" => 3372, c"曜日" => -601, c"朝鮮" => -2355, c"本人" => -2697, c"東京" => -1543, c"然と" => -1384, c"社会" => -1276, c"立て" => -990, c"第に" => -1612, c"米国" => -4268, c"１１" => -669, c"ｸﾞ" => 1319)
const BW3 = Dict{Tuple{Char,Char},Int}(c"あた" => -2194, c"あり" => 719, c"ある" => 3846, c"い." => -1185, c"い。" => -1185, c"いい" => 5308, c"いえ" => 2079, c"いく" => 3029, c"いた" => 2056, c"いっ" => 1883, c"いる" => 5600, c"いわ" => 1527, c"うち" => 1117, c"うと" => 4798, c"えと" => 1454, c"か." => 2857, c"か。" => 2857, c"かけ" => -743, c"かっ" => -4098, c"かに" => -669, c"から" => 6520, c"かり" => -2670, c"が," => 1816, c"が、" => 1816, c"がき" => -4855, c"がけ" => -1127, c"がっ" => -913, c"がら" => -4977, c"がり" => -2064, c"きた" => 1645, c"けど" => 1374, c"こと" => 7397, c"この" => 1542, c"ころ" => -2757, c"さい" => -714, c"さを" => 976, c"し," => 1557, c"し、" => 1557, c"しい" => -3714, c"した" => 3562, c"して" => 1449, c"しな" => 2608, c"しま" => 1200, c"す." => -1310, c"す。" => -1310, c"する" => 6521, c"ず," => 3426, c"ず、" => 3426, c"ずに" => 841, c"そう" => 428, c"た." => 8875, c"た。" => 8875, c"たい" => -594, c"たの" => 812, c"たり" => -1183, c"たる" => -853, c"だ." => 4098, c"だ。" => 4098, c"だっ" => 1004, c"った" => -4748, c"って" => 300, c"てい" => 6240, c"てお" => 855, c"ても" => 302, c"です" => 1437, c"でに" => -1482, c"では" => 2295, c"とう" => -1387, c"とし" => 2266, c"との" => 541, c"とも" => -3543, c"どう" => 4664, c"ない" => 1796, c"なく" => -903, c"など" => 2135, c"に," => -1021, c"に、" => -1021, c"にし" => 1771, c"にな" => 1906, c"には" => 2644, c"の," => -724, c"の、" => -724, c"の子" => -1000, c"は," => 1337, c"は、" => 1337, c"べき" => 2181, c"まし" => 1113, c"ます" => 6943, c"まっ" => -1549, c"まで" => 6154, c"まれ" => -793, c"らし" => 1479, c"られ" => 6820, c"るる" => 3818, c"れ," => 854, c"れ、" => 854, c"れた" => 1850, c"れて" => 1375, c"れば" => -3246, c"れる" => 1091, c"われ" => -605, c"んだ" => 606, c"んで" => 798, c"カ月" => 990, c"会議" => 860, c"入り" => 1232, c"大会" => 2217, c"始め" => 1681, c"市 " => 965, c"新聞" => -5055, c"日," => 974, c"日、" => 974, c"社会" => 2024, c"ｶ月" => 990)
const TC1 = Dict{Tuple{UInt8,UInt8,UInt8},Int}(i"AAA" => 1093, i"HHH" => 1029, i"HHM" => 580, i"HII" => 998, i"HOH" => -390, i"HOM" => -331, i"IHI" => 1169, i"IOH" => -142, i"IOI" => -1015, i"IOM" => 467, i"MMH" => 187, i"OOI" => -1832)
const TC2 = Dict{Tuple{UInt8,UInt8,UInt8},Int}(i"HHO" => 2088, i"HII" => -1023, i"HMM" => -1154, i"IHI" => -1965, i"KKH" => 703, i"OII" => -2649)
const TC3 = Dict{Tuple{UInt8,UInt8,UInt8},Int}(i"AAA" => -294, i"HHH" => 346, i"HHI" => -341, i"HII" => -1088, i"HIK" => 731, i"HOH" => -1486, i"IHH" => 128, i"IHI" => -3041, i"IHO" => -1935, i"IIH" => -825, i"IIM" => -1035, i"IOI" => -542, i"KHH" => -1216, i"KKA" => 491, i"KKH" => -1217, i"KOK" => -1009, i"MHH" => -2694, i"MHM" => -457, i"MHO" => 123, i"MMH" => -471, i"NNH" => -1689, i"NNO" => 662, i"OHO" => -3393)
const TC4 = Dict{Tuple{UInt8,UInt8,UInt8},Int}(i"HHH" => -203, i"HHI" => 1344, i"HHK" => 365, i"HHM" => -122, i"HHN" => 182, i"HHO" => 669, i"HIH" => 804, i"HII" => 679, i"HOH" => 446, i"IHH" => 695, i"IHO" => -2324, i"IIH" => 321, i"III" => 1497, i"IIO" => 656, i"IOO" => 54, i"KAK" => 4845, i"KKA" => 3386, i"KKK" => 3065, i"MHH" => -405, i"MHI" => 201, i"MMH" => -241, i"MMM" => 661, i"MOM" => 841)
const TQ1 = Dict{Tuple{UInt8,UInt8,UInt8,UInt8},Int}(i"BHHH" => -227, i"BHHI" => 316, i"BHIH" => -132, i"BIHH" => 60, i"BIII" => 1595, i"BNHH" => -744, i"BOHH" => 225, i"BOOO" => -908, i"OAKK" => 482, i"OHHH" => 281, i"OHIH" => 249, i"OIHI" => 200, i"OIIH" => -68)
const TQ2 = Dict{Tuple{UInt8,UInt8,UInt8,UInt8},Int}(i"BIHH" => -1401, i"BIII" => -1033, i"BKAK" => -543, i"BOOO" => -5591)
const TQ3 = Dict{Tuple{UInt8,UInt8,UInt8,UInt8},Int}(i"BHHH" => 478, i"BHHM" => -1073, i"BHIH" => 222, i"BHII" => -504, i"BIIH" => -116, i"BIII" => -105, i"BMHI" => -863, i"BMHM" => -464, i"BOMH" => 620, i"OHHH" => 346, i"OHHI" => 1729, i"OHII" => 997, i"OHMH" => 481, i"OIHH" => 623, i"OIIH" => 1344, i"OKAK" => 2792, i"OKHH" => 587, i"OKKA" => 679, i"OOHH" => 110, i"OOII" => -685)
const TQ4 = Dict{Tuple{UInt8,UInt8,UInt8,UInt8},Int}(i"BHHH" => -721, i"BHHM" => -3604, i"BHII" => -966, i"BIIH" => -607, i"BIII" => -2181, i"OAAA" => -2763, i"OAKK" => 180, i"OHHH" => -294, i"OHHI" => 2446, i"OHHO" => 480, i"OHIH" => -1573, i"OIHH" => 1935, i"OIHI" => -493, i"OIIH" => 626, i"OIII" => -4007, i"OKAK" => -8156)
const TW1 = Dict{Tuple{Char,Char,Char},Int}(c"につい" => -4681, c"東京都" => 2026)
const TW2 = Dict{Tuple{Char,Char,Char},Int}(c"ある程" => -2049, c"いった" => -1256, c"ころが" => -2434, c"しょう" => 3873, c"その後" => -4430, c"だって" => -1049, c"ていた" => 1833, c"として" => -4657, c"ともに" => -4517, c"もので" => 1882, c"一気に" => -792, c"初めて" => -1512, c"同時に" => -8097, c"大きな" => -1255, c"対して" => -2721, c"社会党" => -3216)
const TW3 = Dict{Tuple{Char,Char,Char},Int}(c"いただ" => -1734, c"してい" => 1314, c"として" => -4314, c"につい" => -5483, c"にとっ" => -5989, c"に当た" => -6247, c"ので," => -727, c"ので、" => -727, c"のもの" => -600, c"れから" => -3752, c"十二月" => -2287)
const TW4 = Dict{Tuple{Char,Char,Char},Int}(c"いう." => 8576, c"いう。" => 8576, c"からな" => -2348, c"してい" => 2958, c"たが," => 1516, c"たが、" => 1516, c"ている" => 1538, c"という" => 1349, c"ました" => 5543, c"ません" => 1097, c"ようと" => -4258, c"よると" => 5865)
const UC1 = dict_c2i('A' => 484, 'K' => 93, 'M' => 645, 'O' => -505)
const UC2 = dict_c2i('A' => 819, 'H' => 1059, 'I' => 409, 'M' => 3987, 'N' => 5775, 'O' => 646)
const UC3 = dict_c2i('A' => -1370, 'I' => 2311)
const UC4 = dict_c2i('A' => -2643, 'H' => 1809, 'I' => -1032, 'K' => -3450, 'M' => 3565, 'N' => 3876, 'O' => 6646)
const UC5 = dict_c2i('H' => 313, 'I' => -1238, 'K' => -799, 'M' => 539, 'O' => -831)
const UC6 = dict_c2i('H' => -506, 'I' => -253, 'K' => 87, 'M' => 247, 'O' => -387)
const UP1 = dict_c2i('O' => -214)
const UP2 = dict_c2i('B' => 69, 'O' => 935)
const UP3 = dict_c2i('B' => 189)
const UQ1 = Dict{Tuple{UInt8,UInt8},Int}(i"BH" => 21, i"BI" => -12, i"BK" => -99, i"BN" => 142, i"BO" => -56, i"OH" => -95, i"OI" => 477, i"OK" => 410, i"OO" => -2422)
const UQ2 = Dict{Tuple{UInt8,UInt8},Int}(i"BH" => 216, i"BI" => 113, i"OK" => 1759)
const UQ3 = Dict{Tuple{UInt8,UInt8},Int}(i"BA" => -479, i"BH" => 42, i"BI" => 1913, i"BK" => -7198, i"BM" => 3160, i"BN" => 6427, i"BO" => 14761, i"OI" => -827, i"ON" => -3212)
const UW1 = Dict{Char,Int}(',' => 156, '、' => 156, '「' => -463, 'あ' => -941, 'う' => -127, 'が' => -553, 'き' => 121, 'こ' => 505, 'で' => -201, 'と' => -547, 'ど' => -123, 'に' => -789, 'の' => -185, 'は' => -847, 'も' => -466, 'や' => -470, 'よ' => 182, 'ら' => -292, 'り' => 208, 'れ' => 169, 'を' => -446, 'ん' => -137, '・' => -135, '主' => -402, '京' => -268, '区' => -912, '午' => 871, '国' => -460, '大' => 561, '委' => 729, '市' => -411, '日' => -141, '理' => 361, '生' => -408, '県' => -386, '都' => -718, '｢' => -463, '･' => -135)
const UW2 = Dict{Char,Int}(',' => -829, '、' => -829, '〇' => 892, '「' => -645, '」' => 3145, 'あ' => -538, 'い' => 505, 'う' => 134, 'お' => -502, 'か' => 1454, 'が' => -856, 'く' => -412, 'こ' => 1141, 'さ' => 878, 'ざ' => 540, 'し' => 1529, 'す' => -675, 'せ' => 300, 'そ' => -1011, 'た' => 188, 'だ' => 1837, 'つ' => -949, 'て' => -291, 'で' => -268, 'と' => -981, 'ど' => 1273, 'な' => 1063, 'に' => -1764, 'の' => 130, 'は' => -409, 'ひ' => -1273, 'べ' => 1261, 'ま' => 600, 'も' => -1263, 'や' => -402, 'よ' => 1639, 'り' => -579, 'る' => -694, 'れ' => 571, 'を' => -2516, 'ん' => 2095, 'ア' => -587, 'カ' => 306, 'キ' => 568, 'ッ' => 831, '三' => -758, '不' => -2150, '世' => -302, '中' => -968, '主' => -861, '事' => 492, '人' => -123, '会' => 978, '保' => 362, '入' => 548, '初' => -3025, '副' => -1566, '北' => -3414, '区' => -422, '大' => -1769, '天' => -865, '太' => -483, '子' => -1519, '学' => 760, '実' => 1023, '小' => -2009, '市' => -813, '年' => -1060, '強' => 1067, '手' => -1519, '揺' => -1033, '政' => 1522, '文' => -1355, '新' => -1682, '日' => -1815, '明' => -1462, '最' => -630, '朝' => -1843, '本' => -1650, '東' => -931, '果' => -665, '次' => -2378, '民' => -180, '気' => -1740, '理' => 752, '発' => 529, '目' => -1584, '相' => -242, '県' => -1165, '立' => -763, '第' => 810, '米' => 509, '自' => -1353, '行' => 838, '西' => -744, '見' => -3874, '調' => 1010, '議' => 1198, '込' => 3041, '開' => 1758, '間' => -1257, '｢' => -645, '｣' => 3145, 'ｯ' => 831, 'ｱ' => -587, 'ｶ' => 306, 'ｷ' => 568)
const UW3 = Dict{Char,Int}(',' => 4889, '1' => -800, '−' => -1723, '、' => 4889, '々' => -2311, '〇' => 5827, '」' => 2670, '〓' => -3573, 'あ' => -2696, 'い' => 1006, 'う' => 2342, 'え' => 1983, 'お' => -4864, 'か' => -1163, 'が' => 3271, 'く' => 1004, 'け' => 388, 'げ' => 401, 'こ' => -3552, 'ご' => -3116, 'さ' => -1058, 'し' => -395, 'す' => 584, 'せ' => 3685, 'そ' => -5228, 'た' => 842, 'ち' => -521, 'っ' => -1444, 'つ' => -1081, 'て' => 6167, 'で' => 2318, 'と' => 1691, 'ど' => -899, 'な' => -2788, 'に' => 2745, 'の' => 4056, 'は' => 4555, 'ひ' => -2171, 'ふ' => -1798, 'へ' => 1199, 'ほ' => -5516, 'ま' => -4384, 'み' => -120, 'め' => 1205, 'も' => 2323, 'や' => -788, 'よ' => -202, 'ら' => 727, 'り' => 649, 'る' => 5905, 'れ' => 2773, 'わ' => -1207, 'を' => 6620, 'ん' => -518, 'ア' => 551, 'グ' => 1319, 'ス' => 874, 'ッ' => -1350, 'ト' => 521, 'ム' => 1109, 'ル' => 1591, 'ロ' => 2201, 'ン' => 278, '・' => -3794, '一' => -1619, '下' => -1759, '世' => -2087, '両' => 3815, '中' => 653, '主' => -758, '予' => -1193, '二' => 974, '人' => 2742, '今' => 792, '他' => 1889, '以' => -1368, '低' => 811, '何' => 4265, '作' => -361, '保' => -2439, '元' => 4858, '党' => 3593, '全' => 1574, '公' => -3030, '六' => 755, '共' => -1880, '円' => 5807, '再' => 3095, '分' => 457, '初' => 2475, '別' => 1129, '前' => 2286, '副' => 4437, '力' => 365, '動' => -949, '務' => -1872, '化' => 1327, '北' => -1038, '区' => 4646, '千' => -2309, '午' => -783, '協' => -1006, '口' => 483, '右' => 1233, '各' => 3588, '合' => -241, '同' => 3906, '和' => -837, '員' => 4513, '国' => 642, '型' => 1389, '場' => 1219, '外' => -241, '妻' => 2016, '学' => -1356, '安' => -423, '実' => -1008, '家' => 1078, '小' => -513, '少' => -3102, '州' => 1155, '市' => 3197, '平' => -1804, '年' => 2416, '広' => -1030, '府' => 1605, '度' => 1452, '建' => -2352, '当' => -3885, '得' => 1905, '思' => -1291, '性' => 1822, '戸' => -488, '指' => -3973, '政' => -2013, '教' => -1479, '数' => 3222, '文' => -1489, '新' => 1764, '日' => 2099, '旧' => 5792, '昨' => -661, '時' => -1248, '曜' => -951, '最' => -937, '月' => 4125, '期' => 360, '李' => 3094, '村' => 364, '東' => -805, '核' => 5156, '森' => 2438, '業' => 484, '氏' => 2613, '民' => -1694, '決' => -1073, '法' => 1868, '海' => -495, '無' => 979, '物' => 461, '特' => -3850, '生' => -273, '用' => 914, '町' => 1215, '的' => 7313, '直' => -1835, '省' => 792, '県' => 6293, '知' => -1528, '私' => 4231, '税' => 401, '立' => -960, '第' => 1201, '米' => 7767, '系' => 3066, '約' => 3663, '級' => 1384, '統' => -4229, '総' => 1163, '線' => 1255, '者' => 6457, '能' => 725, '自' => -2869, '英' => 785, '見' => 1044, '調' => -562, '財' => -733, '費' => 1777, '車' => 1835, '軍' => 1375, '込' => -1504, '通' => -1136, '選' => -681, '郎' => 1026, '郡' => 4404, '部' => 1200, '金' => 2163, '長' => 421, '開' => -1432, '間' => 1302, '関' => -1282, '雨' => 2009, '電' => -1045, '非' => 2066, '駅' => 1620, '１' => -800, '｣' => 2670, '･' => -3794, 'ｯ' => -1350, 'ｱ' => 551, 'ｽ' => 874, 'ﾄ' => 521, 'ﾑ' => 1109, 'ﾙ' => 1591, 'ﾛ' => 2201, 'ﾝ' => 278)
const UW4 = Dict{Char,Int}(',' => 3930, '.' => 3508, '―' => -4841, '、' => 3930, '。' => 3508, '〇' => 4999, '「' => 1895, '」' => 3798, '〓' => -5156, 'あ' => 4752, 'い' => -3435, 'う' => -640, 'え' => -2514, 'お' => 2405, 'か' => 530, 'が' => 6006, 'き' => -4482, 'ぎ' => -3821, 'く' => -3788, 'け' => -4376, 'げ' => -4734, 'こ' => 2255, 'ご' => 1979, 'さ' => 2864, 'し' => -843, 'じ' => -2506, 'す' => -731, 'ず' => 1251, 'せ' => 181, 'そ' => 4091, 'た' => 5034, 'だ' => 5408, 'ち' => -3654, 'っ' => -5882, 'つ' => -1659, 'て' => 3994, 'で' => 7410, 'と' => 4547, 'な' => 5433, 'に' => 6499, 'ぬ' => 1853, 'ね' => 1413, 'の' => 7396, 'は' => 8578, 'ば' => 1940, 'ひ' => 4249, 'び' => -4134, 'ふ' => 1345, 'へ' => 6665, 'べ' => -744, 'ほ' => 1464, 'ま' => 1051, 'み' => -2082, 'む' => -882, 'め' => -5046, 'も' => 4169, 'ゃ' => -2666, 'や' => 2795, 'ょ' => -1544, 'よ' => 3351, 'ら' => -2922, 'り' => -9726, 'る' => -14896, 'れ' => -2613, 'ろ' => -4570, 'わ' => -1783, 'を' => 13150, 'ん' => -2352, 'カ' => 2145, 'コ' => 1789, 'セ' => 1287, 'ッ' => -724, 'ト' => -403, 'メ' => -1635, 'ラ' => -881, 'リ' => -541, 'ル' => -856, 'ン' => -3637, '・' => -4371, 'ー' => -11870, '一' => -2069, '中' => 2210, '予' => 782, '事' => -190, '井' => -1768, '人' => 1036, '以' => 544, '会' => 950, '体' => -1286, '作' => 530, '側' => 4292, '先' => 601, '党' => -2006, '共' => -1212, '内' => 584, '円' => 788, '初' => 1347, '前' => 1623, '副' => 3879, '力' => -302, '動' => -740, '務' => -2715, '化' => 776, '区' => 4517, '協' => 1013, '参' => 1555, '合' => -1834, '和' => -681, '員' => -910, '器' => -851, '回' => 1500, '国' => -619, '園' => -1200, '地' => 866, '場' => -1410, '塁' => -2094, '士' => -1413, '多' => 1067, '大' => 571, '子' => -4802, '学' => -1397, '定' => -1057, '寺' => -809, '小' => 1910, '屋' => -1328, '山' => -1500, '島' => -2056, '川' => -2667, '市' => 2771, '年' => 374, '庁' => -4556, '後' => 456, '性' => 553, '感' => 916, '所' => -1566, '支' => 856, '改' => 787, '政' => 2182, '教' => 704, '文' => 522, '方' => -856, '日' => 1798, '時' => 1829, '最' => 845, '月' => -9066, '木' => -485, '来' => -442, '校' => -360, '業' => -1043, '氏' => 5388, '民' => -2716, '気' => -910, '沢' => -939, '済' => -543, '物' => -735, '率' => 672, '球' => -1267, '生' => -1286, '産' => -1101, '田' => -2900, '町' => 1826, '的' => 2586, '目' => 922, '省' => -3485, '県' => 2997, '空' => -867, '立' => -2112, '第' => 788, '米' => 2937, '系' => 786, '約' => 2171, '経' => 1146, '統' => -1169, '総' => 940, '線' => -994, '署' => 749, '者' => 2145, '能' => -730, '般' => -852, '行' => -792, '規' => 792, '警' => -1184, '議' => -244, '谷' => -1000, '賞' => 730, '車' => -1481, '軍' => 1158, '輪' => -1433, '込' => -3370, '近' => 929, '道' => -1291, '選' => 2596, '郎' => -4866, '都' => 1192, '野' => -1100, '銀' => -2213, '長' => 357, '間' => -2344, '院' => -2297, '際' => -2604, '電' => -878, '領' => -1659, '題' => -792, '館' => -1984, '首' => 1749, '高' => 2120, '｢' => 1895, '｣' => 3798, '･' => -4371, 'ｯ' => -724, 'ｰ' => -11870, 'ｶ' => 2145, 'ｺ' => 1789, 'ｾ' => 1287, 'ﾄ' => -403, 'ﾒ' => -1635, 'ﾗ' => -881, 'ﾘ' => -541, 'ﾙ' => -856, 'ﾝ' => -3637)
const UW5 = Dict{Char,Int}(',' => 465, '.' => -299, '1' => -514, E2 => -32768, ']' => -2762, '、' => 465, '。' => -299, '「' => 363, 'あ' => 1655, 'い' => 331, 'う' => -503, 'え' => 1199, 'お' => 527, 'か' => 647, 'が' => -421, 'き' => 1624, 'ぎ' => 1971, 'く' => 312, 'げ' => -983, 'さ' => -1537, 'し' => -1371, 'す' => -852, 'だ' => -1186, 'ち' => 1093, 'っ' => 52, 'つ' => 921, 'て' => -18, 'で' => -850, 'と' => -127, 'ど' => 1682, 'な' => -787, 'に' => -1224, 'の' => -635, 'は' => -578, 'べ' => 1001, 'み' => 502, 'め' => 865, 'ゃ' => 3350, 'ょ' => 854, 'り' => -208, 'る' => 429, 'れ' => 504, 'わ' => 419, 'を' => -1264, 'ん' => 327, 'イ' => 241, 'ル' => 451, 'ン' => -343, '中' => -871, '京' => 722, '会' => -1153, '党' => -654, '務' => 3519, '区' => -901, '告' => 848, '員' => 2104, '大' => -1296, '学' => -548, '定' => 1785, '嵐' => -1304, '市' => -2991, '席' => 921, '年' => 1763, '思' => 872, '所' => -814, '挙' => 1618, '新' => -1682, '日' => 218, '月' => -4353, '査' => 932, '格' => 1356, '機' => -1508, '氏' => -1347, '田' => 240, '町' => -3912, '的' => -3149, '相' => 1319, '省' => -1052, '県' => -4003, '研' => -997, '社' => -278, '空' => -813, '統' => 1955, '者' => -2233, '表' => 663, '語' => -1073, '議' => 1219, '選' => -1018, '郎' => -368, '長' => 786, '間' => 1191, '題' => 2368, '館' => -689, '１' => -514, E2 => -32768, '｢' => 363, 'ｲ' => 241, 'ﾙ' => 451, 'ﾝ' => -343)
const UW6 = Dict{Char,Int}(',' => 227, '.' => 808, '1' => -270, E1 => 306, '、' => 227, '。' => 808, 'あ' => -307, 'う' => 189, 'か' => 241, 'が' => -73, 'く' => -121, 'こ' => -200, 'じ' => 1782, 'す' => 383, 'た' => -428, 'っ' => 573, 'て' => -1014, 'で' => 101, 'と' => -105, 'な' => -253, 'に' => -149, 'の' => -417, 'は' => -236, 'も' => -206, 'り' => 187, 'る' => -135, 'を' => 195, 'ル' => -673, 'ン' => -496, '一' => -277, '中' => 201, '件' => -800, '会' => 624, '前' => 302, '区' => 1792, '員' => -1212, '委' => 798, '学' => -960, '市' => 887, '広' => -695, '後' => 535, '業' => -697, '相' => 753, '社' => -507, '福' => 974, '空' => -822, '者' => 1811, '連' => 463, '郎' => 1082, '１' => -270, E1 => 306, 'ﾙ' => -673, 'ﾝ' => -496)

const CHARDICT = Dict{Char, UInt8}()
for (chars,cat) in (
    ("一二三四五六七八九十百千万億兆",'M'),
    ("々〆ヵヶ", 'H'),
    ('ぁ':'ん','I'),
    ('ァ':'ヴ','K'),
    ("ーｰ\uff9e",'K'),
    ('ｱ':'ﾝ','K'),
    (['a':'z';'A':'Z';'ａ':'ｚ';'Ａ':'Ｚ'],'A'),
    (['0':'9';'０':'９'],'N')
  )
  for c in chars
      CHARDICT[c] = cat
  end
end
const Achar = UInt8('A')
const Ichar = UInt8('I')
const Hchar = UInt8('H')
const Ochar = UInt8('O')
const Uchar = UInt8('U')
const Bchar = UInt8('B')
function ctype(c::Char)
  return get(CHARDICT, c, '一' <= c <= '龠' ? Hchar : Ochar)
end

"""
    tokenize(text::AbstractString)

Given a `text` string, `tokenize` attempts to segment it into a list
of words, and in particular tries to segment Japanese text
into words ("tokens" or "segments"), using the TinySegmenter algorithm.
It returns an array of substrings consisting of the guessed tokens in
`text`, in the order that they appear.
"""
function tokenize{T<:AbstractString}(text::T)
  result = SubString{T}[]
  isempty(text) && return result

  wordstart = start(text)
  pos = wordstart

  p1 = Uchar
  p2 = Uchar
  p3 = Uchar
  w1, w2, w3 = B3, B2, B1
  c1, c2, c3 = Ochar, Ochar, Ochar
  w4 = text[pos]
  c4 = ctype(w4)

  pos1 = nextind(text, pos) # pos + 1 character
  pos2 = nextind(text, pos1) # pos + 2 characters
  if pos == endof(text)
    w5, w6 = E1, E2
    c5, c6 = Ochar, Ochar
  else
    w5 = text[pos1]
    c5 = ctype(w5)
    if pos1 == endof(text)
      w6 = E1
      c6 = Ochar
    else
      w6 = text[pos2]
      c6 = ctype(w6)
    end
  end

  while pos < endof(text)
    score = BIAS
    w1,w2,w3,w4,w5 = w2,w3,w4,w5,w6
    c1,c2,c3,c4,c5 = c2,c3,c4,c5,c6
    pos3 = nextind(text, pos2) # pos + 3
    if pos3 <= endof(text)
      w6 = text[pos3]
      c6 = ctype(w6)
    elseif pos2 == endof(text)
      w6 = E1
      c6 = Ochar
    else # pos1 == endof(text)
      w6 = E2
      c6 = Ochar
    end

    if p1 == Ochar; score += -214; end # score += get(UP1, p1, 0)
    if p2 == Bchar; score += 69; elseif p2 == Ochar; score += 935; end # score += get(UP2, p2, 0)
    if p3 == Bchar; score += 189; end # score += get(UP3, p3, 0)
    score += get(BP1, (p1, p2), 0)
    score += get(BP2, (p2, p3), 0)
    score += get(UW1, w1, 0)
    score += get(UW2, w2, 0)
    score += get(UW3, w3, 0)
    score += get(UW4, w4, 0)
    score += get(UW5, w5, 0)
    score += get(UW6, w6, 0)
    score += get(BW1, (w2, w3), 0)
    score += get(BW2, (w3, w4), 0)
    score += get(BW3, (w4, w5), 0)
    score += get(TW1, (w1, w2, w3), 0)
    score += get(TW2, (w2, w3, w4), 0)
    score += get(TW3, (w3, w4, w5), 0)
    score += get(TW4, (w4, w5, w6), 0)
    score += get(UC1, c1, 0)
    score += get(UC2, c2, 0)
    if c3 == Achar; score += -1370; elseif c3 == Ichar; score += 2311; end # score += get(UC3, c3, 0)
    score += get(UC4, c4, 0)
    score += get(UC5, c5, 0)
    score += get(UC6, c6, 0)
    score += get(BC1, (c2, c3), 0)
    score += get(BC2, (c3, c4), 0)
    score += get(BC3, (c4, c5), 0)
    score += get(TC1, (c1, c2, c3), 0)
    score += get(TC2, (c2, c3, c4), 0)
    score += get(TC3, (c3, c4, c5), 0)
    score += get(TC4, (c4, c5, c6), 0)
    score += get(UQ1, (p1, c1), 0)
    score += get(UQ2, (p2, c2), 0)
    score += get(UQ3, (p3, c3), 0)
    score += get(BQ1, (p2, c2, c3), 0)
    score += get(BQ2, (p2, c3, c4), 0)
    score += get(BQ3, (p3, c2, c3), 0)
    score += get(BQ4, (p3, c3, c4), 0)
    score += get(TQ1, (p2, c1, c2, c3), 0)
    score += get(TQ2, (p2, c2, c3, c4), 0)
    score += get(TQ3, (p3, c1, c2, c3), 0)
    score += get(TQ4, (p3, c2, c3, c4), 0)

    p = Ochar
    if score > 0
      push!(result, SubString(text, wordstart, pos))
      wordstart = pos1
      p = Bchar
    end

    p1 = p2
    p2 = p3
    p3 = p
    pos = pos1
    pos1 = pos2
    pos2 = pos3
  end

  push!(result, SubString(text, wordstart, pos))
  return result
end

end # module


text:
using Documenter
push!(LOAD_PATH,"../src/")
using BasesAndSamples

makedocs(
    sitename = "BasesAndSamples.jl Documentation",
    format = Documenter.HTML(),
    modules = [BasesAndSamples]
)

# Documenter can also automatically deploy documentation to gh-pages.
# See "Hosting Documentation" and deploydocs() in the Documenter manual
# for more information.
deploydocs(
    repo = "github.com/nanleij/BasesAndSamples.jl.git",
    devbranch="main"
)

ext: jl


text:
module YetAnotherHelperSpikeJumpThruController

using ..Ahorn, Maple

@mapdef Entity "YetAnotherHelper/SpikeJumpThruController" SpikeJumpThruController(x::Integer, y::Integer, persistent::Bool=false)

const placements = Ahorn.PlacementDict(
    "Spiked Jump Through Controller (Yet Another Helper)" => Ahorn.EntityPlacement(
        SpikeJumpThruController,
        "point"
    )
)

sprite = "ahorn/YetAnotherHelper/spikeJumpThruController"

function Ahorn.selection(entity::SpikeJumpThruController)
    x, y = Ahorn.position(entity)

    return Ahorn.getSpriteRectangle(sprite, x, y)
end

function Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::SpikeJumpThruController, room::Maple.Room)
	Ahorn.drawSprite(ctx, sprite, 0, -0)
end

end

max_stars_repo_name: YetAnotherHelper/YetAnotherHelper

max_issues_repo_name: YetAnotherHelper/YetAnotherHelper

max_forks_repo_name: YetAnotherHelper/YetAnotherHelper


text:
# scep256k1 constants
A = 0
B = 7
P = big(2)^256 - 2^32 - 977
N = big"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"

"Element in an scep256k1 field"
struct S256Element <: PrimeField
     𝑛::BigInt
     𝑝::BigInt
     S256Element(𝑛,𝑝=P) = !infield(𝑛,𝑝) ? throw(DomainError("𝑛 is not in field range")) : new(𝑛,𝑝)
end

S256Element(x::S256Element) = x

"Formats S256Element showing 𝑛 in hexadecimal format"
function show(io::IO, z::S256Element)
    print(io, string(z.𝑛, base = 16),"\n(in scep256k1 field)")
end

"Returns the square root of an S256Element"
function sqrt(𝑃::S256Element)
    return 𝑃^fld(ECC.P + 1, 4)
end

A = S256Element(A)
B = S256Element(B)

"""
    S256Point{T<:Number}

S256Point(𝑥::T, 𝑦::T) where {T<:Union{S256FieldElement, Integer, Infinity}}
represents a point in an scep256k1 field.
"""
struct S256Point{T<:Number} <: AbstractPoint
    𝑥::T
    𝑦::T
    𝑎::S256Element
    𝑏::S256Element
    S256Point{T}(𝑥,𝑦,𝑎=A,𝑏=B) where {T<:Number} = new(𝑥,𝑦,𝑎,𝑏)
end

S256Point(::Infinity,::Infinity) = S256Point{Infinity}(∞,∞)
S256Point(𝑥::S256Element,𝑦::S256Element) = !iselliptic(𝑥,𝑦,A,B) ? throw(DomainError("Point is not on curve")) : S256Point{S256Element}(𝑥,𝑦)
S256Point(x::Integer,y::Integer) = S256Point{S256Element}(S256Element(big(x)),S256Element(big(y)))

"Formats S256Point as (𝑥, 𝑦) in hexadecimal format"
function show(io::IO, z::S256Point)
    if typeof(z.𝑥) <: PrimeField
        x, y = z.𝑥.𝑛, z.𝑦.𝑛
    else
        x, y = z.𝑥, z.𝑦
    end
    print(io, "scep256k1 Point(𝑥,𝑦):\n", string(x, base = 16), ",\n", string(y, base = 16))
end

"Compares two S256Point, returns true if coordinates are equal"
==(x::S256Point, y::S256Point) = x.𝑥 == y.𝑥 && x.𝑦 == y.𝑦

"Scalar multiplication of an S256Point"
function *(λ::Integer,𝑃::S256Point)
    𝑅 = S256Point(∞, ∞)
    λ =  mod(λ, N)
    while λ > 0
        if λ & 1 != 0
            𝑅 += 𝑃
        end
        𝑃 += 𝑃
        λ >>= 1
    end
    return 𝑅
end

"""
Serialize an S256Point() to compressed SEC format, uncompressed if false is set
as second argument.

'point2sec(P::T, compressed::Bool=true) where {T<:S256Point} -> Array{UInt8,1}'
"""
function point2sec(P::T, compressed::Bool=true) where {T<:S256Point}
    xbin = int2bytes(P.𝑥.𝑛)
    if compressed
        if mod(P.𝑦.𝑛, 2) == 0
            prefix = 0x02
        else
            prefix = 0x03
        end
        return cat(prefix,xbin;dims=1)
    else
        return cat(0x04,xbin,int2bytes(P.𝑦.𝑛);dims=1)
    end
end

"""
Parse a SEC binary to an S256Point()

sec2point(sec_bin::AbstractArray{UInt8}) -> S256Point
"""
function sec2point(sec_bin::AbstractArray{UInt8})
    if sec_bin[1] == 4
        𝑥 = bytes2int(sec_bin[2:33])
        𝑦 = bytes2int(sec_bin[34:65])
        return S256Point(𝑥, 𝑦)
    end
    is_even = sec_bin[1] == 2
    𝑥 = ECC.S256Element(bytes2int(sec_bin[2:end]))
    α = 𝑥^3 + ECC.S256Element(ECC.B)
    β = sqrt(α)
    if mod(β.𝑛, 2) == 0
        evenβ = β
        oddβ = S256Element(ECC.P - β.𝑛)
    else
        evenβ = S256Element(ECC.P - β.𝑛)
        oddβ = β
    end
    if is_even
        return S256Point(𝑥, evenβ)
    else
        return S256Point(𝑥, oddβ)
    end
end

"""
Returns true if Signature is valid for 𝑧 given 𝑃, false if not

verify(𝑃::AbstractPoint, 𝑧::Integer, sig::Signature) -> Bool
"""
function verify(𝑃::AbstractPoint,𝑧::Integer,sig::Signature)
    𝑠⁻¹ = powermod(sig.𝑠, N - 2, N)
    𝑢 = mod(𝑧 * 𝑠⁻¹, N)
    𝑣 = mod(sig.𝑟 * 𝑠⁻¹, N)
    𝑅 = 𝑢 * G + 𝑣 * 𝑃
    return 𝑅.𝑥.𝑛 == sig.𝑟
end

# scep256k1 generator point
G = S256Point(big"0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
              big"0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")


text:
struct PolygonGeometry <: Gadfly.GeometryElement
    default_statistic::Gadfly.StatisticElement
    order::Int
    fill::Bool
    preserve_order::Bool
    tag::Symbol
end

PolygonGeometry(default_statistic=Gadfly.Stat.identity(); order=0, fill=false, preserve_order=false, tag=empty_tag) =
        PolygonGeometry(default_statistic, order, fill, preserve_order, tag)

"""
    Geom.polygon[(; order=0, fill=false, preserve_order=false)]

Draw polygons with vertices specified by the `x` and `y` aesthetics.
Optionally plot multiple polygons according to the `group`, `color`, `linestyle`, and/or `alpha`
aesthetics.  `order` controls whether the polygon(s) are underneath or on top
of other forms.  If `fill=true`, fill the polygons using `Theme.lowlight_color` and stroke the polygons using
`Theme.discrete_highlight_color`. If `fill=false` stroke the polygons using `Theme.lowlight_color`.
If `preserve_order=true` connect points in the order they are given, otherwise order the points
around their centroid.
"""
const polygon = PolygonGeometry

element_aesthetics(::PolygonGeometry) = [:x, :y, :color, :group, :linestyle, :alpha]

"""
    Geom.ellipse[(; distribution=MvNormal, levels=[0.95], nsegments=51, fill=false)]

Draw a confidence ellipse, using a parametric multivariate distribution, for a
scatter of points specified by the `x` and `y` aesthetics.  Optionally plot
multiple ellipses according to the `group` and/or `color` aesthetics. `levels` are auto-mapped to the `linestyle` aesthetic.
This geometry is equivalent to [`Geom.polygon`](@ref) with [`Stat.ellipse`](@ref);
see the latter for more information.
"""
ellipse(; distribution::Type{<:ContinuousMultivariateDistribution}=MvNormal,
    levels::Vector=[0.95], nsegments::Int=51, fill::Bool=false) =
    PolygonGeometry(Gadfly.Stat.ellipse(distribution, levels, nsegments), preserve_order=true, fill=fill)

default_statistic(geom::PolygonGeometry) = geom.default_statistic

function polygon_points(x::AbstractVector, y::AbstractVector, preserve_order::Bool)
    XT, YT = eltype(x), eltype(y)
    preserve_order && return collect(Tuple{XT,YT}, zip(x, y))
    p = sortperm(atan.(x.-mean(x), y.-mean(y)))
    return collect(Tuple{XT,YT}, zip(x, y))[p]
end

function render(geom::PolygonGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
    Gadfly.assert_aesthetics_defined("Geom.polygon", aes, :x, :y)

    default_aes = Gadfly.Aesthetics()
    default_aes.group = IndirectArray([1])
    default_aes.color = Colorant[theme.default_color]
    default_aes.linestyle = [1]
    default_aes.alpha = [1]
    aes = inherit(aes, default_aes)

    aes_x, aes_y, aes_color, aes_linestyle, aes_group, aes_alpha = concretize(aes.x, aes.y, aes.color, aes.linestyle, aes.group, aes.alpha)

    XT, YT, CT, GT, LST, AT = eltype(aes_x), eltype(aes_y), eltype(aes_color), eltype(aes_group), eltype(aes_linestyle), eltype(aes_alpha)

    groups = collect((Tuple{CT, GT, LST, AT}), Compose.cyclezip(aes_color, aes_group, aes_linestyle, aes_alpha))
    ugroups = unique(groups)
    nugroups = length(ugroups)

    polys = Vector{Vector{Tuple{XT,YT}}}(undef, nugroups)
    colors = Vector{Colorant}(undef, nugroups)
    stroke_colors = Vector{Colorant}(undef, nugroups)
    linestyles = Vector{Vector{Measure}}(undef, nugroups)
    linestyle_palette_length = length(theme.line_style)
    alphas = Vector{Float64}(undef, nugroups)
    alpha_discrete  = AT <: Int
    linestyle_discrete = LST <: Int

    if nugroups==1
        polys[1] = polygon_points(aes_x, aes_y, geom.preserve_order)
    elseif nugroups>1
        for (k,g) in enumerate(ugroups)
            i = groups.==[g]
            polys[k] = polygon_points(aes_x[i], aes_y[i], geom.preserve_order)
        end
    end

    for (k, (c, g, ls, a)) in enumerate(ugroups)
        colors[k] = parse_colorant(theme.lowlight_color(c))
        stroke_colors[k] = parse_colorant(theme.discrete_highlight_color(c))
        linestyles[k] =  linestyle_discrete ? get_stroke_vector(theme.line_style[mod1(ls, linestyle_palette_length)]) : get_stroke_vector(ls)
        alphas[k] = alpha_discrete ? theme.alphas[a] : a
    end

    properties = geom.fill ? (fill(colors), stroke(stroke_colors), fillopacity(alphas), strokedash(linestyles)) :
        (fill(nothing), stroke(colors), strokedash(linestyles))

    ctx = context(order=geom.order)
    compose!(ctx, Compose.polygon(polys, geom.tag), properties...)

    return compose!(ctx, linewidth(theme.line_width), svgclass("geometry"))
end


text:
# Julia wrapper for header: /usr/local/include/libavfilter/avfilter.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

export
    #avfilter_version,
    avfilter_configuration,
    avfilter_license,
    avfilter_copy_buffer_ref_props,
    avfilter_ref_buffer,
    avfilter_unref_buffer,
    avfilter_make_format_list,
    avfilter_add_format,
    avfilter_all_formats,
    avfilter_merge_formats,
    avfilter_formats_ref,
    avfilter_formats_unref,
    avfilter_formats_changeref,
    avfilter_default_start_frame,
    avfilter_default_draw_slice,
    avfilter_default_end_frame,
    avfilter_default_filter_samples,
    avfilter_default_config_output_link,
    avfilter_default_config_input_link,
    avfilter_default_get_video_buffer,
    avfilter_default_get_audio_buffer,
    avfilter_set_common_formats,
    avfilter_default_query_formats,
    avfilter_null_start_frame,
    avfilter_null_draw_slice,
    avfilter_null_end_frame,
    avfilter_null_filter_samples,
    avfilter_null_get_video_buffer,
    avfilter_null_get_audio_buffer,
    avfilter_link,
    avfilter_config_links,
    avfilter_get_video_buffer,
    avfilter_get_video_buffer_ref_from_arrays,
    avfilter_get_audio_buffer,
    avfilter_request_frame,
    avfilter_poll_frame,
    avfilter_start_frame,
    avfilter_end_frame,
    avfilter_draw_slice,
    avfilter_filter_samples,
    avfilter_register_all,
    avfilter_uninit,
    avfilter_register,
    avfilter_get_by_name,
    av_filter_next,
    avfilter_open,
    avfilter_init_filter,
    avfilter_free,
    avfilter_insert_filter,
    avfilter_insert_pad,
    avfilter_insert_inpad,
    avfilter_insert_outpad,
    avfilter_copy_frame_props

function avfilter_version()
    ccall((:avfilter_version,libavfilter),Uint32,())
end

function avfilter_configuration()
    ccall((:avfilter_configuration,libavfilter),Ptr{Uint8},())
end

function avfilter_license()
    ccall((:avfilter_license,libavfilter),Ptr{Uint8},())
end

function avfilter_copy_buffer_ref_props(dst,src)
    ccall((:avfilter_copy_buffer_ref_props,libavfilter),Void,(Ptr{AVFilterBufferRef},Ptr{AVFilterBufferRef}),dst,src)
end

function avfilter_ref_buffer(ref,pmask::Integer)
    ccall((:avfilter_ref_buffer,libavfilter),Ptr{AVFilterBufferRef},(Ptr{AVFilterBufferRef},Cint),ref,pmask)
end

function avfilter_unref_buffer(ref)
    ccall((:avfilter_unref_buffer,libavfilter),Void,(Ptr{AVFilterBufferRef},),ref)
end

function avfilter_make_format_list(fmts)
    ccall((:avfilter_make_format_list,libavfilter),Ptr{AVFilterFormats},(Ptr{Cint},),fmts)
end

function avfilter_add_format(avff,fmt::Integer)
    ccall((:avfilter_add_format,libavfilter),Cint,(Ptr{Ptr{AVFilterFormats}},Cint),avff,fmt)
end

function avfilter_all_formats(_type::AVMediaType)
    ccall((:avfilter_all_formats,libavfilter),Ptr{AVFilterFormats},(AVMediaType,),_type)
end

function avfilter_merge_formats(a,b)
    ccall((:avfilter_merge_formats,libavfilter),Ptr{AVFilterFormats},(Ptr{AVFilterFormats},Ptr{AVFilterFormats}),a,b)
end

function avfilter_formats_ref(formats,ref)
    ccall((:avfilter_formats_ref,libavfilter),Void,(Ptr{AVFilterFormats},Ptr{Ptr{AVFilterFormats}}),formats,ref)
end

function avfilter_formats_unref(ref)
    ccall((:avfilter_formats_unref,libavfilter),Void,(Ptr{Ptr{AVFilterFormats}},),ref)
end

function avfilter_formats_changeref(oldref,newref)
    ccall((:avfilter_formats_changeref,libavfilter),Void,(Ptr{Ptr{AVFilterFormats}},Ptr{Ptr{AVFilterFormats}}),oldref,newref)
end

function avfilter_default_start_frame(link,picref)
    ccall((:avfilter_default_start_frame,libavfilter),Void,(Ptr{AVFilterLink},Ptr{AVFilterBufferRef}),link,picref)
end

function avfilter_default_draw_slice(link,y::Integer,h::Integer,slice_dir::Integer)
    ccall((:avfilter_default_draw_slice,libavfilter),Void,(Ptr{AVFilterLink},Cint,Cint,Cint),link,y,h,slice_dir)
end

function avfilter_default_end_frame(link)
    ccall((:avfilter_default_end_frame,libavfilter),Void,(Ptr{AVFilterLink},),link)
end

function avfilter_default_filter_samples(link,samplesref)
    ccall((:avfilter_default_filter_samples,libavfilter),Void,(Ptr{AVFilterLink},Ptr{AVFilterBufferRef}),link,samplesref)
end

function avfilter_default_config_output_link(link)
    ccall((:avfilter_default_config_output_link,libavfilter),Cint,(Ptr{AVFilterLink},),link)
end

function avfilter_default_config_input_link(link)
    ccall((:avfilter_default_config_input_link,libavfilter),Cint,(Ptr{AVFilterLink},),link)
end

function avfilter_default_get_video_buffer(link,perms::Integer,w::Integer,h::Integer)
    ccall((:avfilter_default_get_video_buffer,libavfilter),Ptr{AVFilterBufferRef},(Ptr{AVFilterLink},Cint,Cint,Cint),link,perms,w,h)
end

function avfilter_default_get_audio_buffer(link,perms::Integer,sample_fmt::AVSampleFormat,size::Integer,channel_layout::Uint64,planar::Integer)
    ccall((:avfilter_default_get_audio_buffer,libavfilter),Ptr{AVFilterBufferRef},(Ptr{AVFilterLink},Cint,AVSampleFormat,Cint,Uint64,Cint),link,perms,sample_fmt,size,channel_layout,planar)
end

function avfilter_set_common_formats(ctx,formats)
    ccall((:avfilter_set_common_formats,libavfilter),Void,(Ptr{AVFilterContext},Ptr{AVFilterFormats}),ctx,formats)
end

function avfilter_default_query_formats(ctx)
    ccall((:avfilter_default_query_formats,libavfilter),Cint,(Ptr{AVFilterContext},),ctx)
end

function avfilter_null_start_frame(link,picref)
    ccall((:avfilter_null_start_frame,libavfilter),Void,(Ptr{AVFilterLink},Ptr{AVFilterBufferRef}),link,picref)
end

function avfilter_null_draw_slice(link,y::Integer,h::Integer,slice_dir::Integer)
    ccall((:avfilter_null_draw_slice,libavfilter),Void,(Ptr{AVFilterLink},Cint,Cint,Cint),link,y,h,slice_dir)
end

function avfilter_null_end_frame(link)
    ccall((:avfilter_null_end_frame,libavfilter),Void,(Ptr{AVFilterLink},),link)
end

function avfilter_null_filter_samples(link,samplesref)
    ccall((:avfilter_null_filter_samples,libavfilter),Void,(Ptr{AVFilterLink},Ptr{AVFilterBufferRef}),link,samplesref)
end

function avfilter_null_get_video_buffer(link,perms::Integer,w::Integer,h::Integer)
    ccall((:avfilter_null_get_video_buffer,libavfilter),Ptr{AVFilterBufferRef},(Ptr{AVFilterLink},Cint,Cint,Cint),link,perms,w,h)
end

function avfilter_null_get_audio_buffer(link,perms::Integer,sample_fmt::AVSampleFormat,size::Integer,channel_layout::Uint64,planar::Integer)
    ccall((:avfilter_null_get_audio_buffer,libavfilter),Ptr{AVFilterBufferRef},(Ptr{AVFilterLink},Cint,AVSampleFormat,Cint,Uint64,Cint),link,perms,sample_fmt,size,channel_layout,planar)
end

function avfilter_link(src,srcpad::Integer,dst,dstpad::Integer)
    ccall((:avfilter_link,libavfilter),Cint,(Ptr{AVFilterContext},Uint32,Ptr{AVFilterContext},Uint32),src,srcpad,dst,dstpad)
end

function avfilter_config_links(filter)
    ccall((:avfilter_config_links,libavfilter),Cint,(Ptr{AVFilterContext},),filter)
end

function avfilter_get_video_buffer(link,perms::Integer,w::Integer,h::Integer)
    ccall((:avfilter_get_video_buffer,libavfilter),Ptr{AVFilterBufferRef},(Ptr{AVFilterLink},Cint,Cint,Cint),link,perms,w,h)
end

function avfilter_get_video_buffer_ref_from_arrays(data,linesize,perms::Integer,w::Integer,h::Integer,format::PixelFormat)
    ccall((:avfilter_get_video_buffer_ref_from_arrays,libavfilter),Ptr{AVFilterBufferRef},(Ptr{Ptr{Uint8}},Ptr{Cint},Cint,Cint,Cint,PixelFormat),data,linesize,perms,w,h,format)
end

function avfilter_get_audio_buffer(link,perms::Integer,sample_fmt::AVSampleFormat,size::Integer,channel_layout::Uint64,planar::Integer)
    ccall((:avfilter_get_audio_buffer,libavfilter),Ptr{AVFilterBufferRef},(Ptr{AVFilterLink},Cint,AVSampleFormat,Cint,Uint64,Cint),link,perms,sample_fmt,size,channel_layout,planar)
end

function avfilter_request_frame(link)
    ccall((:avfilter_request_frame,libavfilter),Cint,(Ptr{AVFilterLink},),link)
end

function avfilter_poll_frame(link)
    ccall((:avfilter_poll_frame,libavfilter),Cint,(Ptr{AVFilterLink},),link)
end

function avfilter_start_frame(link,picref)
    ccall((:avfilter_start_frame,libavfilter),Void,(Ptr{AVFilterLink},Ptr{AVFilterBufferRef}),link,picref)
end

function avfilter_end_frame(link)
    ccall((:avfilter_end_frame,libavfilter),Void,(Ptr{AVFilterLink},),link)
end

function avfilter_draw_slice(link,y::Integer,h::Integer,slice_dir::Integer)
    ccall((:avfilter_draw_slice,libavfilter),Void,(Ptr{AVFilterLink},Cint,Cint,Cint),link,y,h,slice_dir)
end

function avfilter_filter_samples(link,samplesref)
    ccall((:avfilter_filter_samples,libavfilter),Void,(Ptr{AVFilterLink},Ptr{AVFilterBufferRef}),link,samplesref)
end

function avfilter_register_all()
    ccall((:avfilter_register_all,libavfilter),Void,())
end

function avfilter_uninit()
    ccall((:avfilter_uninit,libavfilter),Void,())
end

function avfilter_register(filter)
    ccall((:avfilter_register,libavfilter),Cint,(Ptr{AVFilter},),filter)
end

function avfilter_get_by_name(name)
    ccall((:avfilter_get_by_name,libavfilter),Ptr{AVFilter},(Ptr{Uint8},),name)
end

function av_filter_next(filter)
    ccall((:av_filter_next,libavfilter),Ptr{Ptr{AVFilter}},(Ptr{Ptr{AVFilter}},),filter)
end

function avfilter_open(filter_ctx,filter,inst_name)
    ccall((:avfilter_open,libavfilter),Cint,(Ptr{Ptr{AVFilterContext}},Ptr{AVFilter},Ptr{Uint8}),filter_ctx,filter,inst_name)
end

function avfilter_init_filter(filter,args,opaque)
    ccall((:avfilter_init_filter,libavfilter),Cint,(Ptr{AVFilterContext},Ptr{Uint8},Ptr{Void}),filter,args,opaque)
end

function avfilter_free(filter)
    ccall((:avfilter_free,libavfilter),Void,(Ptr{AVFilterContext},),filter)
end

function avfilter_insert_filter(link,filt,filt_srcpad_idx::Integer,filt_dstpad_idx::Integer)
    ccall((:avfilter_insert_filter,libavfilter),Cint,(Ptr{AVFilterLink},Ptr{AVFilterContext},Uint32,Uint32),link,filt,filt_srcpad_idx,filt_dstpad_idx)
end

function avfilter_insert_pad(idx::Integer,count,padidx_off::Csize_t,pads,links,newpad)
    ccall((:avfilter_insert_pad,libavfilter),Void,(Uint32,Ptr{Uint32},Csize_t,Ptr{Ptr{AVFilterPad}},Ptr{Ptr{Ptr{AVFilterLink}}},Ptr{AVFilterPad}),idx,count,padidx_off,pads,links,newpad)
end

function avfilter_insert_inpad(f,index::Integer,p)
    ccall((:avfilter_insert_inpad,libavfilter),Void,(Ptr{AVFilterContext},Uint32,Ptr{AVFilterPad}),f,index,p)
end

function avfilter_insert_outpad(f,index::Integer,p)
    ccall((:avfilter_insert_outpad,libavfilter),Void,(Ptr{AVFilterContext},Uint32,Ptr{AVFilterPad}),f,index,p)
end

function avfilter_copy_frame_props(dst,src)
    ccall((:avfilter_copy_frame_props,libavfilter),Cint,(Ptr{AVFilterBufferRef},Ptr{AVFrame}),dst,src)
end


text:
"""
    RecombineMatrix{T} <: AbstractMatrix{T}

Matrix for transformation from coefficients of the recombined basis, to the
corresponding B-spline basis coefficients.

# Extended help

The transformation matrix ``M`` is defined by
```math
ϕ_j = M_{ij} b_i,
```
where ``b_j(x)`` and ``ϕ_i(x)`` are elements of the B-spline and recombined
bases, respectively.

This matrix allows to pass from known coefficients ``u_j`` in the recombined
basis ``ϕ_j``, to the respective coefficients ``v_i`` in the B-spline basis
``b_i``:
```math
\\bm{v} = \\mathbf{M} \\bm{u}.
```

Note that the matrix is not square: it has dimensions ``N × M``, where ``N``
is the length of the B-spline basis, and ``M = N - δ`` is that of the
recombined basis (see [`RecombinedBSplineBasis`](@ref) for details).

Due to the local support of B-splines, basis recombination can be performed
by combining just a small set of B-splines near the boundaries (as discussed in
[`RecombinedBSplineBasis`](@ref)).
This leads to a recombination matrix which is almost a diagonal of ones, plus
a few extra super- and sub-diagonal elements in the upper left and lower right
corners, respectively.
The matrix is stored in a memory-efficient way that also allows fast access to
its elements.

Efficient implementations of matrix-vector products (using the `*` operator or
`LinearAlgebra.mul!`) and of left division of vectors (using `\\` or
`LinearAlgebra.ldiv!`) are included.
These two operations can be used to transform between coefficients in the
original and recombined bases.

Note that, since the recombined basis forms a subspace of the original basis
(which is related to the rectangular shape of the matrix),
it is generally not possible to obtain recombined coefficients from original
coefficients, unless the latter already satisfy the constraints encoded in the
recombined basis.
The left division operation will throw a [`NoUniqueSolutionError`](@ref) if that
is not the case.

---

    RecombineMatrix(ops::Tuple{Vararg{AbstractDifferentialOp}},
                    B::BSplineBasis, [T])

Construct recombination matrix describing a B-spline basis recombination.

The default element type `T` is generally `Float64`, except for specific
differential operators which yield a matrix of zeroes and ones, for which `Bool`
is the default.

See the [`RecombinedBSplineBasis`](@ref) constructor for details on the
`ops` argument.
"""
struct RecombineMatrix{T,
                       DiffOps <: Tuple{Vararg{AbstractDifferentialOp}},
                       n, n1,   # nc = n1 - n
                       Corner <: SMatrix{n1,n,T}} <: AbstractMatrix{T}
    ops :: DiffOps  # list of differential operators for BCs
    M :: Int      # length of recombined basis (= N - 2nc)
    N :: Int      # length of B-spline basis
    ul :: Corner  # upper-left corner of matrix, size (n1, n)
    lr :: Corner  # lower-right corner of matrix, size (n1, n)
    function RecombineMatrix(ops::Tuple{Vararg{AbstractDifferentialOp}},
                             N::Integer, ul::SMatrix{n1,n}, lr::SMatrix{n1,n}) where {n1,n}
        if n1 <= n
            throw(ArgumentError("matrices must have dimensions (m, n) with m > n"))
        end
        M = N - 2 * length(ops)
        T = eltype(ul)
        Corner = typeof(ul)
        Ops = typeof(ops)
        new{T, Ops, n, n1, Corner}(ops, M, N, ul, lr)
    end
end

# Default element type of recombination matrix.
# In some specific cases we can use Bool...
_default_eltype(::Vararg{AbstractDifferentialOp}) = Float64
_default_eltype(::Derivative{0}) = Bool  # Dirichlet BCs
_default_eltype(::Derivative{1}) = Bool  # Neumann BCs

# Case (D(0), D(1), D(2), ...)
_default_eltype(::Derivative{0}, ::Derivative{1}, ::Vararg{Derivative}) = Bool

RecombineMatrix(ops::Tuple{Vararg{AbstractDifferentialOp}}, B::BSplineBasis) =
    RecombineMatrix(ops, B, _default_eltype(ops...))

# Specialisation for Dirichlet BCs.
function RecombineMatrix(op::Tuple{Derivative{0}}, B::BSplineBasis,
                         ::Type{T}) where {T}
    _check_bspline_order(op, B)
    N = length(B)
    ul = SMatrix{1,0,T}()
    lr = copy(ul)
    RecombineMatrix(op, N, ul, lr)
end

# Specialisation for Neumann BCs.
function RecombineMatrix(op::Tuple{Derivative{1}}, B::BSplineBasis,
                         ::Type{T}) where {T}
    _check_bspline_order(op, B)
    N = length(B)
    ul = SMatrix{2,1,T}(1, 1)
    lr = copy(ul)
    RecombineMatrix(op, N, ul, lr)
end

# Generalisation to higher orders and to more general differential operators
# (this includes Robin BCs, for instance).
#
# If more than one operator is passed, they must be of the form
#
#    (D(0), D(1), ..., D(m - 2), D(m - 1), [D(n)]),
#
# where the last D(n) is optional, and satisfies n ≥ m + 1.
# In this case, the first `m` B-splines are dropped, and the next `n - m + 1`
# B-splines are recombined into `q = n - m` functions.
#
# That last operator is allowed to be a linear combination of `Derivative`s.
# In that case, `n` is the maximum degree of the operator.
function RecombineMatrix(ops::Tuple{Vararg{AbstractDifferentialOp}},
                         B::BSplineBasis, ::Type{T}) where {T}
    _check_bspline_order(ops, B)
    op = last(ops)
    n = max_order(op)
    m = _bsplines_to_drop(ops...)
    _make_matrix(Val(n + 1), Val(m), ops, B, T)
end

# Case of mixed BCs (D(0), D(1), ..., D(n)).
# B-splines are dropped, and new functions are not created.
# This is a generalisation of the Dirichlet case.
function _make_matrix(::Val{n}, ::Val{n}, ops, B, ::Type{T}) where {n,T}
    Nc = length(ops)
    @assert Nc >= 2  # case Nc = 1 is treated by different functions
    N = length(B)
    ul = SMatrix{Nc,0,T}()
    lr = copy(ul)
    RecombineMatrix(ops, N, ul, lr)
end

# Case of single BC, or mixed BCs where the last one is "different" from the
# others.
function _make_matrix(::Val{n1}, ::Val{m}, ops, B, ::Type{T}) where {n1,m,T}
    n = n1 - 1
    q = n - m
    @assert q >= 1

    Nc = length(ops)  # this is the number of constraints
    a, b = boundaries(B)
    Ca = zeros(T, q + Nc, q)
    Cb = copy(Ca)

    N = length(B)
    op = last(ops)

    let x = a
        # Indices of B-splines to recombine.
        is = ntuple(d -> m + d, Val(q + 1))

        # Coefficients of odd derivatives must change sign, since d/dn = -d/dx
        # on the left boundary.
        opn = dot(op, LeftNormal())

        # Evaluate n-th derivatives of bⱼ at the boundary.
        # TODO replace with analytical formula?
        bs = evaluate.(B, is, x, opn)
        for l = 1:q
            b0, b1 = bs[l], bs[l + 1]
            @assert !(b0 ≈ b1)
            r = 2 / (b0 - b1)  # normalisation factor
            Ca[l + Nc - 1, l] = -b1 * r
            Ca[l + Nc, l] = b0 * r
        end
    end

    let x = b
        M = N - m  # index of last undropped B-spline
        is = ntuple(d -> M - d + 1, Val(q + 1))
        opn = dot(op, RightNormal())
        @assert opn === op  # the right normal is in the x direction
        bs = evaluate.(B, is, x, opn)
        for l = 1:q
            b0, b1 = bs[q - l + 2], bs[q - l + 1]
            @assert !(b0 ≈ b1)
            r = 2 / (b0 - b1)
            Cb[l, l] = -b1 * r
            Cb[l + 1, l] = b0 * r
        end
    end

    ul = SMatrix{q + Nc, q}(Ca)
    lr = SMatrix{q + Nc, q}(Cb)

    RecombineMatrix(ops, N, ul, lr)
end

# Verify that the B-spline order is compatible with the given differential
# operators.
function _check_bspline_order(ops::Tuple, B::BSplineBasis)
    n = max_order(ops...)
    k = order(B)
    if n >= k
        throw(ArgumentError(
            "cannot resolve operators $ops with B-splines of order $k"))
    end
    nothing
end

# Single BC: no B-splines are dropped.
# (Except if op = Derivative{0}, but that case is treated separately.)
_bsplines_to_drop(op::AbstractDifferentialOp) = 0

_unval(::Val{n}) where {n} = n
_bsplines_to_drop(ops...) = _bsplines_to_drop(Val(0), ops...) |> _unval

function _bsplines_to_drop(::Val{n}, a, b, etc...) where {n}
    if a !== Derivative(n)
        throw(ArgumentError("unsupported combination of boundary conditions"))
    end
    _bsplines_to_drop(Val(n + 1), b, etc...)
end

# This is the case of the last operator, which is allowed to be something
# different than Derivative{n}.
function _bsplines_to_drop(::Val{n}, op) where {n}
    if op === Derivative(n)
        return Val(n + 1)
    end
    if max_order(op) ≤ n
        throw(ArgumentError("order of last operator is too low"))
    end
    Val(n)
end

# Unsupported cases
RecombineMatrix(ops::Tuple{Vararg{AbstractDifferentialOp}}, args...) =
    throw(ArgumentError(
        "boundary condition combination is currently unsupported: $ops"))

Base.size(A::RecombineMatrix) = (A.N, A.M)

constraints(A::RecombineMatrix) = (A.ops, A.ops)
constraints(::UniformScaling) = ((), ())

num_constraints(A::RecombineMatrix) = map(length, constraints(A))
num_constraints(::UniformScaling) = (0, 0)  # case of non-recombined bases

# Returns (left, right) tuple with maximum BC order on each boundary.
_max_order(A::RecombineMatrix) = map(ops -> max_order(ops...), constraints(A))

# Returns number of basis functions that are recombined from the original basis
# near each boundary.
# For instance, Neumann BCs have a single recombined function, ϕ_1 = b_1 + b_2;
# while mixed Dirichlet + Neumann have none, ϕ_1 = b_3.
num_recombined(A::RecombineMatrix) =
    map((m, c) -> m + 1 - c, _max_order(A), num_constraints(A))
num_recombined(::UniformScaling) = (0, 0)

# j: index in recombined basis
# M: length of recombined basis
@inline function which_recombine_block(A::RecombineMatrix, j)
    @boundscheck checkbounds(A, :, j)
    M = A.M
    nl, nr = num_recombined(A)  # left/right number of recombined bases
    j <= nl && return 1
    j > M - nr && return 3
    2
end

"""
    nzrows(A::RecombineMatrix, col::Integer) -> UnitRange{Int}

Returns the range of row indices `i` such that `A[i, col]` is non-zero.
"""
@propagate_inbounds function nzrows(A::RecombineMatrix,
                                    j::Integer) :: UnitRange{Int}
    block = which_recombine_block(A, j)
    j += num_constraints(A)[1]
    if block == 1
        (j - 1):j
    elseif block == 2
        j:j  # shifted diagonal of ones
    else
        j:(j + 1)
    end
end

# Pretty-printing, adapted from BandedMatrices.jl code.
function Base.replace_in_print_matrix(
        A::RecombineMatrix, i::Integer, j::Integer, s::AbstractString)
    iszero(A[i, j]) ? Base.replace_with_centered_mark(s) : s
end

@inline function Base.getindex(A::RecombineMatrix, i::Integer, j::Integer)
    @boundscheck checkbounds(A, i, j)
    T = eltype(A)
    @inbounds block = which_recombine_block(A, j)

    cl, cr = num_constraints(A)  # left/right constraints

    if block == 2
        return T(i == j + cl)  # δ_{i, j+c}
    end

    if block == 1
        C = A.ul
        if i <= size(C, 1)
            return @inbounds C[i, j] :: T
        end
        return zero(T)
    end

    # The lower-right corner starts at column h + 1.
    M = size(A, 2)
    nl, nr = num_recombined(A)
    h = M - nr

    @assert j > h
    C = A.lr
    ii = i - h - cr
    if ii ∈ axes(C, 1)
        return @inbounds C[ii, j - h] :: T
    end

    zero(T)
end

# Efficient implementation of matrix-vector multiplication.
# Generally much faster than using a regular sparse array.
function LinearAlgebra.mul!(y::AbstractVector, A::RecombineMatrix,
                            x::AbstractVector)
    checkdims_mul(y, A, x)
    N, M = size(A)

    nl, nr = num_recombined(A)
    cl, cr = num_constraints(A)
    n1 = nl + cl
    h = M - nr

    @inbounds y[1:n1] = A.ul * @view x[1:nl]

    for i = (nl + 1):h
        @inbounds y[i + cl] = x[i]
    end

    @inbounds y[(N - nr - cr + 1):N] = A.lr * @view x[(h + 1):M]

    y
end

# Five-argument mul!.
# Note that, since I have this, I could remove the 3-argument mul!  (which is
# equal to the 5-argument one with α = 1 and β = 0), but it would be a bit more
# inefficient to compute.
function LinearAlgebra.mul!(y::AbstractVector, A::RecombineMatrix,
                            x::AbstractVector, α::Number, β::Number)
    checkdims_mul(y, A, x)
    N, M = size(A)

    nl, nr = num_recombined(A)
    cl, cr = num_constraints(A)
    n1 = nl + cl
    h = M - nr

    @inbounds y[1:n1] = α * A.ul * view(x, 1:nl) + β * SVector{n1}(view(y, 1:n1))

    for i = (nl + 1):h
        @inbounds y[i + cl] = α * x[i] + β * y[i + cl]
    end

    js = (N - nr - cr + 1):N
    @inbounds y[js] =
        α * A.lr * view(x, (h + 1):M) + β * SVector{n1}(view(y, js))

    y
end

function LinearAlgebra.ldiv!(x::AbstractVector, A::RecombineMatrix,
                             y::AbstractVector)
    checkdims_mul(y, A, x)
    N, M = size(A)

    nl, nr = num_recombined(A)
    cl, cr = num_constraints(A)
    n1 = nl + cl
    h = M - nr

    @inbounds x[1:nl] = _ldiv_unique_solution(A.ul, view(y, 1:n1))

    for i = (nl + 1):h
        @inbounds x[i] = y[i + cl]
    end

    js = (N - nr - cr + 1):N
    @inbounds x[(h + 1):M] = _ldiv_unique_solution(A.lr, view(y, js))

    x
end

function LinearAlgebra.:\(A::RecombineMatrix, y::AbstractVector)
    x = similar(y, size(A, 2))
    ldiv!(x, A, y)
end

"""
    NoUniqueSolutionError <: Exception

Exception thrown when solving linear system using [`RecombineMatrix`](@ref),
when the system has no unique solution.
"""
struct NoUniqueSolutionError <: Exception end

function Base.showerror(io::IO, ::NoUniqueSolutionError)
    print(io,
          "overdetermined system has no unique solution.",
          " This means that the given function expanded in the parent basis",
          " has no exact representation (i.e. cannot be expanded) in the recombined basis."
         )
end

# Solve A \ y for overdetermined system with rectangular matrix A, assuming that
# the system has exactly one solution. Throws error if that's not the case.
function _ldiv_unique_solution(A::SMatrix, y::AbstractVector)
    N, M = size(A)
    @assert length(y) == N
    @assert N > M "system must be overdetermined"

    # Solve the first non-trivial M equations, skipping rows of zeroes.
    n = 1
    if M != 0
        @inbounds while n ≤ N && all(iszero.(A[n, :]))
            n += 1
        end
    end
    m = n + M - 1
    @assert m <= N
    @inbounds Am = SMatrix{M,M}(view(A, n:m, :))
    @inbounds ym = SVector{M}(view(y, n:m))
    x = Am \ ym

    # Check that equations (m+1):N are satisfied.
    @inbounds for i = (m + 1):N
        res = zero(eltype(x))
        for j in axes(A, 2)
            res += A[i, j] * x[j]
        end
        res ≈ y[i] || throw(NoUniqueSolutionError())
    end

    x
end

function checkdims_mul(y, A, x)
    M, N = size(A)
    if length(y) != M
        throw(DimensionMismatch("first dimension of A, $M, " *
                                "does not match length of y, $(length(y))"))
    end
    if length(x) != N
        throw(DimensionMismatch("second dimension of A, $N, " *
                                "does not match length of x, $(length(x))"))
    end
    nothing
end


text:
import Mycelia
import Test
import Documenter
import BioSequences
import Random
import Primes
import Graphs

Test.@testset "Don't support even kmers" begin
    k = 2
    seqlen = 2
    msg = "Even kmers are not supported"
    Test.@test_throws ErrorException(msg) Mycelia.KmerGraph(BioSequences.DNAMer{k}, [BioSequences.randdnaseq(seqlen)])
end

Test.@testset "viterbi, error-free" begin
    Test.@testset "k=1, error_rate = 0.0, # observations = 1" begin
        k = 1
        for seqlen in k:k+2
            error_rate = 0.0
            for nucleotides in Iterators.product([Mycelia.DNA_ALPHABET for i in 1:seqlen]...)
                # convert tuple into actual longdnaseq
                observation = BioSequences.LongDNASeq([nucleotides...])
                graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation])
                optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, observation, error_rate)
                Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == observation
            end
        end
    end

    Test.@testset "k=3, error_rate = 0.0, # observations = 1" begin
        k = 3
        for seqlen in k:k+2
            error_rate = 0.0
            for nucleotides in Iterators.product([Mycelia.DNA_ALPHABET for i in 1:seqlen]...)
                # convert tuple into actual longdnaseq
                observation = BioSequences.LongDNASeq([nucleotides...])
                graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation])
                optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, observation, error_rate)
                Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == observation
            end
        end
    end
end

Test.@testset "viterbi, error-free, both orientations" begin
    Test.@testset "k=1, error_rate = 0.0, # observations = 1" begin
        k = 1
        for seqlen in k:k+2
            error_rate = 0.0
            for nucleotides in Iterators.product([Mycelia.DNA_ALPHABET for i in 1:seqlen]...)
                # convert tuple into actual longdnaseq
                observation = BioSequences.LongDNASeq([nucleotides...])
                rc_observation = BioSequences.reverse_complement(observation)

                graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation])
                optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, rc_observation, error_rate)
                Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == rc_observation

                graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation, rc_observation])
                optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, observation, error_rate)
                Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == observation
                optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, rc_observation, error_rate)
                Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == rc_observation
            end
        end
    end

    Test.@testset "k=3, error_rate = 0.0, # observations = 1" begin
        k = 3
        for seqlen in k:k+2
            error_rate = 0.0
            for nucleotides in Iterators.product([Mycelia.DNA_ALPHABET for i in 1:seqlen]...)
                # convert tuple into actual longdnaseq
                observation = BioSequences.LongDNASeq([nucleotides...])
                rc_observation = BioSequences.reverse_complement(observation)

                graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation])
                optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, rc_observation, error_rate)
                Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == rc_observation

                graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation, rc_observation])
                optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, observation, error_rate)
                Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == observation
                optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, rc_observation, error_rate)
                Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == rc_observation
            end
        end
    end
end

Test.@testset "viterbi, variable-error-rates" begin
    Test.@testset "k=1" begin
        k = 1
        for seqlen in k:k+2
            for error_rate in [0.01, 0.05, 0.10, 0.15]
                for nucleotides in Iterators.product([Mycelia.DNA_ALPHABET for i in 1:seqlen]...)
                    # convert tuple into actual longdnaseq
                    observation = BioSequences.LongDNASeq([nucleotides...])
                    graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation])
                    optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, observation, error_rate)
                    Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == observation
                end
            end
        end
    end

    Test.@testset "k=3" begin
        k = 3
        for seqlen in k:k+2
            for error_rate in [0.01, 0.05, 0.10, 0.15]
                for nucleotides in Iterators.product([Mycelia.DNA_ALPHABET for i in 1:seqlen]...)
                    # convert tuple into actual longdnaseq
                    observation = BioSequences.LongDNASeq([nucleotides...])
                    graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation])
                    optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, observation, error_rate)
                    Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == observation
                end
            end
        end
    end
end

Test.@testset "viterbi, variable-error-rates, both orientations" begin
    Test.@testset "k=1" begin
        k = 1
        for seqlen in k:k+2
            for error_rate in [0.01, 0.05, 0.10, 0.15]
                for nucleotides in Iterators.product([Mycelia.DNA_ALPHABET for i in 1:seqlen]...)
                    # convert tuple into actual longdnaseq
                    observation = BioSequences.LongDNASeq([nucleotides...])
                    rc_observation = BioSequences.reverse_complement(observation)

                    graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation])
                    optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, rc_observation, error_rate)
                    Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == rc_observation

                    graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation, rc_observation])
                    optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, observation, error_rate)
                    Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == observation
                    optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, rc_observation, error_rate)
                    Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == rc_observation
                end
            end
        end
    end

    Test.@testset "k=3" begin
        k = 3
        for seqlen in k:k+2
            for error_rate in [0.01, 0.05, 0.10, 0.15]
                for nucleotides in Iterators.product([Mycelia.DNA_ALPHABET for i in 1:seqlen]...)
                    # convert tuple into actual longdnaseq
                    observation = BioSequences.LongDNASeq([nucleotides...])
                    rc_observation = BioSequences.reverse_complement(observation)

                    graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation])
                    optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, rc_observation, error_rate)
                    Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == rc_observation

                    graph = Mycelia.KmerGraph(BioSequences.DNAMer{k}, [observation, rc_observation])
                    optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, observation, error_rate)
                    Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == observation
                    optimal_path = Mycelia.viterbi_maximum_likelihood_path(graph, rc_observation, error_rate)
                    Test.@test Mycelia.oriented_path_to_sequence(optimal_path[1], graph.kmers) == rc_observation
                end
            end
        end
    end
end

Test.@testset "graph reconstruction with tip clipping" begin
    n_sequences = 1
    seqlen = 10
    n_observations = 100
    error_rate = 0.05

    sequences = [BioSequences.randdnaseq(Random.seed!(i), seqlen) for i in 1:n_sequences]
    Random.seed!(1)
    observations = [
        Mycelia.observe(rand(sequences), error_rate = error_rate)
            for i in 1:n_observations
    ]

    graph, corrected_observations = Mycelia.iterate_until_convergence(Primes.primes(3, 7), observations, error_rate);
    pruned_graph = Mycelia.clip_low_coverage_tips(graph, corrected_observations)

    for connected_component in Graphs.connected_components(pruned_graph.graph)
        primary_path = Mycelia.maximum_likelihood_walk(pruned_graph, connected_component)
        reconstructed_sequence = Mycelia.path_to_sequence(pruned_graph, primary_path)
        Test.@test Mycelia.is_equivalent(reconstructed_sequence, first(sequences))
    end
end

Test.@testset "documentation" begin
    # https://juliadocs.github.io/Documenter.jl/stable/man/doctests/#Doctesting-as-Part-of-Testing
    # doctest(Mycelia; manual = false)
    Documenter.doctest(Mycelia)
end

# # Benchmarking
# using PkgBenchmark
# # compares this current state against master branch
# results = judge(Mycelia, "master")
# export_markdown(stdout, results, export_invariants=true)

max_stars_repo_name: snystrom/Mycelia

max_issues_repo_name: snystrom/Mycelia

max_forks_repo_name: cjprybol/Eisenia


text:
# This file contains functions for the Cost Efficiency DEA model
"""
    CostDEAModel
An data structure representing a cost DEA model.
"""
struct CostDEAModel <: AbstractCostDEAModel
    n::Int64
    m::Int64
    s::Int64
    rts::Symbol
    disposY::Symbol
    dmunames::Union{Vector{String},Nothing}
    eff::Vector
    lambda::SparseMatrixCSC{Float64, Int64}
    techeff::Vector
    alloceff::Vector
    Xtarget::Matrix
    Ytarget::Matrix
end

"""
    deacost(X, Y, W)
Compute cost efficiency using data envelopment analysis for
inputs `X`, outputs `Y` and price of inputs `W`.

# Optional Arguments
- `rts=:VRS`: chooses variable returns to scale. For constant returns to scale choose `:CRS`.
- `dispos=:Strong`: chooses strong disposability of outputs. For weak disposability choose `:Weak`.
- `names`: a vector of strings with the names of the decision making units.

# Examples
```jldoctest
julia> X = [5 3; 2 4; 4 2; 4 8; 7 9.0];

julia> Y = [7 4; 10 8; 8 10; 5 4; 3 6.0];

julia> W = [2 1; 2 1; 2 1; 2 1; 2 1.0];

julia> deacost(X, Y, W)
Cost DEA Model
DMUs = 5; Inputs = 2; Outputs = 2
Orientation = Input; Returns to Scale = VRS
──────────────────────────────────
       Cost  Technical  Allocative
──────────────────────────────────
1  0.615385      0.75     0.820513
2  1.0           1.0      1.0
3  1.0           1.0      1.0
4  0.5           0.5      1.0
5  0.347826      0.375    0.927536
──────────────────────────────────
```
"""
function deacost(X::Union{Matrix,Vector}, Y::Union{Matrix,Vector},
    W::Union{Matrix,Vector}; rts::Symbol = :VRS, dispos::Symbol = :Strong,
    names::Union{Vector{String},Nothing} = nothing,
    optimizer::Union{DEAOptimizer,Nothing} = nothing)::CostDEAModel

    # Check parameters
    nx, m = size(X, 1), size(X, 2)
    ny, s = size(Y, 1), size(Y, 2)

    nw, mw = size(W, 1), size(W, 2)

    if nx != ny
        throw(DimensionMismatch("number of rows in X and Y ($nx, $ny) are not equal"));
    end
    if nw != nx
        throw(DimensionMismatch("number of rows in W and X ($nw, $nx) are not equal"));
    end
    if mw != m
        throw(DimensionMismatch("number of columns in W and X ($mw, $m) are not equal"));
    end

    if dispos != :Strong && dispos != :Weak
        throw(ArgumentError("`disposX` must be :Strong or :Weak"));
    end

    # Default optimizer
    if optimizer === nothing
        optimizer = DEAOptimizer(:LP)
    end

    # Get minimum cost targets and lambdas
    n = nx

    Xtarget, clambdaeff = deamincost(X, Y, W, rts = rts, dispos = dispos, optimizer = optimizer)
    Ytarget = Y[:,:]

    # Cost, technical and allocative efficiency
    cefficiency  = vec( sum(W .* Xtarget, dims = 2) ./ sum(W .* X, dims = 2) )
    techefficiency = efficiency(dea(X, Y, orient = :Input, rts = rts, slack = false, disposY = dispos, optimizer = optimizer))
    allocefficiency = cefficiency ./ techefficiency

    return CostDEAModel(n, m, s, rts, dispos, names, cefficiency, clambdaeff, techefficiency, allocefficiency, Xtarget, Ytarget)

end

ismonetary(model::CostDEAModel)::Bool = false;

function Base.show(io::IO, x::CostDEAModel)
    compact = get(io, :compact, false)

    n = nobs(x)
    m = ninputs(x)
    s = noutputs(x)
    disposY = x.disposY
    dmunames = names(x)

    eff = efficiency(x)
    techeff = efficiency(x, :Technical)
    alloceff = efficiency(x, :Allocative)

    if !compact
        print(io, "Cost DEA Model \n")
        print(io, "DMUs = ", n)
        print(io, "; Inputs = ", m)
        print(io, "; Outputs = ", s)
        print(io, "\n")
        print(io, "Orientation = Input")
        print(io, "; Returns to Scale = ", string(x.rts))
        print(io, "\n")
        if disposY == :Weak print(io, "Weak disposability of outputs \n") end

        show(io, CoefTable(hcat(eff, techeff, alloceff), ["Cost", "Technical", "Allocative"], dmunames))
    end

end


text:
using Documenter
using Metatheory

using Metatheory.EGraphs
using Metatheory.Library

for m in [Metatheory]
  for i in propertynames(m)
    xxx = getproperty(m, i)
    println(xxx)
  end
end

makedocs(
  modules = [Metatheory, Metatheory.EGraphs],
  sitename = "Metatheory.jl",
  pages = [
    "index.md"
    "rewrite.md"
    "egraphs.md"
    "interface.md"
    "api.md"
  ],
)

deploydocs(repo = "github.com/JuliaSymbolics/Metatheory.jl.git")


text:
function WidgetBlock(widgets;name::String="",title::String="",subtitle::String="",ddList::OrderedDict)
    push!(widgets["buttons"], name=> button(title,
        style=Dict(:color => "white",:backgroundColor => "#dddddd",:width => "220px",:height => "34px",:fontSize => "0.9em")))
    subtitle = HTML(string("
$(subtitle)
"))
    push!(widgets["toggles"], name => toggle(""));
    push!(widgets["dropdowns"], name => dropdown(ddList));
    widgets["dropdowns"][name].scope.dom.props[:style] = Dict(:width => "170px",:height => "20px",:fontSize => "0.7em");
    widgets["toggles"][name].scope.dom.props[:style] = Dict(:height => "18px");
    if name == "Census"
        push!(widgets["toggles"], "$(name)_2" => toggle(""));
        toggle_2_text = HTML(string("
OA Boundaries
"))
        widgets["toggles"]["$(name)_2"].scope.dom.props[:style] = Dict(:height => "18px",:fontSize=>"0.7em");
        toggles = vbox(vskip(2px),hbox(widgets["toggles"]["$(name)_2"],toggle_2_text),
                  hbox(vbox(vskip(2px),widgets["toggles"][name]),vbox(widgets["dropdowns"][name]
        )))
    elseif name == "OS"
        push!(widgets["toggles"], "$(name)_2" => toggle(""));
        push!(widgets["toggles"], "$(name)_3" => toggle(""));
        push!(widgets["toggles"], "$(name)_4" => toggle(""));
        toggle_2_text = HTML(string("
Buildings
"))
        toggle_3_text = HTML(string("
Roads/Paths
"))
        toggle_4_text = HTML(string("
Natural Features
"))
        widgets["toggles"]["$(name)_2"].scope.dom.props[:style] = Dict(:height => "18px",:fontSize=>"0.7em");
        widgets["toggles"]["$(name)_3"].scope.dom.props[:style] = Dict(:height => "18px",:fontSize=>"0.7em");
        widgets["toggles"]["$(name)_4"].scope.dom.props[:style] = Dict(:height => "18px",:fontSize=>"0.7em");
        toggles = vbox(vskip(2px),
                hbox(widgets["toggles"]["$(name)_2"],toggle_2_text),
                hbox(widgets["toggles"]["$(name)_3"],toggle_3_text),
                hbox(widgets["toggles"]["$(name)_4"],toggle_4_text)
        )
    else
        toggles = hbox(vbox(vskip(2px),widgets["toggles"][name]),vbox(widgets["dropdowns"][name]))
    end

    push!(widgets["Blocks"], name =>
        CSSUtil.vbox(
            hbox(widgets["buttons"][name]),
            vskip(2px),
            subtitle,
            vskip(4px),
            toggles,
            vskip(20px),
        )
    )
    return widgets
end

function LaunchMainUI(env)

    ## TITLE PANE
    global ui = ParaDwell.UI();
    ui.title = HTML(string("
ParaDwell
"));
    ui.titlePane = vbox(vskip(20px), hbox(hskip(20px),ui.title));

    ## BUILD WIDGETS
    widgets = Dict("buttons"=>Dict(),"toggles"=>Dict(),"dropdowns"=>Dict(),"Blocks"=>Dict())
    widgets = WidgetBlock(widgets;name="OS",title="Ordnance Survey",subtitle="",ddList=OrderedDict("(blank)" => "Value 0", "Pop. density" => "Value 1"))
    widgets = WidgetBlock(widgets;name="Census",title="Census 2011",subtitle="By Output Area",ddList=OrderedDict("(blank)             " => "Value 0", "Pop. density" => "Value 1"))
    widgets = WidgetBlock(widgets;name="HomeAnalytics",title="Home Analytics",subtitle="By Dwelling (all)",ddList=OrderedDict("(blank)" => "Value 0", "Pop. density" => "Value 1"))
    widgets = WidgetBlock(widgets;name="EPC",title="EPC",subtitle="By Dwelling (partial)",ddList=OrderedDict("(blank)" => "Value 0", "Pop. density" => "Value 1"))
    widgets = WidgetBlock(widgets;name="IMD",title="Deprivation Indicies",subtitle="By LSOA",ddList=OrderedDict("(blank)" => "Value 0", "Pop. density" => "Value 1"))
    widgets = WidgetBlock(widgets;name="Acorn",title="Acorn (CACI)",subtitle="By Dwelling",ddList=OrderedDict("(blank)" => "Value 0", "Pop. density" => "Value 1"))
    widgets = WidgetBlock(widgets;name="Census",title="Census 2011",subtitle="By Output Area",ddList=OrderedDict("(blank)" => "Value 0", "Pop. density" => "Value 1"))
    widgets = WidgetBlock(widgets;name="Archetypes",title="Archetypes",subtitle="By Dwelling",ddList=OrderedDict("(blank)" => "Value 0", "Pop. density" => "Value 1"))

    ## LAUNCH ELECTRON
    ui.subPanelLeft1 = CSSUtil.width(250px,
        vbox(
        widgets["Blocks"]["OS"],
        widgets["Blocks"]["Census"],
        widgets["Blocks"]["HomeAnalytics"],
        widgets["Blocks"]["EPC"],
        widgets["Blocks"]["Acorn"],
        widgets["Blocks"]["IMD"],
        vskip(10px),
        CSSUtil.hline(),
        vskip(10px),
        widgets["Blocks"]["Archetypes"],
        )
    );
    ui.panelLeft = vbox(CSSUtil.height(1000px,vbox(ui.titlePane,vskip(20px),CSSUtil.hline(), vskip(30px), hbox(hskip(20px), ui.subPanelLeft1))));

    ## CREATE WIDGETS FOR RHS PANEL
    global wgt = ParaDwell.Wgt(ParaDwell.Toggle(),ParaDwell.Dropdown(),ParaDwell.Radio(),ParaDwell.Button(),ParaDwell.Check(),ParaDwell.Spinbox());
    wgt.spinbox.dimensionalRounding = spinbox(1:1:5,value=2);
    wgt.spinbox.maxPlanDepth = spinbox(7:1:15,value=12);
    wgt.dropdown.orient = dropdown(["(ignore)", "nearest 180°", "nearest 90°", "nearest 45°", "nearest 22.5°"]);
    wgt.button.generateArch = button(HTML(string("
Generate archetypes
")));
    # wgt.dropdown.selectArch = dropdown([])
    wgt.button.generateIdf = button(HTML(string("
Generate EnergyPlus files (.idf)
")));

    ## FORMAT WIDGETS FOR RHS PANEL
    wgt.button.generateArch.scope.dom.props[:style] = Dict("height"=>36px, "width"=>260px);
    wgt.button.generateIdf.scope.dom.props[:style] = Dict("height"=>36px, "width"=>260px);
    wgt.spinbox.dimensionalRounding.scope.dom.props[:style] = Dict("width"=>60px);
    wgt.spinbox.maxPlanDepth.scope.dom.props[:style] = Dict("width"=>60px);
    wgt.dropdown.orient.scope.dom.props[:style] = Dict("width"=>140px);
    # wgt.dropdown.selectArch.scope.dom.props[:style] = Dict("width"=>260px);

    ui.panelRight = vbox(vskip(2em),
        HTML(string("
Archetype constraints:
")),
        vskip(10px),
        hbox(CSSUtil.width(200px,hbox(vbox(vskip(8px),
        HTML(string("
Round plan to nearest (m):
"))))),
        wgt.spinbox.dimensionalRounding),
        vskip(10px),
        hbox(CSSUtil.width(120px,hbox(vbox(vskip(8px),
        HTML(string("
Bldg orientation:
"))))),
        wgt.dropdown.orient),
        vskip(10px),
        hbox(CSSUtil.width(200px,hbox(vbox(vskip(8px),
        HTML(string("
Max. bldg plan depth (m):
"))))),
        wgt.spinbox.maxPlanDepth),
        vskip(10px),
        wgt.button.generateArch,
        #CSSUtil.width(300px,hbox(wgt.button.selectArch)),
        vskip(10px),
        wgt.button.generateIdf
        )

    layout = Layout(
        showlegend=false,
        xaxis=attr(title="Easting",zeroline=false,tickformat=".0f",scaleanchor="y", scaleratio=1),
        yaxis=attr(title="Northing",zeroline=false,tickformat=".0d"),
        hovermode="closest",
        margin=attr(l=100,b=60)
    )

    ui.p0 = plot(scatter(x=[0],y=[0],mode="lines",name="blank"),layout)

    ui.mainWindow = Window(async=false,Dict(:title=>"ParaDwell","width"=>2100,"height"=>1200,:x=>0,:y=>0));
    body!(ui.mainWindow,
        CSSUtil.height(1000px,hbox(
        ui.panelLeft,
        vskip(2em),
        CSSUtil.vline(),
        vskip(2em),CSSUtil.width(1350px,vbox(
            vskip(2em),
            ui.p0)),
        ui.panelRight)));

    # sleep(1)

    ##########################################

    # ui.plt_macro = ParaDwell.DIVA(adminLevel=2,exclShapeBelowLen=20);
    ui.plt_macro = ParaDwell.DIVA(adminLevel=0,exclShapeBelowLen=200);
    traces=scatter(
        name="OS 5km Tile",
        text=project.tileRegister.tileRefs,
        x=project.tileRegister.Lon_mid,
        y=project.tileRegister.Lat_mid,
        mode="markers",
        marker=attr(symbol=:square,
            size=5,color="#0652DD80"))

    addtraces!(ui.plt_macro,traces)

    w_nationwide = Window(Dict(:title=>"Macro-map",:width=>500,:height=>700,:x=>1430,:y=>360))
    body!(w_nationwide,ui.plt_macro)

    ##########################################
    return ui
end


text:
function sortEdgeFace(v::SVector{3,Int64}, k::Int64)
    three = 3
    (1 <= k <= three) || error("a triangle has three sides")
    i1 = v[mod1(k + 1, three)]
    i2 = v[mod1(k + 2, three)]
    return SVector{2,Int64}(minmax(i1, i2))
end

function sortEdgeFace(v::SVector{4,Int64}, k::Int64)
    four = 4
    (1 <= k <= four) || error("a tetrahedron has four sides")
    i1 = v[mod1(k + 1, four)]
    i2 = v[mod1(k + 2, four)]
    i3 = v[mod1(k + 3, four)]
    i1, i2 = minmax(i1, i2)  # --> i2 is not lowest
    i2, i3 = minmax(i2, i3)  # --> i3 is highest
    i1, i2 = minmax(i1, i2)  # --> i1 and i2 are sorted
    return SVector{3,Int64}(i1, i2, i3)
end


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

mutable struct IoK8sApiCoreV1VolumeDevice <: SwaggerModel
    devicePath::Any # spec type: Union{ Nothing, String } # spec name: devicePath
    name::Any # spec type: Union{ Nothing, String } # spec name: name

    function IoK8sApiCoreV1VolumeDevice(;devicePath=nothing, name=nothing)
        o = new()
        validate_property(IoK8sApiCoreV1VolumeDevice, Symbol("devicePath"), devicePath)
        setfield!(o, Symbol("devicePath"), devicePath)
        validate_property(IoK8sApiCoreV1VolumeDevice, Symbol("name"), name)
        setfield!(o, Symbol("name"), name)
        o
    end
end # type IoK8sApiCoreV1VolumeDevice

const _property_map_IoK8sApiCoreV1VolumeDevice = Dict{Symbol,Symbol}(Symbol("devicePath")=>Symbol("devicePath"), Symbol("name")=>Symbol("name"))
const _property_types_IoK8sApiCoreV1VolumeDevice = Dict{Symbol,String}(Symbol("devicePath")=>"String", Symbol("name")=>"String")
Base.propertynames(::Type{ IoK8sApiCoreV1VolumeDevice }) = collect(keys(_property_map_IoK8sApiCoreV1VolumeDevice))
Swagger.property_type(::Type{ IoK8sApiCoreV1VolumeDevice }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_IoK8sApiCoreV1VolumeDevice[name]))}
Swagger.field_name(::Type{ IoK8sApiCoreV1VolumeDevice }, property_name::Symbol) =  _property_map_IoK8sApiCoreV1VolumeDevice[property_name]

function check_required(o::IoK8sApiCoreV1VolumeDevice)
    (getproperty(o, Symbol("devicePath")) === nothing) && (return false)
    (getproperty(o, Symbol("name")) === nothing) && (return false)
    true
end

function validate_property(::Type{ IoK8sApiCoreV1VolumeDevice }, name::Symbol, val)
end


text:
# This file is part of RLinearAlgebra.jl

module ProceduralTestLinSysStopCriterion

using Test, RLinearAlgebra

@testset "Linear System Stopping Criteria Abstractions" begin

    # Verify export
    @test @isdefined LinSysStopCriterion

end

end # End module


text:
using SymbolicUtils, Test
using SymbolicUtils: Term, Sym, to_symbolic, istree, operation, arguments, symtype

SymbolicUtils.istree(ex::Expr) = ex.head == :call
SymbolicUtils.operation(ex::Expr) = ex.args[1]
SymbolicUtils.arguments(ex::Expr) = ex.args[2:end]
SymbolicUtils.to_symbolic(s::Symbol) = Sym(s)

for f ∈ [:+, :-, :*, :/, :^]
    @eval begin
        Base.$f(x::Union{Expr, Symbol}, y::Number) = Expr(:call, $f, x, y)
        Base.$f(x::Number, y::Union{Expr, Symbol}) = Expr(:call, $f, x, y)
        Base.$f(x::Union{Expr, Symbol}, y::Union{Expr, Symbol}) = (Expr(:call, $f, x, y))
    end
end

ex = 1 + (:x - 2)

@test to_symbolic(ex) == Term{Any}(+, [1, Term{Any}(-, [Sym{Any}(:x), 2])])
@test simplify(ex) == to_symbolic(-1 + :x)

to_expr(t::Term) = Expr(:call, operation(t), to_expr.(arguments(t))...)
to_expr(s::Sym) = s.name
to_expr(x) = x

@test to_expr(simplify(ex)) == Expr(:call, +, -1, :x)

SymbolicUtils.symtype(::Symbol) = Real

@test symtype(simplify(ex)) == Real


text:
mutable struct myresponse
  status::Int
  headers::Dict
  body::String
  function myresponse(code)
      new(code,Dict(),"")
  end
end

mutable struct myrequest
  query::Dict
  params::RegexMatch
  body::Any
  version::VersionNumber
  headers::Array
  function myrequest()
    new(Dict(),match(r"\s"," "),"",VersionNumber(1),[])
  end
end

my_headers= HTTP.mkheaders(["Content-Type" => "text/plain"])

function searchroute_regex(ruta::String)
  for i in 1:length(routes_patterns_array)
    if(occursin(routes_patterns_array[i],ruta))
      return routes_patterns_array[i]
    end
 end
 return ""
end

function handler(request::HTTP.Request)
  data = split(request.target,"?")
  url=data[1]
  searchroute = request.method*url

  my_request=myrequest()
  my_request.version=request.version
  my_request.headers=request.headers
  if (length(data)>1) my_request.query= HTTP.queryparams(data[2]) end

  response = myresponse(200)

  if ((request.method=="POST"  )||(request.method=="PUT"  )||(request.method=="PATCH"))
    header_content_type = HTTP.header(request, "Content-Type")
    if((length(header_content_type)>0) && (haskey(formats,header_content_type)))
      my_request.body= getindex(formats, header_content_type)(String(request.body))
    else
      my_request.body = getindex(formats, "*/*")(String(request.body))
    end
  end

  if (searchroute in routes_array)
    response.body = getindex(routes, searchroute)(my_request,response)
  else
    pattern = searchroute_regex(searchroute)
    if (typeof(pattern) <:Regex)
      my_request.params = match(pattern,searchroute)
      _function = getindex(routes_patterns,pattern)
      response.body = _function(my_request,response)
      sal = collect((m.match for m = eachmatch(Regex("{{(\\w\\d*)+}}"), response.body)))
      for i in sal
        response.body = replace(response.body,Regex(i) => my_request.params["$(i[3:end-2])"])
      end
    else
      response.body = getindex(routes, "notfound")(my_request,response)
    end
  end
  responsefinal = HTTP.Response(response.status,my_headers, body=response.body)
  for (key, value) in response.headers
    HTTP.setheader(responsefinal,key => value )
  end
  return responsefinal
end

"""
Contains server configuration
"""
rootbase = pwd()

export webserverpath
function webserverpath(folder::AbstractString)
  global rootbase = joinpath(pwd(),folder)
end

export File
"""
File(file::String)

Return a file content located in "rootbase"
"""
function File(file::String)
    return File("", file)
end

"""
File(folder::String, file::String)

Return a file content located in "joinpath(rootbase, folder)"
"""
function File(folder::String, file::String)
  path = joinpath(rootbase, folder, file)
  f = open(path)
  return read(f, String)
end

"""
files(roop::String, file::String)

Create a GET route to file
"""
function files(folder::String, file::String)
    extension="text/plain"
    ext= split(file,".")
    if(length(ext)>1)
      my_extension = ext[end]
      if (haskey(mimetypes, my_extension))
        extension = mimetypes[my_extension]
      end
    end
    data = File(folder, file)
    folder = replace(folder,"\\" => "/")
    createurl("GET/"*joinpath(folder,file), (req,res)->(begin
      res.headers["Content-Type"]= extension
      res.status = 200
      res.body = data
    end))
end

"""
Create routes to files inside "rootbase"
"""
function WebServer(folder::String, exten::String)
  path = joinpath(rootbase, folder)
  ls= readdir(path)
  for i = 1:length(ls)
    if isfile( joinpath(path, ls[i]) )
      ext = split(ls[i], ".")
      if length(ext) > 1 && ext[1] != "" && occursin(exten, ext[end] )
        files(folder,ls[i])
      end
    elseif isdir( joinpath(path, ls[i]) )
      WebServer(joinpath(folder, ls[i]) ,exten)
    end
  end
end

export useCORS
function useCORS(activate::Bool)
  HTTP.setheader(my_headers,"Access-Control-Allow-Origin" => "*")
  HTTP.setheader(my_headers,"Access-Control-Allow-Methods" => "POST,GET,OPTIONS")
  return true
end

export headersalways
function headersalways(head::AbstractString,value::AbstractString)
  HTTP.setheader(my_headers,head => value)
end

export notfound
function notfound(text::String)
  if occursin(".html", text)
    notfound_message= File(text)
    addnotfound(notfound_message)
  else
    addnotfound(text)
  end
end

export webserverfiles
function webserverfiles(load::AbstractString)
  if load == "*"
    WebServer("", "")
  else
    WebServer("", load)
  end
end

export start
function start( ;host = "127.0.0.1", port = "8080", verbose = false)
  my_host = host
  if '.' in my_host
    my_host = Sockets.IPv4(my_host)
  elseif ':' in my_host
    my_host = Sockets.IPv6(my_host)
  end
  HTTP.serve(handler, my_host, port, verbose=verbose)
end


text:
import SparseArrays.SparseMatrixCSC
import SparseArrays: findnz, dropzeros!, spdiagm
import StaticArrays: SVector
using NearestNeighbors: BallTree, KDTree
using Distances: PeriodicEuclidean

# q: total number of subdivisions, leading to a number dofs given by 2^{qd}
function subdivision_2d(q)
    ##################################################################
    # Construct the domains
    ##################################################################
    n = 2 ^ q
    N = n ^ 2
    Δx = Δy = 1 / (n + 1)
    # The evaluation points of the finite difference discretization.
    domains = array2domains(mapreduce(identity, hcat, [[x; y] for x in Δx .* (1/2 : (n - 1/2)) for y in Δy .* (1/2 : (n - 1/2))]))

    ##################################################################
    # Construct the domain decomposition
    ##################################################################

    # Note that the ids of all bu the finest scale domains are arbitrary
    next_id = maximum(id.(domains)) + 1
    for k = (q - 1) : -1 : 1
        new_domains = Vector{eltype(domains)}(undef, 2 ^ (2 * k))
        # return assignment to a node on the coarser scale
        # TODO: Still need to test that ij -> ji is doing the right thing
        function return_assignment(domain)
            i, j = Int.(div.(center(domain), 1 / 2^k) .+ 1)
            return LinearIndices(zeros(2^k, 2^k))[i, j]
        end
        # go through all domains on the next finer level
        for domain in domains
            parent_index = return_assignment(domain)
            # eithercreate the domain if it doesn't exist yet
            if !isassigned(new_domains, parent_index)
                new_domains[parent_index] = Domain([domain], next_id)
                next_id += 1
            # or else add the new child
            else
                new_domains[parent_index] = add_children(new_domains[parent_index], [domain])
            end
        end
        domains = new_domains
    end
    scales = 1 ./ (2 .^ (1 : q))

    ##################################################################
    # Construct the basis functions
    ##################################################################
    basis_functions = compute_basis_functions(domains)

    return domains, scales, basis_functions
end

# function for selecting the aggregation centers in the square
function aggregation_centers_square(ρh)
    if ρh < Inf
        ticks = ρh : (ρh) : (1 - ρh)
    else
        ticks = [zero(ρh)]
    end
    # if ticks is empty, add a single entry to it, resulting in all nodes being summarized in the same supernode
    if isempty(ticks)
        ticks = [zero(ρh)]
    end
    return SVector{2}.([[x; y] for x in ticks for y in ticks])
end

# Create a finite difference Laplacian problem on a quadratic mesh using sudivision, with dirichlet boundary conditions.
# q: total number of subdivisions, leading to a number dofs given by 2^{qd}
# α: the coefficient function. an edge between x and y will have conductivity (α(x) + α(y)) / 2
# Possibly remore the implicit choice of ρ
function FD_Laplacian_subdivision_2d(q, ρ = 2.0, α = x -> 1)
    n = 2 ^ q
    N = n ^ 2
    Δx = Δy = 1 / (n + 1)

    # actual multiscale domains are provided by subdivision_2d. fine_domains only
    # there fore the

    ##################################################################
    # Construct the Laplace operator
    ##################################################################
    # Create the sparsity pattern of the Laplace operator
    A = spdiagm(-n => -ones(N-n), -1 => -ones(N-1) .* (mod.(1 : (N - 1), n) .!= 0), 0 => 4 * ones(N), 1 => -ones(N-1) .* (mod.(1 : (N - 1), n) .!= 0), n => -ones(N-n)) # / Δx^2

    # Important to multiply A.nzval and not A, to prevent dropping of structural nonzeros.
    A.nzval .*= 0
   ##################################################################
    # Construct the domain decomposition
    ##################################################################
    domains, scales, basis_functions = subdivision_2d(q)

    # collect the finest Domains and sorts them to be in accordance with the construction of the matrix dofs
    fine_domains = sort(gather_descendants(domains), by=id)

    for (i, j, val) in zip(findnz(A)...)
        # only look at edges
        if i != j
            val = (α(center(fine_domains[i])) + α(center(fine_domains[j]))) / 2 / Δx^2
            A[i, i] += val
            A[j, j] += val
            A[i, j] -= val
            A[j, i] -= val
        end
    end
    # # adding zero order term for now
    # for i = 1 : size(A, 1)
    #     A[i, i] += 1.0
    # end

    # constructing the tree function
    function tree_function(x)
        return KDTree(x)
    end

    ##################################################################
    # Constructing the multicolor ordering
    ##################################################################
    # The supernodes corresponding to different columns of 𝐋
    multicolor_ordering = construct_multicolor_ordering(basis_functions, ρ * scales, tree_function)

    return A, domains, scales, basis_functions, multicolor_ordering, fine_domains, tree_function
end

# Create a finite difference Laplacian problem on a quadratic mesh using sudivision, with dirichlet boundary conditions.
# q: total number of subdivisions, leading to a number dofs given by 2^{qd}
# α: the coefficient function. an edge between x and y will have conductivity (α(x) + α(y)) / 2
# Possibly remore the implicit choice of ρ
function FD_periodic_Laplacian_subdivision_2d(q, ρ = 2.0, α = x -> 1)
    n = 2 ^ q
    N = n ^ 2
    Δx = Δy = 1 / (n + 1)
    h = Δx
    # actual multiscale domains are provided by subdivision_2d. fine_domains only
    # there fore the

    ##################################################################
    # Construct the Laplace operator
    ##################################################################
    # Create the sparsity pattern of the Laplace operator
    lin_inds = LinearIndices((n, n))
    row_inds = Int[]
    col_inds = Int[]
    S = Float64[]
    for i in 1 : n, j in 1 : n
        # adding self-interaction 2
        push!(col_inds, lin_inds[mod(i - 1, n) + 1, mod(j - 1, n) + 1])
        push!(row_inds, lin_inds[mod(i - 1, n) + 1, mod(j - 1, n) + 1])
        push!(S, 4.0)
        # interaction to next element in i direction
        push!(col_inds, lin_inds[mod(i - 1, n) + 1, mod(j - 1, n) + 1])
        push!(row_inds, lin_inds[mod(i - 1 + 1, n) + 1, mod(j - 1, n) + 1])
        push!(S, -1.0)

        # interaction to previous element in i direction
        push!(col_inds, lin_inds[mod(i - 1, n) + 1, mod(j - 1, n) + 1])
        push!(row_inds, lin_inds[mod(i - 1 - 1, n) + 1, mod(j - 1, n) + 1])
        push!(S, -1.0)

        # interaction to next element in j direction
        push!(col_inds, lin_inds[mod(i - 1, n) + 1, mod(j - 1, n) + 1])
        push!(row_inds, lin_inds[mod(i - 1, n) + 1, mod(j - 1 + 1, n) + 1])
        push!(S, -1.0)

        # interaction to previous element in j direction
        push!(col_inds, lin_inds[mod(i - 1, n) + 1, mod(j - 1, n) + 1])
        push!(row_inds, lin_inds[mod(i - 1, n) + 1, mod(j - 1 - 1, n) + 1])
        push!(S, -1.0)
    end
    A = sparse(row_inds, col_inds, S) / (h^2)

    # Important to multiply A.nzval and not A, to prevent dropping of structural nonzeros.
    A.nzval .*= 0
   ##################################################################
    # Construct the domain decomposition
    ##################################################################
    domains, scales, basis_functions = subdivision_2d(q)

    # collect the finest Domains and sorts them to be in accordance with the construction of the matrix dofs
    fine_domains = sort(gather_descendants(domains), by=id)

    for (i, j, val) in zip(findnz(A)...)
        # only look at edges
        if i < j
            val = (α(center(fine_domains[i])) + α(center(fine_domains[j]))) / 2 / Δx^2
            A[i, i] += val
            A[j, j] += val
            A[i, j] -= val
            A[j, i] -= val
        end
    end

    # adding zero order term for now
    for i = 1 : size(A, 1)
        A[i, i] += 1.0 + rand()
    end

    # constructing the tree function
    function tree_function(x)
        return BallTree(x, PeriodicEuclidean([1.0, 1.0]))
    end

    ##################################################################
    # Constructing the multicolor ordering
    ##################################################################
    # The supernodes corresponding to different columns of 𝐋
    multicolor_ordering = construct_multicolor_ordering(basis_functions, ρ * scales, tree_function)

    return A, domains, scales, basis_functions, multicolor_ordering, fine_domains, tree_function
end