diff --git a/assets/bravura.woff2.b64 b/assets/bravura.woff2.b64 new file mode 100644 index 0000000..bc83293 --- /dev/null +++ b/assets/bravura.woff2.b64 @@ -0,0 +1 @@ +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 diff --git a/info-pm_e-2.html b/info-pm_e-2.html new file mode 100644 index 0000000..4f79260 --- /dev/null +++ b/info-pm_e-2.html @@ -0,0 +1,74 @@ + + + + + +VARASYS PM_E‑2 PolyMeter Editor (Notation) — what it is + + + + + + + +/*@BUILD:include:src/header.html@*/ + +
+
+

PM_E‑2 PolyMeter Editor — Notation

+

The second-generation editor, built around proper engraved drum notation. Design a groove and read it as a real percussion staff — the same program string still plays identically on every form factor.

+
+ + /*@BUILD:include:src/infoembed.html@*/ + +
+

What it is

+
Web appEngraved notationRuns in any browser
+

Where the first-generation PM_E‑1 editor is built around a step-pad grid, + PM_E‑2 is built around notation. Grooves render on a 5-line percussion staff engraved with the + Bravura music font (the open SMuFL + standard used by professional scoring apps): real noteheads (X for cymbals, filled for drums), stems up for + hands and down for feet, group-aware beaming, accents, ghost notes in parentheses, and the full + ornament vocabulary — flams, drags and rolls. You can edit directly on the staff: click a step to + cycle its dynamic, Shift-click to cycle its ornament.

+

Three views share one engine: the Staff, a TUBS grid (Time Unit Box System — the clearest way to + read odd meters, polyrhythms and West-African bell patterns at a glance), and a Konnakol syllable view + (South-Indian solkattu — “ta ka di mi”) for spoken rhythm. Clave patterns are detected and labelled + (2-3 / 3-2). It's zero-install, runs in any modern browser, and works fully offline.

+

Everything you design saves to the same compact program string in the shared share-language, so a groove + built here loads into the original editor, the hardware concepts, or an embedded widget and plays back identically + everywhere.

+
+ +

Embed the editor (or any device) elsewhere with one <div> + a script — + see the embed docs.

