ome-zarr.js
Version:
Some JavaScript utils for simple rendering of OME-Zarr images
2,424 lines • 230 kB
JavaScript
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,