UNPKG

ome-zarr.js

Version:

Some JavaScript utils for simple rendering of OME-Zarr images

2,424 lines 230 kB
var V1 = Object.defineProperty; var H1 = (r, t, e) => t in r ? V1(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e; var w = (r, t, e) => H1(r, typeof t != "symbol" ? t + "" : t, e); import * as A from "zarrita"; import { slice as N } from "zarrita"; function B(r, t, e) { const { dst: a, blending: n = "additive" } = e ?? {}, [i, l] = r.shape, s = a ?? new Uint8ClampedArray(4 * i * l).fill(0), c = i * l * 4; let o = 0; for (let h = 0; h < c; h += 4) { const u = Number(r.data[o]); o += 1; const [g, p, v, M = 255] = t(u), d = s[h + 3] / 255, b = (M ?? 255) / 255; if (n === "additive") s[h] = Math.min(s[h] * d + g, 255), s[h + 1] = Math.min(s[h + 1] * d + p, 255), s[h + 2] = Math.min(s[h + 2] * d + v, 255), s[h + 3] = Math.min(d + b, 1) * 255; else if (n === "translucent") s[h] = g * b + s[h] * d * (1 - b), s[h + 1] = p * b + s[h + 1] * d * (1 - b), s[h + 2] = v * b + s[h + 2] * d * (1 - b), s[h + 3] = (b + d * (1 - b)) * 255; else throw new Error("Invalid blending mode"); } return s; } function O(r, t, e) { const a = t.length, { dst: n, blending: i = "additive" } = e ?? {}; let l; if (e != null && e.range) { const s = e.range; l = function(c) { const [o, h] = s; return c < o && (c = o), c > h && (c = h), c = Math.round((a - 1) * (c - o) / (h - o)), t[c]; }; } else l = function(s) { if (s <= 0) return t[0]; const c = (s - 1) % (a - 1) + 1; return t[c]; }; return B(r, l, { dst: n, blending: i }); } function L(r, t, e) { const { dst: a, blending: n = "additive", fillValue: i = [0, 0, 0, 0] } = e ?? {}; function l(s) { return t.get(s) ?? i; } return B(r, l, { dst: a, blending: n }); } async function P(r, t, e, a, n, i) { const { signal: l, calcMinMaxForRange: s } = i ?? {}; l == null || l.throwIfAborted(); let c = r.shape, o = (t == null ? void 0 : t.map((f) => f.name || f.toString())) || [ "t", "c", "z", "y", "x" ], h = o.indexOf("c"), u = c[h] || 1, g, p, v = [], M; if (e) { let f = 0; g = e.map((m) => (m.active == null && (m.active = !0), f += m.active ? 1 : 0, m.active && f <= I)), p = e.map((m) => U(m.color)), v = e.map( (m) => "lut" in m && m.lut ? m.lut : "colorMap" in m ? m.colorMap : void 0 ); } else g = D(u), p = q1(u, g); let d = g.reduce( (f, m, z) => (m && f.push(z), f), [] ); p = d.map((f) => p[f]), M = d.map( (f) => { var m; return !!((m = e == null ? void 0 : e[f]) != null && m.inverted); } ), v !== void 0 && (v = v.filter((f, m) => d.includes(m))); let E = r2( d, c, o, a ).map( (f) => A.get(r, f, { opts: { signal: l } }) ), x = await Promise.all(E); l == null || l.throwIfAborted(); let y = d.map( (f, m) => { var z, C; if (e && e[f]) { let _ = e[f]; if (((z = _ == null ? void 0 : _.window) == null ? void 0 : z.start) !== void 0 && ((C = _ == null ? void 0 : _.window) == null ? void 0 : C.end) !== void 0) return [_.window.start, _.window.end]; } if (s) return Q1(x[m]); } ), U1 = W1( x, y, p, v, M, n ); const D1 = x[0].shape[0], k1 = x[0].shape[1]; return { data: U1, width: k1, height: D1 }; } function W1(r, t, e, a, n, i = !1) { let l = e.map((o, h) => { let u = a != null && a.length ? a[h] : void 0; return u || (u = Array.from({ length: 256 }, (g, p) => [o[0] * p / 255, o[1] * p / 255, o[2] * p / 255, 255])), n && n[h] && Array.isArray(u) && (u = u.reverse()), u; }), s = performance.now(), c; if (l[0] instanceof Map) { let o = l[0], h = o.get(K1); c = L(r[0], o, { fillValue: h }); } else c = O(r[0], l[0], { range: t[0] }); for (let o = 1; o < r.length; o++) if (l[o] instanceof Map) { let h = l[o], u = h.get(1 / 0); c = L(r[o], h, { blending: "additive", dst: c, fillValue: u }); } else c = O(r[o], l[o], { blending: "additive", dst: c, range: t[o] }); if (performance.now() - s < 100 && i) { let o = 5; a2(c, o)[o - 1] < 1 && (c = e2(c, 2)); } return c; } function Y1(r, t) { return r + (r.endsWith("/") ? "" : "/") + "|zarr" + t + ":"; } function Z1(r) { return r.split("/").filter(Boolean).pop() || "Default"; } function $1(r, t, e, a, n) { var h; const i = {}; a.forEach((u, g) => { i[u.name] = { ...u, index: g }; }); let l = "4panel-alt"; if ("z" in i) { const u = i.z.index; n[u] === 1 && (l = "xy"); } else l = "xy"; const s = e === "segmentation" && (!i.c || n[(h = i.c) == null ? void 0 : h.index] === 1) ? "segmentation" : "auto", c = { layers: [ { name: Z1(r), source: Y1(r, t), type: s } ], layout: l }, o = JSON.stringify(c); return encodeURIComponent(o); } class R { constructor(t, e) { /** * This is the main Image class for the API. It handles both v0.4 and v0.5 formats, * and provides a consistent interface for accessing the multiscale datasets, * omero metadata, and zarr version. * * @minItems 1 */ w(this, "attrs"); w(this, "imgAttrs"); w(this, "store"); w(this, "multiscales"); w(this, "paths"); w(this, "scales"); w(this, "shapes"); w(this, "arrays", {}); w(this, "omero"); w(this, "axes"); w(this, "zarr_version"); w(this, "omezarr_version"); var a, n; this.store = e, "ome" in t ? (this.attrs = t, this.imgAttrs = JSON.parse(JSON.stringify(this.attrs.ome)), this.zarr_version = 3, this.omezarr_version = this.imgAttrs.version, this.axes = this.imgAttrs.multiscales[0].axes, !this.axes && ((n = (a = this.imgAttrs.multiscales[0].coordinateSystems) == null ? void 0 : a[0]) != null && n.axes) && (this.axes = this.imgAttrs.multiscales[0].coordinateSystems[0].axes)) : (this.attrs = t, this.imgAttrs = JSON.parse(JSON.stringify(this.attrs)), this.zarr_version = 2, this.omezarr_version = this.imgAttrs.multiscales[0].version || "0.4", this.axes = this.imgAttrs.multiscales[0].axes || ["t", "c", "z", "y", "x"].map((i) => ({ name: i }))), this.multiscales = this.imgAttrs.multiscales, this.omero = this.imgAttrs.omero, this.calcMinMaxForRange = !0, this.paths = this.multiscales[0].datasets.map((i) => i.path), this.scales = this.getScales(); } // static method to load an image from a zarr store or url static async load(t, e = {}) { const { signal: a } = e ?? {}; a == null || a.throwIfAborted(), typeof t == "string" && (t = new A.FetchStore(t)); let n; if (e.attrs) n = e.attrs; else { let s; t instanceof A.Group ? s = t : (s = await G(t, void 0, void 0, { signal: a }), a == null || a.throwIfAborted()), n = s.attrs; } const i = new this(n, t), l = e.datasetIndex ?? 0; return await i.openArray(l), i; } checkChannelIndex(t) { if (!this.omero) throw new Error("No Omero metadata found in image"); if (t < 0 || t >= this.omero.channels.length) throw new Error(`Invalid channel index: ${t} for image with ${this.omero.channels.length} channels`); return this.omero; } setChannelActive(t, e) { let a = this.checkChannelIndex(t); a.channels[t].active = e; } setChannelColor(t, e) { let a = this.checkChannelIndex(t); a.channels[t].color = e; } setChannelStart(t, e) { let a = this.checkChannelIndex(t); a.channels[t].window.start = e; } setChannelEnd(t, e) { let a = this.checkChannelIndex(t); a.channels[t].window.end = e; } setChannelInverted(t, e) { let a = this.checkChannelIndex(t); a.channels[t].inverted = e; } setChannelLut(t, e) { let a = this.checkChannelIndex(t); e == null ? delete a.channels[t].lut : a.channels[t].lut = e; } setChannelColorMap(t, e) { let a = this.checkChannelIndex(t); a.channels[t].colorMap = e; } setZIndex(t) { if (!this.omero) throw new Error("No Omero metadata found in image"); this.omero.rdefs.defaultZ = t; } setTIndex(t) { if (!this.omero) throw new Error("No Omero metadata found in image"); this.omero.rdefs.defaultT = t; } async getShape(t = 0) { return (await this.openArray(t)).shape; } getAxesNames() { return this.axes.map((t) => t.name || t.toString()); } getVersion() { return this.omezarr_version; } getZarrVersion() { return this.zarr_version; } async getLabelsPaths() { var e; let t = []; try { let a = await G(this.store, "labels", this.zarr_version); a && ((e = a.attrs) != null && e.labels) && (t = a.attrs.labels); } catch (a) { console.info("Failed to load labels group:", a); } return t; } async getNeuroglancerUrl() { const t = "https://neuroglancer-demo.appspot.com/#!"; let e = this.store.url || ""; if (!e) throw new Error("Cannot generate Neuroglancer URL: store does not have a URL"); let a = this.getZarrVersion(), n = this.imgAttrs["image-label"] ? "segmentation" : "auto", i = await this.getShape(); return t + $1(e.toString(), a, n, this.axes, i); } async openArray(t, e) { let a; if (typeof t == "number" ? (t < 0 && (t = this.paths.length + t), a = this.paths[t]) : a = t, this.arrays[a]) return this.arrays[a]; let n = await H(this.store, a, this.zarr_version, e); if (this.arrays[a] = n, !this.omero) { let i = await this.calcShapes(), l = (i == null ? void 0 : i[0]) || n.shape, s = this.axes.map((u) => u.name || u.toString()), c = l[s.findIndex((u) => u === "c")] || 1, o = l[s.findIndex((u) => u === "z")] || 1, h = l[s.findIndex((u) => u === "t")] || 1; if (this.omero = X1({ sizeC: c, sizeZ: o, sizeT: h }, n.dtype), s.includes("z")) { let u = l[s.findIndex((g) => g === "z")] || 1; this.omero.rdefs.defaultZ = Math.floor(u / 2); } } return n; } async calcShapes(t) { if (this.shapes !== void 0) return this.shapes; if (t === void 0) { for (let s = 0; s < this.paths.length; s++) if (this.arrays[this.paths[s]]) { t = s; break; } } t === void 0 && (t = 0); const a = (await this.openArray(t)).shape, n = this.scales, i = n[t], l = n.map((s) => a.map( (c, o) => Math.floor(c * i[o] / s[o]) )); return this.shapes = l, l; } // private method to get scales for each level, if they exist. Returns undefined if no scales are found. getScales() { const t = this.multiscales[0].datasets.map((e) => { let a; if (Array.isArray(e.coordinateTransformations)) { for (const n of e.coordinateTransformations) if ("scale" in n) { a = n.scale; break; } else if ("transformations" in n) { for (const i of n.transformations) if ("scale" in i) { a = i.scale; break; } } } return a; }).filter((e) => e !== void 0); if (t.length > 0 && t.length !== this.multiscales[0].datasets.length) throw new Error("Could not determine scales for all datasets"); return t; } async getPathForTargetSize(t, e) { let a = []; if (e == null) { e = 0; for (let l = 0; l < this.paths.length; l++) if (this.arrays[this.paths[l]]) { e = l; break; } } if (this.scales.length == 0) { let s = (await this.openArray(e)).shape, c = s.length, o = s[c - 1], h = s[c - 2], u = Math.max(o, h); a = this.paths.map( (g, p) => u * 2 ** (e - p) ); } else { let l = await this.calcShapes(), s = l[0].length; a = l.map( (c) => Math.max(c[s - 1], c[s - 2]) ); } let n; for (n = 0; n < a.length; n++) { let l = a[n], s = a[n + 1]; if (s) { if (s > t) continue; { let c = (l + s) / 2; t < c && (n += 1); break; } } else break; } return this.paths[n]; } async renderArray(t = {}) { var M, d, b, E, x; let e; if (t.arr) if (typeof t.arr == "string") { const y = new A.FetchStore(t.arr); e = await A.open(y, { kind: "array" }); } else e = t.arr; else { let y; if (t.arrayPathOrIndex !== void 0) y = t.arrayPathOrIndex; else if (t.targetSize !== void 0) y = await this.getPathForTargetSize(t.targetSize); else throw new Error("Need to specify arr OR targetSize OR arrayPathOrIndex "); e = await this.openArray(y); } let a = t.maxSize ?? 1e3, n = e.shape, i = n.length, l = n[i - 1], s = n[i - 2]; if (s * l > a * a && !t.slices) throw new Error( `Array size (${l} * ${s}) is larger than specified 'maxSize' of ${a} * ${a}` ); let c = t.slices || {}; c.z == null && (c.z = (d = (M = this.omero) == null ? void 0 : M.rdefs) == null ? void 0 : d.defaultZ); let o = this.getAxesNames().indexOf("z"); if (o != -1 && Number.isInteger(c.z)) { const y = await this.getShape(); y && y[o] != n[o] && (c.z = Math.floor(c.z * n[o] / y[o])); } c.t == null && (c.t = (E = (b = this.omero) == null ? void 0 : b.rdefs) == null ? void 0 : E.defaultT); let h = t.channels || ((x = this.omero) == null ? void 0 : x.channels), u = this.calcMinMaxForRange ?? !0; (t == null ? void 0 : t.calcMinMaxForRange) != null && (u = t.calcMinMaxForRange); let { data: g, width: p, height: v } = await P( e, this.axes, h, c, !!t.autoBoost, { signal: t.signal, calcMinMaxForRange: !!u } ); return { data: g, width: p, height: v }; } async render(t = {}) { let { data: e, width: a } = await this.renderArray(t); return W(e, a); } } class c2 extends R { constructor(t, e) { super(t, e), this.calcMinMaxForRange = !1; } static async load(t, e = {}) { let a = await super.load(t, e); if (a.omero && a.omero.channels) for (let n of a.omero.channels) console.log("BEFORE", n.window), n.window && (delete n.window.start, delete n.window.end); return a; } } const I = 3, S = { cyan: "#00FFFF", yellow: "#FFFF00", magenta: "#FF00FF", red: "#FF0000", green: "#00FF00", blue: "#0000FF", white: "#FFFFFF" }, J1 = [S.magenta, S.green], j1 = [S.red, S.green, S.blue], T = Object.values(S), K1 = 1 / 0; function U(r) { r.startsWith("#") && (r = r.slice(1)); const t = parseInt(r.slice(0, 2), 16), e = parseInt(r.slice(2, 4), 16), a = parseInt(r.slice(4, 6), 16); return [t, e, a]; } function D(r) { let t; return r <= I ? t = Array(r).fill(!0) : t = [ ...Array(I).fill(!0), ...Array(r - I).fill(!1) ], t; } function X1({ sizeC: r, sizeZ: t, sizeT: e }, a) { let n = D(r), i = k(r, n), l = t2(a), s = n.map((o, h) => ({ active: o, color: i[h], window: { min: l.min, max: l.max } })), c = { defaultT: e !== void 0 ? Math.floor(e / 2) : 0, defaultZ: t !== void 0 ? Math.floor(t / 2) : 0, model: "color" }; return { channels: s, rdefs: c }; } function k(r, t) { let e = []; if (r == 1) e = [S.white]; else if (r == 2) e = J1; else if (r === 3) e = j1; else if (r <= I) e = T.slice(0, r); else { e = Array(r).fill(S.white); const a = t.flatMap((n, i) => n ? i : []); for (const [n, i] of a.entries()) e[i] = T[n]; } return e = e.map((a) => (a.startsWith("#") && (a = a.slice(1)), a)), e; } function q1(r, t) { return k(r, t).map(U); } function Q1(r) { const t = r.data; let e = 0, a = 1 / 0, n = r.data.length; for (let i = 0; i < n; i++) { let l = Number(t[i]); e = Math.max(e, l), a = Math.min(a, l); } return [a, e]; } function t2(r) { let t = 0, e = 65535; if (r) if (r.includes("int") || r.includes("uint")) { const a = r.match(/\d+/); if (a) { const n = parseInt(a[0]); r.startsWith("u") ? (t = 0, e = 2 ** n - 1) : (t = -(2 ** (n - 1)), e = 2 ** (n - 1) - 1); } else { const n = r.match(/^[<>|]([iuf])(\d+)$/); if (n) { const i = n[1], s = parseInt(n[2], 10) * 8; i === "i" ? (t = -(2 ** (s - 1)), e = 2 ** (s - 1) - 1) : i === "u" && (t = 0, e = 2 ** s - 1); } else console.warn("Could not determine min/max values for dtype: ", r); } } else console.warn("Unrecognized dtype format: ", r); return { min: t, max: e }; } function e2(r, t) { for (let e = 0; e < r.length / 4; e++) for (let a = 0; a < 3; a++) { let n = r[e * 4 + a]; n = Math.min(255, n * t), r[e * 4 + a] = n; } return r; } function a2(r, t = 5) { let e = new Array(t).fill(0); const a = 256 / t; let n = r.length / 4; for (let i = 0; i < n; i++) { let l = r[i * 4]; l = Math.max(r[i * 4 + 1], l), l = Math.max(r[i * 4 + 2], l); let s = Math.floor(l / a); e[s] += 1; } return e = e.map((i) => 100 * i / n), e; } async function h2(r, t) { const e = await R.load(r, t); return { multiscale: e.multiscales[0], omero: e.omero, zarr_version: e.zarr_version }; } async function u2(r, t = 0, e) { const a = await R.load(r, e), n = a.multiscales[0], i = a.omero, l = a.zarr_version, s = a.scales, c = await a.openArray(t, e); let o = await a.calcShapes(); return o.length == 0 && (o = void 0), { arr: c, shapes: o, multiscale: n, omero: i, scales: s, zarr_version: l }; } async function V(r, t, e, a, n) { const { signal: i } = n ?? {}; i == null || i.throwIfAborted(); const l = a === 3 ? A.open.v3 : a === 2 ? A.open.v2 : A.open; let s; if (r instanceof A.Group) s = r; else { const o = typeof r == "string" ? new A.FetchStore(r) : r; s = A.root(o); } e && (s = s.resolve(e)); const c = await l(s, { kind: t }); return i == null || i.throwIfAborted(), c; } async function m2(r, t, e, a) { console.warn( "getArray is deprecated and will be removed in future versions. Please use openArray() instead." ); const { signal: n } = a ?? {}; return H(r, t, e, { signal: n }); } async function H(r, t, e, a) { const { signal: n } = a ?? {}; return n == null || n.throwIfAborted(), V(r, "array", t, e, { signal: n }); } async function G(r, t, e, a) { const { signal: n } = a ?? {}; return n == null || n.throwIfAborted(), V(r, "group", t, e, { signal: n }); } function r2(r, t, e, a) { return r.map((i) => t.map((s, c) => { let o = e[c]; if (o == "c") return i; if (o in a) { let h = a[o]; if (Array.isArray(h)) return N(h[0], h[1]); if (Number.isInteger(h)) return h !== void 0 ? h : void 0; } return o == "x" || o == "y" ? N(0, s) : o == "z" || o == "t" ? parseInt(s / 2 + "") : 0; })); } async function W(r, t) { let e = r.length / (t * 4); if (typeof document < "u") { const a = document.createElement("canvas"); a.width = t, a.height = e; const n = a.getContext("2d"); return n ? (n.putImageData(new ImageData(r, t, e), 0, 0), a.toDataURL("image/png")) : ""; } else { const { PNG: a } = await import("./png-K1gqQ34g.js").then((c) => c.p), { Buffer: n } = await import("./__vite-browser-external-YbutIfMq.js").then((c) => c._), i = new a({ width: t, height: e }); i.data = n.from( r.buffer, r.byteOffset, r.byteLength ); const l = [], s = i.pack(); return new Promise((c, o) => { s.on("data", (h) => l.push(h)), s.on("end", () => { c( `data:image/png;base64,${n.concat(l).toString("base64")}` ); }), s.on("error", o); }); } } function n2() { return F.map((r) => ({ name: r.name, png: Y(r.rgb) })); } function s2(r) { let t = F.find((e) => e.name === r); return (t == null ? void 0 : t.rgb) || F[0].rgb; } function Y(r) { let t = 1, e = 256, a = new Uint8ClampedArray(4 * t * e).fill(255), n = 0; for (let c = 0; c < t; c++) for (let o = 0; o < e; o++) { let h = r[o]; for (let u = 0; u < 3; u++) a[n * 4 + u] = h[u]; n += 1; } const i = document.createElement("canvas"); i.width = e, i.height = t; const l = i.getContext("2d"); return l ? (l.putImageData(new ImageData(a, e, t), 0, 0), i.toDataURL("image/png")) : ""; } const Z = [ [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [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, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 171], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [1, 1, 224], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [0, 110, 255], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 171, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 224, 254], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [1, 254, 1], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [190, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 224, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [255, 141, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [250, 94, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 0], [245, 0, 135], [245, 0, 141], [245, 0, 147], [245, 0, 153], [245, 0, 160], [245, 0, 166], [245, 0, 172], [245, 0, 178], [245, 0, 185], [245, 0, 191], [245, 0, 197], [245, 0, 203], [245, 0, 210], [245, 0, 216], [245, 0, 222], [245, 0, 228], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [222, 180, 222], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255] ], $ = [ [0, 0, 0], [0, 0, 64], [0, 0, 128], [0, 0, 192], [0, 32, 0], [0, 32, 64], [0, 32, 128], [0, 32, 192], [0, 64, 0], [0, 64, 64], [0, 64, 128], [0, 64, 192], [0, 96, 0], [0, 96, 64], [0, 96, 128], [0, 96, 192], [0, 128, 0], [0, 128, 64], [0, 128, 128], [0, 128, 192], [0, 160, 0], [0, 160, 64], [0, 160, 128], [0, 160, 192], [0, 192, 0], [0, 192, 64], [0, 192, 128], [0, 192, 192], [0, 224, 0], [0, 224, 64], [0, 224, 128], [0, 224, 192], [32, 0, 0], [32, 0, 64], [32, 0, 128], [32, 0, 192], [32, 32, 0], [32, 32, 64], [32, 32, 128], [32, 32, 192], [32, 64, 0], [32, 64, 64], [32, 64, 128], [32, 64, 192], [32, 96, 0], [32, 96, 64], [32, 96, 128], [32, 96, 192], [32, 128, 0], [32, 128, 64], [32, 128, 128], [32, 128, 192], [32, 160, 0], [32, 160, 64], [32, 160, 128], [32, 160, 192], [32, 192, 0], [32, 192, 64], [32, 192, 128], [32, 192, 192], [32, 224, 0], [32, 224, 64], [32, 224, 128], [32, 224, 192], [64, 0, 0], [64, 0, 64], [64, 0, 128], [64, 0, 192], [64, 32, 0], [64, 32, 64], [64, 32, 128], [64, 32, 192], [64, 64, 0], [64, 64, 64], [64, 64, 128], [64, 64, 192], [64, 96, 0], [64, 96, 64], [64, 96, 128], [64, 96, 192], [64, 128, 0], [64, 128, 64], [64, 128, 128], [64, 128, 192], [64, 160, 0], [64, 160, 64], [64, 160, 128], [64, 160, 192], [64, 192, 0], [64, 192, 64], [64, 192, 128], [64, 192, 192], [64, 224, 0], [64, 224, 64], [64, 224, 128], [64, 224, 192], [96, 0, 0], [96, 0, 64], [96, 0, 128], [96, 0, 192], [96, 32, 0], [96, 32, 64], [96, 32, 128], [96, 32, 192], [96, 64, 0], [96, 64, 64], [96, 64, 128], [96, 64, 192], [96, 96, 0], [96, 96, 64], [96, 96, 128], [96, 96, 192], [96, 128, 0], [96, 128, 64], [96, 128, 128], [96, 128, 192], [96, 160, 0], [96, 160, 64], [96, 160, 128], [96, 160, 192], [96, 192, 0], [96, 192, 64], [96, 192, 128], [96, 192, 192], [96, 224, 0], [96, 224, 64], [96, 224, 128], [96, 224, 192], [128, 0, 0], [128, 0, 64], [128, 0, 128], [128, 0, 192], [128, 32, 0], [128, 32, 64], [128, 32, 128], [128, 32, 192], [128, 64, 0], [128, 64, 64], [128, 64, 128], [128, 64, 192], [128, 96, 0], [128, 96, 64], [128, 96, 128], [128, 96, 192], [128, 128, 0], [128, 128, 64], [128, 128, 128], [128, 128, 192], [128, 160, 0], [128, 160, 64], [128, 160, 128], [128, 160, 192], [128, 192, 0], [128, 192, 64], [128, 192, 128], [128, 192, 192], [128, 224, 0], [128, 224, 64], [128, 224, 128], [128, 224, 192], [160, 0, 0], [160, 0, 64], [160, 0, 128], [160, 0, 192], [160, 32, 0], [160, 32, 64], [160, 32, 128], [160, 32, 192], [160, 64, 0], [160, 64, 64], [160, 64, 128], [160, 64, 192], [160, 96, 0], [160, 96, 64], [160, 96, 128], [160, 96, 192], [160, 128, 0], [160, 128, 64], [160, 128, 128], [160, 128, 192], [160, 160, 0], [160, 160, 64], [160, 160, 128], [160, 160, 192], [160, 192, 0], [160, 192, 64], [160, 192, 128], [160, 192, 192], [160, 224, 0], [160, 224, 64], [160, 224, 128], [160, 224, 192], [192, 0, 0], [192, 0, 64], [192, 0, 128], [192, 0, 192], [192, 32, 0], [192, 32, 64], [192, 32, 128], [192, 32, 192], [192, 64, 0], [192, 64, 64], [192, 64, 128], [192, 64, 192], [192, 96, 0], [192, 96, 64], [192, 96, 128], [192, 96, 192], [192, 128, 0], [192, 128, 64], [192, 128, 128], [192, 128, 192], [192, 160, 0], [192, 160, 64], [192, 160, 128], [192, 160, 192], [192, 192, 0], [192, 192, 64], [192, 192, 128], [192, 192, 192], [192, 224, 0], [192, 224, 64], [192, 224, 128], [192, 224, 192], [224, 0, 0], [224, 0, 64], [224, 0, 128], [224, 0, 192], [224, 32, 0], [224, 32, 64], [224, 32, 128], [224, 32, 192], [224, 64, 0], [224, 64, 64], [224, 64, 128], [224, 64, 192], [224, 96, 0], [224, 96, 64], [224, 96, 128], [224, 96, 192], [224, 128, 0], [224, 128, 64], [224, 128, 128], [224, 128, 192], [224, 160, 0], [224, 160, 64], [224, 160, 128], [224, 160, 192], [224, 192, 0], [224, 192, 64], [224, 192, 128], [224, 192, 192], [224, 224, 0], [224, 224, 64], [224, 224, 128], [224, 224, 192] ], J = [ [0, 0, 1], [0, 0, 5], [0, 0, 10], [0, 0, 15], [0, 0, 20], [0, 0, 25], [0, 0, 30], [0, 0, 35], [0, 0, 40], [0, 0, 45], [0, 0, 50], [0, 0, 55], [0, 0, 60], [0, 0, 65], [0, 0, 70], [0, 0, 75], [0, 0, 80], [0, 0, 85], [0, 0, 90], [0, 0, 95], [0, 0, 100], [0, 0, 105], [0, 0, 110], [0, 0, 115], [0, 0, 120], [0, 0, 125], [0, 0, 130], [0, 0, 135], [0, 0, 140], [0, 0, 145], [0, 0, 150], [0, 0, 155], [0, 0, 160], [0, 0, 165], [0, 0, 170], [0, 0, 175], [0, 0, 180], [0, 0, 185], [0, 0, 190], [0, 0, 195], [0, 0, 200], [0, 0, 205], [0, 0, 210], [0, 0, 215], [0, 0, 220], [0, 0, 225], [0, 0, 230], [0, 0, 235], [0, 0, 240], [0, 0, 245], [0, 0, 250], [0, 1, 0], [0, 5, 0], [0, 10, 0], [0, 15, 0], [0, 20, 0], [0, 25, 0], [0, 30, 0], [0, 35, 0], [0, 40, 0], [0, 45, 0], [0, 50, 0], [0, 55, 0], [0, 60, 0], [0, 65, 0], [0, 70, 0], [0, 75, 0], [0, 80, 0], [0, 85, 0], [0, 90, 0], [0, 95, 0], [0, 100, 0], [0, 105, 0], [0, 110, 0], [0, 115, 0], [0, 120, 0], [0, 125, 0], [0, 130, 0], [0, 135, 0], [0, 140, 0], [0, 145, 0], [0, 150, 0], [0, 155, 0], [0, 160, 0], [0, 165, 0], [0, 170, 0], [0, 175, 0], [0, 180, 0], [0, 185, 0], [0, 190, 0], [0, 195, 0], [0, 200, 0], [0, 205, 0], [0, 210, 0], [0, 215, 0], [0, 220, 0], [0, 225, 0], [0, 230, 0], [0, 235, 0], [0, 240, 0], [0, 245, 0], [0, 250, 0], [1, 1, 0], [5, 5, 0], [10, 10, 0], [15, 15, 0], [20, 20, 0], [25, 25, 0], [30, 30, 0], [35, 35, 0], [40, 40, 0], [45, 45, 0], [50, 50, 0], [55, 55, 0], [60, 60, 0], [65, 65, 0], [70, 70, 0], [75, 75, 0], [80, 80, 0], [85, 85, 0], [90, 90, 0], [95, 95, 0], [100, 100, 0], [105, 105, 0], [110, 110, 0], [115, 115, 0], [120, 120, 0], [125, 125, 0], [130, 130, 0], [135, 135, 0], [140, 140, 0], [145, 145, 0], [150, 150, 0], [155, 155, 0], [160, 160, 0], [165, 165, 0], [170, 170, 0], [175, 175, 0], [180, 180, 0], [185, 185, 0], [190, 190, 0], [195, 195, 0], [200, 200, 0], [205, 205, 0], [210, 210, 0], [215, 215, 0], [220, 220, 0], [225, 225, 0], [230, 230, 0], [235, 235, 0], [240, 240, 0], [245, 245, 0], [250, 250, 0], [1, 0, 0], [5, 0, 0], [10, 0, 0], [15, 0, 0], [20, 0, 0], [25, 0, 0], [30, 0, 0], [35, 0, 0], [40, 0, 0], [45, 0, 0], [50, 0, 0], [55, 0, 0], [60, 0, 0], [65, 0, 0], [70, 0, 0], [75, 0, 0], [80, 0, 0], [85, 0, 0], [90, 0, 0], [95, 0, 0], [100, 0, 0], [105, 0, 0], [110, 0, 0], [115, 0, 0], [120, 0, 0], [125, 0, 0], [130, 0, 0], [135, 0, 0], [140, 0, 0], [145, 0, 0], [150, 0, 0], [155, 0, 0], [160, 0, 0], [165, 0, 0], [170, 0, 0], [175, 0, 0], [180, 0, 0], [185, 0, 0], [190, 0, 0], [195, 0, 0], [200, 0, 0], [205, 0, 0], [210, 0, 0], [215, 0, 0], [220, 0, 0], [225, 0, 0], [230, 0, 0], [235, 0, 0], [240, 0, 0], [245, 0, 0], [250, 0, 0], [1, 1, 1], [5, 5, 5], [10, 10, 10], [15, 15, 15], [20, 20, 20], [25, 25, 25], [30, 30, 30], [35, 35, 35], [40, 40, 40], [45, 45, 45], [50, 50, 50], [55, 55, 55], [60, 60, 60], [65, 65, 65], [70, 70, 70], [75, 75, 75], [80, 80, 80], [85, 85, 85], [90, 90, 90], [95, 95, 95], [100, 100, 100], [105, 105, 105], [110, 110, 110], [115, 115, 115], [120, 120, 120], [125, 125, 125], [130, 130, 130], [135, 135, 135], [140, 140, 140], [145, 145, 145], [150, 150, 150], [155, 155, 155], [160, 160, 160], [165, 165, 165], [170, 170, 170], [175, 175, 175], [180, 180, 180], [185, 185, 185], [190, 190, 190], [195, 195, 195], [200, 200, 200], [205, 205, 205], [210, 210, 210], [215, 215, 215], [220, 220, 220], [225, 225, 225], [230, 230, 230], [235, 235, 235], [240, 240, 240], [245, 245, 245], [250, 250, 250], [255, 255, 255] ], j = [ [0, 0, 0], [3, 0, 0], [7, 0, 0], [11, 0, 0], [15, 0, 0], [19, 0, 0], [23, 0, 0], [27, 0, 0], [31, 0, 0], [35, 0, 0], [39, 0, 0], [43, 0, 0], [47, 0, 0], [51, 0, 0], [55, 0, 0], [59, 0, 0], [63, 0, 0], [67, 0, 0], [71, 0, 0], [75, 0, 0], [79, 0, 0], [83, 0, 0], [87, 0, 0], [91, 0, 0], [95, 0, 0], [99, 0, 0], [103, 0, 0], [107, 0, 0], [111, 0, 0], [115, 0, 0], [119, 0, 0], [123, 0, 0], [127, 0, 0], [131, 0, 0], [135, 0, 0], [139, 0, 0], [143, 0, 0], [147, 0, 0], [151, 0, 0], [155, 0, 0], [159, 0, 0], [163, 0, 0], [167, 0, 0], [171, 0, 0], [175, 0, 0], [179, 0, 0], [183, 0, 0], [187, 0, 0], [191, 0, 0], [195, 0, 0], [199, 0, 0], [203, 0, 0], [207, 0, 0], [211, 0, 0], [215, 0, 0], [219, 0, 0], [223, 0, 0], [227, 0, 0], [231, 0, 0], [235, 0, 0], [239, 0, 0], [243, 0, 0], [247, 0, 0], [251, 0, 0], [255, 0, 0], [247, 7, 0], [239, 15, 0], [231, 23, 0], [223, 31, 0], [215, 39, 0], [207, 47, 0], [199, 55, 0], [191, 63, 0], [183, 71, 0], [175, 79, 0], [167, 87, 0], [159, 95, 0], [151, 103, 0], [143, 111, 0], [135, 119, 0], [127, 127, 0], [119, 135, 0], [111, 143, 0], [103, 151, 0], [95, 159, 0], [87, 167, 0], [79, 175, 0], [71, 183, 0], [63, 191, 0], [55, 199, 0], [47, 207, 0], [39, 215, 0], [31, 223, 0], [23, 231, 0], [15, 239, 0], [7, 247, 0], [0, 255, 0], [0, 247, 7], [0, 239, 15], [0, 231, 23], [0, 223, 31], [0, 215, 39], [0, 207, 47], [0, 199, 55], [0, 191, 63], [0, 183, 71], [0, 175, 79], [0, 167, 87], [0, 159, 95], [0, 151, 103], [0, 143, 111], [0, 135, 119], [0, 127, 127], [0, 119, 135], [0, 111, 143], [0, 103, 151], [0, 95, 159], [0, 87, 167], [0, 79, 175], [0, 71, 183], [0, 63, 191], [0, 55, 199], [0, 47, 207], [0, 39, 215], [0, 31, 223], [0, 23, 231], [0, 15, 239], [0, 7, 247], [0, 0, 255], [0, 7, 255], [0, 15, 255], [0, 23, 255], [0, 31, 255], [0, 39, 255], [0, 47, 255], [0, 55, 255], [0, 63, 255], [0, 71, 255], [0, 79, 255], [0, 87, 255], [0, 95, 255], [0, 103, 255], [0, 111, 255], [0, 119, 255], [0, 127, 255], [0, 135, 255], [0, 143, 255], [0, 151, 255], [0, 159, 255], [0, 167, 255], [0, 175, 255], [0, 183, 255], [0, 191, 255], [0, 199, 255], [0, 207, 255], [0, 215, 255], [0, 223, 255], [0, 231, 255], [0, 239, 255], [0, 247, 255], [0, 255, 255], [7, 247, 255], [15, 239, 255], [23, 231, 255], [31, 223, 255], [39, 215, 255], [47, 207, 255], [55, 199, 255], [63, 191, 255], [71, 183, 255], [79, 175, 255], [87, 167, 255], [95, 159, 255], [103, 151, 255], [111, 143, 255], [119, 135, 255], [127, 127, 255], [135, 119, 255], [143, 111, 255], [151, 103, 255], [159, 95, 255], [167, 87, 255], [175, 79, 255], [183, 71, 255], [191, 63, 255], [199, 55, 255], [207, 47, 255], [215, 39, 255], [223, 31, 255], [231, 23, 255], [239, 15, 255], [247, 7, 255], [255, 0, 255], [255, 7, 247], [255, 15, 239], [255, 23, 231], [255, 31, 223], [255, 39, 215], [255, 47, 207], [255, 55, 199], [255, 63, 191], [255, 71, 183], [255, 79, 175], [255, 87, 167], [255, 95, 159], [255, 103, 151], [255, 111, 143], [255, 119, 135], [255, 127, 127], [255, 135, 119], [255, 143, 111], [255, 151, 103], [255, 159, 95], [255, 167, 87], [255, 175, 79], [255, 183, 71], [255, 191, 63], [255, 199, 55], [255, 207, 47], [255, 215, 39], [255, 223, 31], [255, 231, 23], [255, 239, 15], [255, 247, 7], [255, 255, 0], [255, 255, 7], [255, 255, 15], [255, 255, 23], [255, 255, 31], [255, 255, 39], [255, 255, 47], [255, 255, 55], [255, 255, 63], [255, 255, 71], [255, 255, 79], [255, 255, 87], [255, 255, 95], [255, 255, 103], [255, 255, 111], [255, 255, 119], [255, 255, 127], [255, 255, 135], [255, 255, 143], [255, 255, 151], [255, 255, 159], [255, 255, 167], [255, 255, 175], [255, 255, 183], [255, 255, 191], [255, 255, 199], [255, 255, 207], [255, 255, 215], [255, 255, 223], [255, 255, 231], [255, 255, 239], [255, 255, 247] ], K = [ [1, 2, 1], [1, 2, 1], [1, 3, 1], [1, 4, 1], [1, 5, 1], [1, 6, 1], [1, 7, 1], [1, 8, 1], [1, 9, 1], [1, 10, 1], [1, 11, 1], [1, 12, 1], [1, 13, 1], [1, 14, 1], [1, 15, 1], [1, 16, 1], [1, 17, 1], [1, 18, 1], [1, 19, 1], [1, 20, 1], [1, 21, 1], [1, 22, 1], [1, 23, 1], [1, 24, 1], [1, 25, 1], [1, 26, 1], [1, 27, 1], [1, 28, 1], [1, 29, 1], [1, 30, 1], [1, 31, 1], [1, 32, 1], [1, 33, 1], [1, 34, 1], [1, 35, 1], [1, 36, 1], [1, 37, 1], [1, 38, 1], [1, 39, 1], [1, 40, 1], [1, 41, 1], [1, 42, 1], [1, 43, 1], [1, 44, 1], [1, 45, 1], [1, 46, 1], [1, 47, 1], [1, 48, 1], [1, 49, 1], [1, 50, 1], [1, 51, 1], [1, 52, 1], [1, 53, 1], [1, 54, 1], [1, 55, 1], [1, 56, 1], [1, 57, 1], [1, 58, 1], [1, 59, 1], [1, 60, 1], [1, 61, 1], [1, 62, 1], [1, 63, 1], [1, 64, 1], [2, 64, 2], [4, 63, 4], [6, 62, 6], [8, 61, 8], [10, 60, 10], [12, 59, 12], [14, 58, 14], [16, 57, 16], [18, 56, 18], [20, 55, 20], [22, 54, 22], [24, 53, 24], [26, 52, 26], [28, 51, 28], [30, 50, 30], [32, 49, 32], [34, 48, 34], [36, 47, 36], [38, 46, 38], [40, 45, 40], [42, 44, 42], [44, 43, 44], [46, 42, 46], [48, 41, 48], [50, 40, 50], [52, 39, 52], [54, 38, 54], [56, 37, 56], [58, 36, 58], [60, 35, 60], [62, 34, 62], [64, 33, 64], [65, 32, 65], [67, 31, 67], [69, 30, 69], [71, 29, 71], [73, 28, 73], [75, 27, 75], [77, 26, 77], [79, 25, 79], [81, 24, 81], [83, 23, 83], [85, 22, 85], [87, 21, 87], [89, 20, 89], [91, 19, 91], [93, 18, 93], [95, 17, 95], [97, 16, 97], [99, 15, 99], [101, 14, 101], [103, 13, 103], [105, 12, 105], [107, 11, 107], [109, 10, 109], [111, 9, 111], [113, 8, 113], [115, 7, 115], [117, 6, 117], [119, 5, 119], [121, 4, 121], [123, 3, 123], [125, 2, 125], [127, 1, 127], [129, 1, 125], [131, 3, 123], [133, 5, 121], [135, 7, 119], [137, 9, 117], [139, 11, 115], [141, 13, 113], [143, 15, 111], [145, 17, 109], [147, 19, 107], [149, 21, 105], [151, 23, 103], [153, 25, 101], [155, 27, 99], [157, 29, 97], [159, 31, 95], [161, 33, 93], [163, 35, 91], [165, 37, 89], [167, 39, 87], [169, 41, 85], [171, 43, 83], [173, 45, 81], [175, 47, 79], [177, 49, 77], [179, 51, 75], [181, 53, 73], [183, 55, 71], [185, 57, 69], [187, 59, 67], [189, 61, 65], [191, 63, 64], [192, 64, 62], [194, 66, 60], [196, 68, 58], [198, 70, 56], [200, 72, 54], [202, 74, 52], [204, 76, 50], [206, 78, 48], [208, 80, 46], [210, 82, 44], [212, 84, 42], [214, 86, 40], [216, 88, 38], [218, 90, 36], [220, 92, 34], [222, 94, 32], [224, 96, 30], [226, 98, 28], [228, 100, 26], [230, 102, 24], [232, 104, 22], [234, 106, 20], [236, 108, 18], [238, 110, 16], [240, 112, 14], [242, 114, 12], [244, 116, 10], [246, 118, 8], [248, 120, 6], [250, 122, 4], [252, 124, 2], [254, 126, 1], [254, 128, 4], [254, 130, 8], [254, 132, 12], [254, 134, 16], [254, 136, 20], [254, 138, 24], [254, 140, 28], [254, 142, 32], [254, 144, 36], [254, 146, 40], [254, 148, 44], [254, 150, 48], [254, 152, 52], [254, 154, 56], [254, 156, 60], [254, 158, 64], [254, 160, 67], [254, 162, 71], [254, 164, 75], [254, 166, 79], [254, 168, 83], [254, 170, 87], [254, 172, 91], [254, 174, 95], [254, 176, 99], [254, 178, 103], [254, 180, 107], [254, 182, 111], [254, 184, 115], [254, 186, 119], [254, 188, 123], [254, 190, 127], [254, 191, 131], [254, 193, 135], [254, 195, 139], [254, 197, 143], [254, 199, 147], [254, 201, 151], [254, 203, 155], [254, 205, 159], [254, 207, 163], [254, 209, 167], [254, 211, 171], [254, 213, 175], [254, 215, 179], [254, 217, 183], [254, 219, 187], [254, 221, 191], [254, 223, 194], [254, 225, 198], [254, 227, 202], [254, 229, 206], [254, 231, 210], [254, 233, 214], [254, 235, 218], [254, 237, 222], [254, 239, 226], [254, 241, 230], [254, 243, 234], [254, 245, 238], [254, 247, 242], [254, 249, 246], [254, 251, 250], [254, 251, 250] ], X = [ [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [255, 0, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 255, 0], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [0, 255, 255], [248, 0, 255], [248, 0, 255], [248, 0, 255], [248, 0, 255], [248, 0, 255], [249, 0, 255], [249, 0, 255], [249, 0, 255], [249, 0, 255], [249, 0, 255], [250, 0, 255], [250, 0, 255], [250, 0, 255], [250, 0, 255], [251, 0, 255], [251, 0, 255], [251, 0, 255], [251, 0, 255], [251, 0, 255], [252, 0, 255], [252, 0, 255], [252, 0, 255], [252, 0, 255], [253, 0, 255], [253, 0, 255], [253, 0, 255], [253, 0, 255], [253, 0, 255], [254, 0, 255], [254, 0, 255], [254, 0, 255], [254, 0, 255], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 0], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255], [255, 255, 255] ], q = [ [0, 32, 76], [0, 32, 78], [0, 33, 80], [0, 34, 81], [0, 35, 83], [0, 35, 85], [0, 36, 86], [0, 37, 88], [0, 38, 90], [0, 38, 91], [0, 39, 93], [0, 40, 95], [0, 40, 97], [0, 41, 99], [0, 42, 100], [0, 42, 102], [0, 43, 104], [0, 44, 106], [0, 45, 108], [0, 45, 109], [0, 46, 110], [0, 46, 111], [0, 47, 111], [0, 47, 111], [0, 48, 111], [0, 49, 111], [0, 49, 111], [0, 50, 110], [0, 51, 110], [0, 52, 110], [0, 52, 110], [1, 53, 110], [6, 54, 110], [10, 55, 109], [14, 55, 109], [18, 56, 109], [21, 57, 109], [23, 57, 109], [26, 58, 108], [28, 59, 108], [30, 60, 108], [32, 60, 108], [34, 61, 108], [36, 62, 108], [38, 62, 108], [39, 63, 108], [41, 64, 107], [43, 65, 107], [44, 65, 107], [46, 66, 107], [47, 67, 107], [49, 68, 107], [50, 68, 107], [51, 69, 107], [53, 70, 107], [54, 70, 107], [55, 71, 107], [56, 72, 107], [58, 73, 107], [59, 73, 107], [60, 74, 107], [61, 75, 107], [62, 75, 107], [64, 76, 107], [65, 77, 107], [66, 78, 107], [67, 78, 107], [68, 79, 107], [69, 80, 107], [70, 80, 107], [71, 81, 107], [72, 82, 107], [73, 83, 107], [74, 83, 107], [75, 84, 107], [76, 85, 107], [77, 85, 107], [78, 86, 107], [79, 87, 108], [80, 88, 108], [81, 88, 108], [82, 89, 108], [83, 90, 108], [84, 90, 108], [85, 91, 108], [86, 92, 108], [87, 93, 109], [88, 93, 109], [89, 94, 109], [90, 95, 109], [91, 95, 109], [92, 96, 109], [93, 97, 110], [94, 98, 110], [95, 98, 110], [95, 99, 110], [96, 100, 110], [97, 101, 111], [98, 101, 111], [99, 102, 111], [100, 103, 111], [101, 103, 111], [102, 104, 112], [103, 105, 112], [104, 106, 112], [104, 106, 112], [105, 107, 113], [106, 108, 113], [107, 109, 113], [108, 109, 114], [109, 110, 114], [110, 111, 114], [111, 111, 114], [111, 112, 115], [112, 113, 115], [113, 114, 115], [114, 114, 116], [115, 115, 116], [116, 116, 117], [117, 117, 117], [117, 117, 117], [118, 118, 118], [119, 119, 118], [120, 120, 118], [121, 120, 119], [122, 121, 119], [123, 122, 119], [123, 123, 120], [124, 123, 120], [125, 124, 120], [126, 125, 120], [127, 126, 120], [128, 126, 120], [129, 127, 120], [130, 128, 120], [131, 129, 120], [132, 129, 120], [133, 130, 120], [134, 131, 120], [135, 132, 120], [136, 133, 120], [137, 133, 120], [138, 134, 120], [139, 135, 120], [140, 136, 120], [141, 136, 120], [142, 137, 120], [143, 138, 120], [144, 139, 120], [145, 140, 120], [146, 140, 120], [147, 141, 120], [148, 142, 120], [149, 143, 120], [150, 143, 119], [151, 144, 119], [152, 145, 119], [153, 146, 119], [154, 147, 119], [155, 147, 119], [156, 148, 119], [157, 149, 119], [158, 150, 118], [159, 151, 118], [160, 152, 118], [161, 152, 118], [162, 153, 118], [163, 154, 117], [164, 155, 117], [165, 156, 117], [166, 156, 117], [167, 157, 117], [168, 158, 116], [169, 159, 116], [170, 160, 116], [171, 161, 116], [172, 161, 115], [173, 162, 115], [174, 163, 115], [175, 164, 115], [176, 165, 114], [177, 166, 114], [178, 166, 114], [180, 167, 113], [181, 168, 113], [182, 169, 113], [183, 170, 112], [184, 171, 112], [185, 171, 112], [186, 172, 111], [187, 173, 111], [188, 174, 110], [189, 175, 110], [190, 176, 110], [191, 177, 109], [192, 177, 109], [193, 178, 108], [194, 179, 108], [195, 180, 108], [197, 181, 107], [198, 182, 107], [199, 183, 106], [200, 184, 106], [201, 184, 105], [202, 185, 105], [203, 186, 104], [204, 187, 104], [205, 188, 103], [206, 189, 103], [208, 190, 102], [209, 191, 102], [210, 192, 101], [211, 192, 101], [212, 193, 100], [213, 194, 99], [214, 195, 99], [215, 196, 98], [216, 197, 97], [217, 198, 97], [219, 199, 96], [220, 200, 96], [221, 201, 95], [222, 202, 94], [223, 203, 93], [224, 203, 93], [225, 204, 92], [227, 205, 91], [228, 206, 91], [229, 207, 90], [230, 208, 89], [231, 209, 88], [232, 210, 87], [233, 211, 86], [235, 212, 86], [236, 213, 85], [237, 214, 84], [238, 215, 83], [239, 216, 82], [240, 217, 81], [241, 218, 80], [243, 219, 79], [244, 220, 78], [245, 221, 77], [246, 222, 76], [247, 223, 75], [249, 224, 73], [250, 224, 72], [251, 225, 71], [252, 226, 70], [253, 227, 69], [255, 228, 67], [255, 229, 66], [255, 230,