base: slug test

This commit is contained in:
luboslenco
2026-03-30 15:53:28 +02:00
parent 263bc88575
commit afdade943a
8 changed files with 594 additions and 756 deletions
+213
View File
@@ -0,0 +1,213 @@
// Slug font rendering algorithm by Eric Lengyel
// Licensed under Apache-2.0
// https://github.com/EricLengyel/Slug
#[set(everything)]
const constants: {
pos: float4;
col: float4;
em_rect: float4; // xoff, yoff, glyph_w, glyph_h
glyph_loc: int4;
band_max: int4;
band_tf: float4;
};
#[set(everything)]
const sampler_linear: sampler;
#[set(everything)]
const curve_tex: tex2d;
#[set(everything)]
const band_tex: tex2d;
struct vert_in {
pos: float2;
}
struct vert_out {
pos: float4;
em: float2;
}
fun draw_slug_vert(input: vert_in): vert_out {
var output: vert_out;
var cpos: float4 = constants.pos;
output.pos = float4(input.pos, 0.0, 1.0);
output.pos.xy = output.pos.xy * cpos.zw + cpos.xy;
output.pos.xy = output.pos.xy * 2.0 - 1.0;
output.pos.y = -output.pos.y;
var er: float4 = constants.em_rect;
output.em = input.pos * er.zw + er.xy;
return output;
}
fun curve_fetch(x: int, y: int): float4 {
var coord: uint2 = uint2(uint(x), uint(y));
return curve_tex[coord];
}
fun band_fetch(x: int, y: int): float4 {
var coord: uint2 = uint2(uint(x), uint(y));
return band_tex[coord];
}
fun calc_root_code(y1: float, y2: float, y3: float): uint {
var shift: uint = uint(0);
if (y1 < 0.0) { shift = shift | 1; }
if (y2 < 0.0) { shift = shift | 2; }
if (y3 < 0.0) { shift = shift | 4; }
// return (0x2E74 >> shift) & 0x0101;
return uint((11892 >> shift) & 257);
}
fun solve_horiz(p12: float4, p3: float2): float2 {
var a: float2 = p12.xy - p12.zw * 2.0 + p3;
var b: float2 = p12.xy - p12.zw;
var d: float = sqrt(max(b.y * b.y - a.y * p12.y, 0.0));
var t1: float;
var t2: float;
if (abs(a.y) < (1.0 / 65536.0)) {
t1 = p12.y * (0.5 / b.y);
t2 = t1;
}
else {
var ra: float = 1.0 / a.y;
t1 = (b.y - d) * ra;
t2 = (b.y + d) * ra;
}
var r: float2;
r.x = (a.x * t1 - b.x * 2.0) * t1 + p12.x;
r.y = (a.x * t2 - b.x * 2.0) * t2 + p12.x;
return r;
}
fun solve_vert(p12: float4, p3: float2): float2 {
var a: float2 = p12.xy - p12.zw * 2.0 + p3;
var b: float2 = p12.xy - p12.zw;
var d: float = sqrt(max(b.x * b.x - a.x * p12.x, 0.0));
var t1: float;
var t2: float;
if (abs(a.x) < (1.0 / 65536.0)) {
t1 = p12.x * (0.5 / b.x);
t2 = t1;
}
else {
var ra: float = 1.0 / a.x;
t1 = (b.x - d) * ra;
t2 = (b.x + d) * ra;
}
var r: float2;
r.x = (a.y * t1 - b.y * 2.0) * t1 + p12.y;
r.y = (a.y * t2 - b.y * 2.0) * t2 + p12.y;
return r;
}
fun band_loc_x(base_x: int, offset: int): int {
return (base_x + offset) & 4095;
}
fun band_loc_y(base_x: int, base_y: int, offset: int): int {
return base_y + ((base_x + offset) >> 12);
}
fun draw_slug_frag(input: vert_out): float4 {
var gx: int = constants.glyph_loc.x;
var gy: int = constants.glyph_loc.y;
var vband_max: int = constants.band_max.x;
var hband_max: int = constants.band_max.y;
var tf: float4 = constants.band_tf;
var band_ix: int = int(clamp(input.em.x * tf.x, 0.0, float(vband_max)));
var band_iy: int = int(clamp(input.em.y * tf.y, 0.0, float(hband_max)));
var xcov: float = 0.0;
var xwgt: float = 0.0;
var hb: float4 = band_fetch(band_loc_x(gx, band_iy), band_loc_y(gx, gy, band_iy));
var hb_count: int = int(hb.x);
var hb_off: int = int(hb.y);
var hb_lx: int = band_loc_x(gx, hb_off);
var hb_ly: int = band_loc_y(gx, gy, hb_off);
var ci: int = 0;
while (ci < hb_count) {
var cl: float4 = band_fetch(band_loc_x(hb_lx, ci), band_loc_y(hb_lx, hb_ly, ci));
var cx: int = int(cl.x);
var cy: int = int(cl.y);
var p12: float4 = curve_fetch(cx, cy) - float4(input.em.x, input.em.y, input.em.x, input.em.y);
var p3: float2 = curve_fetch(cx + 1, cy).xy - input.em;
if (max(max(p12.x, p12.z), p3.x) < -0.5) {
ci = hb_count;
}
else {
var code: uint = calc_root_code(p12.y, p12.w, p3.y);
if (code != 0) {
var r: float2 = solve_horiz(p12, p3);
if ((code & 1) != 0) {
xcov += clamp(r.x + 0.5, 0.0, 1.0);
xwgt = max(xwgt, clamp(1.0 - abs(r.x) * 2.0, 0.0, 1.0));
}
if (code > 1) {
xcov -= clamp(r.y + 0.5, 0.0, 1.0);
xwgt = max(xwgt, clamp(1.0 - abs(r.y) * 2.0, 0.0, 1.0));
}
}
ci += 1;
}
}
var ycov: float = 0.0;
var ywgt: float = 0.0;
var vb_di: int = hband_max + 1 + band_ix;
var vb: float4 = band_fetch(band_loc_x(gx, vb_di), band_loc_y(gx, gy, vb_di));
var vb_count: int = int(vb.x);
var vb_off: int = int(vb.y);
var vb_lx: int = band_loc_x(gx, vb_off);
var vb_ly: int = band_loc_y(gx, gy, vb_off);
ci = 0;
while (ci < vb_count) {
var cl: float4 = band_fetch(band_loc_x(vb_lx, ci), band_loc_y(vb_lx, vb_ly, ci));
var cx: int = int(cl.x);
var cy: int = int(cl.y);
var p12: float4 = curve_fetch(cx, cy) - float4(input.em.x, input.em.y, input.em.x, input.em.y);
var p3: float2 = curve_fetch(cx + 1, cy).xy - input.em;
if (max(max(p12.y, p12.w), p3.y) < -0.5) {
ci = vb_count;
}
else {
var code: uint = calc_root_code(p12.x, p12.z, p3.x);
if (code != 0) {
var r: float2 = solve_vert(p12, p3);
if ((code & 1) != 0) {
ycov -= clamp(r.x + 0.5, 0.0, 1.0);
ywgt = max(ywgt, clamp(1.0 - abs(r.x) * 2.0, 0.0, 1.0));
}
if (code > 1) {
ycov += clamp(r.y + 0.5, 0.0, 1.0);
ywgt = max(ywgt, clamp(1.0 - abs(r.y) * 2.0, 0.0, 1.0));
}
}
ci += 1;
}
}
var denom: float = max(xwgt + ywgt, 1.0 / 65536.0);
var coverage: float = max(abs(xcov * xwgt + ycov * ywgt) / denom, min(abs(xcov), abs(ycov)));
coverage = clamp(coverage, 0.0, 1.0);
var c: float4 = constants.col;
return float4(c.rgb, c.a * coverage);
}
#[pipe]
struct pipe {
vertex = draw_slug_vert;
fragment = draw_slug_frag;
}
-560
View File
@@ -179,566 +179,6 @@ const float _const_data_skydome_nor[] = {
0.0, -0.26891, 0.96317};
const int _const_data_skydome_nor_count = sizeof(_const_data_skydome_nor) / sizeof(_const_data_skydome_nor[0]);
// Baked font data
const char iron_font_13_x0[] = {1, 2, 6, 10, 18, 25, 34, 42, 45, 50, 55, 61, 68, 71, 75, 79, 85, 92, 97, 104, 111, 118, 1, 8,
15, 22, 29, 32, 35, 41, 48, 55, 61, 72, 81, 89, 97, 105, 112, 119, 1, 9, 13, 20, 28, 35, 45, 53,
61, 69, 77, 85, 93, 101, 109, 1, 12, 20, 28, 36, 40, 46, 50, 56, 62, 66, 73, 80, 87, 94, 101, 106,
113, 120, 123, 1, 8, 11, 21, 28, 35, 42, 49, 54, 61, 66, 73, 80, 90, 97, 104, 111, 116, 119, 1};
const char iron_font_13_y0[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 37, 37, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 62};
const char iron_font_13_x1[] = {1, 5, 9, 17, 24, 33, 41, 44, 49, 54, 60, 67, 70, 74, 78, 84, 91, 96, 103, 110, 117, 124, 7, 14,
21, 28, 31, 34, 40, 47, 54, 60, 71, 80, 88, 96, 104, 111, 118, 126, 8, 12, 19, 27, 34, 44, 52, 60,
68, 76, 84, 92, 100, 108, 116, 11, 19, 27, 35, 39, 45, 49, 55, 61, 65, 72, 79, 86, 93, 100, 105, 112,
119, 122, 126, 7, 10, 20, 27, 34, 41, 48, 53, 60, 65, 72, 79, 89, 96, 103, 110, 115, 118, 123, 8};
const char iron_font_13_y1[] = {1, 10, 5, 9, 13, 11, 10, 5, 13, 13, 6, 8, 5, 3, 4, 10, 10, 9, 9, 10, 9, 10, 23, 22, 23, 23, 21, 22, 19, 18, 19, 23,
25, 22, 22, 23, 22, 22, 22, 23, 34, 34, 35, 34, 34, 34, 34, 35, 34, 36, 34, 35, 34, 35, 34, 45, 45, 45, 45, 49, 46, 49, 42, 38,
40, 44, 47, 44, 47, 44, 46, 46, 46, 45, 48, 59, 59, 56, 56, 57, 59, 59, 56, 57, 59, 57, 56, 56, 56, 59, 56, 61, 60, 61, 65};
const char iron_font_13_xoff[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const char iron_font_13_yoff[] = {10, 2, 1, 2, 0, 1, 2, 1, 1, 1, 2, 3, 8, 6, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 2, 10,
1, 4, 1, 4, 1, 4, 1, 4, 1, 2, 2, 1, 1, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 1, 2, 1, 5};
const float iron_font_13_xadvance[] = {2.74625f, 2.85458f, 3.54791f, 6.83041f, 6.22916f, 8.125f, 6.89541f, 1.93375f, 3.79166f, 3.85666f, 4.7775f, 6.28875f,
2.1775f, 3.06041f, 2.91958f, 4.57166f, 6.22916f, 6.22916f, 6.22916f, 6.22916f, 6.22916f, 6.22916f, 6.22916f, 6.22916f,
6.22916f, 6.22916f, 2.68666f, 2.34541f, 5.63875f, 6.08833f, 5.79583f, 5.23791f, 9.96125f, 7.23666f, 6.90625f, 7.22041f,
7.27458f, 6.305f, 6.13166f, 7.55625f, 7.9083f, 3.01708f, 6.12083f, 6.955f, 5.96916f, 9.685f, 7.90833f, 7.62666f,
6.99833f, 7.62666f, 6.83041f, 6.58125f, 6.61916f, 7.19333f, 7.05791f, 9.84208f, 6.955f, 6.6625f, 6.64083f, 2.94125f,
4.55f, 2.94125f, 4.63666f, 5.005f, 3.42875f, 6.03416f, 6.22375f, 5.80666f, 6.25625f, 5.87708f, 3.85125f, 6.22375f,
6.11f, 2.69208f, 2.64875f, 5.6225f, 2.69208f, 9.72291f, 6.12083f, 6.32666f, 6.22375f, 6.305f, 3.75375f, 5.72f,
3.62375f, 6.11541f, 5.37333f, 8.33625f, 5.49791f, 5.24875f, 5.49791f, 3.75375f, 2.70291f, 3.75375f, 7.54541f};
const unsigned char iron_font_13_pixels[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 20, 215, 0, 0, 21, 41, 62, 0, 0, 0, 11, 164, 0, 176, 1, 0, 0, 0, 7, 27, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 49, 191, 205, 94, 0, 0, 0, 36, 30, 0, 0, 0, 38, 93, 0, 115, 15, 0, 0, 0, 0, 1, 181,
0, 0, 0, 0, 0, 51, 85, 0, 0, 0, 15, 32, 0, 155, 194, 163, 0, 0, 12, 0, 0, 0, 0, 0, 173, 20, 0, 0, 65, 181, 198,
99, 0, 0, 0, 22, 112, 194, 0, 0, 100, 194, 205, 125, 0, 0, 0, 103, 197, 200, 111, 0, 0, 0, 0, 0, 106, 200, 0, 0, 0, 119,
226, 226, 226, 126, 0, 0, 0, 0, 0, 0, 20, 239, 0, 0, 66, 124, 190, 0, 0, 0, 58, 139, 10, 189, 0, 0, 0, 0, 41, 165, 0,
0, 0, 12, 167, 172, 67, 0, 4, 0, 0, 0, 0, 165, 89, 12, 224, 1, 0, 0, 112, 91, 0, 0, 18, 216, 31, 0, 52, 187, 1, 0,
0, 95, 57, 195, 69, 63, 0, 0, 0, 96, 160, 0, 0, 0, 83, 165, 0, 12, 15, 13, 0, 32, 230, 0, 0, 0, 0, 37, 181, 0, 0,
1, 224, 40, 21, 207, 38, 0, 17, 211, 134, 242, 0, 33, 213, 18, 12, 211, 52, 0, 34, 213, 13, 10, 215, 29, 0, 0, 0, 32, 223, 226,
0, 0, 0, 159, 87, 10, 10, 6, 0, 0, 0, 0, 0, 0, 17, 235, 0, 0, 67, 104, 171, 0, 0, 152, 196, 200, 176, 220, 111, 0, 0,
70, 207, 235, 130, 5, 0, 91, 98, 10, 177, 0, 165, 21, 0, 0, 0, 167, 126, 82, 188, 0, 0, 0, 112, 77, 0, 0, 128, 101, 0, 0,
0, 158, 74, 0, 0, 67, 176, 255, 148, 49, 0, 34, 59, 133, 182, 59, 49, 0, 152, 107, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,
134, 84, 0, 0, 41, 195, 0, 0, 140, 101, 0, 1, 0, 15, 242, 0, 46, 65, 0, 0, 162, 88, 0, 18, 29, 0, 0, 191, 72, 0, 0,
0, 183, 95, 226, 0, 0, 0, 185, 53, 18, 0, 0, 0, 0, 0, 0, 0, 0, 14, 232, 0, 0, 24, 32, 56, 0, 0, 29, 172, 62, 126,
110, 21, 0, 1, 220, 50, 15, 199, 68, 0, 62, 135, 45, 157, 78, 124, 0, 0, 0, 0, 39, 245, 193, 16, 0, 0, 0, 31, 19, 0, 1,
236, 27, 0, 0, 0, 65, 182, 0, 0, 5, 194, 142, 134, 0, 0, 106, 183, 210, 228, 183, 152, 0, 80, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 4, 209, 6, 0, 0, 91, 160, 0, 0, 104, 150, 0, 0, 0, 15, 242, 0, 0, 0, 0, 32, 216, 16, 0, 0, 0, 98, 164,
171, 6, 0, 0, 94, 155, 31, 226, 0, 0, 0, 211, 221, 222, 181, 27, 0, 0, 0, 0, 0, 0, 10, 229, 0, 0, 0, 0, 0, 0, 0,
0, 195, 2, 156, 43, 0, 0, 6, 234, 20, 0, 70, 67, 0, 1, 101, 136, 39, 184, 6, 0, 0, 0, 9, 185, 172, 216, 19, 94, 51, 0,
0, 0, 0, 26, 231, 0, 0, 0, 0, 21, 226, 0, 0, 19, 86, 2, 112, 0, 0, 0, 0, 96, 160, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 76, 143, 0, 0, 0, 94, 160, 0, 0, 103, 149, 0, 0, 0, 15, 242, 0, 0, 0, 12, 202, 70, 0, 0,
0, 0, 88, 149, 194, 21, 0, 23, 212, 17, 31, 226, 0, 0, 0, 35, 6, 2, 153, 119, 0, 0, 0, 0, 0, 0, 6, 175, 0, 0, 0,
0, 0, 0, 67, 194, 236, 189, 240, 190, 54, 0, 0, 127, 214, 92, 5, 0, 0, 0, 0, 0, 141, 66, 90, 95, 7, 0, 85, 203, 3, 111,
192, 199, 21, 0, 0, 0, 0, 59, 190, 0, 0, 0, 0, 1, 245, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 160, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 46, 0, 0, 0, 50, 194, 0, 0, 134, 103, 0, 0, 0, 15, 242, 0, 0, 5, 184,
106, 0, 0, 0, 10, 11, 0, 0, 162, 103, 0, 154, 214, 165, 176, 245, 162, 0, 3, 15, 0, 0, 75, 180, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 51, 146, 6, 193, 0, 0, 0, 0, 0, 48, 183, 219, 29, 0, 0, 0, 50, 152, 95, 120, 109, 106, 0,
48, 204, 2, 2, 192, 216, 0, 0, 0, 0, 0, 47, 218, 0, 0, 0, 0, 10, 246, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 34,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 197, 0, 0, 0, 0, 2, 225, 23, 7, 198, 44, 0, 0, 0, 15, 242,
0, 1, 163, 126, 0, 0, 0, 0, 61, 193, 1, 1, 189, 56, 0, 31, 43, 43, 69, 231, 42, 0, 5, 215, 23, 0, 141, 113, 0, 0, 0,
0, 0, 0, 13, 231, 2, 0, 0, 0, 0, 0, 0, 101, 96, 49, 150, 0, 0, 0, 29, 54, 0, 0, 146, 137, 0, 0, 3, 181, 18, 136,
52, 40, 150, 0, 0, 133, 205, 221, 188, 193, 114, 0, 0, 0, 0, 13, 254, 18, 0, 0, 0, 52, 215, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 105, 0, 0, 0, 0, 0, 87, 199, 203, 122, 2, 0,
0, 0, 15, 242, 0, 79, 252, 209, 209, 209, 172, 0, 0, 144, 205, 203, 143, 0, 0, 0, 0, 0, 31, 226, 0, 0, 0, 80, 200, 204, 166,
22, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 223, 9, 0, 155, 111, 0, 0,
3, 42, 0, 44, 177, 174, 55, 0, 0, 0, 2, 11, 0, 0, 0, 0, 0, 0, 0, 0, 205, 71, 0, 0, 0, 96, 151, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 16, 0, 0, 0, 0, 0, 0, 1,
6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 224, 221,
174, 19, 0, 0, 0, 0, 0, 0, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 142, 0, 0, 5, 202, 34,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 67, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 169, 66,
0, 127, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 8, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 4, 47, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 183, 127,
0, 0, 122, 210, 210, 210, 215, 163, 0, 0, 83, 194, 205, 120, 0, 0, 0, 103, 214, 186, 67, 0, 0, 39, 191, 0, 66, 164, 0, 0, 0,
3, 86, 159, 0, 13, 72, 72, 72, 72, 24, 0, 62, 156, 44, 0, 0, 0, 0, 8, 156, 220, 177, 37, 0, 0, 0, 3, 66, 137, 169, 109,
34, 0, 0, 0, 0, 0, 10, 217, 55, 0, 0, 0, 0, 19, 226, 218, 213, 155, 51, 0, 0, 0, 15, 161, 219, 191, 98, 0, 0, 19, 226,
218, 201, 139, 18, 0, 0, 19, 226, 218, 218, 218, 190, 0, 19, 226, 218, 218, 218, 175, 0, 0, 16, 112, 206, 196, 111, 0, 0, 0, 0, 0,
95, 198, 75, 4, 0, 0, 0, 0, 0, 0, 146, 97, 0, 6, 226, 29, 11, 211, 42, 0, 45, 225, 26, 38, 226, 9, 0, 4, 42, 0, 10,
37, 0, 9, 105, 214, 168, 59, 0, 27, 151, 151, 151, 151, 51, 0, 9, 97, 196, 185, 72, 1, 0, 94, 157, 3, 115, 149, 0, 0, 0, 150,
125, 43, 7, 50, 174, 41, 0, 0, 0, 0, 93, 221, 154, 0, 0, 0, 0, 22, 244, 0, 5, 93, 198, 0, 0, 0, 188, 139, 16, 25, 211,
50, 0, 22, 244, 0, 31, 137, 200, 11, 0, 22, 244, 0, 0, 0, 0, 0, 22, 244, 0, 0, 0, 0, 0, 0, 170, 139, 17, 21, 201, 67,
0, 0, 0, 0, 177, 46, 18, 0, 0, 0, 0, 0, 0, 20, 221, 7, 0, 27, 231, 3, 0, 177, 84, 0, 101, 156, 0, 0, 165, 73, 0,
0, 0, 0, 0, 0, 0, 150, 221, 45, 0, 0, 0, 1, 7, 7, 7, 7, 2, 0, 0, 0, 0, 93, 246, 83, 0, 0, 0, 0, 95, 151,
0, 0, 118, 115, 0, 19, 77, 20, 3, 181, 4, 0, 0, 0, 191, 65, 227, 11, 0, 0, 0, 22, 244, 0, 0, 31, 242, 4, 0, 31, 248,
10, 0, 0, 78, 94, 0, 22, 244, 0, 0, 0, 206, 83, 0, 22, 244, 0, 0, 0, 0, 0, 22, 244, 0, 0, 0, 0, 0, 6, 234, 11,
0, 0, 45, 68, 0, 0, 0, 6, 226, 174, 203, 180, 18, 0, 0, 0, 0, 126, 124, 0, 0, 0, 144, 183, 159, 185, 11, 0, 77, 195, 0,
0, 158, 123, 0, 0, 0, 0, 0, 0, 0, 8, 103, 212, 166, 59, 0, 38, 214, 214, 214, 214, 73, 0, 11, 104, 204, 180, 67, 0, 0, 0,
0, 25, 216, 35, 0, 0, 193, 0, 39, 207, 110, 206, 0, 117, 37, 0, 0, 34, 216, 0, 157, 94, 0, 0, 0, 22, 250, 133, 142, 216, 97,
0, 0, 79, 192, 0, 0, 0, 0, 0, 0, 22, 244, 0, 0, 0, 130, 140, 0, 22, 249, 126, 126, 126, 47, 0, 22, 247, 85, 85, 85, 23,
0, 65, 197, 0, 0, 0, 0, 0, 0, 0, 0, 59, 224, 15, 0, 156, 100, 0, 0, 0, 10, 225, 20, 0, 0, 7, 180, 149, 130, 197, 29,
0, 9, 203, 177, 166, 231, 101, 0, 0, 12, 0, 12, 35, 0, 0, 0, 3, 85, 158, 0, 0, 0, 0, 0, 0, 0, 0, 61, 152, 40, 0,
0, 0, 0, 0, 0, 186, 110, 0, 0, 34, 162, 0, 174, 56, 6, 198, 0, 88, 75, 0, 0, 131, 126, 0, 64, 192, 0, 0, 0, 22, 247,
79, 83, 149, 186, 1, 0, 77, 186, 0, 0, 0, 0, 0, 0, 22, 244, 0, 0, 0, 126, 144, 0, 22, 248, 90, 90, 90, 34, 0, 22, 250,
132, 132, 132, 35, 0, 78, 195, 0, 26, 215, 222, 175, 0, 0, 0, 33, 212, 0, 0, 94, 156, 0, 0, 0, 107, 152, 0, 0, 0, 70, 191,
0, 0, 134, 127, 0, 0, 9, 69, 46, 218, 62, 0, 44, 218, 0, 67, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 4, 195, 13, 0, 0, 80, 119, 0, 219, 2, 28, 175, 0, 91, 83, 0, 2, 225, 225, 218, 219, 250, 35,
0, 0, 22, 244, 0, 0, 0, 223, 47, 0, 13, 234, 4, 0, 0, 57, 76, 0, 22, 244, 0, 0, 0, 203, 90, 0, 22, 244, 0, 0, 0,
0, 0, 22, 244, 0, 0, 0, 0, 0, 28, 249, 14, 0, 0, 76, 188, 0, 0, 0, 0, 207, 48, 1, 163, 85, 0, 0, 3, 219, 40, 0,
0, 0, 35, 215, 3, 0, 162, 91, 0, 0, 0, 19, 116, 203, 1, 0, 0, 3, 0, 135, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 49, 147, 0, 210, 1, 89, 169, 0, 150, 14, 0, 70, 195, 0,
0, 0, 134, 132, 0, 0, 22, 244, 0, 0, 41, 231, 9, 0, 0, 180, 109, 3, 6, 200, 60, 0, 22, 244, 0, 17, 112, 217, 18, 0, 22,
244, 0, 0, 0, 0, 0, 22, 244, 0, 0, 0, 0, 0, 0, 193, 134, 10, 0, 96, 188, 0, 0, 0, 0, 58, 187, 208, 152, 9, 0, 0,
87, 179, 0, 0, 0, 0, 0, 126, 206, 203, 163, 6, 0, 0, 74, 186, 90, 8, 0, 0, 0, 0, 0, 76, 9, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 233, 4, 0, 0, 11, 186, 0, 127, 205, 141, 142, 158, 109, 0,
0, 168, 103, 0, 0, 0, 41, 226, 3, 0, 22, 253, 217, 216, 187, 82, 0, 0, 0, 30, 143, 210, 204, 124, 0, 0, 22, 253, 217, 220, 166,
30, 0, 0, 22, 253, 217, 217, 217, 201, 0, 22, 244, 0, 0, 0, 0, 0, 0, 18, 180, 225, 203, 202, 47, 0, 0, 0, 0, 0, 0, 7,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 153, 88, 0, 8, 0,
0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
172, 150, 83, 77, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 27, 91, 96, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 216, 0, 0, 0, 16, 221, 0, 2, 226, 7, 0, 0, 0, 0, 0, 176, 60, 0,
19, 216, 0, 0, 16, 195, 73, 0, 19, 217, 0, 0, 0, 0, 0, 19, 226, 99, 0, 0, 0, 0, 172, 173, 0, 19, 226, 57, 0, 0, 13,
221, 0, 0, 13, 157, 224, 205, 104, 0, 0, 19, 226, 218, 218, 170, 82, 0, 0, 0, 18, 162, 226, 202, 96, 0, 0, 20, 226, 218, 213, 152,
57, 0, 0, 0, 79, 184, 221, 188, 38, 0, 0, 160, 218, 220, 225, 218, 218, 80, 0, 55, 178, 0, 0, 0, 131, 106, 0, 155, 99, 0, 0,
0, 85, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 244, 0, 0, 0, 18, 249, 0, 2, 255, 8, 0, 0, 0, 0,
0, 199, 68, 0, 22, 244, 0, 8, 193, 123, 0, 0, 22, 245, 0, 0, 0, 0, 0, 22, 248, 208, 0, 0, 0, 37, 247, 195, 0, 22, 255,
213, 7, 0, 15, 249, 0, 0, 178, 150, 22, 59, 207, 86, 0, 22, 244, 0, 0, 49, 221, 41, 0, 2, 189, 142, 19, 65, 212, 76, 0, 23,
244, 0, 5, 79, 223, 3, 0, 16, 228, 34, 2, 90, 222, 0, 0, 0, 0, 52, 212, 0, 0, 0, 0, 62, 201, 0, 0, 0, 147, 119, 0,
85, 194, 0, 0, 0, 179, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 244, 0, 0, 0, 18, 249, 0, 2, 255, 8,
0, 0, 0, 0, 0, 199, 68, 0, 22, 244, 3, 172, 150, 0, 0, 0, 22, 245, 0, 0, 0, 0, 0, 22, 224, 203, 55, 0, 0, 138, 170,
195, 0, 22, 245, 169, 132, 0, 15, 249, 0, 26, 248, 11, 0, 0, 100, 186, 0, 22, 244, 0, 0, 0, 141, 123, 0, 39, 242, 6, 0, 0,
112, 175, 0, 23, 244, 0, 0, 0, 219, 51, 0, 40, 228, 7, 0, 1, 97, 9, 0, 0, 0, 52, 212, 0, 0, 0, 0, 62, 201, 0, 0,
0, 147, 119, 0, 8, 237, 29, 0, 18, 241, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 249, 126, 126, 126, 135, 249,
0, 2, 255, 8, 0, 0, 0, 0, 0, 199, 68, 0, 22, 244, 149, 210, 3, 0, 0, 0, 22, 245, 0, 0, 0, 0, 0, 22, 232, 99, 157,
0, 6, 227, 81, 195, 0, 22, 245, 22, 230, 48, 15, 249, 0, 75, 191, 0, 0, 0, 35, 234, 0, 22, 244, 0, 0, 37, 214, 48, 0, 88,
180, 0, 0, 0, 47, 223, 0, 23, 244, 10, 19, 101, 234, 7, 0, 0, 146, 219, 116, 20, 0, 0, 0, 0, 0, 52, 212, 0, 0, 0, 0,
62, 201, 0, 0, 0, 147, 119, 0, 0, 152, 115, 0, 100, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 248, 90,
90, 90, 102, 249, 0, 2, 255, 8, 0, 0, 0, 0, 0, 199, 68, 0, 22, 255, 188, 223, 78, 0, 0, 0, 22, 245, 0, 0, 0, 0, 0,
22, 240, 11, 229, 15, 87, 166, 67, 195, 0, 22, 245, 0, 91, 205, 19, 249, 0, 82, 188, 0, 0, 0, 26, 239, 0, 22, 253, 217, 217, 180,
98, 0, 0, 94, 177, 0, 0, 0, 39, 228, 0, 23, 253, 206, 213, 240, 31, 0, 0, 0, 0, 36, 152, 237, 107, 0, 0, 0, 0, 52, 212,
0, 0, 0, 0, 62, 201, 0, 0, 0, 147, 119, 0, 0, 57, 203, 0, 189, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 22, 244, 0, 0, 0, 18, 249, 0, 2, 255, 8, 0, 31, 16, 0, 0, 203, 63, 0, 22, 247, 10, 55, 232, 32, 0, 0, 22, 245, 0,
0, 0, 0, 0, 22, 244, 0, 147, 106, 189, 63, 70, 195, 0, 22, 245, 0, 0, 179, 136, 249, 0, 33, 245, 7, 0, 0, 90, 192, 0, 22,
244, 0, 0, 0, 0, 0, 0, 46, 238, 3, 0, 0, 102, 184, 0, 23, 244, 0, 2, 208, 73, 0, 0, 38, 40, 0, 0, 35, 247, 13, 0,
0, 0, 52, 212, 0, 0, 0, 0, 48, 214, 0, 0, 0, 161, 106, 0, 0, 1, 217, 61, 228, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 22, 244, 0, 0, 0, 18, 249, 0, 2, 255, 8, 0, 115, 148, 0, 27, 232, 7, 0, 22, 244, 0, 0, 109, 202, 7,
0, 22, 245, 0, 0, 0, 0, 0, 22, 244, 0, 44, 225, 213, 1, 70, 195, 0, 22, 245, 0, 0, 27, 236, 249, 0, 0, 200, 125, 8, 29,
190, 107, 0, 22, 244, 0, 0, 0, 0, 0, 0, 3, 209, 116, 6, 34, 199, 97, 0, 23, 244, 0, 0, 73, 211, 3, 0, 82, 214, 11, 0,
37, 224, 7, 0, 0, 0, 52, 212, 0, 0, 0, 0, 0, 211, 55, 0, 20, 231, 23, 0, 0, 0, 123, 221, 140, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 244, 0, 0, 0, 18, 249, 0, 2, 255, 8, 0, 20, 176, 210, 208, 96, 0, 0, 22, 244, 0,
0, 0, 170, 148, 0, 22, 254, 217, 217, 217, 151, 0, 22, 244, 0, 0, 195, 111, 0, 70, 195, 0, 22, 245, 0, 0, 0, 101, 249, 0, 0,
23, 187, 227, 228, 135, 0, 0, 22, 244, 0, 0, 0, 0, 0, 0, 0, 29, 192, 227, 251, 204, 1, 0, 23, 244, 0, 0, 0, 191, 100, 0,
1, 123, 227, 206, 198, 81, 0, 0, 0, 0, 52, 212, 0, 0, 0, 0, 0, 66, 187, 209, 207, 94, 0, 0, 0, 0, 31, 253, 45, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 25, 184, 157, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 30, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 107, 0, 0, 130, 124,
0, 0, 123, 112, 0, 79, 192, 4, 0, 6, 197, 72, 0, 153, 114, 0, 0, 2, 191, 71, 0, 101, 218, 218, 218, 220, 226, 7, 0, 1, 3,
3, 0, 139, 77, 0, 0, 0, 0, 3, 3, 0, 0, 0, 49, 189, 0, 0, 0, 204, 209, 209, 209, 205, 0, 45, 51, 0, 0, 0, 114, 207,
200, 101, 0, 0, 20, 62, 0, 0, 0, 0, 0, 0, 87, 204, 200, 105, 0, 0, 0, 0, 0, 0, 44, 38, 0, 0, 74, 200, 191, 87, 0,
0, 0, 0, 48, 85, 0, 0, 79, 201, 165, 146, 103, 0, 20, 62, 0, 0, 0, 0, 0, 35, 203, 0, 0, 51, 184, 0, 0, 0, 85, 176,
0, 0, 211, 204, 0, 0, 193, 68, 0, 1, 189, 117, 0, 125, 183, 0, 0, 43, 234, 15, 0, 87, 202, 1, 0, 0, 0, 0, 0, 148, 154,
0, 0, 53, 245, 172, 0, 64, 179, 0, 0, 0, 0, 196, 250, 25, 0, 0, 154, 223, 57, 0, 0, 0, 0, 0, 0, 0, 0, 24, 209, 29,
0, 29, 176, 9, 15, 229, 18, 0, 62, 194, 0, 0, 0, 0, 0, 41, 225, 37, 13, 206, 38, 0, 0, 0, 0, 0, 138, 117, 0, 32, 227,
30, 19, 216, 17, 0, 0, 97, 205, 96, 0, 15, 232, 45, 40, 205, 120, 0, 62, 194, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1, 15, 0,
0, 0, 24, 234, 1, 32, 202, 205, 24, 5, 241, 11, 0, 0, 36, 236, 70, 236, 32, 0, 0, 0, 155, 129, 4, 216, 63, 0, 0, 0, 0,
0, 70, 219, 12, 0, 0, 53, 204, 0, 0, 1, 216, 26, 0, 0, 0, 0, 231, 25, 0, 15, 213, 72, 161, 0, 0, 0, 0, 0, 0, 0,
0, 0, 29, 33, 0, 0, 25, 92, 139, 230, 57, 0, 62, 194, 0, 0, 0, 0, 0, 104, 161, 0, 0, 21, 16, 0, 0, 0, 0, 0, 138,
117, 0, 97, 207, 119, 119, 200, 88, 0, 0, 178, 76, 0, 0, 84, 174, 0, 0, 137, 120, 0, 62, 194, 0, 0, 0, 0, 0, 34, 186, 0,
0, 46, 174, 0, 0, 0, 0, 217, 39, 105, 129, 135, 93, 54, 200, 0, 0, 0, 0, 120, 252, 114, 0, 0, 0, 0, 25, 230, 117, 178, 0,
0, 0, 0, 0, 17, 225, 59, 0, 0, 0, 53, 204, 0, 0, 0, 123, 120, 0, 0, 0, 0, 231, 25, 0, 109, 126, 2, 213, 19, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 220, 87, 45, 208, 57, 0, 62, 210, 140, 210, 116, 6, 0, 96, 150, 0, 0, 0, 0, 0, 0,
77, 201, 168, 181, 117, 0, 100, 193, 91, 91, 91, 43, 0, 133, 241, 212, 100, 0, 88, 160, 0, 0, 137, 120, 0, 62, 207, 126, 211, 147, 0,
0, 40, 216, 0, 0, 53, 202, 0, 0, 0, 0, 155, 98, 177, 54, 63, 163, 111, 138, 0, 0, 0, 0, 112, 254, 106, 0, 0, 0, 0, 0,
129, 251, 41, 0, 0, 0, 0, 0, 167, 135, 0, 0, 0, 0, 53, 204, 0, 0, 0, 28, 215, 1, 0, 0, 0, 231, 25, 0, 8, 4, 0,
9, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 187, 0, 21, 229, 59, 0, 62, 238, 83, 21, 192, 74, 0, 19, 216, 13, 0,
160, 62, 0, 15, 230, 44, 40, 205, 117, 0, 18, 224, 18, 0, 58, 18, 0, 0, 191, 65, 0, 0, 19, 224, 19, 21, 191, 120, 0, 62, 236,
37, 9, 213, 45, 0, 40, 216, 0, 0, 53, 202, 0, 0, 0, 0, 94, 159, 220, 2, 5, 218, 168, 76, 0, 0, 0, 33, 236, 82, 236, 29,
0, 0, 0, 0, 51, 215, 0, 0, 0, 0, 0, 88, 207, 6, 0, 0, 0, 0, 53, 204, 0, 0, 0, 0, 182, 62, 0, 0, 0, 231, 25,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 184, 214, 167, 210, 92, 0, 62, 194, 0, 0, 105, 145, 0,
0, 101, 201, 211, 152, 4, 0, 85, 171, 0, 0, 138, 117, 0, 0, 96, 201, 178, 107, 8, 0, 0, 191, 65, 0, 0, 0, 108, 219, 191, 198,
119, 0, 62, 194, 0, 0, 162, 93, 0, 40, 216, 0, 0, 53, 202, 0, 0, 0, 0, 32, 240, 159, 0, 0, 173, 237, 16, 0, 0, 0, 185,
125, 0, 132, 178, 0, 0, 0, 0, 51, 214, 0, 0, 0, 0, 27, 230, 44, 0, 0, 0, 0, 0, 53, 204, 0, 0, 0, 0, 83, 160, 0,
0, 0, 231, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 62, 194, 0,
0, 101, 156, 0, 0, 0, 1, 9, 0, 0, 0, 93, 158, 0, 0, 138, 117, 0, 0, 0, 0, 6, 0, 0, 0, 0, 191, 65, 0, 0, 0,
34, 6, 0, 189, 58, 0, 62, 194, 0, 0, 162, 94, 0, 40, 216, 0, 0, 53, 202, 0, 0, 0, 0, 0, 225, 85, 0, 0, 101, 207, 0,
0, 0, 94, 212, 6, 0, 8, 218, 87, 0, 0, 0, 51, 214, 0, 0, 0, 0, 132, 245, 217, 217, 217, 217, 45, 0, 53, 204, 0, 0, 0,
0, 6, 223, 14, 0, 0, 231, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 62, 230, 52, 5, 177, 84, 0, 0, 0, 0, 0, 0, 0, 0, 21, 223, 19, 21, 192, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191,
65, 0, 0, 8, 204, 184, 183, 180, 1, 0, 62, 194, 0, 0, 162, 94, 0, 40, 216, 0, 0, 53, 202, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53,
204, 0, 0, 0, 0, 0, 107, 58, 0, 0, 231, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 62, 208, 169, 219, 151, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 219, 188, 186, 117, 0, 0, 0, 0, 0, 0,
0, 0, 0, 191, 65, 0, 0, 0, 4, 51, 32, 0, 0, 0, 62, 194, 0, 0, 162, 94, 0, 0, 0, 0, 0, 57, 198, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 53, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 183, 138,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 53, 210, 28, 0, 0, 0, 0, 0, 0, 0, 32, 234, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 27, 67, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 176, 147, 0, 0, 0, 0, 0, 0, 0, 167, 176, 17, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 62, 0, 0, 0, 0, 0, 13, 69, 0, 54, 176, 139, 207, 99, 92,
207, 203, 73, 0, 53, 172, 124, 210, 147, 0, 0, 0, 77, 201, 197, 100, 4, 0, 53, 174, 142, 210, 116, 6, 0, 0, 80, 200, 169, 155, 100,
0, 53, 179, 154, 140, 0, 0, 114, 201, 193, 80, 0, 0, 0, 63, 8, 0, 0, 58, 162, 0, 0, 143, 77, 0, 146, 76, 0, 7, 204, 10,
0, 141, 75, 0, 85, 151, 0, 10, 203, 3, 0, 95, 153, 0, 52, 192, 7, 0, 159, 78, 0, 21, 206, 5, 0, 100, 211, 211, 214, 210, 0,
0, 0, 0, 32, 74, 0, 12, 171, 0, 95, 11, 0, 0, 0, 0, 0, 0, 0, 0, 60, 195, 0, 0, 0, 0, 0, 40, 216, 0, 63, 233,
66, 13, 220, 174, 7, 71, 199, 0, 62, 236, 37, 9, 213, 45, 0, 35, 230, 46, 19, 185, 77, 0, 62, 232, 64, 25, 200, 71, 0, 16, 232,
42, 31, 197, 116, 0, 62, 241, 96, 3, 0, 37, 217, 5, 33, 194, 4, 0, 0, 225, 30, 0, 0, 67, 188, 0, 0, 166, 90, 0, 84, 166,
0, 75, 173, 0, 0, 95, 150, 0, 172, 226, 7, 68, 173, 0, 0, 4, 204, 68, 202, 75, 0, 0, 99, 170, 0, 97, 163, 0, 0, 0, 0,
1, 175, 121, 0, 0, 0, 27, 215, 35, 0, 13, 193, 0, 73, 203, 0, 0, 0, 0, 0, 0, 0, 0, 60, 195, 0, 0, 0, 0, 0, 40,
216, 0, 63, 193, 0, 0, 166, 93, 0, 9, 247, 0, 62, 194, 0, 0, 162, 93, 0, 101, 171, 0, 0, 83, 163, 0, 62, 194, 0, 0, 111,
142, 0, 85, 172, 0, 0, 140, 116, 0, 62, 194, 0, 0, 0, 19, 220, 145, 60, 2, 0, 0, 188, 248, 204, 42, 0, 67, 188, 0, 0, 166,
90, 0, 8, 226, 9, 157, 82, 0, 0, 23, 215, 8, 202, 144, 74, 133, 99, 0, 0, 0, 46, 237, 161, 0, 0, 0, 16, 236, 11, 177, 74,
0, 0, 0, 0, 113, 183, 2, 0, 0, 0, 102, 148, 0, 0, 13, 193, 0, 0, 215, 35, 0, 0, 0, 0, 0, 0, 0, 60, 195, 0, 64,
189, 16, 0, 40, 216, 0, 63, 193, 0, 0, 164, 92, 0, 8, 247, 0, 62, 194, 0, 0, 162, 94, 0, 94, 156, 0, 0, 77, 191, 0, 62,
194, 0, 0, 105, 154, 0, 94, 158, 0, 0, 140, 116, 0, 62, 194, 0, 0, 0, 0, 11, 85, 178, 193, 2, 0, 0, 225, 30, 0, 0, 67,
189, 0, 0, 166, 90, 0, 0, 154, 84, 219, 7, 0, 0, 0, 202, 105, 134, 62, 153, 196, 26, 0, 0, 0, 38, 240, 150, 0, 0, 0, 0,
170, 95, 226, 5, 0, 0, 0, 55, 221, 20, 0, 0, 0, 0, 129, 127, 0, 0, 13, 193, 0, 0, 194, 62, 0, 0, 0, 0, 0, 0, 0,
60, 195, 54, 221, 41, 0, 0, 40, 216, 0, 63, 193, 0, 0, 164, 92, 0, 8, 247, 0, 62, 194, 0, 0, 162, 94, 0, 15, 221, 20, 4,
163, 127, 0, 62, 221, 30, 5, 182, 82, 0, 23, 225, 16, 12, 182, 116, 0, 62, 194, 0, 0, 0, 74, 147, 0, 5, 236, 19, 0, 0, 225,
30, 0, 0, 26, 226, 2, 37, 210, 90, 0, 0, 62, 221, 154, 0, 0, 0, 0, 128, 235, 55, 3, 211, 200, 0, 0, 0, 2, 196, 84, 207,
66, 0, 0, 0, 78, 232, 152, 0, 0, 0, 18, 220, 59, 0, 0, 0, 0, 0, 169, 54, 0, 0, 13, 193, 0, 0, 115, 102, 0, 0, 0,
0, 0, 0, 0, 60, 221, 235, 74, 0, 0, 0, 40, 216, 0, 63, 193, 0, 0, 164, 92, 0, 8, 247, 0, 62, 194, 0, 0, 162, 94, 0,
0, 91, 198, 216, 169, 6, 0, 62, 223, 176, 216, 149, 11, 0, 0, 111, 216, 190, 203, 116, 0, 62, 194, 0, 0, 0, 12, 175, 209, 201, 125,
0, 0, 0, 225, 30, 0, 0, 0, 152, 218, 191, 205, 90, 0, 0, 1, 223, 63, 0, 0, 0, 0, 54, 229, 1, 0, 154, 131, 0, 0, 0,
113, 177, 0, 56, 221, 12, 0, 0, 6, 236, 63, 0, 0, 0, 127, 244, 209, 209, 209, 27, 0, 142, 188, 0, 0, 0, 13, 193, 0, 0, 6,
228, 80, 0, 0, 0, 0, 0, 0, 60, 244, 155, 188, 2, 0, 0, 40, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 62, 194, 0, 7, 0, 0, 0, 0, 0, 6, 1, 140, 116, 0, 0, 0, 0, 0, 0, 0,
0, 10, 3, 0, 0, 0, 0, 218, 37, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 215, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 193, 20, 0, 0, 13,
193, 0, 0, 66, 157, 13, 0, 0, 0, 0, 0, 0, 60, 195, 1, 176, 126, 0, 0, 40, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 116, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 217, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 202, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134,
116, 0, 0, 13, 193, 0, 0, 183, 67, 0, 0, 0, 0, 0, 0, 0, 60, 195, 0, 17, 220, 64, 0, 40, 216, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35,
29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 118, 134, 0, 0, 13, 193, 0, 0, 200, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 50, 196, 2, 0, 6, 89, 0, 18, 226, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 106, 106, 0, 0, 0, 0, 149, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 6, 68, 18, 0, 1, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 2, 204, 159, 218, 83, 86, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 108, 0, 37, 174, 160, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void const_data_create_screen_aligned_data(void) {
// Over-sized triangle
float data[] = {-1.0f, -1.0f, 3.0f, -1.0f, -1.0f, 3.0f};
-9
View File
@@ -10,12 +10,3 @@ extern gpu_buffer_t *const_data_skydome_ib;
void const_data_create_screen_aligned_data(void);
void const_data_create_skydome_data(void);
extern const char iron_font_13_x0[];
extern const char iron_font_13_y0[];
extern const char iron_font_13_x1[];
extern const char iron_font_13_y1[];
extern const char iron_font_13_xoff[];
extern const char iron_font_13_yoff[];
extern const float iron_font_13_xadvance[];
extern const unsigned char iron_font_13_pixels[];
+367 -175
View File
@@ -8,14 +8,15 @@
#include "iron_string.h"
#include "iron_system.h"
#include <math.h>
#include <string.h>
draw_font_t *draw_font = NULL;
int draw_font_size;
gpu_texture_t *_draw_current = NULL;
static mat3_t draw_transform;
static uint32_t draw_color = 0;
static gpu_pipeline_t *draw_custom_pipeline = NULL;
static mat3_t draw_transform;
static uint32_t draw_color = 0;
static gpu_pipeline_t *draw_custom_pipeline = NULL;
static gpu_buffer_t rect_vertex_buffer;
static gpu_buffer_t rect_index_buffer;
@@ -49,6 +50,17 @@ static int text_pos_loc;
static int text_tex_loc;
static int text_col_loc;
static gpu_pipeline_t slug_pipeline;
static gpu_pipeline_t slug_rt_pipeline;
static int slug_curve_tex_unit;
static int slug_band_tex_unit;
static int slug_pos_loc;
static int slug_col_loc;
static int slug_em_rect_loc;
static int slug_glyph_loc_loc;
static int slug_band_max_loc;
static int slug_band_tf_loc;
static i32_array_t *draw_font_glyph_blocks = NULL;
static i32_array_t *draw_font_glyphs = NULL;
static int draw_glyphs_version = 0;
@@ -93,7 +105,8 @@ static void draw_pipeline_init(gpu_pipeline_t *pipe, gpu_shader_t *vert, gpu_sha
}
void draw_init(buffer_t *image_vert, buffer_t *image_frag, buffer_t *image_transform_vert, buffer_t *image_transform_frag, buffer_t *rect_vert,
buffer_t *rect_frag, buffer_t *tris_vert, buffer_t *tris_frag, buffer_t *text_vert, buffer_t *text_frag) {
buffer_t *rect_frag, buffer_t *tris_vert, buffer_t *tris_frag, buffer_t *text_vert, buffer_t *text_frag, buffer_t *slug_vert,
buffer_t *slug_frag) {
draw_transform = mat3_nan();
draw_structure.size = 0;
gpu_vertex_structure_add(&draw_structure, "pos", GPU_VERTEX_DATA_F32_2X);
@@ -206,6 +219,27 @@ void draw_init(buffer_t *image_vert, buffer_t *image_frag, buffer_t *image_trans
text_rt_pipeline.blend_source = GPU_BLEND_SOURCE_ALPHA;
gpu_pipeline_compile(&text_rt_pipeline);
}
// Slug painter
{
gpu_shader_init(&vert_shader, slug_vert->buffer, slug_vert->length, GPU_SHADER_TYPE_VERTEX);
gpu_shader_init(&frag_shader, slug_frag->buffer, slug_frag->length, GPU_SHADER_TYPE_FRAGMENT);
draw_pipeline_init(&slug_pipeline, &vert_shader, &frag_shader);
slug_pipeline.blend_source = GPU_BLEND_SOURCE_ALPHA;
gpu_pipeline_compile(&slug_pipeline);
slug_curve_tex_unit = 0;
slug_band_tex_unit = 1;
slug_pos_loc = 0;
slug_col_loc = 16;
slug_em_rect_loc = 32;
slug_glyph_loc_loc = 48;
slug_band_max_loc = 64;
slug_band_tf_loc = 80;
draw_pipeline_init(&slug_rt_pipeline, &vert_shader, &frag_shader);
slug_rt_pipeline.blend_source = GPU_BLEND_SOURCE_ALPHA;
gpu_pipeline_compile(&slug_rt_pipeline);
}
}
void draw_begin(gpu_texture_t *target, bool clear, unsigned color) {
@@ -226,7 +260,9 @@ void draw_end(void) {
void draw_scaled_sub_image(gpu_texture_t *tex, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh) {
if (mat3_isnan(draw_transform)) {
gpu_set_pipeline(draw_custom_pipeline != NULL ? draw_custom_pipeline : (_draw_current != NULL && _draw_current->format == GPU_TEXTURE_FORMAT_R8) ? &image_r8_pipeline : &image_pipeline);
gpu_set_pipeline(draw_custom_pipeline != NULL ? draw_custom_pipeline
: (_draw_current != NULL && _draw_current->format == GPU_TEXTURE_FORMAT_R8) ? &image_r8_pipeline
: &image_pipeline);
}
else {
gpu_set_pipeline(draw_custom_pipeline != NULL ? draw_custom_pipeline : &image_transform_pipeline);
@@ -322,18 +358,38 @@ void draw_line_aa(float x0, float y0, float x1, float y1, float strength) {
#define STB_TRUETYPE_IMPLEMENTATION
#include <stb_truetype.h>
typedef struct draw_font_aligned_quad {
float x0, y0, s0, t0; // Top-left
float x1, y1, s1, t1; // Bottom-right
typedef struct draw_glyph {
int16_t x0, y0, x1, y1;
float xoff, yoff, xadvance;
} draw_glyph_t;
#define SLUG_HBAND_COUNT 16
#define SLUG_VBAND_COUNT 16
#define SLUG_CURVE_TEX_WIDTH 4096
#define SLUG_BAND_TEX_WIDTH 4096
typedef struct slug_glyph {
int band_tex_x, band_tex_y;
float xoff, yoff, glyph_w, glyph_h;
float xadvance;
} draw_font_aligned_quad_t;
float band_scale_x, band_scale_y;
} slug_glyph_t;
typedef struct draw_font_image {
float m_size;
stbtt_bakedchar *chars;
gpu_texture_t *tex;
int width, height, first_unused_y;
float baseline, descent, line_gap;
float m_size;
slug_glyph_t *slug_glyphs;
gpu_texture_t *curve_tex;
gpu_texture_t *band_tex;
int curve_tex_width;
int curve_tex_height;
int band_tex_width;
int band_tex_height;
int width;
int height;
int first_unused_y;
float baseline;
float descent;
float line_gap;
} draw_font_image_t;
draw_font_image_t *draw_font_get_image_internal(draw_font_t *font, int size) {
@@ -364,49 +420,98 @@ static inline bool draw_prepare_font_load_internal(draw_font_t *font, int size)
return true;
}
static int stbtt_BakeFontBitmapArr(unsigned char *data, int offset, // Font location (use offset=0 for plain .ttf)
float pixel_height, // Height of font in pixels
unsigned char *pixels, int pw, int ph, // Bitmap to be filled in
int *chars, int num_chars, // Characters to bake
stbtt_bakedchar *chardata) {
float scale;
int x, y, bottom_y, i;
stbtt_fontinfo f;
f.userdata = NULL;
if (!stbtt_InitFont(&f, data, offset))
return -1;
STBTT_memset(pixels, 0, pw * ph); // Background of 0 around pixels
x = y = 1;
bottom_y = 1;
typedef struct {
float p1x, p1y, p2x, p2y, p3x, p3y;
} _slug_curve_t;
scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
for (i = 0; i < num_chars; ++i) {
int advance, lsb, x0, y0, x1, y1, gw, gh;
int g = stbtt_FindGlyphIndex(&f, chars[i]);
stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
stbtt_GetGlyphBitmapBox(&f, g, scale, scale, &x0, &y0, &x1, &y1);
gw = x1 - x0;
gh = y1 - y0;
if (x + gw + 1 >= pw)
y = bottom_y, x = 1; // Advance to next row
if (y + gh + 1 >= ph) // Check if it fits vertically AFTER potentially moving to next row
return -i;
STBTT_assert(x + gw < pw);
STBTT_assert(y + gh < ph);
stbtt_MakeGlyphBitmap(&f, pixels + x + y * pw, gw, gh, pw, scale, scale, g);
chardata[i].x0 = (stbtt_int16)x;
chardata[i].y0 = (stbtt_int16)y;
chardata[i].x1 = (stbtt_int16)(x + gw);
chardata[i].y1 = (stbtt_int16)(y + gh);
chardata[i].xadvance = scale * advance;
chardata[i].xoff = (float)x0;
chardata[i].yoff = (float)y0;
x = x + gw + 1;
if (y + gh + 1 > bottom_y)
bottom_y = y + gh + 1;
static int _slug_extract_curves(stbtt_fontinfo *info, int glyph_index, float scale, int bx0, int by0, _slug_curve_t **out) {
stbtt_vertex *verts;
int nv = stbtt_GetGlyphShape(info, glyph_index, &verts);
if (nv == 0) {
*out = NULL;
return 0;
}
return bottom_y;
_slug_curve_t *c = (_slug_curve_t *)malloc(nv * 2 * sizeof(_slug_curve_t));
int nc = 0;
float cx = 0.0f, cy = 0.0f;
for (int i = 0; i < nv; i++) {
float vx = verts[i].x * scale - bx0;
float vy = -verts[i].y * scale - by0;
float vcx = verts[i].cx * scale - bx0;
float vcy = -verts[i].cy * scale - by0;
switch (verts[i].type) {
case STBTT_vmove:
cx = vx;
cy = vy;
break;
case STBTT_vline:
c[nc++] = (_slug_curve_t){cx, cy, (cx + vx) * 0.5f, (cy + vy) * 0.5f, vx, vy};
cx = vx;
cy = vy;
break;
case STBTT_vcurve:
c[nc++] = (_slug_curve_t){cx, cy, vcx, vcy, vx, vy};
cx = vx;
cy = vy;
break;
case STBTT_vcubic: {
float cx2 = verts[i].cx1 * scale - bx0;
float cy2 = -verts[i].cy1 * scale - by0;
float m1x = (cx + vcx) * 0.5f, m1y = (cy + vcy) * 0.5f;
float m2x = (vcx + cx2) * 0.5f, m2y = (vcy + cy2) * 0.5f;
float m3x = (cx2 + vx) * 0.5f, m3y = (cy2 + vy) * 0.5f;
float m12x = (m1x + m2x) * 0.5f, m12y = (m1y + m2y) * 0.5f;
float m23x = (m2x + m3x) * 0.5f, m23y = (m2y + m3y) * 0.5f;
float midx = (m12x + m23x) * 0.5f, midy = (m12y + m23y) * 0.5f;
c[nc++] = (_slug_curve_t){cx, cy, m12x, m12y, midx, midy};
c[nc++] = (_slug_curve_t){midx, midy, m23x, m23y, vx, vy};
cx = vx;
cy = vy;
break;
}
}
}
stbtt_FreeShape(info, verts);
*out = c;
return nc;
}
static _slug_curve_t *_slug_sort_curves;
static int _slug_cmp_hband(const void *a, const void *b) {
int ia = *(const int *)a, ib = *(const int *)b;
float ma = fmaxf(fmaxf(_slug_sort_curves[ia].p1x, _slug_sort_curves[ia].p2x), _slug_sort_curves[ia].p3x);
float mb = fmaxf(fmaxf(_slug_sort_curves[ib].p1x, _slug_sort_curves[ib].p2x), _slug_sort_curves[ib].p3x);
return (ma < mb) - (ma > mb);
}
static int _slug_cmp_vband(const void *a, const void *b) {
int ia = *(const int *)a, ib = *(const int *)b;
float ma = fmaxf(fmaxf(_slug_sort_curves[ia].p1y, _slug_sort_curves[ia].p2y), _slug_sort_curves[ia].p3y);
float mb = fmaxf(fmaxf(_slug_sort_curves[ib].p1y, _slug_sort_curves[ib].p2y), _slug_sort_curves[ib].p3y);
return (ma < mb) - (ma > mb);
}
typedef struct {
float *data;
int texels;
int cap;
} _slug_fbuf_t;
static void _slug_push(_slug_fbuf_t *b, float r, float g, float bv, float a) {
if (b->texels >= b->cap) {
b->cap = b->cap < 64 ? 256 : b->cap * 2;
b->data = (float *)realloc(b->data, (size_t)b->cap * 4 * sizeof(float));
}
int i = b->texels * 4;
b->data[i] = r;
b->data[i + 1] = g;
b->data[i + 2] = bv;
b->data[i + 3] = a;
b->texels++;
}
bool draw_font_load(draw_font_t *font, int size) {
@@ -416,49 +521,180 @@ bool draw_font_load(draw_font_t *font, int size) {
draw_font_image_t *img = &(font->images[font->m_images_len]);
font->m_images_len += 1;
int width = 64;
int height = 32;
stbtt_bakedchar *baked = (stbtt_bakedchar *)malloc(draw_font_glyphs->length * sizeof(stbtt_bakedchar));
unsigned char *pixels = NULL;
int status = -1;
while (status <= 0) {
if (height < width)
height *= 2;
else
width *= 2;
if (pixels == NULL)
pixels = (unsigned char *)malloc(width * height);
else
pixels = (unsigned char *)realloc(pixels, width * height);
if (pixels == NULL)
return false;
status =
stbtt_BakeFontBitmapArr(font->blob, font->offset, (float)size, pixels, width, height, draw_font_glyphs->buffer, draw_font_glyphs->length, baked);
}
memset(img, 0, sizeof(draw_font_image_t));
img->m_size = (float)size;
stbtt_fontinfo info;
int ascent, descent, line_gap;
stbtt_InitFont(&info, font->blob, font->offset);
stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap);
float scale = stbtt_ScaleForPixelHeight(&info, (float)size);
img->m_size = (float)size;
img->baseline = (float)((int)((float)ascent * scale + 0.5f));
img->descent = (float)((int)((float)descent * scale + 0.5f));
img->line_gap = (float)((int)((float)line_gap * scale + 0.5f));
img->width = width;
img->height = height;
img->chars = baked;
img->first_unused_y = status;
img->tex = (gpu_texture_t *)malloc(sizeof(gpu_texture_t));
gpu_texture_init_from_bytes(img->tex, pixels, width, height, GPU_TEXTURE_FORMAT_R8);
free(pixels);
return true;
}
gpu_texture_t *draw_font_get_texture(draw_font_t *font, int size) {
draw_font_image_t *img = draw_font_get_image_internal(font, size);
return img->tex;
int ascent, descent, line_gap;
stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap);
float scale = stbtt_ScaleForPixelHeight(&info, (float)size);
img->baseline = (float)((int)(ascent * scale + 0.5f));
img->descent = (float)((int)(descent * scale + 0.5f));
img->line_gap = (float)((int)(line_gap * scale + 0.5f));
int num_glyphs = draw_font_glyphs->length;
img->slug_glyphs = (slug_glyph_t *)malloc((size_t)num_glyphs * sizeof(slug_glyph_t));
memset(img->slug_glyphs, 0, (size_t)num_glyphs * sizeof(slug_glyph_t));
_slug_fbuf_t curve_buf = {NULL, 0, 0};
_slug_fbuf_t band_buf = {NULL, 0, 0};
int total_bands = SLUG_HBAND_COUNT + SLUG_VBAND_COUNT;
for (int gi = 0; gi < num_glyphs; gi++) {
int codepoint = draw_font_glyphs->buffer[gi];
int glyph_index = stbtt_FindGlyphIndex(&info, codepoint);
int advance, lsb;
stbtt_GetGlyphHMetrics(&info, glyph_index, &advance, &lsb);
img->slug_glyphs[gi].xadvance = advance * scale;
int bx0, by0, bx1, by1;
stbtt_GetGlyphBitmapBox(&info, glyph_index, scale, scale, &bx0, &by0, &bx1, &by1);
int gw = bx1 - bx0, gh = by1 - by0;
img->slug_glyphs[gi].xoff = (float)bx0;
img->slug_glyphs[gi].yoff = (float)by0;
img->slug_glyphs[gi].glyph_w = (float)gw;
img->slug_glyphs[gi].glyph_h = (float)gh;
if (gw <= 0 || gh <= 0) {
continue; // whitespace or zero-size glyph
}
_slug_curve_t *curves;
int nc = _slug_extract_curves(&info, glyph_index, scale, bx0, by0, &curves);
// Glyph's band texture origin (top-left of its band data block)
int glyph_band_start = band_buf.texels;
img->slug_glyphs[gi].band_tex_x = glyph_band_start % SLUG_BAND_TEX_WIDTH;
img->slug_glyphs[gi].band_tex_y = glyph_band_start / SLUG_BAND_TEX_WIDTH;
img->slug_glyphs[gi].band_scale_x = (gw > 0) ? (float)(SLUG_VBAND_COUNT - 1) / (float)gw : 0.0f;
img->slug_glyphs[gi].band_scale_y = (gh > 0) ? (float)(SLUG_HBAND_COUNT - 1) / (float)gh : 0.0f;
// Reserve descriptor texels: HBAND_COUNT + VBAND_COUNT
int descriptor_start = band_buf.texels;
for (int b = 0; b < total_bands; b++) {
_slug_push(&band_buf, 0.0f, 0.0f, 0.0f, 0.0f); // placeholder
}
// Build per-band curve index lists (use COUNT-1 to match shader's band_scale)
float hband_h = (float)gh / (SLUG_HBAND_COUNT - 1);
float vband_w = (float)gw / (SLUG_VBAND_COUNT - 1);
// Per-band curve index arrays (stored as flat array: band * nc + index)
int *band_indices = (int *)malloc((size_t)(total_bands * (nc + 1)) * sizeof(int));
int *band_sizes = (int *)calloc((size_t)total_bands, sizeof(int));
_slug_sort_curves = curves;
for (int c = 0; c < nc; c++) {
float ymin = fminf(fminf(curves[c].p1y, curves[c].p2y), curves[c].p3y);
float ymax = fmaxf(fmaxf(curves[c].p1y, curves[c].p2y), curves[c].p3y);
float xmin = fminf(fminf(curves[c].p1x, curves[c].p2x), curves[c].p3x);
float xmax = fmaxf(fmaxf(curves[c].p1x, curves[c].p2x), curves[c].p3x);
int hlo = (int)(ymin / hband_h);
if (hlo < 0)
hlo = 0;
int hhi = (int)(ymax / hband_h);
if (hhi >= SLUG_HBAND_COUNT)
hhi = SLUG_HBAND_COUNT - 1;
for (int b = hlo; b <= hhi; b++) {
band_indices[b * (nc + 1) + band_sizes[b]] = c;
band_sizes[b]++;
}
int vlo = (int)(xmin / vband_w);
if (vlo < 0)
vlo = 0;
int vhi = (int)(xmax / vband_w);
if (vhi >= SLUG_VBAND_COUNT)
vhi = SLUG_VBAND_COUNT - 1;
for (int b = vlo; b <= vhi; b++) {
int bi = SLUG_HBAND_COUNT + b;
band_indices[bi * (nc + 1) + band_sizes[bi]] = c;
band_sizes[bi]++;
}
}
// Sort horizontal bands by descending max-x, vertical by descending max-y
for (int b = 0; b < SLUG_HBAND_COUNT; b++) {
qsort(&band_indices[b * (nc + 1)], (size_t)band_sizes[b], sizeof(int), _slug_cmp_hband);
}
for (int b = 0; b < SLUG_VBAND_COUNT; b++) {
int bi = SLUG_HBAND_COUNT + b;
qsort(&band_indices[bi * (nc + 1)], (size_t)band_sizes[bi], sizeof(int), _slug_cmp_vband);
}
// Write each curve exactly once to the curve texture; record its (tx, ty) position.
int *curve_tex_pos_x = (int *)malloc((size_t)nc * sizeof(int));
int *curve_tex_pos_y = (int *)malloc((size_t)nc * sizeof(int));
for (int c = 0; c < nc; c++) {
curve_tex_pos_x[c] = curve_buf.texels % SLUG_CURVE_TEX_WIDTH;
curve_tex_pos_y[c] = curve_buf.texels / SLUG_CURVE_TEX_WIDTH;
_slug_push(&curve_buf, curves[c].p1x, curves[c].p1y, curves[c].p2x, curves[c].p2y);
_slug_push(&curve_buf, curves[c].p3x, curves[c].p3y, 0.0f, 0.0f);
}
// Write band curve-location lists into band texture; back-fill descriptors.
for (int b = 0; b < total_bands; b++) {
int count = band_sizes[b];
int offset = band_buf.texels - glyph_band_start;
for (int k = 0; k < count; k++) {
int ci = band_indices[b * (nc + 1) + k];
_slug_push(&band_buf, (float)curve_tex_pos_x[ci], (float)curve_tex_pos_y[ci], 0.0f, 0.0f);
}
int desc_abs = descriptor_start + b;
band_buf.data[desc_abs * 4 + 0] = (float)count;
band_buf.data[desc_abs * 4 + 1] = (float)offset;
band_buf.data[desc_abs * 4 + 2] = 0.0f;
band_buf.data[desc_abs * 4 + 3] = 0.0f;
}
free(curve_tex_pos_x);
free(curve_tex_pos_y);
free(band_indices);
free(band_sizes);
free(curves);
}
// Build GPU textures
int ctw = SLUG_CURVE_TEX_WIDTH;
int cth = (curve_buf.texels + ctw - 1) / ctw;
if (cth < 1)
cth = 1;
int btw = SLUG_BAND_TEX_WIDTH;
int bth = (band_buf.texels + btw - 1) / btw;
if (bth < 1)
bth = 1;
// Pad to full rows
int curve_total = ctw * cth;
int band_total = btw * bth;
curve_buf.data = (float *)realloc(curve_buf.data, (size_t)curve_total * 4 * sizeof(float));
if (curve_buf.texels < curve_total)
memset(&curve_buf.data[curve_buf.texels * 4], 0, (size_t)(curve_total - curve_buf.texels) * 4 * sizeof(float));
band_buf.data = (float *)realloc(band_buf.data, (size_t)band_total * 4 * sizeof(float));
if (band_buf.texels < band_total)
memset(&band_buf.data[band_buf.texels * 4], 0, (size_t)(band_total - band_buf.texels) * 4 * sizeof(float));
img->curve_tex = (gpu_texture_t *)malloc(sizeof(gpu_texture_t));
img->band_tex = (gpu_texture_t *)malloc(sizeof(gpu_texture_t));
img->curve_tex_width = ctw;
img->curve_tex_height = cth;
img->band_tex_width = btw;
img->band_tex_height = bth;
gpu_texture_init_from_bytes(img->curve_tex, curve_buf.data, ctw, cth, GPU_TEXTURE_FORMAT_RGBA128);
gpu_texture_init_from_bytes(img->band_tex, band_buf.data, btw, bth, GPU_TEXTURE_FORMAT_RGBA128);
free(curve_buf.data);
free(band_buf.data);
return true;
}
int draw_font_get_char_index_internal(int char_index) {
@@ -484,57 +720,50 @@ int draw_font_get_char_index_internal(int char_index) {
return char_index - offset;
}
bool draw_font_get_baked_quad(draw_font_t *font, int size, draw_font_aligned_quad_t *q, int char_code, float xpos, float ypos) {
draw_font_image_t *img = draw_font_get_image_internal(font, size);
int char_index = draw_font_get_char_index_internal(char_code);
if (char_index >= draw_font_glyphs->length) {
return false;
}
float ipw = 1.0f / (float)img->width;
float iph = 1.0f / (float)img->height;
stbtt_bakedchar b = img->chars[char_index];
int round_x = (int)(xpos + b.xoff + 0.5);
int round_y = (int)(ypos + b.yoff + 0.5);
q->x0 = (float)round_x;
q->y0 = (float)round_y;
q->x1 = (float)round_x + b.x1 - b.x0;
q->y1 = (float)round_y + b.y1 - b.y0;
q->s0 = b.x0 * ipw;
q->t0 = b.y0 * iph;
q->s1 = b.x1 * ipw;
q->t1 = b.y1 * iph;
q->xadvance = b.xadvance;
return true;
}
void draw_string(const char *text, float x, float y) {
draw_font_image_t *img = draw_font_get_image_internal(draw_font, draw_font_size);
float xpos = x;
float ypos = y + img->baseline;
draw_font_aligned_quad_t q;
draw_font_image_t *img = draw_font_get_image_internal(draw_font, draw_font_size);
float xpos = x;
float ypos = y + img->baseline;
float cr = _draw_color_r(draw_color) / 255.0f;
float cg = _draw_color_g(draw_color) / 255.0f;
float cb = _draw_color_b(draw_color) / 255.0f;
float ca = _draw_color_a(draw_color) / 255.0f;
gpu_set_pipeline(draw_custom_pipeline != NULL ? draw_custom_pipeline : _draw_current != NULL ? &text_rt_pipeline : &text_pipeline);
gpu_set_vertex_buffer(&rect_vertex_buffer);
gpu_set_index_buffer(&rect_index_buffer);
gpu_set_texture(text_tex_unit, img->tex);
// Slug vector rendering path
for (int i = 0; text[i] != 0;) {
gpu_set_pipeline(draw_custom_pipeline != NULL ? draw_custom_pipeline : _draw_current != NULL ? &slug_rt_pipeline : &slug_pipeline);
gpu_set_vertex_buffer(&rect_vertex_buffer);
gpu_set_index_buffer(&rect_index_buffer);
gpu_set_texture(slug_curve_tex_unit, img->curve_tex);
gpu_set_texture(slug_band_tex_unit, img->band_tex);
gpu_set_float4(slug_col_loc, cr, cg, cb, ca);
int l = 0;
int codepoint = string_utf8_decode(&text[i], &l);
i += l;
if (draw_font_get_baked_quad(draw_font, draw_font_size, &q, codepoint, xpos, ypos)) {
xpos += q.xadvance;
gpu_set_float4(text_pos_loc, (int)q.x0 / vw(), (int)q.y0 / vh(), (int)(q.x1 - q.x0) / vw(), (q.y1 - q.y0) / vh());
gpu_set_float4(text_tex_loc, q.s0, q.t0, q.s1 - q.s0, q.t1 - q.t0);
gpu_set_float4(text_col_loc, _draw_color_r(draw_color) / 255.0, _draw_color_g(draw_color) / 255.0, _draw_color_b(draw_color) / 255.0,
_draw_color_a(draw_color) / 255.0);
gpu_draw();
int char_index = draw_font_get_char_index_internal(codepoint);
if (char_index >= draw_font_glyphs->length) {
continue;
}
slug_glyph_t *g = &img->slug_glyphs[char_index];
xpos += g->xadvance;
if (g->glyph_w <= 0.0f || g->glyph_h <= 0.0f) {
continue;
}
float rx = (float)(int)(xpos - g->xadvance + g->xoff + 0.5f);
float ry = (float)(int)(ypos + g->yoff + 0.5f);
gpu_set_float4(slug_pos_loc, rx / vw(), ry / vh(), g->glyph_w / vw(), g->glyph_h / vh());
gpu_set_float4(slug_em_rect_loc, 0.0f, 0.0f, g->glyph_w, g->glyph_h);
gpu_set_int4(slug_glyph_loc_loc, g->band_tex_x, g->band_tex_y, 0, 0);
gpu_set_int4(slug_band_max_loc, SLUG_VBAND_COUNT - 1, SLUG_HBAND_COUNT - 1, 0, 0);
gpu_set_float4(slug_band_tf_loc, g->band_scale_x, g->band_scale_y, 0.0f, 0.0f);
gpu_draw();
}
}
@@ -560,43 +789,6 @@ void draw_font_destroy(draw_font_t *font) {
font->buf = NULL;
}
void draw_font_13(draw_font_t *font) {
if (draw_font_glyphs == NULL) {
draw_font_init_glyphs(32, 127);
}
font->blob = font->buf->buffer;
font->images = NULL;
font->m_images_len = 0;
font->m_capacity = 0;
font->offset = 0;
draw_prepare_font_load_internal(font, 13);
draw_font_image_t *img = &(font->images[font->m_images_len]);
font->m_images_len += 1;
img->m_size = 13;
img->baseline = 0; // 10
img->descent = 0;
img->line_gap = 0;
img->width = 128;
img->height = 128;
img->first_unused_y = 0;
img->tex = (gpu_texture_t *)malloc(sizeof(gpu_texture_t));
gpu_texture_init_from_bytes(img->tex, (void *)iron_font_13_pixels, 128, 128, GPU_TEXTURE_FORMAT_R8);
stbtt_bakedchar *baked = (stbtt_bakedchar *)malloc(95 * sizeof(stbtt_bakedchar));
for (int i = 0; i < 95; ++i) {
baked[i].x0 = iron_font_13_x0[i];
baked[i].x1 = iron_font_13_x1[i];
baked[i].y0 = iron_font_13_y0[i];
baked[i].y1 = iron_font_13_y1[i];
baked[i].xoff = iron_font_13_xoff[i];
baked[i].yoff = iron_font_13_yoff[i];
baked[i].xadvance = iron_font_13_xadvance[i];
}
img->chars = baked;
}
void draw_font_init_glyphs(int from, int to) {
gc_unroot(draw_font_glyphs);
gc_unroot(draw_font_glyph_blocks);
@@ -673,7 +865,7 @@ int draw_font_height(draw_font_t *font, int font_size) {
float draw_font_get_char_width_internal(draw_font_image_t *img, int char_index) {
int i = draw_font_get_char_index_internal(char_index);
return img->chars[i].xadvance;
return img->slug_glyphs[i].xadvance;
}
float draw_sub_string_width(draw_font_t *font, int font_size, const char *text, int start, int end) {
@@ -745,7 +937,7 @@ void draw_inner_line(float x1, float y1, float x2, float y2, float strength) {
else {
vec = vec2_create(1, -(x2 - x1) / (y2 - y1));
}
vec = vec2_set_len(vec, strength);
vec = vec2_set_len(vec, strength);
vec2_t p1 = {x1 + side * vec.x, y1 + side * vec.y};
vec2_t p2 = {x2 + side * vec.x, y2 + side * vec.y};
vec2_t p3 = vec2_sub(p1, vec);
+2 -2
View File
@@ -26,7 +26,8 @@ typedef struct draw_font {
} draw_font_t;
void draw_init(buffer_t *image_vert, buffer_t *image_frag, buffer_t *image_transform_vert, buffer_t *image_transform_frag, buffer_t *rect_vert,
buffer_t *rect_frag, buffer_t *tris_vert, buffer_t *tris_frag, buffer_t *text_vert, buffer_t *text_frag);
buffer_t *rect_frag, buffer_t *tris_vert, buffer_t *tris_frag, buffer_t *text_vert, buffer_t *text_frag,
buffer_t *slug_vert, buffer_t *slug_frag);
void draw_begin(gpu_texture_t *target, bool clear, unsigned color);
void draw_scaled_sub_image(gpu_texture_t *img, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh);
void draw_scaled_image(gpu_texture_t *tex, float dx, float dy, float dw, float dh);
@@ -46,7 +47,6 @@ void draw_set_transform(mat3_t matrix);
bool draw_set_font(draw_font_t *font, int size);
void draw_font_init(draw_font_t *font);
void draw_font_destroy(draw_font_t *font);
void draw_font_13(draw_font_t *font);
bool draw_font_has_glyph(int glyph);
void draw_font_add_glyph(int glyph);
void draw_font_init_glyphs(int from, int to);
+10 -1
View File
@@ -123,6 +123,8 @@ void sys_start(iron_window_options_t *ops) {
char path_tris_frag[512];
char path_text_vert[512];
char path_text_frag[512];
char path_slug_vert[512];
char path_slug_frag[512];
strcpy(path_image_vert, dp);
strcat(path_image_vert, "draw_image.vert");
@@ -154,10 +156,17 @@ void sys_start(iron_window_options_t *ops) {
strcpy(path_text_frag, dp);
strcat(path_text_frag, "draw_text.frag");
strcat(path_text_frag, ext);
strcpy(path_slug_vert, dp);
strcat(path_slug_vert, "draw_slug.vert");
strcat(path_slug_vert, ext);
strcpy(path_slug_frag, dp);
strcat(path_slug_frag, "draw_slug.frag");
strcat(path_slug_frag, ext);
draw_init(iron_load_blob(path_image_vert), iron_load_blob(path_image_frag), iron_load_blob(path_image_transform_vert),
iron_load_blob(path_image_transform_frag), iron_load_blob(path_rect_vert), iron_load_blob(path_rect_frag), iron_load_blob(path_tris_vert),
iron_load_blob(path_tris_frag), iron_load_blob(path_text_vert), iron_load_blob(path_text_frag));
iron_load_blob(path_tris_frag), iron_load_blob(path_text_vert), iron_load_blob(path_text_frag),
iron_load_blob(path_slug_vert), iron_load_blob(path_slug_frag));
_iron_set_update_callback(sys_render);
_iron_set_drop_files_callback(sys_drop_files_callback);
+1 -2
View File
@@ -1815,7 +1815,7 @@ void minic_register_builtins() {
minic_register_native("shape_draw_sphere", mn_shape_draw_sphere);
// iron_draw
R(draw_init, "v(p,p,p,p,p,p,p,p,p,p)");
R(draw_init, "v(p,p,p,p,p,p,p,p,p,p,p,p)");
R(draw_begin, "v(p,i,i)");
R(draw_scaled_sub_image, "v(p,f,f,f,f,f,f,f,f)");
R(draw_scaled_image, "v(p,f,f,f,f)");
@@ -1835,7 +1835,6 @@ void minic_register_builtins() {
R(draw_set_font, "i(p,i)");
R(draw_font_init, "v(p)");
R(draw_font_destroy, "v(p)");
R(draw_font_13, "v(p)");
R(draw_font_has_glyph, "i(i)");
R(draw_font_add_glyph, "v(i)");
R(draw_font_init_glyphs, "v(i,i)");
+1 -7
View File
@@ -65,13 +65,7 @@ void base_init() {
sys_title_set(tr("untitled"));
#endif
// Baked font for fast startup
if (string_equals(config_raw->locale, "en")) {
draw_font_13(base_font);
}
else {
draw_font_init(base_font);
}
draw_font_init(base_font);
ui_nodes_enum_texts = base_enum_texts;
gc_root(ui_nodes_enum_texts);