+
+ +/*@BUILD:include:src/footer.html@*/ + + + + diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 0000000..60bb37b --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1,5 @@ +# Workspace build artifacts (the virtual workspace shares one target/ dir at rust/). +target/ +Cargo.lock +# notesim/uisim write PNGs into the CWD when run via the container's default workdir. +*.png diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 0000000..49f4f27 --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,15 @@ +[workspace] +resolver = "2" +members = [ + "track-format", + "pm-ui", + "uisim", + "glyphgen", +] +# pm-kit is the embedded firmware (thumbv8m, no_std + its own profile/build); it is built on its +# own via `cargo build --manifest-path pm-kit/Cargo.toml` (the firmware target), so it is kept OUT +# of this host workspace to avoid pulling its cortex-m deps into host `cargo build`/`cargo test`. +exclude = ["pm-kit"] + +# Profiles live at the workspace root (member profiles are ignored in a workspace). The firmware's +# size/LTO profile stays in pm-kit/Cargo.toml since pm-kit is excluded. diff --git a/rust/assets/bravura/Bravura.otf b/rust/assets/bravura/Bravura.otf new file mode 100644 index 0000000..afa95d6 Binary files /dev/null and b/rust/assets/bravura/Bravura.otf differ diff --git a/rust/assets/bravura/OFL.txt b/rust/assets/bravura/OFL.txt new file mode 100644 index 0000000..cfe591f --- /dev/null +++ b/rust/assets/bravura/OFL.txt @@ -0,0 +1,94 @@ +Copyright © 2015, Steinberg Media Technologies GmbH (http://www.steinberg.net/), +with Reserved Font Name "Bravura". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/rust/glyphgen/.gitignore b/rust/glyphgen/.gitignore new file mode 100644 index 0000000..2c96eb1 --- /dev/null +++ b/rust/glyphgen/.gitignore @@ -0,0 +1,2 @@ +target/ +Cargo.lock diff --git a/rust/glyphgen/Cargo.toml b/rust/glyphgen/Cargo.toml new file mode 100644 index 0000000..73d7299 --- /dev/null +++ b/rust/glyphgen/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "glyphgen" +version = "0.1.0" +edition = "2021" +description = "Host tool: rasterize the frozen Bravura SMuFL subset into a 4-bit-alpha atlas and emit pm-ui/src/notation/glyphs.rs (committed, generated, no_std const data)." + +[dependencies] +fontdue = "0.9" diff --git a/rust/glyphgen/src/main.rs b/rust/glyphgen/src/main.rs new file mode 100644 index 0000000..e10a95b --- /dev/null +++ b/rust/glyphgen/src/main.rs @@ -0,0 +1,254 @@ +//! Glyph atlas generator (host, std). +//! +//! Rasterizes the SAME frozen Bravura SMuFL subset the web uses (see `tools/bravura/subset.py`'s +//! GLYPHS list, 39 names) with the pure-Rust `fontdue` rasterizer, packs the coverage into a +//! row-major 4-bit-alpha atlas, and emits the COMMITTED, generated, `no_std`-compatible +//! `rust/pm-ui/src/notation/glyphs.rs` (a `Glyph` enum + a `GlyphMeta` metrics table + the atlas +//! bytes). Run after the subset changes: +//! +//! cargo run --manifest-path rust/glyphgen/Cargo.toml +//! +//! Device staff geometry: 1 SMuFL em = 4 staff spaces. We pick STAFF_SPACE = 10 px → EM = 40 px, +//! which fits the ST7796 320×480 staff (5 lines × 10 px = 40 px tall) and matches the web's S≈11. + +use std::fmt::Write as _; +use std::path::PathBuf; + +const STAFF_SPACE: f32 = 10.0; +const EM: f32 = 4.0 * STAFF_SPACE; // 40 px — SMuFL: 1 em = 4 staff spaces + +/// (enum variant identifier, SMuFL glyph name) — order defines the `Glyph` enum + table index. +/// Keep in lockstep with `src/notation.js` GLYPH map and `tools/bravura/subset.py` GLYPHS. +const GLYPHS: &[(&str, char)] = &[ + // clef + ("Clef", '\u{E069}'), // unpitchedPercussionClef1 + // noteheads + ("NoteheadBlack", '\u{E0A4}'), + ("NoteheadX", '\u{E0A9}'), // noteheadXBlack + ("NoteheadCircleX", '\u{E0B3}'), // noteheadCircleX + ("ParenL", '\u{E0F5}'), // noteheadParenthesisLeft + ("ParenR", '\u{E0F6}'), // noteheadParenthesisRight + ("NoteheadHalf", '\u{E0A3}'), + ("NoteheadWhole", '\u{E0A2}'), + // flags + ("Flag8Up", '\u{E240}'), + ("Flag8Down", '\u{E241}'), + ("Flag16Up", '\u{E242}'), + ("Flag16Down", '\u{E243}'), + // rests + ("RestWhole", '\u{E4E3}'), + ("RestHalf", '\u{E4E4}'), + ("RestQuarter", '\u{E4E5}'), + ("Rest8", '\u{E4E6}'), + ("Rest16", '\u{E4E7}'), + // articulations + dot + ("AccentAbove", '\u{E4A0}'), // articAccentAbove + ("AccentBelow", '\u{E4A1}'), // articAccentBelow + ("Dot", '\u{E1E7}'), // augmentationDot + // time signature digits + ("Sig0", '\u{E080}'), + ("Sig1", '\u{E081}'), + ("Sig2", '\u{E082}'), + ("Sig3", '\u{E083}'), + ("Sig4", '\u{E084}'), + ("Sig5", '\u{E085}'), + ("Sig6", '\u{E086}'), + ("Sig7", '\u{E087}'), + ("Sig8", '\u{E088}'), + ("Sig9", '\u{E089}'), + ("SigPlus", '\u{E08C}'), + ("SigCommon", '\u{E08A}'), + ("SigCut", '\u{E08B}'), + // ornaments + ("GraceAcc", '\u{E560}'), // graceNoteAcciaccaturaStemUp + ("GraceSlash", '\u{E564}'), // graceNoteSlashStemUp + ("Trem1", '\u{E220}'), + ("Trem2", '\u{E221}'), + ("Trem3", '\u{E222}'), + ("BuzzRoll", '\u{E22A}'), +]; + +struct Packed { + ident: &'static str, + atlas_x: u16, + atlas_y: u16, + w: u16, + h: u16, + bearing_x: i16, // left edge of bitmap relative to the glyph origin (xmin) + bearing_y: i16, // top edge of bitmap above the baseline (ymin + height) + advance: i16, // horizontal advance (rounded) +} + +fn main() { + let here = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let root = here.parent().unwrap().parent().unwrap(); // repo root + // prefer the vendored copy under rust/assets, fall back to tools/ + let font_path = { + let a = here.parent().unwrap().join("assets/bravura/Bravura.otf"); + if a.exists() { + a + } else { + root.join("tools/bravura/Bravura.otf") + } + }; + let font_bytes = std::fs::read(&font_path).expect("read Bravura.otf"); + let font = fontdue::Font::from_bytes(font_bytes, fontdue::FontSettings::default()).expect("parse font"); + + // rasterize each glyph + struct Raster { + ident: &'static str, + metrics: fontdue::Metrics, + bitmap: Vec, + } + let mut rasters: Vec = Vec::new(); + for &(ident, ch) in GLYPHS { + let (metrics, bitmap) = font.rasterize(ch, EM); + rasters.push(Raster { ident, metrics, bitmap }); + } + + // ---- pack into a simple shelf/grid atlas, ATLAS_W wide, 1px padding between cells ---- + const ATLAS_W: u16 = 256; + const PAD: u16 = 1; + let mut packed: Vec = Vec::new(); + let mut atlas_h: u16 = 0; + let mut cx: u16 = PAD; + let mut cy: u16 = PAD; + let mut shelf_h: u16 = 0; + // pre-compute placements + let mut placements: Vec<(u16, u16)> = Vec::with_capacity(rasters.len()); + for r in &rasters { + let w = r.metrics.width as u16; + let h = r.metrics.height as u16; + if cx + w + PAD > ATLAS_W { + cx = PAD; + cy += shelf_h + PAD; + shelf_h = 0; + } + placements.push((cx, cy)); + cx += w + PAD; + if h > shelf_h { + shelf_h = h; + } + let bottom = cy + h + PAD; + if bottom > atlas_h { + atlas_h = bottom; + } + } + + // 8-bit coverage atlas, then we 4-bit pack it row by row at emit time. + let mut cov = vec![0u8; ATLAS_W as usize * atlas_h as usize]; + for (r, &(px, py)) in rasters.iter().zip(placements.iter()) { + let w = r.metrics.width; + let h = r.metrics.height; + for row in 0..h { + for col in 0..w { + let a = r.bitmap[row * w + col]; + let ax = px as usize + col; + let ay = py as usize + row; + cov[ay * ATLAS_W as usize + ax] = a; + } + } + packed.push(Packed { + ident: r.ident, + atlas_x: px, + atlas_y: py, + w: w as u16, + h: h as u16, + bearing_x: r.metrics.xmin as i16, + bearing_y: (r.metrics.ymin + h as i32) as i16, + advance: r.metrics.advance_width.round() as i16, + }); + } + + // 4-bit pack: two pixels per byte, row-major, ATLAS_W pixels per row → ATLAS_W/2 bytes per row + // (ATLAS_W is even). High nibble = even column, low nibble = odd column. Coverage 0..255 → 0..15. + let row_bytes = ATLAS_W as usize / 2; + let mut atlas = vec![0u8; row_bytes * atlas_h as usize]; + for y in 0..atlas_h as usize { + for x in 0..ATLAS_W as usize { + let a4 = (cov[y * ATLAS_W as usize + x] as u16 * 15 / 255) as u8; + let bi = y * row_bytes + x / 2; + if x & 1 == 0 { + atlas[bi] |= a4 << 4; + } else { + atlas[bi] |= a4; + } + } + } + + // ---- emit glyphs.rs ---- + let mut out = String::new(); + out.push_str("//! GENERATED by `rust/glyphgen` — do not edit by hand. Re-run:\n"); + out.push_str("//! cargo run --manifest-path rust/glyphgen/Cargo.toml\n"); + out.push_str("//!\n"); + out.push_str("//! A 4-bit-alpha atlas of the frozen Bravura SMuFL subset (39 glyphs, the SAME set the web\n"); + out.push_str("//! froze in tools/bravura/subset.py) rasterized at em = 4 x staff_space. `no_std` const data.\n"); + out.push_str("#![allow(dead_code)]\n\n"); + let _ = writeln!(out, "/// Staff space the atlas was rasterized for (px). 1 SMuFL em = 4 staff spaces."); + let _ = writeln!(out, "pub const STAFF_SPACE: i32 = {};", STAFF_SPACE as i32); + let _ = writeln!(out, "pub const EM: i32 = {};", EM as i32); + let _ = writeln!(out, "/// Atlas dimensions in pixels (4-bit alpha, row-packed: 2 px per byte)."); + let _ = writeln!(out, "pub const ATLAS_W: usize = {};", ATLAS_W); + let _ = writeln!(out, "pub const ATLAS_H: usize = {};", atlas_h); + out.push('\n'); + + // GlyphMeta struct + out.push_str("/// Per-glyph atlas placement + placement metrics (all in px).\n"); + out.push_str("#[derive(Clone, Copy)]\n"); + out.push_str("pub struct GlyphMeta {\n"); + out.push_str(" pub atlas_x: u16,\n pub atlas_y: u16,\n pub w: u16,\n pub h: u16,\n"); + out.push_str(" /// left edge of the bitmap relative to the glyph origin (pen x)\n pub bearing_x: i16,\n"); + out.push_str(" /// top edge of the bitmap ABOVE the baseline (positive = up)\n pub bearing_y: i16,\n"); + out.push_str(" /// horizontal advance\n pub advance: i16,\n"); + out.push_str("}\n\n"); + + // Glyph enum + out.push_str("/// One frozen SMuFL glyph. `as usize` indexes `GLYPHS`.\n"); + out.push_str("#[derive(Clone, Copy, PartialEq, Eq)]\n"); + out.push_str("pub enum Glyph {\n"); + for p in &packed { + let _ = writeln!(out, " {},", p.ident); + } + out.push_str("}\n\n"); + + // metrics table + let _ = writeln!(out, "pub const GLYPHS: [GlyphMeta; {}] = [", packed.len()); + for p in &packed { + let _ = writeln!( + out, + " GlyphMeta {{ atlas_x: {}, atlas_y: {}, w: {}, h: {}, bearing_x: {}, bearing_y: {}, advance: {} }}, // {}", + p.atlas_x, p.atlas_y, p.w, p.h, p.bearing_x, p.bearing_y, p.advance, p.ident + ); + } + out.push_str("];\n\n"); + + // atlas bytes + let _ = writeln!(out, "/// Row-packed 4-bit alpha. byte = (even_col << 4) | odd_col; coverage 0..15."); + let _ = writeln!(out, "pub const ATLAS: &[u8] = &["); + for (i, b) in atlas.iter().enumerate() { + if i % 16 == 0 { + out.push_str(" "); + } + let _ = write!(out, "0x{:02x},", b); + if i % 16 == 15 { + out.push('\n'); + } else { + out.push(' '); + } + } + if atlas.len() % 16 != 0 { + out.push('\n'); + } + out.push_str("];\n"); + + let dest = here.parent().unwrap().join("pm-ui/src/notation/glyphs.rs"); + std::fs::write(&dest, out).expect("write glyphs.rs"); + println!( + "wrote {} ({} glyphs, atlas {}x{} = {} bytes 4-bit)", + dest.display(), + packed.len(), + ATLAS_W, + atlas_h, + atlas.len() + ); +} diff --git a/rust/pm-ui/src/notation/atlas.rs b/rust/pm-ui/src/notation/atlas.rs new file mode 100644 index 0000000..57ee128 --- /dev/null +++ b/rust/pm-ui/src/notation/atlas.rs @@ -0,0 +1,64 @@ +//! Device glyph blitter — the firmware equivalent of the web `drawGlyph`. +//! +//! The web draws Bravura as a font; the device blits the SAME glyphs from a pre-rasterized 4-bit +//! alpha atlas (`glyphs.rs`, generated by `rust/glyphgen`). Each glyph's coverage is alpha-blended +//! over a KNOWN solid background (the notation panel is a flat fill, and a write-only DrawTarget +//! can't read back), so blends are computed against `BG`. + +use embedded_graphics::{pixelcolor::Rgb565, prelude::*}; + +use super::glyphs::{Glyph, ATLAS, ATLAS_W, GLYPHS}; + +/// Alpha-blend `fg` over `bg` by 4-bit coverage `a` (0..15). +#[inline] +fn blend(fg: Rgb565, bg: Rgb565, a: u8) -> Rgb565 { + let a = a as u32; + let mix = |f: u8, b: u8, max: u32| -> u8 { + ((f as u32 * a + b as u32 * (15 - a)) / 15).min(max) as u8 + }; + Rgb565::new(mix(fg.r(), bg.r(), 31), mix(fg.g(), bg.g(), 63), mix(fg.b(), bg.b(), 31)) +} + +/// Draw a glyph so its SMuFL origin (pen point = on the reference staff line, the baseline) lands at +/// `origin`. `ink` is blended over `bg`. Fully-transparent pixels are skipped (so glyphs overlap +/// cleanly); partial coverage is blended against `bg` — keep `bg` equal to the panel fill behind it. +pub fn draw_glyph(d: &mut D, glyph: Glyph, origin: Point, ink: Rgb565, bg: Rgb565) -> Result<(), D::Error> +where + D: DrawTarget, +{ + let m = GLYPHS[glyph as usize]; + // top-left of the bitmap in screen space: pen x + bearing_x ; baseline y - bearing_y (up) + let ox = origin.x + m.bearing_x as i32; + let oy = origin.y - m.bearing_y as i32; + let row_bytes = ATLAS_W / 2; + for ry in 0..m.h as usize { + let ay = m.atlas_y as usize + ry; + for rx in 0..m.w as usize { + let ax = m.atlas_x as usize + rx; + let byte = ATLAS[ay * row_bytes + ax / 2]; + let a = if ax & 1 == 0 { byte >> 4 } else { byte & 0x0F }; + if a == 0 { + continue; + } + let c = if a >= 15 { ink } else { blend(ink, bg, a) }; + d.fill_solid( + &embedded_graphics::primitives::Rectangle::new( + Point::new(ox + rx as i32, oy + ry as i32), + Size::new(1, 1), + ), + c, + )?; + } + } + Ok(()) +} + +/// Advance width of a glyph (px) — for laying out time-signature digit runs. +pub fn advance(glyph: Glyph) -> i32 { + GLYPHS[glyph as usize].advance as i32 +} + +/// Bitmap width of a glyph (px) — for centering a glyph on a column. +pub fn width(glyph: Glyph) -> i32 { + GLYPHS[glyph as usize].w as i32 +} diff --git a/rust/pm-ui/src/notation/glyphs.rs b/rust/pm-ui/src/notation/glyphs.rs new file mode 100644 index 0000000..55bbc28 --- /dev/null +++ b/rust/pm-ui/src/notation/glyphs.rs @@ -0,0 +1,854 @@ +//! GENERATED by `rust/glyphgen` — do not edit by hand. Re-run: +//! cargo run --manifest-path rust/glyphgen/Cargo.toml +//! +//! A 4-bit-alpha atlas of the frozen Bravura SMuFL subset (39 glyphs, the SAME set the web +//! froze in tools/bravura/subset.py) rasterized at em = 4 x staff_space. `no_std` const data. +#![allow(dead_code)] + +/// Staff space the atlas was rasterized for (px). 1 SMuFL em = 4 staff spaces. +pub const STAFF_SPACE: i32 = 10; +pub const EM: i32 = 40; +/// Atlas dimensions in pixels (4-bit alpha, row-packed: 2 px per byte). +pub const ATLAS_W: usize = 256; +pub const ATLAS_H: usize = 92; + +/// Per-glyph atlas placement + placement metrics (all in px). +#[derive(Clone, Copy)] +pub struct GlyphMeta { + pub atlas_x: u16, + pub atlas_y: u16, + pub w: u16, + pub h: u16, + /// left edge of the bitmap relative to the glyph origin (pen x) + pub bearing_x: i16, + /// top edge of the bitmap ABOVE the baseline (positive = up) + pub bearing_y: i16, + /// horizontal advance + pub advance: i16, +} + +/// One frozen SMuFL glyph. `as usize` indexes `GLYPHS`. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Glyph { + Clef, + NoteheadBlack, + NoteheadX, + NoteheadCircleX, + ParenL, + ParenR, + NoteheadHalf, + NoteheadWhole, + Flag8Up, + Flag8Down, + Flag16Up, + Flag16Down, + RestWhole, + RestHalf, + RestQuarter, + Rest8, + Rest16, + AccentAbove, + AccentBelow, + Dot, + Sig0, + Sig1, + Sig2, + Sig3, + Sig4, + Sig5, + Sig6, + Sig7, + Sig8, + Sig9, + SigPlus, + SigCommon, + SigCut, + GraceAcc, + GraceSlash, + Trem1, + Trem2, + Trem3, + BuzzRoll, +} + +pub const GLYPHS: [GlyphMeta; 39] = [ + GlyphMeta { atlas_x: 1, atlas_y: 1, w: 16, h: 20, bearing_x: 0, bearing_y: 10, advance: 15 }, // Clef + GlyphMeta { atlas_x: 18, atlas_y: 1, w: 12, h: 10, bearing_x: 0, bearing_y: 5, advance: 12 }, // NoteheadBlack + GlyphMeta { atlas_x: 31, atlas_y: 1, w: 12, h: 10, bearing_x: 0, bearing_y: 5, advance: 12 }, // NoteheadX + GlyphMeta { atlas_x: 44, atlas_y: 1, w: 10, h: 10, bearing_x: 0, bearing_y: 5, advance: 10 }, // NoteheadCircleX + GlyphMeta { atlas_x: 55, atlas_y: 1, w: 5, h: 16, bearing_x: 0, bearing_y: 8, advance: 3 }, // ParenL + GlyphMeta { atlas_x: 61, atlas_y: 1, w: 5, h: 16, bearing_x: -2, bearing_y: 8, advance: 3 }, // ParenR + GlyphMeta { atlas_x: 67, atlas_y: 1, w: 12, h: 10, bearing_x: 0, bearing_y: 5, advance: 12 }, // NoteheadHalf + GlyphMeta { atlas_x: 80, atlas_y: 1, w: 17, h: 10, bearing_x: 0, bearing_y: 5, advance: 17 }, // NoteheadWhole + GlyphMeta { atlas_x: 98, atlas_y: 1, w: 11, h: 34, bearing_x: 0, bearing_y: 1, advance: 11 }, // Flag8Up + GlyphMeta { atlas_x: 110, atlas_y: 1, w: 13, h: 34, bearing_x: 0, bearing_y: 33, advance: 12 }, // Flag8Down + GlyphMeta { atlas_x: 124, atlas_y: 1, w: 12, h: 34, bearing_x: 0, bearing_y: 1, advance: 11 }, // Flag16Up + GlyphMeta { atlas_x: 137, atlas_y: 1, w: 12, h: 34, bearing_x: 0, bearing_y: 33, advance: 12 }, // Flag16Down + GlyphMeta { atlas_x: 150, atlas_y: 1, w: 12, h: 7, bearing_x: 0, bearing_y: 1, advance: 11 }, // RestWhole + GlyphMeta { atlas_x: 163, atlas_y: 1, w: 12, h: 7, bearing_x: 0, bearing_y: 6, advance: 11 }, // RestHalf + GlyphMeta { atlas_x: 176, atlas_y: 1, w: 11, h: 30, bearing_x: 0, bearing_y: 15, advance: 11 }, // RestQuarter + GlyphMeta { atlas_x: 188, atlas_y: 1, w: 10, h: 18, bearing_x: 0, bearing_y: 7, advance: 10 }, // Rest8 + GlyphMeta { atlas_x: 199, atlas_y: 1, w: 13, h: 28, bearing_x: 0, bearing_y: 8, advance: 13 }, // Rest16 + GlyphMeta { atlas_x: 213, atlas_y: 1, w: 14, h: 10, bearing_x: 0, bearing_y: 10, advance: 14 }, // AccentAbove + GlyphMeta { atlas_x: 228, atlas_y: 1, w: 14, h: 10, bearing_x: 0, bearing_y: 0, advance: 14 }, // AccentBelow + GlyphMeta { atlas_x: 243, atlas_y: 1, w: 4, h: 4, bearing_x: 0, bearing_y: 2, advance: 4 }, // Dot + GlyphMeta { atlas_x: 1, atlas_y: 36, w: 18, h: 21, bearing_x: 0, bearing_y: 11, advance: 19 }, // Sig0 + GlyphMeta { atlas_x: 20, atlas_y: 36, w: 13, h: 21, bearing_x: 0, bearing_y: 11, advance: 13 }, // Sig1 + GlyphMeta { atlas_x: 34, atlas_y: 36, w: 18, h: 22, bearing_x: 0, bearing_y: 11, advance: 18 }, // Sig2 + GlyphMeta { atlas_x: 53, atlas_y: 36, w: 17, h: 21, bearing_x: 0, bearing_y: 10, advance: 17 }, // Sig3 + GlyphMeta { atlas_x: 71, atlas_y: 36, w: 18, h: 21, bearing_x: 0, bearing_y: 11, advance: 19 }, // Sig4 + GlyphMeta { atlas_x: 90, atlas_y: 36, w: 16, h: 21, bearing_x: 0, bearing_y: 10, advance: 16 }, // Sig5 + GlyphMeta { atlas_x: 107, atlas_y: 36, w: 17, h: 21, bearing_x: 0, bearing_y: 11, advance: 17 }, // Sig6 + GlyphMeta { atlas_x: 125, atlas_y: 36, w: 17, h: 20, bearing_x: 0, bearing_y: 10, advance: 18 }, // Sig7 + GlyphMeta { atlas_x: 143, atlas_y: 36, w: 17, h: 22, bearing_x: 0, bearing_y: 11, advance: 17 }, // Sig8 + GlyphMeta { atlas_x: 161, atlas_y: 36, w: 17, h: 21, bearing_x: 0, bearing_y: 11, advance: 17 }, // Sig9 + GlyphMeta { atlas_x: 179, atlas_y: 36, w: 21, h: 20, bearing_x: -1, bearing_y: 10, advance: 20 }, // SigPlus + GlyphMeta { atlas_x: 201, atlas_y: 36, w: 17, h: 21, bearing_x: 0, bearing_y: 11, advance: 17 }, // SigCommon + GlyphMeta { atlas_x: 219, atlas_y: 36, w: 17, h: 30, bearing_x: 0, bearing_y: 15, advance: 17 }, // SigCut + GlyphMeta { atlas_x: 237, atlas_y: 36, w: 15, h: 25, bearing_x: 0, bearing_y: 21, advance: 14 }, // GraceAcc + GlyphMeta { atlas_x: 1, atlas_y: 67, w: 21, h: 17, bearing_x: 0, bearing_y: 17, advance: 20 }, // GraceSlash + GlyphMeta { atlas_x: 23, atlas_y: 67, w: 12, h: 8, bearing_x: -6, bearing_y: 4, advance: 6 }, // Trem1 + GlyphMeta { atlas_x: 36, atlas_y: 67, w: 13, h: 16, bearing_x: -7, bearing_y: 8, advance: 6 }, // Trem2 + GlyphMeta { atlas_x: 50, atlas_y: 67, w: 12, h: 24, bearing_x: -6, bearing_y: 12, advance: 6 }, // Trem3 + GlyphMeta { atlas_x: 63, atlas_y: 67, w: 14, h: 10, bearing_x: -7, bearing_y: 5, advance: 6 }, // BuzzRoll +]; + +/// Row-packed 4-bit alpha. byte = (even_col << 4) | odd_col; coverage 0..15. +pub const ATLAS: &[u8] = &[ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0xff, 0xff, 0xe3, 0x00, 0xdf, 0xff, 0xfe, 0x20, 0x00, 0x00, 0x49, 0xce, 0xda, 0x30, 0x0b, + 0x50, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x3a, 0xdd, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0xad, 0xed, 0xa3, 0x00, 0x00, 0x01, 0x6a, 0xcc, 0xee, 0xc9, 0x40, 0x00, + 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x25, 0x55, 0x55, 0x55, 0x55, + 0x30, 0x06, 0xaa, 0xaa, 0xaa, 0xaa, 0xa8, 0x00, 0x09, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xdb, + 0x30, 0x00, 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x83, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xbb, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xbb, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x2b, 0xff, 0xff, 0xff, 0xe3, 0x04, + 0xe7, 0x00, 0x00, 0x01, 0xcb, 0x10, 0x07, 0xe7, 0x33, 0x7e, 0x60, 0x00, 0x00, 0x71, 0x01, 0x70, + 0x00, 0x00, 0x03, 0xcf, 0xff, 0xeb, 0xce, 0x20, 0x01, 0x9e, 0xe4, 0x00, 0x06, 0xef, 0xfd, 0x50, + 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0xd5, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x30, 0xdf, 0xff, 0xff, 0xff, 0xff, + 0xf2, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x0a, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xff, + 0xe1, 0x02, 0xdb, 0x00, 0x00, 0x2d, 0xfe, 0x50, 0x00, 0x48, 0x08, 0xef, 0xd8, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x5c, 0xfe, 0xb6, 0x10, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xb0, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x02, 0xef, 0xff, 0xff, 0xff, 0xf9, 0x00, + 0x2c, 0x90, 0x00, 0x3d, 0x80, 0x00, 0x3e, 0xe5, 0x00, 0x5e, 0xe3, 0x00, 0x0a, 0x10, 0x00, 0x19, + 0x00, 0x00, 0x3e, 0xff, 0xc5, 0x00, 0x0b, 0x90, 0x1c, 0xff, 0x70, 0x00, 0x00, 0x2d, 0xff, 0xf9, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xf6, 0x00, 0xfa, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf4, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x01, 0xdf, 0x60, 0x00, 0x00, 0x00, 0xef, 0xff, + 0xf4, 0x5e, 0xf7, 0x00, 0x00, 0xcf, 0xff, 0xe1, 0x04, 0xe8, 0x00, 0x05, 0xae, 0xfc, 0x72, 0x00, + 0x00, 0x00, 0x00, 0x27, 0xcf, 0xea, 0x51, 0x00, 0x00, 0x0b, 0xff, 0xb0, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x0d, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x00, + 0x01, 0xbb, 0x15, 0xe6, 0x00, 0x00, 0xa7, 0x4e, 0x55, 0xe4, 0x89, 0x00, 0x94, 0x00, 0x00, 0x05, + 0x80, 0x00, 0xdf, 0xe5, 0x00, 0x00, 0x08, 0xb0, 0x9f, 0xff, 0x50, 0x00, 0x00, 0x05, 0xff, 0xff, + 0x60, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xf9, 0x00, 0xfe, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf4, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x00, 0x5f, 0xe4, 0x00, 0x00, 0x00, 0xbf, 0xff, + 0xfe, 0xff, 0xf3, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x8e, 0xf4, 0x00, 0x00, 0x01, 0x6b, 0xef, 0xc7, + 0x20, 0x00, 0x00, 0x00, 0x03, 0x8d, 0xfe, 0xa5, 0x00, 0x03, 0xbb, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x09, 0xde, 0x40, 0x00, 0x00, 0xd3, 0x04, 0xee, 0x40, 0x4c, 0x03, 0xd0, 0x00, 0x00, 0x00, + 0xd2, 0x07, 0xfc, 0x10, 0x00, 0x00, 0x2e, 0x80, 0xef, 0xff, 0x80, 0x00, 0x00, 0x00, 0xcf, 0xff, + 0xb0, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x00, 0xff, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf4, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x00, 0x0c, 0xfe, 0x30, 0x00, 0x00, 0x2d, 0xff, + 0xfc, 0xbf, 0xd0, 0x00, 0x00, 0xcf, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x16, 0xcf, + 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x39, 0xff, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xe2, 0x00, + 0x00, 0x09, 0xde, 0x40, 0x00, 0x00, 0xd2, 0x05, 0xee, 0x50, 0x4c, 0x09, 0x90, 0x00, 0x00, 0x00, + 0xa8, 0x0b, 0xb0, 0x00, 0x00, 0x04, 0xef, 0x30, 0xdf, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x8f, 0xff, + 0xb0, 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xff, 0xf4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0xdf, 0xff, 0xff, 0xff, 0xff, + 0xf2, 0x0b, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x10, 0x00, 0x08, 0xff, 0xd1, 0x00, 0x00, 0x00, 0x45, + 0x30, 0x7f, 0x90, 0x00, 0x00, 0x2c, 0xff, 0xea, 0x9f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x04, 0xaf, + 0xfe, 0x30, 0x00, 0x00, 0x00, 0x02, 0x7c, 0xfe, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0xef, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, + 0x01, 0xba, 0x04, 0xe6, 0x00, 0x00, 0xa6, 0x4e, 0x44, 0xe5, 0x79, 0x0c, 0x80, 0x00, 0x00, 0x00, + 0x8b, 0x0e, 0x30, 0x00, 0x00, 0x7e, 0xfa, 0x00, 0x9f, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x7f, 0xff, + 0x80, 0xff, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x10, 0xff, 0xfe, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x26, 0x66, 0x66, 0x66, 0x66, + 0x40, 0x00, 0x11, 0x11, 0x11, 0x11, 0x10, 0x00, 0x00, 0x05, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xcf, 0x50, 0x00, 0x00, 0x00, 0x23, 0x00, 0x8f, 0x60, 0x00, 0x00, 0x00, 0x49, 0xdf, 0xe9, + 0x40, 0x00, 0x00, 0x00, 0x27, 0xcf, 0xfb, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0xcf, 0xff, 0xff, 0xff, 0xf9, 0x00, 0x00, + 0x2d, 0x80, 0x00, 0x2d, 0x90, 0x00, 0x3e, 0xe4, 0x00, 0x4e, 0xe3, 0x0e, 0x70, 0x00, 0x00, 0x00, + 0x8c, 0x0c, 0x60, 0x00, 0x5d, 0xff, 0xd1, 0x00, 0x2e, 0xff, 0xfe, 0x30, 0x00, 0x00, 0xbf, 0xfd, + 0x10, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x20, 0xff, 0xff, + 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xa0, 0x00, 0x00, 0x00, + 0x02, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x20, 0x00, 0x03, 0x8d, 0xfe, 0xa4, 0x00, + 0x00, 0x00, 0x01, 0x6b, 0xff, 0xc6, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x5f, 0xff, 0xff, 0xfe, 0x60, 0x00, 0x04, + 0xe6, 0x00, 0x00, 0x01, 0xbb, 0x10, 0x07, 0xe7, 0x33, 0x7e, 0x60, 0x0d, 0x70, 0x00, 0x00, 0x00, + 0x8c, 0x05, 0xe9, 0xae, 0xff, 0xfb, 0x10, 0x00, 0x02, 0xcf, 0xff, 0xe7, 0x10, 0x07, 0xff, 0xb2, + 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x30, 0xff, 0xff, + 0xfe, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xf4, 0x00, 0x00, 0x00, + 0x07, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfd, 0x00, 0x06, 0xdf, 0xea, 0x50, 0x00, 0x00, + 0x00, 0x00, 0x9e, 0xfc, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x04, 0xbe, 0xeb, 0x60, 0x00, 0x00, 0x0b, + 0x40, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x3a, 0xdd, 0xa3, 0x00, 0x0c, 0x80, 0x00, 0x00, 0x00, + 0x9a, 0x00, 0x4b, 0xee, 0xc9, 0x40, 0x00, 0x00, 0x00, 0x03, 0x8b, 0xde, 0xed, 0xdb, 0x83, 0x00, + 0x00, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x20, 0xfe, 0xad, + 0xff, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff, 0xe2, 0x00, 0x00, 0x00, + 0x0c, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x0a, 0xa5, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x77, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xa0, 0x00, 0x00, 0x00, + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xef, 0xff, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x10, 0xfb, 0x00, + 0x3c, 0xfe, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x90, 0x00, 0x00, 0x00, + 0x2f, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0x00, + 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0xef, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x00, 0xff, 0x20, + 0x00, 0x9f, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xef, 0xff, 0xfd, 0x10, 0x00, 0x00, 0x00, + 0x7f, 0xd0, 0x00, 0x01, 0xbe, 0xd5, 0x00, 0x2f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x05, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5e, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfb, 0x00, 0xff, 0x90, + 0x00, 0x0a, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, + 0xcf, 0x90, 0x00, 0x0a, 0xff, 0xfe, 0x20, 0x8f, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xf7, 0x00, 0xff, 0xf4, + 0x00, 0x00, 0xcf, 0x40, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x02, + 0xff, 0x50, 0x00, 0x0e, 0xff, 0xff, 0x66, 0xef, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x01, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf2, 0x00, 0xff, 0xfe, + 0x30, 0x00, 0x4f, 0x90, 0x00, 0x00, 0x00, 0x02, 0xee, 0xef, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xb0, 0x00, 0x00, 0x00, 0x07, + 0xfe, 0x10, 0x00, 0x0b, 0xff, 0xff, 0xff, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xc0, 0x00, 0xff, 0xff, + 0xe3, 0x00, 0x0c, 0xc0, 0x00, 0x00, 0x00, 0x2d, 0xf5, 0x4f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xff, 0x90, 0x00, 0x00, 0x00, 0x0c, + 0xfb, 0x00, 0x00, 0x02, 0xcf, 0xff, 0xcd, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0xef, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x50, 0x00, 0xde, 0xff, + 0xfd, 0x20, 0x09, 0xe0, 0x00, 0x00, 0x17, 0xef, 0x90, 0x2f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0x90, 0x00, 0x00, 0x00, 0x0d, + 0xd5, 0x00, 0x00, 0x00, 0x03, 0x42, 0x0d, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x05, 0xfd, 0x00, 0x00, 0x00, 0x16, + 0xcf, 0xc0, 0x08, 0xe0, 0x08, 0x9b, 0xef, 0xfa, 0x00, 0x3f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xef, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xf6, 0x01, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf6, 0x00, 0x00, 0x00, 0x00, + 0x09, 0xfa, 0x09, 0xd0, 0x0f, 0xff, 0xff, 0xa0, 0x00, 0x5f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0xff, 0xff, 0xe3, 0x00, 0xdf, 0xff, 0xfe, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xd0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xaf, 0xae, 0xa0, 0x0f, 0xff, 0xfa, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x3e, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x0a, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0d, 0xff, 0x70, 0x0f, 0xff, 0xa0, 0x00, 0x04, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xff, 0xff, 0xff, 0x90, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x10, 0x00, 0x02, 0xbf, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0xff, 0x20, 0x0f, 0xfc, 0x00, 0x00, 0x2e, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xff, 0xff, 0xf5, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x40, 0x01, 0x7e, 0xff, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xbe, 0x00, 0x0f, 0xf4, 0x00, 0x02, 0xdf, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0xff, 0xff, 0xff, 0xfe, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x60, 0x9e, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5f, 0x40, 0x0f, 0xd0, 0x00, 0x6e, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xfa, 0x32, 0x48, 0x70, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x70, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x90, 0x0f, 0xd6, 0x9d, 0xff, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0xff, 0xff, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0xd0, 0x0f, 0xff, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0xff, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x70, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x09, 0xe0, 0x0f, 0xff, 0xff, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xff, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x60, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0xf2, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0xdb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x40, 0xff, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0xf2, 0x0f, 0xff, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x20, 0xff, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xf1, 0x0f, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x00, 0xff, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0xf1, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xfb, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0xf0, 0x0f, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xe7, 0x00, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0xd0, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8c, 0xdd, 0xb8, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xa9, + 0x87, 0x68, 0x9a, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xad, 0xdb, 0x50, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x02, 0x45, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0xbe, 0xed, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xed, 0xee, 0x70, + 0x00, 0x00, 0x00, 0x6b, 0xdd, 0xdf, 0xfd, 0x93, 0x00, 0x00, 0x00, 0x01, 0xae, 0xc7, 0x8b, 0xff, + 0xfb, 0x20, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xee, 0xfe, 0x30, 0x00, 0x00, 0x02, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x05, 0xad, 0xee, 0xc8, 0x20, 0x00, 0x02, 0xc1, + 0x4e, 0xff, 0xff, 0xfb, 0x10, 0x00, 0xec, 0x00, 0x00, 0x18, 0xdf, 0xec, 0xde, 0xd8, 0x20, 0x00, + 0x00, 0x00, 0x05, 0xac, 0xee, 0xdb, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0xce, 0xec, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xdf, 0xfa, 0x5c, 0xff, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xff, 0xa0, + 0x00, 0x00, 0x2d, 0xe4, 0x00, 0x03, 0xdf, 0xff, 0xa0, 0x00, 0x00, 0x1c, 0xff, 0x30, 0x00, 0x5f, + 0xff, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf3, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xe4, 0x04, 0xff, 0xe5, 0x00, 0x03, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xd2, 0x07, 0xfb, 0x00, 0x04, 0xef, 0xc3, 0x00, 0x01, 0x7e, 0xe6, 0x00, + 0x00, 0x01, 0xcf, 0xff, 0x82, 0x8f, 0xfc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xef, 0xc4, 0x10, 0x17, 0xc2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4e, 0xff, 0xd0, 0x01, 0xef, 0xfd, 0x20, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0xa0, + 0x00, 0x02, 0xef, 0xa0, 0x00, 0x00, 0x3f, 0xff, 0xfb, 0x00, 0x00, 0x9f, 0xff, 0xe7, 0x00, 0x0b, + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xe2, 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x5e, 0xff, 0x50, 0x0a, 0xff, 0xfe, 0x10, 0x03, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xae, 0xf9, 0x00, 0x3e, 0xfe, 0x00, 0x00, 0x00, 0x04, 0xee, 0x30, + 0x00, 0x0c, 0xff, 0xfb, 0x00, 0x0c, 0xff, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xfc, 0x10, 0x00, 0x00, 0xcd, 0x10, 0x00, 0x00, 0x00, + 0x00, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xef, 0xff, 0x50, 0x00, 0x9f, 0xff, 0xc0, 0x00, 0x00, 0x06, 0xff, 0xff, 0xff, 0xa0, + 0x00, 0x0b, 0xff, 0xfb, 0x10, 0x00, 0x0d, 0xff, 0xff, 0x60, 0x00, 0xdf, 0xff, 0xfe, 0x00, 0x09, + 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x1e, 0xff, 0xff, 0x60, 0x10, 0x00, 0x00, 0x05, 0xfb, 0x8a, + 0xbc, 0xcb, 0x82, 0x00, 0x00, 0x00, 0x02, 0xef, 0xfe, 0x00, 0x2f, 0xff, 0xff, 0x50, 0x03, 0xff, + 0xd9, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xf5, 0x00, 0xaf, 0xfb, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x90, + 0x00, 0x7f, 0xff, 0xf6, 0x00, 0x07, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xf3, 0x00, 0x00, 0x7c, 0xff, 0x90, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0b, 0xff, 0xff, 0x10, 0x00, 0x4f, 0xff, 0xf8, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, 0xa0, + 0x00, 0x0e, 0xff, 0xff, 0xc0, 0x00, 0x0b, 0xff, 0xff, 0xc0, 0x00, 0xbf, 0xff, 0xfe, 0x00, 0x0b, + 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x4f, 0xff, 0xfa, 0x02, 0xe6, 0x00, 0x00, 0x05, 0xf3, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xfa, 0x00, 0x4f, 0xff, 0xff, 0x30, 0x03, 0xfd, + 0x10, 0x08, 0xef, 0xff, 0xff, 0xff, 0xe1, 0x00, 0xdf, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x9f, 0xa0, + 0x00, 0xdf, 0xff, 0xf3, 0x00, 0x04, 0xff, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xff, 0xb0, 0x00, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x3a, 0xfe, 0xca, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe2, 0x01, 0x81, 0x00, 0x00, + 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x00, 0x0e, 0xff, 0xfe, 0x10, 0x00, 0x4f, 0xff, 0xff, 0xff, 0xa0, + 0x00, 0x2f, 0xff, 0xff, 0xf2, 0x00, 0x0c, 0xff, 0xff, 0xe0, 0x00, 0x3e, 0xff, 0xfa, 0x00, 0x0e, + 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xff, 0xd1, 0x1d, 0xf7, 0x00, 0x00, 0x06, 0xf1, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x2f, 0xff, 0xf7, 0x00, 0x0d, 0xff, 0xf9, 0x00, 0x03, 0xf6, + 0x00, 0x00, 0x3d, 0xff, 0xfb, 0xff, 0x90, 0x00, 0xef, 0xff, 0xd3, 0x00, 0x00, 0x00, 0xcf, 0x90, + 0x01, 0xff, 0xff, 0xf2, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xff, 0x70, 0x00, 0x0d, 0xff, 0xff, 0xf1, 0x00, 0x00, 0x1a, + 0xff, 0xfc, 0x10, 0x3b, 0x90, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc5, 0xdc, 0x4d, 0xb0, 0x00, 0x00, + 0x00, 0x9f, 0xff, 0xf9, 0x00, 0x00, 0x0c, 0xff, 0xff, 0x60, 0x00, 0xbf, 0xaf, 0xff, 0xff, 0xa0, + 0x00, 0x0e, 0xff, 0xff, 0xf2, 0x00, 0x0e, 0xff, 0xff, 0xe0, 0x00, 0x02, 0x79, 0x60, 0x00, 0xaf, + 0xff, 0xe4, 0x00, 0x00, 0x00, 0x01, 0xef, 0xfe, 0x30, 0xbf, 0xf7, 0x00, 0x00, 0x07, 0xf1, 0x5b, + 0xef, 0xff, 0xc7, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xf5, 0x00, 0x01, 0x79, 0x50, 0x00, 0x03, 0xe0, + 0x00, 0x00, 0x00, 0x47, 0x33, 0xff, 0x30, 0x00, 0xbf, 0xff, 0xfe, 0xa4, 0x00, 0x05, 0xff, 0x30, + 0x02, 0xff, 0xff, 0xf3, 0x00, 0x04, 0xff, 0xff, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff, 0x40, 0x00, 0x0d, 0xff, 0xff, 0xe0, 0x00, 0x01, 0xcf, + 0xfe, 0xf6, 0x00, 0x01, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x1e, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0xdf, 0xff, 0xf8, 0x00, 0x00, 0x0b, 0xff, 0xff, 0xa0, 0x02, 0xfc, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x6f, 0xff, 0xff, 0xb0, 0x00, 0x00, 0x00, 0x02, 0x5c, 0xff, + 0xea, 0x20, 0x00, 0x00, 0x00, 0x08, 0xff, 0xf6, 0x09, 0xff, 0xf7, 0x00, 0x00, 0x08, 0xfe, 0xa5, + 0x5b, 0xff, 0xff, 0xc2, 0x00, 0x00, 0xdf, 0xff, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x1d, 0xfb, 0x00, 0x00, 0x6f, 0xff, 0xff, 0xff, 0xe9, 0x8e, 0xf8, 0x00, + 0x00, 0xef, 0xff, 0xf6, 0x00, 0x07, 0xff, 0xff, 0xf4, 0x00, 0x57, 0x77, 0x77, 0x77, 0xef, 0xfd, + 0x77, 0x77, 0x77, 0x74, 0x06, 0xff, 0xff, 0x30, 0x00, 0x09, 0xff, 0xff, 0x90, 0x00, 0x0c, 0xff, + 0xe2, 0xf6, 0x00, 0x8d, 0xff, 0x50, 0x00, 0x00, 0x00, 0x01, 0xc1, 0xae, 0xd0, 0x00, 0x00, 0x00, + 0x01, 0xff, 0xff, 0xf7, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xd0, 0x09, 0xf3, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x00, 0x7e, 0xfd, 0x30, 0x00, 0xdf, 0xff, 0xfe, 0x30, 0x00, 0x00, 0x02, 0xef, 0xff, 0xff, + 0x91, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xff, 0x90, 0x6f, 0xff, 0xf7, 0x00, 0x00, 0x08, 0xe4, 0x00, + 0x00, 0x6f, 0xff, 0xfd, 0x10, 0x01, 0xff, 0xff, 0xf4, 0x08, 0xce, 0xd9, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xcf, 0xf5, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x00, + 0x00, 0x8f, 0xff, 0xfb, 0x00, 0x0c, 0xff, 0xff, 0xf6, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x09, 0xff, 0xff, 0x20, 0x00, 0x00, 0x9e, 0xe9, 0x00, 0x00, 0x6f, 0xff, + 0x90, 0xf6, 0x0a, 0xff, 0xff, 0xa0, 0x00, 0x00, 0x00, 0x01, 0xdd, 0xc2, 0xb3, 0x00, 0x00, 0x00, + 0x02, 0xff, 0xff, 0xf6, 0x00, 0x00, 0x09, 0xff, 0xff, 0xe0, 0x0e, 0x90, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x0a, 0xff, 0xff, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x13, 0x6c, 0xff, + 0xfe, 0xa1, 0x00, 0x00, 0x00, 0x9f, 0xfc, 0x00, 0xdf, 0xff, 0xf7, 0x00, 0x00, 0x02, 0x20, 0x00, + 0x00, 0x0b, 0xff, 0xff, 0x80, 0x02, 0xff, 0xff, 0xfc, 0xde, 0xff, 0xff, 0xe5, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x00, + 0x00, 0x1c, 0xff, 0xff, 0x71, 0x8f, 0xff, 0xff, 0xf7, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x0a, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, + 0x40, 0xf6, 0x1f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x06, 0xf9, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x02, 0xff, 0xff, 0xf6, 0x00, 0x00, 0x09, 0xff, 0xff, 0xe0, 0x07, 0x10, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xd8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, + 0xff, 0xfd, 0x10, 0x00, 0x03, 0xef, 0xd1, 0x00, 0xef, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x37, 0x72, + 0x00, 0x05, 0xff, 0xff, 0xe0, 0x02, 0xff, 0xff, 0xff, 0xb1, 0x2d, 0xff, 0xff, 0x50, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xcf, 0xff, 0x80, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb0, + 0x00, 0x01, 0xbf, 0xff, 0xff, 0xe9, 0xff, 0xff, 0xf7, 0x00, 0x57, 0x77, 0x77, 0x77, 0xdf, 0xfd, + 0x77, 0x77, 0x77, 0x75, 0x0b, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, + 0x10, 0xf6, 0x2f, 0xff, 0xff, 0xb0, 0x00, 0x00, 0x00, 0x9e, 0xc0, 0x00, 0x3b, 0x00, 0x00, 0x00, + 0x01, 0xff, 0xff, 0xf7, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xd0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x00, 0x00, 0x00, 0x1a, 0xfe, 0x93, 0x00, 0x00, 0x00, 0x00, 0x05, 0xbb, 0x70, 0x00, 0x0c, + 0xff, 0xff, 0x80, 0x00, 0x0c, 0xfe, 0x20, 0x00, 0xef, 0xff, 0xf7, 0x00, 0x00, 0x05, 0xef, 0xfe, + 0x40, 0x02, 0xff, 0xff, 0xf3, 0x00, 0xff, 0xff, 0xff, 0x20, 0x05, 0xff, 0xff, 0xd0, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0xff, 0xff, 0x30, 0x00, 0x00, 0x04, 0xef, 0xa6, 0xcf, 0xff, 0xff, 0xff, 0xf4, + 0x00, 0x00, 0x05, 0xad, 0xc9, 0x20, 0xef, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, 0x09, 0xff, 0xfe, + 0x00, 0xf6, 0x0d, 0xff, 0xff, 0x60, 0x00, 0x00, 0x1c, 0xd5, 0xc0, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x00, 0xdf, 0xff, 0xf8, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xa0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x00, 0x00, 0x03, 0xde, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xf7, 0x00, 0x08, + 0xff, 0xff, 0xd0, 0x00, 0x7f, 0xe3, 0x00, 0x00, 0xef, 0xff, 0xf7, 0x00, 0x00, 0x0e, 0xff, 0xff, + 0xd0, 0x01, 0xff, 0xff, 0xf4, 0x00, 0xef, 0xff, 0xfc, 0x00, 0x00, 0xef, 0xff, 0xf5, 0x00, 0x00, + 0x00, 0x00, 0xaf, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x3e, 0xe6, 0x00, 0x04, 0xbf, 0xff, 0xff, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xff, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x0c, 0xff, 0xfe, + 0x00, 0xf6, 0x02, 0xcf, 0xe7, 0x00, 0x00, 0x00, 0x5a, 0x11, 0xc0, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x00, 0x9f, 0xff, 0xfb, 0x00, 0x00, 0x0e, 0xff, 0xff, 0x60, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x00, 0x00, 0x7e, 0xd4, 0x10, 0x00, 0x00, 0x02, 0x80, 0x00, 0xef, 0xff, 0xfc, 0x00, 0x07, + 0xff, 0xff, 0xe0, 0x01, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x2f, 0xff, 0xff, + 0xf0, 0x02, 0xff, 0xff, 0xf3, 0x00, 0xaf, 0xff, 0xf9, 0x00, 0x00, 0xcf, 0xff, 0xf7, 0x00, 0x00, + 0x00, 0x07, 0xff, 0xff, 0xf9, 0x00, 0x00, 0x00, 0xcf, 0x80, 0x00, 0x00, 0x06, 0xef, 0xff, 0xf9, + 0x00, 0x00, 0x39, 0xa5, 0x00, 0x00, 0xff, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x0e, 0xff, 0xfe, + 0x00, 0xf6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x00, 0x2f, 0xff, 0xfe, 0x10, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x00, 0x09, 0xff, 0xef, 0xfe, 0xc7, 0x20, 0x0a, 0xa0, 0x02, 0xff, 0xff, 0xfb, 0x00, 0x09, + 0xff, 0xff, 0xd0, 0x00, 0x67, 0x77, 0x77, 0x77, 0xef, 0xff, 0xfa, 0x77, 0x40, 0x2f, 0xff, 0xff, + 0xc0, 0x04, 0xff, 0xff, 0xe0, 0x00, 0x6f, 0xff, 0xf8, 0x00, 0x00, 0xbf, 0xff, 0xf7, 0x00, 0x00, + 0x00, 0x1e, 0xff, 0xff, 0xf6, 0x00, 0x00, 0x01, 0xff, 0x30, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xf7, + 0x00, 0x05, 0xef, 0xff, 0x50, 0x02, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0e, 0xff, 0xfe, + 0x00, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x87, 0x00, 0x00, 0x00, + 0x00, 0x0b, 0xff, 0xff, 0x30, 0x00, 0x6f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xcf, 0x70, 0x01, 0xef, 0xff, 0xf5, 0x00, 0x0d, + 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xff, 0xf7, 0x00, 0x00, 0x0e, 0xff, 0xfe, + 0x40, 0x0a, 0xff, 0xff, 0x80, 0x00, 0x0d, 0xff, 0xfa, 0x00, 0x00, 0xdf, 0xff, 0xf3, 0x00, 0x00, + 0x00, 0x8f, 0xff, 0xff, 0xf3, 0x00, 0x00, 0x02, 0xff, 0x20, 0x00, 0x00, 0x00, 0x1e, 0xff, 0xf4, + 0x00, 0x0d, 0xff, 0xff, 0xa0, 0x05, 0xff, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xe1, 0x00, 0x00, 0x00, 0x01, 0xd2, 0x0d, 0xff, 0xff, + 0x00, 0xf6, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x31, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xef, 0xff, 0xa0, 0x00, 0xdf, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xa0, + 0x00, 0x02, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x00, 0xaf, 0xff, 0xf1, 0x00, 0x8f, + 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xff, 0xf7, 0x00, 0x00, 0x09, 0xff, 0xf5, + 0x00, 0x6f, 0xff, 0xfc, 0x10, 0x00, 0x04, 0xff, 0xfd, 0x00, 0x01, 0xef, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0xef, 0xff, 0xff, 0xf2, 0x00, 0x00, 0x00, 0xef, 0x60, 0x00, 0x00, 0x00, 0x0e, 0xff, 0xd0, + 0x00, 0x0e, 0xff, 0xff, 0x70, 0x09, 0xff, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x0a, 0x90, 0x0b, 0xff, 0xff, + 0x20, 0xf6, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x02, 0x21, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4e, 0xff, 0xf5, 0x08, 0xff, 0xfd, 0x20, 0x00, 0x00, 0x00, 0x2f, 0xff, 0xff, 0xb0, + 0x00, 0x09, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x1b, 0xff, 0xfa, 0x7b, 0xff, + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xfa, 0x00, 0x00, 0x00, 0xbf, 0xfc, + 0x8b, 0xff, 0xff, 0xb1, 0x00, 0x00, 0x00, 0x8f, 0xff, 0x30, 0x07, 0xff, 0xfe, 0x30, 0x00, 0x00, + 0x02, 0xff, 0xff, 0xff, 0xf1, 0x00, 0x00, 0x00, 0x8f, 0xe2, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x40, + 0x00, 0x09, 0xff, 0xfe, 0x10, 0x1e, 0xff, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xcf, 0xfe, 0x50, 0x00, 0x02, 0xac, 0x00, 0x07, 0xff, 0xff, + 0x40, 0xf6, 0x00, 0x00, 0x00, 0x98, 0x00, 0x07, 0xef, 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xcf, 0xff, 0xdf, 0xff, 0xb1, 0x00, 0x00, 0x00, 0x05, 0xcf, 0xff, 0xff, 0xf7, + 0x00, 0x0e, 0xfb, 0x20, 0x1a, 0xff, 0xff, 0xff, 0xe2, 0x00, 0x00, 0x00, 0x39, 0xcd, 0xfe, 0xdb, + 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x9d, 0xff, 0xff, 0xfe, 0xa3, 0x00, 0x00, 0x04, 0x9c, + 0xef, 0xed, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x07, 0xef, 0xd4, 0x5e, 0xff, 0xd4, 0x00, 0x00, 0x00, + 0x01, 0xdd, 0xba, 0xbd, 0xc0, 0x00, 0x00, 0x00, 0x0a, 0xfe, 0x82, 0x00, 0x27, 0xef, 0xe5, 0x00, + 0x00, 0x01, 0xcf, 0xf9, 0x02, 0xcf, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xff, 0xea, 0x66, 0xae, 0xa0, 0x00, 0x01, 0xef, 0xff, + 0x80, 0xf6, 0x00, 0x00, 0x00, 0xc4, 0x00, 0xbf, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0xad, 0xed, 0x94, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xff, 0xff, 0xff, 0xff, + 0x40, 0x0d, 0xc0, 0x00, 0x00, 0x4a, 0xce, 0xd9, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xef, 0xff, 0xff, 0xff, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xbd, 0xdc, 0xa6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0xef, 0xfe, 0xff, 0xe9, 0x10, 0x00, + 0x00, 0x00, 0x05, 0xac, 0xec, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xcd, 0xdb, 0x82, 0x00, 0x00, 0x00, 0x9f, 0xff, + 0xc0, 0xf6, 0x00, 0x00, 0x04, 0xd0, 0x08, 0xff, 0xff, 0xff, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x45, 0x42, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xff, + 0xf6, 0xf6, 0x00, 0x00, 0x1d, 0x50, 0x0c, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xef, + 0xff, 0xf6, 0x00, 0x04, 0xd8, 0x00, 0x0d, 0xff, 0xff, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, + 0xff, 0xfc, 0x67, 0xbe, 0x60, 0x00, 0x06, 0xef, 0xfc, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4c, 0xfe, 0xdb, 0x71, 0x00, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xc0, 0x00, 0x00, 0x03, 0x69, 0xce, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x25, 0x8b, 0xef, 0xe0, 0x00, 0x00, 0x00, 0x02, 0x58, 0xce, 0x03, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xef, 0xe0, 0x05, 0x8b, 0xef, 0xff, 0xff, + 0xff, 0xf0, 0x01, 0x47, 0xbe, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x15, 0x8b, 0xef, 0xff, 0xff, 0x00, + 0x44, 0x44, 0x44, 0x46, 0xef, 0xfb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xfd, 0x40, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xad, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0xfd, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xff, 0xb1, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x3c, 0xfe, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xef, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfe, + 0xb8, 0x50, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xec, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x19, 0xef, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xfe, 0x50, 0x00, 0x00, 0x0f, 0xff, 0xeb, 0x85, 0x20, + 0x00, 0x00, 0x0f, 0xff, 0xfe, 0xc9, 0x63, 0x00, 0x00, 0xff, 0xff, 0xff, 0xec, 0x96, 0x20, 0x00, + 0x05, 0xdf, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xff, 0xc2, 0x00, 0x00, 0x00, 0x09, 0x63, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0d, 0xa7, 0x40, 0x00, 0x00, 0x00, 0x00, 0xff, 0xda, 0x63, 0x00, 0x00, 0x00, 0x01, + 0xbf, 0xfd, 0x64, 0x44, 0x44, 0x44, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x7b, 0xd0, 0x41, 0x00, 0x00, 0x00, 0x01, 0x48, 0x03, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0xfe, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x37, 0xad, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x14, 0x7a, 0xdf, 0xff, 0x01, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1b, 0xff, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x09, 0xce, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x37, 0xad, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xdf, 0xfa, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x6e, 0xfe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0xff, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xda, 0x74, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xa6, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xcf, 0xfb, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0xfe, 0xb7, 0x41, 0x00, 0x00, 0x00, 0xff, 0xff, 0xda, 0x74, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x41, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x8b, 0xef, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x47, 0xae, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xc9, 0x63, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xa7, 0x41, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; diff --git a/rust/pm-ui/src/notation/mod.rs b/rust/pm-ui/src/notation/mod.rs new file mode 100644 index 0000000..e8ac948 --- /dev/null +++ b/rust/pm-ui/src/notation/mod.rs @@ -0,0 +1,633 @@ +//! Drum-notation engine for the device — a faithful port of the web reference `src/notation.js`. +//! +//! `src/notation.js` is the DEBUGGED source of truth for layout (voice->staff map, group-aware +//! beaming, tuplet numerals, ghost parens, accents, flam/drag/roll ornaments, the common-lcm time +//! grid across all lanes incl. polyrhythm, the TUBS box grid, and Konnakol solkattu). This ports the +//! same MATH; the only difference is glyph delivery — the web draws Bravura as a font, the device +//! blits the SAME glyphs from a pre-rasterized atlas (`glyphs.rs` via `atlas::draw_glyph`). +//! +//! Palette choice: LIGHT INK ON DARK, to match the device's other screens (`draw_metronome`). The +//! atlas blit alpha-blends ink over the panel `BG`. (The web uses dark-ink-on-white "paper"; the +//! layout math is identical — only colors differ.) + +mod atlas; +pub mod glyphs; + +use embedded_graphics::{ + mono_font::{ascii::{FONT_6X10, FONT_9X18_BOLD, FONT_10X20}, MonoTextStyle}, + pixelcolor::Rgb565, + prelude::*, + primitives::{Line, PrimitiveStyle, Rectangle}, + text::{Alignment, Text}, +}; + +use crate::{LaneView, Screen}; +use atlas::{advance as gadv, draw_glyph, width as gw}; +use glyphs::{Glyph, STAFF_SPACE}; + +/// Which notation view to render. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum ViewMode { + Staff, + Tubs, + Konnakol, +} + +// ---- palette (light ink on the device's dark panel) ---- +const fn rgb(hex: u32) -> Rgb565 { + Rgb565::new(((hex >> 19) & 0x1F) as u8, ((hex >> 10) & 0x3F) as u8, ((hex >> 3) & 0x1F) as u8) +} +const BG: Rgb565 = rgb(0x06090E); // matches pm-ui BG so the atlas blends cleanly +const INK: Rgb565 = rgb(0xE6ECF3); // staff lines, noteheads, stems, beams +const FAINT: Rgb565 = rgb(0x3A4554); // box outlines / gridlines +const ACCENT: Rgb565 = rgb(0xFF9B2E); // accents +const GHOST: Rgb565 = rgb(0x9A86E0); // ghost notes +const PLAY: Rgb565 = rgb(0x2B7FFF); // playhead + +const S: i32 = STAFF_SPACE; // staff space (px); 1 em = 4 S + +fn gcd(mut a: u32, mut b: u32) -> u32 { + while b != 0 { + let t = b; + b = a % b; + a = t; + } + if a == 0 { + 1 + } else { + a + } +} +fn lcm(a: u32, b: u32) -> u32 { + a / gcd(a, b) * b +} + +/// Voice -> (p, head, stem-up). `p` = half-staff-spaces below the TOP line (top line p=0, each +/// line/space step = 1, bottom line p=8). Ported verbatim from notation.js `voice()`. +struct Voice { + p: i32, + head: Glyph, + up: bool, +} +fn voice(name: &str) -> Voice { + let v = |p, head, up| Voice { p, head, up }; + if name.starts_with("kick") { + v(7, Glyph::NoteheadBlack, false) + } else if name.starts_with("snare") || name.starts_with("clap") || name.starts_with("rim") { + v(3, Glyph::NoteheadBlack, true) + } else if name.starts_with("openHat") || name.starts_with("hatOpen") || name.starts_with("hat") { + v(-1, Glyph::NoteheadX, true) + } else if name.starts_with("ride") { + v(0, Glyph::NoteheadX, true) + } else if name.starts_with("crash") { + v(-3, Glyph::NoteheadX, true) + } else if name.starts_with("tomHigh") { + v(1, Glyph::NoteheadBlack, true) + } else if name.starts_with("tomMid") || name == "tom808" { + v(2, Glyph::NoteheadBlack, true) + } else if name.starts_with("tomLow") || name.starts_with("tom") { + v(5, Glyph::NoteheadBlack, true) + } else if name.starts_with("cowbell") { + v(-1, Glyph::NoteheadCircleX, true) + } else if name.starts_with("claves") || name.starts_with("woodblock") || name.starts_with("jamblock") { + v(1, Glyph::NoteheadX, true) + } else if name.starts_with("tambourine") { + v(-2, Glyph::NoteheadX, true) + } else { + v(3, Glyph::NoteheadBlack, true) + } +} + +/// Digit glyph for a 0..9 value. +fn sig_digit(d: u8) -> Glyph { + // Sig0..Sig9 are contiguous in the enum. + match d { + 0 => Glyph::Sig0, + 1 => Glyph::Sig1, + 2 => Glyph::Sig2, + 3 => Glyph::Sig3, + 4 => Glyph::Sig4, + 5 => Glyph::Sig5, + 6 => Glyph::Sig6, + 7 => Glyph::Sig7, + 8 => Glyph::Sig8, + _ => Glyph::Sig9, + } +} + +fn fmt_u32(mut n: u32, buf: &mut [u8; 12]) -> &str { + if n == 0 { + buf[11] = b'0'; + return core::str::from_utf8(&buf[11..]).unwrap(); + } + let mut i = buf.len(); + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + core::str::from_utf8(&buf[i..]).unwrap() +} + +/// y for a staff position `p` (half-staff-spaces below the top line). +#[inline] +fn y0(staff_top: i32, p: i32) -> i32 { + staff_top + p * S / 2 +} + +fn hline>(d: &mut D, x1: i32, y: i32, x2: i32, c: Rgb565, w: u32) -> Result<(), D::Error> { + Line::new(Point::new(x1, y), Point::new(x2, y)).into_styled(PrimitiveStyle::with_stroke(c, w)).draw(d) +} +fn vline>(d: &mut D, x: i32, y1: i32, y2: i32, c: Rgb565, w: u32) -> Result<(), D::Error> { + Line::new(Point::new(x, y1), Point::new(x, y2)).into_styled(PrimitiveStyle::with_stroke(c, w)).draw(d) +} + +/// Draw a glyph centered horizontally on column `cx`, baseline on staff position `p`. +fn cglyph>(d: &mut D, g: Glyph, cx: i32, staff_top: i32, p: i32, ink: Rgb565) -> Result<(), D::Error> { + draw_glyph(d, g, Point::new(cx - gw(g) / 2, y0(staff_top, p)), ink, BG) +} + +/// Header: track name (left) + big BPM (right). Shared by all views. +fn header>(d: &mut D, name: &str, bpm: i64, w: i32) -> Result<(), D::Error> { + Text::new(name, Point::new(14, 22), MonoTextStyle::new(&FONT_10X20, INK)).draw(d)?; + let mut nb = [0u8; 12]; + Text::with_alignment( + fmt_u32(bpm.max(0) as u32, &mut nb), + Point::new(w - 14, 20), + MonoTextStyle::new(&FONT_9X18_BOLD, ACCENT), + Alignment::Right, + ) + .draw(d)?; + Ok(()) +} + +/// Top-level notation entry; dispatches on `view`. Replaces the old first-pass `draw_notation`. +pub fn draw(d: &mut D, s: &Screen, view: ViewMode) -> Result<(), D::Error> +where + D: DrawTarget, +{ + d.clear(BG)?; + match view { + ViewMode::Staff => draw_staff(d, s), + ViewMode::Tubs => draw_tubs(d, s), + ViewMode::Konnakol => draw_konnakol(d, s), + } +} + +/// Active (unmuted, non-empty) lanes. +fn active<'a>(s: &'a Screen<'a>) -> impl Iterator> { + s.lanes.iter().filter(|l| !l.muted && !l.levels.is_empty()) +} + +/// Common time grid: lcm of ALL active lanes' step counts. +fn grid_res(s: &Screen) -> u32 { + let mut res = 1u32; + for l in active(s) { + res = lcm(res, l.levels.len() as u32); + } + res.max(1) +} + +/// First non-poly lane is the master (defines the meter); its `beats` field is the summed groups. +fn master_groups<'a>(s: &'a Screen<'a>) -> Option<&'a LaneView<'a>> { + active(s).find(|l| !l.poly).or_else(|| active(s).next()) +} + +// =============================== STAFF ==================================== +fn draw_staff(d: &mut D, s: &Screen) -> Result<(), D::Error> +where + D: DrawTarget, +{ + let bb = d.bounding_box(); + let w = bb.size.width as i32; + header(d, s.name, s.bpm, w)?; + + let m = 14; + let clef_w = (glyphs::EM * 6) / 10; // em * 0.6 + let staff_top = 70; + let x1 = w - m; + + // groups: from the master lane. LaneView exposes `groups`; default [4]. + let master = master_groups(s); + let groups: &[u32] = master.map(|l| l.groups).filter(|g| !g.is_empty()).unwrap_or(&[4]); + let beats: u32 = groups.iter().sum::().max(1); + + // time signature reserved width (additive numerator) + let ts_digit = gadv(Glyph::Sig4).max((glyphs::EM * 4) / 10); + let num_parts: &[u32] = if groups.len() > 1 { groups } else { core::slice::from_ref(&beats) }; + let mut num_glyphs = num_parts.len() as i32 - 1; // the '+' separators + for &n in num_parts { + num_glyphs += digits(n); + } + let ts_x = m + clef_w; + let ts_w = num_glyphs.max(1) * ts_digit; + let x0 = ts_x + ts_w + 14; + let bar_w = (x1 - x0).max(1); + + // staff (5 lines) + barlines + for i in 0..5 { + hline(d, m, staff_top + i * S, x1, INK, 1)?; + } + vline(d, m, staff_top, staff_top + 4 * S, INK, 2)?; + vline(d, x1, staff_top, staff_top + 4 * S, INK, 2)?; + // percussion clef centered on middle line (p=4) + cglyph(d, Glyph::Clef, m + clef_w / 2, staff_top, 4, INK)?; + + // time signature: additive numerator over a quarter denominator + draw_sig_row(d, staff_top, ts_x, ts_w, 2, num_parts, ts_digit)?; + draw_sig_row(d, staff_top, ts_x, ts_w, 6, &[4], ts_digit)?; + + let res = grid_res(s); + let beamable = res / beats >= 2; + let head_half = gw(Glyph::NoteheadBlack) / 2; + + let up_tip = staff_top - (S * 26) / 10; // S*2.6 + let dn_tip = staff_top + 4 * S + (S * 26) / 10; + + // beaming carry per stem direction: (stem_x, beat, beam_y) + let mut up_prev: Option<(i32, u32, i32)> = None; + let mut dn_prev: Option<(i32, u32, i32)> = None; + + for c in 0..res { + let cx = x0 + ((2 * c + 1) as i32 * bar_w) / (2 * res as i32); + let beat = c * beats / res; + // accumulators per direction: (lo_p, hi_p, any) + let (mut up_lo, mut up_hi, mut up_any) = (i32::MIN, i32::MAX, false); + let (mut dn_lo, mut dn_hi, mut dn_any) = (i32::MIN, i32::MAX, false); + + for l in active(s) { + let steps = l.levels.len() as u32; + if (c * steps) % res != 0 { + continue; + } + let si = (c * steps / res) as usize; + let lvl = l.levels[si]; + if lvl == 0 { + continue; + } + let orn = l.orns.get(si).copied().unwrap_or(0); + let vc = voice(l.name); + let color = match lvl { + 2 => ACCENT, + 3 => GHOST, + _ => INK, + }; + + // ghost = parenthesized notehead + if lvl == 3 { + cglyph(d, Glyph::ParenL, cx - (S * 85) / 100, staff_top, vc.p, color)?; + } + cglyph(d, vc.head, cx, staff_top, vc.p, color)?; + if lvl == 3 { + cglyph(d, Glyph::ParenR, cx + (S * 85) / 100, staff_top, vc.p, color)?; + } + + // accent mark above/below the staff edge + if lvl == 2 { + let g = if vc.up { Glyph::AccentAbove } else { Glyph::AccentBelow }; + cglyph(d, g, cx, staff_top, if vc.up { -2 } else { 10 }, color)?; + } + + // ornaments: flam = one slashed grace; drag = two; roll = tremolo strokes on the stem + match orn { + 1 => cglyph(d, Glyph::GraceSlash, cx - (S * 14) / 10, staff_top, vc.p, color)?, + 2 => { + cglyph(d, Glyph::GraceSlash, cx - (S * 19) / 10, staff_top, vc.p, color)?; + cglyph(d, Glyph::GraceSlash, cx - (S * 11) / 10, staff_top, vc.p, color)?; + } + 3 => { + let dx = if vc.up { (S * 55) / 100 } else { -(S * 55) / 100 }; + let dp = if vc.up { -2 } else { 2 }; + cglyph(d, Glyph::Trem3, cx + dx, staff_top, vc.p + dp, color)?; + } + _ => {} + } + + // ledger lines above (p<=-2) / below (p>=10) the staff + let mut lp = -2; + while lp >= vc.p { + hline(d, cx - (S * 9) / 10, y0(staff_top, lp), cx + (S * 9) / 10, INK, 1)?; + lp -= 2; + } + let mut lp = 10; + while lp <= vc.p { + hline(d, cx - (S * 9) / 10, y0(staff_top, lp), cx + (S * 9) / 10, INK, 1)?; + lp += 2; + } + + if vc.up { + up_any = true; + up_lo = up_lo.max(vc.p); + up_hi = up_hi.min(vc.p); + } else { + dn_any = true; + dn_lo = dn_lo.max(vc.p); + dn_hi = dn_hi.min(vc.p); + } + } + + // shared up-stem (hands): right side of head + if up_any { + let sx = cx + head_half; + let top = up_tip.min(y0(staff_top, up_hi) - (S * 12) / 10); + vline(d, sx, y0(staff_top, up_lo), top, INK, 1)?; + if beamable { + if let Some((px, pb, _)) = up_prev { + if pb == beat { + // beam: thick segment between previous stem-top and this one + Rectangle::new(Point::new(px.min(sx), top), Size::new((px - sx).unsigned_abs(), 3)) + .into_styled(PrimitiveStyle::with_fill(INK)) + .draw(d)?; + } + } + up_prev = Some((sx, beat, top)); + } else { + up_prev = None; + } + } else { + up_prev = None; + } + // shared down-stem (feet): left side + if dn_any { + let sx = cx - head_half; + let bot = dn_tip.max(y0(staff_top, dn_lo) + (S * 12) / 10); + vline(d, sx, y0(staff_top, dn_hi), bot, INK, 1)?; + if beamable { + if let Some((px, pb, _)) = dn_prev { + if pb == beat { + Rectangle::new(Point::new(px.min(sx), bot - 3), Size::new((px - sx).unsigned_abs(), 3)) + .into_styled(PrimitiveStyle::with_fill(INK)) + .draw(d)?; + } + } + dn_prev = Some((sx, beat, bot)); + } else { + dn_prev = None; + } + } else { + dn_prev = None; + } + } + + // tuplet numeral: common subdivision per beat (3,5,6,7…), printed over each beat when not pow2 + let tup_n = ((res + beats / 2) / beats).max(1); // round(res/beats) + if tup_n >= 3 && (tup_n & (tup_n - 1)) != 0 { + let ty = up_tip - (S * 7) / 10; + let mut nb = [0u8; 12]; + let txt = fmt_u32(tup_n, &mut nb); + for b in 0..beats as i32 { + let tx = x0 + ((2 * b + 1) * bar_w) / (2 * beats as i32); + Text::with_alignment(txt, Point::new(tx, ty), MonoTextStyle::new(&FONT_6X10, INK), Alignment::Center).draw(d)?; + } + } + + // playhead (shifted half a cell so it lands on the note onset, like the web) + if s.playing { + let pf = (s.phase + 0.5 / res as f32).clamp(0.0, 1.0); + let px = x0 + (pf * bar_w as f32) as i32; + vline(d, px, staff_top - S, staff_top + 4 * S + S, PLAY, 2)?; + } + Ok(()) +} + +fn digits(mut n: u32) -> i32 { + if n == 0 { + return 1; + } + let mut c = 0; + while n > 0 { + c += 1; + n /= 10; + } + c +} + +/// One time-signature row: additive numerator parts joined by `+`, centered in width `tw`. +fn draw_sig_row>( + d: &mut D, + staff_top: i32, + tx: i32, + tw: i32, + p: i32, + parts: &[u32], + dw: i32, +) -> Result<(), D::Error> { + // build the glyph sequence length first (digits + separators) + let mut seq_len = parts.len() as i32 - 1; + for &n in parts { + seq_len += digits(n); + } + seq_len = seq_len.max(1); + let mut xx = tx + (tw - seq_len * dw) / 2 + dw / 2; + for (i, &n) in parts.iter().enumerate() { + if i > 0 { + cglyph(d, Glyph::SigPlus, xx, staff_top, p, INK)?; + xx += dw; + } + // digits of n, most significant first + let mut div = 1u32; + while n / div >= 10 { + div *= 10; + } + let mut nn = n; + loop { + let dgt = (nn / div) as u8; + cglyph(d, sig_digit(dgt), xx, staff_top, p, INK)?; + xx += dw; + nn %= div; + if div == 1 { + break; + } + div /= 10; + } + } + Ok(()) +} + +// =============================== TUBS ===================================== +// Rows = voices, columns = time units, filled boxes = hits. All lanes share the common lcm grid so +// columns line up; each lane draws ONE box per real step at its grid column. +fn draw_tubs(d: &mut D, s: &Screen) -> Result<(), D::Error> +where + D: DrawTarget, +{ + let bb = d.bounding_box(); + let w = bb.size.width as i32; + let h = bb.size.height as i32; + header(d, s.name, s.bpm, w)?; + + let lanes: usize = active(s).count(); + if lanes == 0 { + return Ok(()); + } + let m = 14; + let x0 = m + 92; + let x1 = w - m; + let gw_px = (x1 - x0).max(1); + let top = 42; + let bot = h - 12; + let row_h = (((bot - top) / lanes as i32).clamp(20, 40)).max(20); + + let res = grid_res(s); + let cw = gw_px / res as i32; + let bs = (row_h - 8).min(cw - 3).clamp(11, 30); + + let groups: &[u32] = master_groups(s).map(|l| l.groups).filter(|g| !g.is_empty()).unwrap_or(&[4]); + let mbeats: u32 = groups.iter().sum::().max(1); + + let y_a = top - 4; + let y_b = top + lanes as i32 * row_h; + + // beat / group dividers — group starts brighter + let mut starts = [false; 64]; + { + let mut acc = 0usize; + for &g in groups { + if acc < 64 { + starts[acc] = true; + } + acc += g as usize; + } + } + for b in 0..=mbeats { + let lx = x0 + ((b * res / mbeats) as i32) * cw; + let bright = (b < mbeats && (b as usize) < 64 && starts[b as usize]) || b == 0 || b == mbeats; + vline(d, lx, y_a, y_b, if bright { GHOST } else { FAINT }, 1)?; + } + // playhead + if s.playing { + let px = x0 + ((s.phase + 0.5 / res as f32).clamp(0.0, 1.0) * gw_px as f32) as i32; + vline(d, px, y_a, y_b, PLAY, 2)?; + } + + let lbl = MonoTextStyle::new(&FONT_6X10, INK); + for (r, l) in active(s).enumerate() { + let cy = top + r as i32 * row_h + row_h / 2; + Text::new(l.name, Point::new(m, cy + 4), lbl).draw(d)?; + if l.poly { + Text::new("~", Point::new(m + 80, cy + 4), MonoTextStyle::new(&FONT_6X10, GHOST)).draw(d)?; + } + let steps = l.levels.len() as u32; + let span = res / steps; + for i in 0..steps { + let cx = x0 + ((2 * i * span + span) as i32 * cw) / 2; + let lvl = l.levels[i as usize]; + // box outline + Rectangle::new(Point::new(cx - bs / 2, cy - bs / 2), Size::new(bs as u32, bs as u32)) + .into_styled(PrimitiveStyle::with_stroke(FAINT, 1)) + .draw(d)?; + if lvl > 0 { + let col = match lvl { + 2 => ACCENT, + 3 => GHOST, + _ => INK, + }; + let p = (bs * 2) / 10; + Rectangle::new(Point::new(cx - bs / 2 + p, cy - bs / 2 + p), Size::new((bs - 2 * p) as u32, (bs - 2 * p) as u32)) + .into_styled(PrimitiveStyle::with_fill(col)) + .draw(d)?; + // ornament marker letter inside the box + let orn = l.orns.get(i as usize).copied().unwrap_or(0); + if orn > 0 { + let ch = match orn { + 1 => "f", + 2 => "d", + _ => "z", + }; + Text::with_alignment(ch, Point::new(cx, cy + 4), MonoTextStyle::new(&FONT_6X10, BG), Alignment::Center).draw(d)?; + } + } + } + } + Ok(()) +} + +// ============================= KONNAKOL =================================== +// Spoken-rhythm solkattu syllables for the master lane's subdivision (nadai = lcm/beats). +const SOLKATTU: [&[&str]; 9] = [ + &["ta"], // 0 (unused) + &["ta"], // 1 + &["ta", "ka"], // 2 + &["ta", "ki", "ta"], // 3 + &["ta", "ka", "di", "mi"], // 4 + &["ta", "ka", "ta", "ki", "ta"], // 5 + &["ta", "ki", "ta", "ta", "ki", "ta"], // 6 + &["ta", "ka", "ta", "ki", "ta", "ki", "ta"], // 7 + &["ta", "ka", "di", "mi", "ta", "ka", "ju", "nu"], // 8 +]; + +fn draw_konnakol(d: &mut D, s: &Screen) -> Result<(), D::Error> +where + D: DrawTarget, +{ + let bb = d.bounding_box(); + let w = bb.size.width as i32; + let h = bb.size.height as i32; + header(d, s.name, s.bpm, w)?; + + let master = match master_groups(s) { + Some(l) => l, + None => return Ok(()), + }; + let groups: &[u32] = if master.groups.is_empty() { &[4] } else { master.groups }; + let beats: u32 = groups.iter().sum::().max(1); + let res = grid_res(s); + let sub = ((res + beats / 2) / beats).max(1); // nadai (round) + let bols = SOLKATTU[(sub as usize).min(8)]; + + let m = 14; + let x0 = m; + let x1 = w - m; + let gw_px = x1 - x0; + let col_w = gw_px / (beats * sub) as i32; + let cy = h / 2; + + let mut starts = [false; 64]; + { + let mut acc = 0usize; + for &g in groups { + if acc < 64 { + starts[acc] = true; + } + acc += g as usize; + } + } + + let big = MonoTextStyle::new(&FONT_10X20, INK); + let big_acc = MonoTextStyle::new(&FONT_10X20, ACCENT); + let big_ghost = MonoTextStyle::new(&FONT_10X20, GHOST); + let small = MonoTextStyle::new(&FONT_6X10, FAINT); + + for b in 0..beats { + let gs = (b as usize) < 64 && starts[b as usize]; + let sam = b == 0; + let marker = if sam { "X" } else if gs { "O" } else { "." }; + let mx = x0 + ((2 * b * sub + sub) as i32 * col_w) / 2; + Text::with_alignment(marker, Point::new(mx, cy - 22), small, Alignment::Center).draw(d)?; + for sidx in 0..sub { + let idx = b * sub + sidx; + let cx = x0 + ((2 * idx + 1) as i32 * col_w) / 2; + let bol = bols[(sidx as usize) % bols.len()]; + let style = if sam && sidx == 0 { + big_acc + } else if sidx == 0 { + big + } else { + big_ghost + }; + Text::with_alignment(bol, Point::new(cx, cy + 6), style, Alignment::Center).draw(d)?; + } + } + // beat/group dividers + for b in 0..=beats { + let lx = x0 + (b * sub) as i32 * col_w; + let bright = ((b as usize) < 64 && starts[b as usize]) || b == 0 || b == beats; + vline(d, lx, cy - 30, cy + 22, if bright { GHOST } else { FAINT }, 1)?; + } + // footer: tala + nadai + let foot = MonoTextStyle::new(&FONT_6X10, GHOST); + Text::new("tala / nadai", Point::new(m, h - 12), foot).draw(d)?; + let mut nb = [0u8; 12]; + Text::with_alignment(fmt_u32(sub, &mut nb), Point::new(w - 14, h - 12), foot, Alignment::Right).draw(d)?; + Ok(()) +} diff --git a/src/notation.js b/src/notation.js new file mode 100644 index 0000000..88e94f4 --- /dev/null +++ b/src/notation.js @@ -0,0 +1,403 @@ +/* ========================================================================= + PM_E-2 NOTATION ENGINE — inlined into pm_e-2.html by build.sh. + Engraves a groove as a 5-line drum staff onto a 2D , using the + Bravura SMuFL music font (subset inlined via @BUILD:bravura@). The draw API + is deliberately IMMEDIATE-MODE and mirrors embedded-graphics (drawGlyph / + line / rect) so the layout math ports near-mechanically to the device + (rust/pm-ui). Pure view over a normalized model — no engine.js internals. + + model = { + name, bpm, playing, phase, // phase 0..1 across the master bar (playhead) + lanes: [ { sound, groups:[Int], sub, swing, poly, muted, + levels:[0..3], orns:[0..3] } ] // levels: rest/normal/accent/ghost + } + ========================================================================= */ +const NOTATION = (() => { + // SMuFL codepoints (resolved from glyphnames.json by tools/bravura/subset.py — keep in sync). + const GLYPH = { + clef: 0xe069, + black: 0xe0a4, x: 0xe0a9, circleX: 0xe0b3, half: 0xe0a3, whole: 0xe0a2, + parenL: 0xe0f5, parenR: 0xe0f6, + flag8U: 0xe240, flag8D: 0xe241, flag16U: 0xe242, flag16D: 0xe243, + restW: 0xe4e3, restH: 0xe4e4, restQ: 0xe4e5, rest8: 0xe4e6, rest16: 0xe4e7, + accentA: 0xe4a0, accentB: 0xe4a1, dot: 0xe1e7, + sig: [0xe080, 0xe081, 0xe082, 0xe083, 0xe084, 0xe085, 0xe086, 0xe087, 0xe088, 0xe089], + sigPlus: 0xe08c, sigCommon: 0xe08a, sigCut: 0xe08b, + graceAcc: 0xe560, graceSlash: 0xe564, + trem1: 0xe220, trem2: 0xe221, trem3: 0xe222, buzz: 0xe22a, + }; + const chr = (cp) => String.fromCodePoint(cp); + + // Voice -> staff position. `p` = half-staff-spaces below the TOP line (top line p=0, each line/space + // step = 1; bottom line p=8). `head` = notehead glyph; `up` = stem direction (hands up / feet down). + // PAS-style drum key; refined visually in the browser. + function voice(name) { + const s = name || ""; + const F = (p, head, up) => ({ p, head, up }); + if (s.startsWith("kick")) return F(7, "black", false); // bass drum (feet, stem down) + if (s.startsWith("snare") || s.startsWith("clap") || s.startsWith("rim")) return F(3, "black", true); + if (s.startsWith("openHat") || s.startsWith("hatOpen") || s.startsWith("hat")) return F(-1, "x", true); + if (s.startsWith("ride")) return F(0, "x", true); + if (s.startsWith("crash")) return F(-3, "x", true); + if (s.startsWith("tomHigh")) return F(1, "black", true); + if (s.startsWith("tomMid") || s === "tom808") return F(2, "black", true); + if (s.startsWith("tomLow") || s.startsWith("tom")) return F(5, "black", true); + if (s.startsWith("cowbell")) return F(-1, "circleX", true); + if (s.startsWith("claves") || s.startsWith("woodblock") || s.startsWith("jamblock")) return F(1, "x", true); + if (s.startsWith("tambourine")) return F(-2, "x", true); + return F(3, "black", true); + } + + function gcd(a, b) { while (b) { [a, b] = [b, a % b]; } return a || 1; } + function lcm(a, b) { return a / gcd(a, b) * b; } + + // --- palette --- + // The notation panel is engraved like paper: dark ink on a WHITE background, theme-independent + // (matches print sheet music and reads in both page themes). + function palette() { + return { + ink: "#161a1f", // staff lines, noteheads, stems, beams + faint: "#aeb6c0", // box outlines / gridlines / poly-row baseline + accent: "#c0392b", // accents (notehead tint + > mark) — reads on white + ghost: "#7c8794", // ghost notes + play: "#2b7fff", // playhead + bg: "#ffffff", + }; + } + + function draw(canvas, model, opts) { + const view = (model && model.view) || "staff"; + if (view === "tubs") return drawTUBS(canvas, model); + if (view === "konnakol") return drawKonnakol(canvas, model); + opts = opts || {}; + const ctx = canvas.getContext("2d"); + const dpr = window.devicePixelRatio || 1; + const W = canvas.clientWidth, H = canvas.clientHeight; + if (canvas.width !== W * dpr || canvas.height !== H * dpr) { + canvas.width = W * dpr; canvas.height = H * dpr; + } + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); + const pal = palette(); + ctx.clearRect(0, 0, W, H); + + const S = opts.staffSpace || 11; // staff space in px + const em = 4 * S; // SMuFL: 1 em = 4 staff spaces + const y0 = (p) => staffTop + p * (S / 2); // staff-position -> y + ctx.textAlign = "center"; + ctx.textBaseline = "alphabetic"; + + const glyph = (name, x, p, color, scale) => { + const cp = typeof name === "number" ? name : GLYPH[name]; + ctx.fillStyle = color; + ctx.font = (em * (scale || 1)) + "px Bravura"; + // SMuFL glyphs sit on the baseline = the reference staff line; fillText baseline aligns there. + ctx.fillText(chr(cp), x, y0(p)); + }; + const line = (x1, yy1, x2, yy2, color, w) => { + ctx.strokeStyle = color; ctx.lineWidth = w || 1; + ctx.beginPath(); ctx.moveTo(x1, yy1); ctx.lineTo(x2, yy2); ctx.stroke(); + }; + + // geometry + model + const m = 14; + const clefW = em * 0.6; + const x1 = W - m; + const staffTop = 56; + const lanes = (model.lanes || []).filter((l) => !l.muted && l.levels && l.levels.length); + const onStaff = lanes.filter((l) => !l.poly); // first non-poly lane = master (defines the meter) + + const groups = (onStaff[0] && onStaff[0].groups && onStaff[0].groups.length) ? onStaff[0].groups : [4]; + const beats = groups.reduce((a, b) => a + b, 0) || 4; + // time signature: additive numerator (2+2+3) for grouped meters; PM's beat is the quarter -> denom 4. + const tsDigit = em * 0.4; + const numParts = groups.length > 1 ? groups : [beats]; + const numGlyphs = numParts.reduce((a, n) => a + String(n).length, 0) + (numParts.length - 1); + const tsX = m + clefW; + const tsW = Math.max(numGlyphs, 1) * tsDigit; + // notes start clear of the time signature, or at a shared gutter (so all views' beats line up) + const x0 = model.gutter != null ? model.gutter : tsX + tsW + 14; + const barW = Math.max(1, x1 - x0); + + // ---- header: name + BPM ---- + ctx.textAlign = "left"; + ctx.font = "600 15px system-ui, sans-serif"; + ctx.fillStyle = pal.ink; + ctx.fillText(model.name || "", m, 26); + ctx.textAlign = "right"; + ctx.font = "700 18px 'Courier New', monospace"; + ctx.fillStyle = pal.accent; + ctx.fillText((model.bpm | 0) + " BPM", x1, 26); + ctx.textAlign = "center"; + + // ---- staff + barlines + clef + time signature ---- + for (let i = 0; i < 5; i++) line(m, staffTop + i * S, x1, staffTop + i * S, pal.ink, 1); + line(m, staffTop, m, staffTop + 4 * S, pal.ink, 1.5); + line(x1, staffTop, x1, staffTop + 4 * S, pal.ink, 1.5); + glyph("clef", m + clefW * 0.5, 4, pal.ink); // percussion clef centered on middle line (p=4) + + drawTimeSig(tsX, tsW, numParts, tsDigit); + + // ---- time grid: lcm of ALL lanes' step counts (incl. polyrhythm `~` lanes) → the right common + // time scale so every voice, including cross-rhythms, sits on ONE staff at aligned columns ---- + let res = 1; + for (const l of lanes) res = lcm(res, l.levels.length); + res = Math.max(res, 1); + const beamable = res / Math.max(beats, 1) >= 2; // bar has subdivisions → beam within beats + ctx.font = em + "px Bravura"; + const headHalf = ctx.measureText(chr(GLYPH.black)).width / 2; // real notehead half-width → stems touch it + + // beaming state per stem direction (carry previous column's stem x within a beat) + let upPrev = null, dnPrev = null; + const upTip = staffTop - S * 2.6, dnTip = staffTop + 4 * S + S * 2.6; + + for (let c = 0; c < res; c++) { + const cx = x0 + (c + 0.5) * barW / res; + const beat = Math.floor(c * beats / res); + let up = null, dn = null; // {loP, hiP, sub2} accumulators per direction + + for (const l of lanes) { + const steps = l.levels.length; + if ((c * steps) % res !== 0) continue; // no note for this lane at this column + const si = (c * steps / res) | 0; + const lvl = l.levels[si] | 0; + if (!lvl) continue; + const orn = (l.orns && l.orns[si]) | 0; + const vc = voice(l.sound); + const color = lvl === 2 ? pal.accent : lvl === 3 ? pal.ghost : pal.ink; + + // ghost = parenthesized notehead + if (lvl === 3) glyph("parenL", cx - S * 0.85, vc.p, color); + const head = vc.head === "x" ? "x" : vc.head === "circleX" ? "circleX" : "black"; + glyph(head, cx, vc.p, color); + if (lvl === 3) glyph("parenR", cx + S * 0.85, vc.p, color); + + // accent mark above/below the staff edge + if (lvl === 2) glyph(vc.up ? "accentA" : "accentB", cx, vc.up ? -2 : 10, color, 0.8); + + // ornaments: flam = slashed grace note up-left; roll = tremolo strokes on the stem + if (orn === 1) glyph("graceSlash", cx - S * 1.4, vc.p - 0.5, color, 0.7); + else if (orn === 2) { glyph("graceSlash", cx - S * 1.9, vc.p - 0.5, color, 0.7); glyph("graceSlash", cx - S * 1.1, vc.p - 0.5, color, 0.7); } + else if (orn === 3) glyph("trem3", cx + (vc.up ? S * 0.55 : -S * 0.55), vc.p + (vc.up ? -2 : 2), color, 0.8); + + // ledger lines + for (let lp = -2; lp >= vc.p; lp -= 2) line(cx - S * 0.9, y0(lp), cx + S * 0.9, y0(lp), pal.ink, 1); + for (let lp = 10; lp <= vc.p; lp += 2) line(cx - S * 0.9, y0(lp), cx + S * 0.9, y0(lp), pal.ink, 1); + + const sub2 = beamable; + const acc = vc.up ? (up = up || { loP: -99, hiP: 99, sub2: false }) : (dn = dn || { loP: -99, hiP: 99, sub2: false }); + acc.loP = Math.max(acc.loP, vc.p); // lowest (largest p) + acc.hiP = Math.min(acc.hiP, vc.p); // highest (smallest p) + acc.sub2 = acc.sub2 || sub2; + } + + // shared up-stem (hands): right side of head, from lowest head up past the highest + if (up) { + const sx = cx + headHalf; + const top = Math.min(upTip, y0(up.hiP) - S * 1.2); + line(sx, y0(up.loP), sx, top, pal.ink, 1.4); + if (up.sub2 && upPrev && upPrev.beat === beat) line(upPrev.x, top, sx, top, pal.ink, 3); + else if (up.sub2) {} // first of a beam group; flag drawn only if it stays solo (handled below) + upPrev = up.sub2 ? { x: sx, beat, y: top } : null; + } else upPrev = null; + // shared down-stem (feet): left side + if (dn) { + const sx = cx - headHalf; + const bot = Math.max(dnTip, y0(dn.loP) + S * 1.2); + line(sx, y0(dn.hiP), sx, bot, pal.ink, 1.4); + if (dn.sub2 && dnPrev && dnPrev.beat === beat) line(dnPrev.x, bot, sx, bot, pal.ink, 3); + dnPrev = dn.sub2 ? { x: sx, beat, y: bot } : null; + } else dnPrev = null; + } + + // ---- tuplet number: the common subdivision per beat (3=triplet, 6=sextuplet, 5, 7…). For beamed + // groups the modern convention is just the numeral over the beam (no bracket). ---- + const isPow2 = (n) => n > 0 && (n & (n - 1)) === 0; + const tupN = Math.round(res / Math.max(1, beats)); + if (tupN >= 3 && !isPow2(tupN)) { + ctx.fillStyle = pal.ink; ctx.textAlign = "center"; + ctx.font = "italic 600 13px Georgia, 'Times New Roman', serif"; + const ty = upTip - S * 0.7; + for (let b = 0; b < beats; b++) ctx.fillText(String(tupN), x0 + (b + 0.5) * barW / beats, ty); + } + + // ---- playhead ---- + // `phase` is the master-bar fraction (0..1). Noteheads sit at column CENTERS ((c+0.5)/res), so + // shift the line by half a cell to land exactly on the note at its onset instead of leading it. + if (model.playing && model.phase != null) { + const pf = Math.max(0, Math.min(1, model.phase + 0.5 / res)); + const px = x0 + pf * barW; + ctx.save(); ctx.globalAlpha = 0.55; + line(px, staffTop - S, px, staffTop + 4 * S + S, pal.play, 2); + ctx.restore(); + } + + // ---- hit map for on-staff editing (all in CSS px) ---- + // Each on-staff lane exposes its staff row (p) + column geometry; the page maps a click to the + // nearest voice row (y) and the column (x) → (laneIndex, step). `idx` indexes model.lanes/meters. + canvas._hit = { + kind: "staff", staffTop, S, x0, barW, + lanes: lanes.map((l) => ({ idx: l.idx, p: voice(l.sound).p, steps: l.levels.length })), + }; + + // time signature: numerator (additive parts joined by timeSigPlus) over a quarter-note denominator, + // each row centered within the reserved width `tw`. Defined here so it closes over glyph()/em/pal. + function drawTimeSig(tx, tw, parts, dw) { + drawSigRow(tx, tw, 2, parts, dw); // numerator in the upper half of the staff + drawSigRow(tx, tw, 6, [4], dw); // denominator (PM beat = quarter) in the lower half + } + function drawSigRow(tx, tw, p, parts, dw) { + const seq = []; + parts.forEach((n, i) => { + if (i) seq.push(GLYPH.sigPlus); + String(n).split("").forEach((d) => seq.push(GLYPH.sig[+d])); + }); + let xx = tx + (tw - seq.length * dw) / 2 + dw / 2; + for (const cp of seq) { glyph(cp, xx, p, pal.ink, 0.92); xx += dw; } + } + } + + function drawPolyRow(ctx, glyph, line, pal, l, x0, x1, py, S) { + ctx.textAlign = "left"; ctx.font = "11px system-ui, sans-serif"; ctx.fillStyle = pal.ghost; + ctx.fillText(l.sound + " ~", x0, py - S * 1.6); ctx.textAlign = "center"; + line(x0, py, x1, py, pal.faint, 1); + const steps = l.levels.length, barW = x1 - x0; + const vc = voice(l.sound); + for (let i = 0; i < steps; i++) { + const lvl = l.levels[i] | 0; if (!lvl) continue; + const cx = x0 + (i + 0.5) * barW / steps; + const color = lvl === 2 ? pal.accent : lvl === 3 ? pal.ghost : pal.ink; + const head = vc.head === "x" ? "x" : "black"; + ctx.fillStyle = color; ctx.font = (4 * S) + "px Bravura"; + ctx.fillText(chr(vc.head === "x" ? GLYPH.x : GLYPH.black), cx, py); + } + } + + // ---- shared setup for the alternate views ---- + function begin(canvas) { + const ctx = canvas.getContext("2d"); + const dpr = window.devicePixelRatio || 1; + const W = canvas.clientWidth, H = canvas.clientHeight; + if (canvas.width !== W * dpr || canvas.height !== H * dpr) { canvas.width = W * dpr; canvas.height = H * dpr; } + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); + ctx.clearRect(0, 0, W, H); + return { ctx, W, H, pal: palette() }; + } + function header(ctx, W, model, pal) { + ctx.textAlign = "left"; ctx.font = "600 15px system-ui, sans-serif"; ctx.fillStyle = pal.ink; + ctx.fillText(model.name || "", 14, 26); + ctx.textAlign = "right"; ctx.font = "700 18px 'Courier New', monospace"; ctx.fillStyle = pal.accent; + ctx.fillText((model.bpm | 0) + " BPM", W - 14, 26); + ctx.textAlign = "center"; + } + // Son/rumba clave fingerprint: split the bar in half, count hits each side → 2-3 or 3-2. + function claveLabel(l) { + if (!/^clave/.test(l.sound || "")) return ""; + const n = l.levels.length, h = n >> 1; + if (!h) return "(clave)"; + const a = l.levels.slice(0, h).filter((v) => v > 0).length; + const b = l.levels.slice(h).filter((v) => v > 0).length; + return a === 2 && b === 3 ? "(2-3)" : a === 3 && b === 2 ? "(3-2)" : "(clave)"; + } + + // ---- TUBS (Time Unit Box System): rows = voices, columns = time units, filled boxes = hits ---- + // All bar-sharing lanes are drawn on ONE common time grid (lcm of their step counts) so every + // column lines up vertically across rows; a coarser lane just fills every Nth cell. Polymeter + // lanes keep their own spacing across the full width (that IS the cross-rhythm). + function drawTUBS(canvas, model) { + const { ctx, W, H, pal } = begin(canvas); + header(ctx, W, model, pal); + const lanes = (model.lanes || []).filter((l) => !l.muted && l.levels && l.levels.length); + if (!lanes.length) { canvas._hit = null; return; } + const m = 14, x0 = model.gutter != null ? model.gutter : m + 96, x1 = W - m, gw = Math.max(1, x1 - x0); + const top = 42, bot = H - 12; + const rowH = Math.min(40, Math.max(20, (bot - top) / lanes.length)); + + // common grid = lcm of ALL lanes' step counts so columns line up; each lane draws ONE box per + // REAL step at its grid column → aligned AND each box is a clickable step. + let res = 1; for (const l of lanes) res = lcm(res, l.levels.length); + res = Math.max(res, 1); + const cw = gw / res, bs = Math.max(11, Math.min(rowH - 8, cw - 3, 30)); + const master = lanes.find((l) => !l.poly) || lanes[0]; + const mg = master.groups && master.groups.length ? master.groups : [4]; + const mbeats = mg.reduce((a, b) => a + b, 0) || 1; + const starts = new Set(); let acc = 0; for (const g of mg) { starts.add(acc); acc += g; } + const yA = top - 4, yB = top + lanes.length * rowH; + + // beat / group dividers (group starts brighter) + for (let b = 0; b <= mbeats; b++) { + const lx = x0 + (b * res / mbeats) * cw; + ctx.strokeStyle = (b < mbeats && starts.has(b)) || b === 0 || b === mbeats ? pal.ghost : pal.faint; + ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(lx, yA); ctx.lineTo(lx, yB); ctx.stroke(); + } + // playhead column (aligned to box centers like the staff) + if (model.playing && model.phase != null) { + const px = x0 + Math.max(0, Math.min(1, model.phase + 0.5 / res)) * gw; + ctx.save(); ctx.globalAlpha = 0.5; ctx.strokeStyle = pal.play; ctx.lineWidth = 2; + ctx.beginPath(); ctx.moveTo(px, yA); ctx.lineTo(px, yB); ctx.stroke(); ctx.restore(); + } + + const rows = []; + lanes.forEach((l, r) => { + const cy = top + r * rowH + rowH / 2; + ctx.textAlign = "left"; ctx.font = "12px system-ui, sans-serif"; ctx.fillStyle = pal.ink; + ctx.fillText(l.sound + (l.poly ? " ~" : "") + (claveLabel(l) ? " " + claveLabel(l) : ""), m, cy + 4); + const steps = l.levels.length, span = res / steps; + rows.push({ idx: l.idx, steps, span }); + for (let i = 0; i < steps; i++) { + const cx = x0 + (i * span + 0.5) * cw, lvl = l.levels[i] | 0; + ctx.strokeStyle = pal.faint; ctx.lineWidth = 1; ctx.strokeRect(cx - bs / 2, cy - bs / 2, bs, bs); + if (lvl > 0) { + ctx.fillStyle = lvl === 2 ? pal.accent : lvl === 3 ? pal.ghost : pal.ink; + const p = bs * 0.2; ctx.fillRect(cx - bs / 2 + p, cy - bs / 2 + p, bs - 2 * p, bs - 2 * p); + const orn = (l.orns && l.orns[i]) | 0; // flam/drag/roll marker inside the box + if (orn) { ctx.fillStyle = pal.bg; ctx.font = "700 9px system-ui, sans-serif"; ctx.textAlign = "center"; ctx.fillText(orn === 1 ? "f" : orn === 2 ? "d" : "z", cx, cy + 3.5); ctx.textAlign = "left"; } + } + } + }); + // hit map for editing: click a box to cycle dynamic; Shift-click cycles ornament + canvas._hit = { kind: "tubs", x0, cw, top, rowH, rows }; + } + + // ---- Konnakol: spoken-rhythm syllables (solkattu) for the master lane's subdivision ---- + const SOLKATTU = { + 1: ["ta"], 2: ["ta", "ka"], 3: ["ta", "ki", "ta"], 4: ["ta", "ka", "di", "mi"], + 5: ["ta", "ka", "ta", "ki", "ta"], 6: ["ta", "ki", "ta", "ta", "ki", "ta"], + 7: ["ta", "ka", "ta", "ki", "ta", "ki", "ta"], 8: ["ta", "ka", "di", "mi", "ta", "ka", "ju", "nu"], + }; + function drawKonnakol(canvas, model) { + const { ctx, W, H, pal } = begin(canvas); + canvas._hit = null; + header(ctx, W, model, pal); + const lanes = (model.lanes || []).filter((l) => !l.muted && l.levels && l.levels.length); + const m0 = lanes.find((l) => !l.poly) || lanes[0]; + if (!m0) return; + const groups = m0.groups && m0.groups.length ? m0.groups : [4]; + const beats = groups.reduce((a, b) => a + b, 0) || 1; + let res = 1; for (const l of lanes) res = lcm(res, l.levels.length); // common (finest) grid + const sub = Math.max(1, Math.round(res / beats)); // nadai = subdivisions per beat + const bols = SOLKATTU[sub] || SOLKATTU[4]; + const m = 14, x0 = model.gutter != null ? model.gutter : m, x1 = W - m, gw = x1 - x0, colW = gw / (beats * sub), cy = H / 2; + const starts = new Set(); let acc = 0; for (const g of groups) { starts.add(acc); acc += g; } + ctx.textAlign = "center"; + for (let b = 0; b < beats; b++) { + const gs = starts.has(b), sam = b === 0; + ctx.font = "10px system-ui, sans-serif"; ctx.fillStyle = pal.faint; + ctx.fillText(sam ? "X" : gs ? "O" : "·", x0 + (b * sub + 0.5) * colW, cy - 22); // sam / anga / beat + for (let s = 0; s < sub; s++) { + const idx = b * sub + s, cx = x0 + (idx + 0.5) * colW; + ctx.font = (s === 0 ? "600 " : "") + "16px system-ui, sans-serif"; + ctx.fillStyle = sam && s === 0 ? pal.accent : s === 0 ? pal.ink : pal.ghost; + ctx.fillText(bols[s % bols.length], cx, cy + 6); + } + } + for (let b = 0; b <= beats; b++) { // beat/group dividers + const lx = x0 + b * sub * colW; + ctx.strokeStyle = starts.has(b) || b === 0 || b === beats ? pal.ghost : pal.faint; + ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(lx, cy - 30); ctx.lineTo(lx, cy + 22); ctx.stroke(); + } + ctx.textAlign = "left"; ctx.font = "11px system-ui, sans-serif"; ctx.fillStyle = pal.ghost; + ctx.fillText("tala " + groups.join("+") + " · nadai " + sub + " · X=sam O=anga", m, H - 12); + } + + return { draw, GLYPH, voice }; +})();