Add untracked notation deliverables (build/compile depend on these)

- src/notation.js — web notation engine inlined into pm_e-2.html (@BUILD:include)
- rust/pm-ui/src/notation/ — the notation module pm-ui/lib.rs imports
- rust/glyphgen/ + rust/assets/bravura/ (Bravura.otf + OFL.txt) — host atlas generator + font src
- rust/Cargo.toml (workspace) + rust/.gitignore
- assets/bravura.woff2.b64 (web font subset, @BUILD:bravura@) + info-pm_e-2.html

Without these a clean checkout couldn't build pm_e-2.html or compile pm-ui. (Left hardware/eda
make_svg* + kicad/_svgtest.json untracked — unrelated scratch.)
This commit is contained in:
Me Here 2026-06-02 13:46:45 -05:00
parent cb54b4d689
commit 5dcef691c1
13 changed files with 2407 additions and 0 deletions

1
assets/bravura.woff2.b64 Normal file

File diff suppressed because one or more lines are too long

74
info-pm_e-2.html Normal file
View file

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>VARASYS PM_E2 PolyMeter Editor (Notation) — what it is</title>
<meta name="description" content="PM_E2 PolyMeter Editor — the second-generation web workbench built around proper engraved drum notation: a 5-line percussion staff in the Bravura (SMuFL) music font, with Staff / TUBS / Konnakol views, edit-on-staff, and the full vocabulary — accents, ghosts, flams, drags, rolls, odd meters, polyrhythm and clave. Same share-language program string as every form factor." />
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,@BUILD:favicon@">
<script>
(function(){ try{ var p = localStorage.getItem("metronome.theme");
if (p!=="light" && p!=="dark" && p!=="system") p = "system";
document.documentElement.dataset.theme = p==="system" ? (matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark") : p;
} catch(e){ document.documentElement.dataset.theme = "dark"; } })();
</script>
<style>
/*@BUILD:include:src/base.css@*/
:root{ --bg1:#12151c; --bg2:#05070a; --txt:#c7d0db; --muted:#7f8b9a; --link:#6cb6ff;
--panel-bg:#161b22; --panel-bd:#2a313c; --field-bg:#0e1116; --field-bd:#2a313c; --silk:#aab2bc; }
:root[data-theme="light"]{ --bg1:#f5f8fc; --bg2:#dde4ec; --txt:#1e2630; --muted:#5c6776; --link:#1769c4;
--panel-bg:#ffffff; --panel-bd:#d2dae4; --field-bg:#f1f4f8; --field-bd:#d2dae4; }
body{ margin:0; min-height:100vh; padding:22px 16px 56px; color:var(--txt);
background:radial-gradient(circle at 50% -8%, var(--bg1), var(--bg2)); }
a{ color:var(--link); }
main{ width:100%; max-width:980px; margin:0 auto; }
.info-hero{ text-align:center; padding:16px 8px 2px; }
.info-hero h1{ font-size:clamp(24px,5vw,36px); margin:0; letter-spacing:-.01em; }
.info-hero .sub{ margin:9px auto 0; max-width:64ch; font-size:14.5px; }
</style>
</head>
<body>
/*@BUILD:include:src/header.html@*/
<main>
<section class="info-hero">
<h1>PM_E2 PolyMeter Editor — Notation</h1>
<p class="sub">The second-generation editor, built around <b>proper engraved drum notation</b>. Design a groove and read it as a real percussion staff — the same program string still plays identically on every form factor.</p>
</section>
/*@BUILD:include:src/infoembed.html@*/
<section class="about">
<h2>What it is</h2>
<div class="ff-tags"><span>Web app</span><span>Engraved notation</span><span>Runs in any browser</span></div>
<p>Where the first-generation <a href="/info-editor.html">PM_E1 editor</a> is built around a step-pad grid,
<b>PM_E2 is built around notation</b>. Grooves render on a 5-line percussion staff engraved with the
<b>Bravura</b> music font (the open <a href="https://www.smufl.org/" target="_blank" rel="noopener">SMuFL</a>
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, <b>accents</b>, <b>ghost notes</b> in parentheses, and the full
ornament vocabulary — <b>flams, drags and rolls</b>. You can <b>edit directly on the staff</b>: click a step to
cycle its dynamic, Shift-click to cycle its ornament.</p>
<p>Three views share one engine: the <b>Staff</b>, a <b>TUBS</b> grid (Time Unit Box System — the clearest way to
read odd meters, polyrhythms and West-African bell patterns at a glance), and a <b>Konnakol</b> syllable view
(South-Indian solkattu — “ta&nbsp;ka&nbsp;di&nbsp;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.</p>
<p>Everything you design saves to the same compact <b>program string</b> 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.</p>
</section>
<p class="sub" style="max-width:760px;margin:14px auto 0">Embed the editor (or any device) elsewhere with one <code>&lt;div&gt;</code> + a script —
see <a href="/embed.html">the embed docs</a>.</p>
</main>
/*@BUILD:include:src/footer.html@*/
<script>
const APP_VERSION = "v0.0.1-dev";
window.INFO_DEVICE = { file:"/pm_e-2.html", name:"PM_E2 PolyMeter Editor" };
/*@BUILD:include:src/infoembed.js@*/
/*@BUILD:include:src/chrome.js@*/
</script>
</body>
</html>

5
rust/.gitignore vendored Normal file
View file

@ -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

15
rust/Cargo.toml Normal file
View file

@ -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.

Binary file not shown.

View file

@ -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.

2
rust/glyphgen/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
target/
Cargo.lock

8
rust/glyphgen/Cargo.toml Normal file
View file

@ -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"

254
rust/glyphgen/src/main.rs Normal file
View file

@ -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<u8>,
}
let mut rasters: Vec<Raster> = 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<Packed> = 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()
);
}

View file

@ -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>(d: &mut D, glyph: Glyph, origin: Point, ink: Rgb565, bg: Rgb565) -> Result<(), D::Error>
where
D: DrawTarget<Color = Rgb565>,
{
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
}

View file

@ -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,
];

View file

@ -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: DrawTarget<Color = Rgb565>>(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: DrawTarget<Color = Rgb565>>(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: DrawTarget<Color = Rgb565>>(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: DrawTarget<Color = Rgb565>>(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>(d: &mut D, s: &Screen, view: ViewMode) -> Result<(), D::Error>
where
D: DrawTarget<Color = Rgb565>,
{
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<Item = &'a LaneView<'a>> {
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>(d: &mut D, s: &Screen) -> Result<(), D::Error>
where
D: DrawTarget<Color = Rgb565>,
{
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::<u32>().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: DrawTarget<Color = Rgb565>>(
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>(d: &mut D, s: &Screen) -> Result<(), D::Error>
where
D: DrawTarget<Color = Rgb565>,
{
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::<u32>().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>(d: &mut D, s: &Screen) -> Result<(), D::Error>
where
D: DrawTarget<Color = Rgb565>,
{
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::<u32>().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(())
}

403
src/notation.js Normal file
View file

@ -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 <canvas>, 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 };
})();