Drop the QR-code share button, its external-service warning banner/CSS, and the api.qrserver.com handler — sharing is now copy/open link only, so the app makes no external requests at all. README: remove QR references and the Deploy section, refresh Features/sounds/dynamics/swing, list the 808/909 voices, and note which acoustic voices use CC0 samples. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1508 lines
245 KiB
HTML
1508 lines
245 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Stackable Metronome — Mockup</title>
|
||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiByeD0iNyIgZmlsbD0iIzFDMjgzRiIvPjxwYXRoIGQ9Ik0xMiA2aDhsNCAyMUg4eiIgZmlsbD0iIzBBQjNGNyIvPjxwYXRoIGQ9Ik0xNiAyNEwxOS42IDkiIHN0cm9rZT0iIzFDMjgzRiIgc3Ryb2tlLXdpZHRoPSIxLjgiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgZmlsbD0ibm9uZSIvPjxyZWN0IHg9IjE2LjQiIHk9IjEzLjIiIHdpZHRoPSI0LjQiIGhlaWdodD0iMi44IiByeD0iMC42IiB0cmFuc2Zvcm09InJvdGF0ZSgtMTMgMTguNiAxNC42KSIgZmlsbD0iIzFDMjgzRiIvPjwvc3ZnPgo=">
|
||
<script>
|
||
// Set theme before first paint (avoids a flash). Preference is system|light|dark
|
||
// (default system → follows the OS); "system" resolves to the OS scheme here.
|
||
(function () {
|
||
try {
|
||
var p = localStorage.getItem("metronome.theme");
|
||
if (p !== "light" && p !== "dark" && p !== "system") p = "system";
|
||
var eff = p === "system" ? (matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark") : p;
|
||
document.documentElement.dataset.theme = eff;
|
||
} catch (e) { document.documentElement.dataset.theme = "dark"; }
|
||
})();
|
||
</script>
|
||
<!--
|
||
Stackable Metronome — a polymetric groove trainer / metronome.
|
||
Copyright (C) 2026 Varasys
|
||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||
|
||
This program is free software: you can redistribute it and/or modify it
|
||
under the terms of the GNU Affero General Public License as published by
|
||
the Free Software Foundation, either version 3 of the License, or (at your
|
||
option) any later version. It is distributed WITHOUT ANY WARRANTY; without
|
||
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||
PURPOSE. See the GNU Affero General Public License for more details. You
|
||
should have received a copy of the license along with this program (see the
|
||
LICENSE file); if not, see <https://www.gnu.org/licenses/>.
|
||
-->
|
||
<!--
|
||
Browser mockup / simulator for the Pi Pico metronome.
|
||
|
||
DESIGN: a basic metronome (tempo / volume / start-stop) PLUS an arbitrary
|
||
number of "meter lanes". Each lane is its own little metronome with a
|
||
grouping (e.g. 2+2+3), a subdivision, and a sound. All lanes share the global
|
||
tempo; layering lanes with different groupings/subdivisions is what creates
|
||
polymeter / polyrhythm — no special "voice" or ratio mode required.
|
||
|
||
Functions marked PORTS TO FIRMWARE carry over to the RP2040 with little change.
|
||
Web Audio's look-ahead scheduler stands in for the hardware timer.
|
||
-->
|
||
<style>
|
||
:root {
|
||
--bg:#14171c; --bg2:#1b212b; --panel:#1d222b; --panel-2:#242b36; --edge:#333d4b;
|
||
--txt:#c7d0db; --muted:#7f8b9a; --hot:#ffd166; --led-off:#2b323d; --ring:#ffffff;
|
||
}
|
||
:root[data-theme="light"] {
|
||
--bg:#e9edf2; --bg2:#f6f8fb; --panel:#ffffff; --panel-2:#eef2f7; --edge:#d2dae4;
|
||
--txt:#1e2630; --muted:#5c6776; --hot:#a9760a; --led-off:#cdd6e0; --ring:#16202c;
|
||
}
|
||
* { box-sizing: border-box; }
|
||
body {
|
||
margin:0; padding:24px; min-height:100vh;
|
||
background: radial-gradient(circle at 50% -10%, var(--bg2), var(--bg));
|
||
color: var(--txt); font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
h1 { font-size:18px; font-weight:600; letter-spacing:.5px; margin:0 0 2px; }
|
||
.sub { color:var(--muted); font-size:12px; margin-bottom:18px; }
|
||
.kbd-legend { color:var(--muted); font-size:13px; font-family:"Courier New",monospace; text-align:right; }
|
||
#app { display:flex; gap:18px; max-width:1400px; margin:0 auto; align-items:flex-start; justify-content:center; }
|
||
.device { flex:1 1 auto; min-width:0; max-width:1000px; background:linear-gradient(180deg, var(--panel), var(--bg));
|
||
border:1px solid var(--edge); border-radius:16px; padding:18px; box-shadow:0 18px 50px rgba(0,0,0,.5); }
|
||
.row { display:flex; gap:18px; flex-wrap:wrap; }
|
||
.card { background:var(--panel-2); border:1px solid var(--edge); border-radius:12px; padding:13px; flex:1; min-width:240px; }
|
||
.card h2 { font-size:11px; text-transform:uppercase; letter-spacing:1.4px; color:var(--muted); margin:0 0 14px; }
|
||
.display { background:#0a0d11; border:1px solid #000; border-radius:8px; padding:8px 14px; text-align:center; box-shadow:inset 0 2px 10px rgba(0,0,0,.7); }
|
||
.display .big { font-family:"Courier New",monospace; font-weight:700; font-size:80px; color:#ffd166; letter-spacing:2px; line-height:1.0; text-shadow:0 0 12px rgba(255,209,102,.5); }
|
||
.display .dtimers { font-family:"Courier New",monospace; font-size:26px; color:#4dd0e1; margin:6px 0; display:flex; gap:18px; justify-content:center; flex-wrap:wrap; }
|
||
.display .dtimers[hidden] { display:none; }
|
||
.display .ctx { font-family:"Courier New",monospace; font-size:19px; color:#4dd0e1; min-height:22px; line-height:1.25; }
|
||
.display .ctx.muted-cue { color:#ffb454; }
|
||
.knob { margin-bottom:10px; }
|
||
.knob label { display:flex; justify-content:space-between; font-size:12px; margin-bottom:5px; }
|
||
.knob label b { color:#fff; font-variant-numeric:tabular-nums; }
|
||
input[type=range] { width:100%; accent-color:var(--hot); }
|
||
.btnrow { display:flex; gap:10px; flex-wrap:wrap; }
|
||
/* VARASYS brand lockup — show the tagline variant that matches the theme */
|
||
.brand-logo { height:40px; width:auto; display:block; }
|
||
.brand-light { display:none; }
|
||
:root[data-theme="light"] .brand-dark { display:none; }
|
||
:root[data-theme="light"] .brand-light { display:block; }
|
||
button { background:var(--panel); color:var(--txt); border:1px solid var(--edge); border-radius:8px; padding:9px 14px; font-size:13px; cursor:pointer; transition:.12s; }
|
||
button:hover { border-color:var(--muted); }
|
||
button.primary { background:#2e7d32; border-color:#2e7d32; color:#fff; font-weight:600; }
|
||
button.primary.on { background:#c0392b; border-color:#c0392b; }
|
||
button.add { background:#2c3a4d; border-color:#3b5168; color:#cfe3ff; font-weight:600; }
|
||
.seg { display:inline-flex; border:1px solid var(--edge); border-radius:8px; overflow:hidden; }
|
||
.seg button { border:none; border-radius:0; padding:8px 10px; }
|
||
.seg button.active { background:var(--hot); color:#000; }
|
||
input[type=text].txt { background:var(--panel); color:var(--txt); border:1px solid var(--edge); border-radius:8px; padding:8px; font-size:13px; font-family:"Courier New",monospace; }
|
||
.checkrow, .mini-check { display:flex; align-items:center; gap:8px; font-size:13px; }
|
||
.mini-check { color:var(--muted); }
|
||
/* LED strip */
|
||
.strip { display:flex; gap:6px; flex-wrap:wrap; }
|
||
.led { width:30px; height:30px; border-radius:7px; background:var(--led-off); border:1px solid #000; position:relative;
|
||
display:flex; align-items:center; justify-content:center; font-size:9px; color:#4a5562; cursor:default; transition:background .04s, box-shadow .04s; }
|
||
.led.on { background:var(--lc,#888); box-shadow:0 0 8px var(--lc); color:rgba(0,0,0,.55); }
|
||
.led.accent { box-shadow:0 0 4px #fff, 0 0 14px var(--lc); }
|
||
.led.accent::after { content:"▲"; position:absolute; top:-1px; font-size:7px; color:#fff; }
|
||
.led.ghost { opacity:.4; box-shadow:none; } /* ghost note — lit but faint */
|
||
.led.ghost::after { content:"·"; position:absolute; top:-4px; font-size:13px; color:#fff; }
|
||
.led.playhead { outline:2px solid var(--ring); outline-offset:1px; }
|
||
.led.sub { width:20px; height:20px; opacity:.9; } /* subdivision step — smaller than a downbeat */
|
||
.led.beatstart { margin-left:11px; } /* extra gap between beats within a group */
|
||
.led.groupstart { margin-left:16px; }
|
||
.led.groupstart::before { content:""; position:absolute; left:-9px; top:4px; bottom:4px; width:2px; background:var(--muted); }
|
||
/* meter lanes — compact single-row controls + strip */
|
||
#meters { display:flex; flex-direction:column; gap:10px; }
|
||
.meter-card { background:var(--panel-2); border:1px solid var(--edge); border-radius:12px; padding:9px 14px; }
|
||
.lane-row { display:flex; gap:9px; align-items:center; flex-wrap:wrap; margin-bottom:0; }
|
||
.lane-row .strip { margin-left:4px; }
|
||
.lane-title { font-weight:700; font-size:13px; min-width:28px; }
|
||
.txt.grp { width:80px; text-align:center; }
|
||
.sum { font-family:"Courier New",monospace; font-size:12px; color:var(--muted); min-width:24px; }
|
||
.bar { font-family:"Courier New",monospace; font-size:12px; color:var(--hot); min-width:46px; text-align:right; }
|
||
.cmp { background:var(--panel); color:var(--txt); border:1px solid var(--edge); border-radius:8px; padding:7px 8px; font-size:12px; }
|
||
.meter-card .led { width:26px; height:26px; border-radius:6px; }
|
||
.meter-card .led.sub { width:17px; height:17px; }
|
||
.x { background:transparent; border:1px solid var(--edge); color:var(--muted); padding:4px 9px; border-radius:7px; margin-left:auto; }
|
||
.x:hover { color:#ff9a8a; border-color:#c0392b; }
|
||
.hint { font-size:11px; color:var(--muted); margin-top:8px; }
|
||
code { background:#0d1014; padding:1px 5px; border-radius:4px; color:#cfe3ff; }
|
||
.ex-item { display:flex; gap:8px; align-items:center; padding:7px 9px; border:1px solid var(--edge); border-radius:8px; margin-bottom:6px; font-size:13px; background:var(--panel); cursor:pointer; }
|
||
.ex-item:hover { border-color:var(--muted); }
|
||
.ex-item.active { border-color:#2e7d32; box-shadow:inset 3px 0 0 #2e7d32; } /* loaded / playing */
|
||
.ex-item.cued { outline:2px solid #ffb454; outline-offset:-2px; } /* cue cursor (coexists with .active) */
|
||
.ex-item .nm { flex:1; }
|
||
.ex-item .meta { color:var(--muted); font-family:"Courier New",monospace; font-size:11px; }
|
||
.ex-item .row-actions { display:none; gap:4px; }
|
||
.ex-item.active .row-actions, .ex-item:hover .row-actions { display:inline-flex; }
|
||
.nowplaying { background:var(--panel); border:1px solid var(--edge); border-radius:10px; padding:10px 12px; margin-bottom:12px; }
|
||
.np-label { font-size:10px; letter-spacing:1.4px; color:var(--muted); text-transform:uppercase; }
|
||
.np-name { font-size:16px; font-weight:600; margin:2px 0; }
|
||
.np-sub { font-size:12px; color:var(--muted); font-family:"Courier New",monospace; word-break:break-word; }
|
||
.np-desc { font-size:12px; color:var(--muted); margin-top:4px; }
|
||
.iconbtn { padding:3px 8px; font-size:12px; }
|
||
.log-item { padding:8px 10px; border:1px solid var(--edge); border-radius:8px; margin-bottom:6px; background:var(--panel); }
|
||
.log-head { font-weight:600; font-size:13px; margin-bottom:5px; display:flex; align-items:center; gap:8px; }
|
||
.log-head-nm { flex:1; }
|
||
.hist-row { display:flex; align-items:center; gap:6px; margin:2px 0 0 12px; }
|
||
.hist-txt { flex:1; font-size:12px; color:var(--muted); font-family:"Courier New",monospace; }
|
||
.hist-del { display:none; background:transparent; border:none; color:#ff6b5e; cursor:pointer; font-size:12px; line-height:1; padding:2px 4px; border-radius:4px; }
|
||
.hist-del:hover { background:rgba(255,107,94,.15); }
|
||
.hist-row:hover .hist-del, .hist-row:focus-within .hist-del { display:inline; }
|
||
.practice { border-top:1px solid var(--edge); margin-top:16px; padding-top:4px; }
|
||
/* set-list panel: always shown — sticky beside the metronome on desktop,
|
||
stacks below it on narrow screens */
|
||
#routineTray { flex:0 0 340px; align-self:flex-start; position:sticky; top:18px;
|
||
max-height:calc(100vh - 36px); overflow:auto; background:linear-gradient(180deg, var(--panel), var(--bg));
|
||
border:1px solid var(--edge); border-radius:14px; padding:16px; box-shadow:0 10px 30px rgba(0,0,0,.25); }
|
||
.tval { font-family:"Courier New",monospace; font-size:inherit; color:var(--hot); min-width:64px; }
|
||
.tval.low { color:#ffb454; }
|
||
.tval.over { color:#ff7b6b; }
|
||
@media (max-width: 820px) {
|
||
#app { display:block; }
|
||
#routineTray { position:static; max-height:none; width:auto; margin-top:18px; }
|
||
}
|
||
.tray-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:14px; }
|
||
.practice-col { border-left:1px solid var(--edge); padding-left:18px; }
|
||
.fbox { border:1px solid var(--edge); border-radius:10px; padding:9px 11px; margin-bottom:10px; transition:border-color .15s, background .15s; }
|
||
.fbox .fhead { display:flex; align-items:center; gap:8px; }
|
||
.fbox .ftitle { font-weight:600; font-size:12px; }
|
||
.fbox .fbody { margin-top:8px; }
|
||
.fbox.on { border-color:#2e7d32; background:rgba(46,125,50,.12); }
|
||
.fbox.toggleable:not(.on) .fbody { display:none; } /* hide a feature's parameters until it's enabled */
|
||
.lane-enable { accent-color:#2e7d32; margin:0 2px; cursor:pointer; }
|
||
.lane-row.lane-off { opacity:.5; }
|
||
#themeBtn, #helpBtn { padding:4px 11px; }
|
||
/* --- responsive --- */
|
||
@media (max-width: 760px) {
|
||
body { padding: 12px; }
|
||
.device { padding: 13px; border-radius:12px; }
|
||
.row { gap: 14px; }
|
||
/* when the practice column wraps under the others, swap its side rule for a top one */
|
||
.practice-col { border-left:none; padding-left:0; border-top:1px solid var(--edge); padding-top:12px; margin-top:4px; }
|
||
}
|
||
@media (max-width: 620px) {
|
||
.kbd-legend { display:none; } /* the ? overlay covers discovery on small screens */
|
||
#routineTray { width:100%; }
|
||
.meter-card .led { width:24px; height:24px; }
|
||
}
|
||
.num { width:54px; background:var(--panel); color:var(--txt); border:1px solid var(--edge); border-radius:8px; padding:6px 6px; font-size:13px; text-align:center; }
|
||
#helpBtn { padding:4px 11px; }
|
||
.overlay { position:fixed; inset:0; background:rgba(0,0,0,.55); display:flex; align-items:center; justify-content:center; z-index:80; }
|
||
.overlay[hidden] { display:none; }
|
||
.overlay-box { background:var(--panel-2); border:1px solid var(--edge); border-radius:14px; padding:16px 20px; width:380px; max-width:92vw; box-shadow:0 20px 60px rgba(0,0,0,.6); }
|
||
#shareUrl { width:100%; resize:vertical; background:var(--panel); color:var(--txt); border:1px solid var(--edge); border-radius:8px; padding:8px; font-family:"Courier New",monospace; font-size:12px; }
|
||
.help-about { margin-top:14px; padding-top:12px; border-top:1px solid var(--edge); font-size:12px; color:var(--muted); line-height:1.45; }
|
||
.help-about p { margin:0 0 8px; }
|
||
.help-about p:last-child { margin-bottom:0; }
|
||
.help-about a { color:#6cb6ff; }
|
||
.kbd-table { width:100%; border-collapse:collapse; font-size:13px; }
|
||
.kbd-table td { padding:6px 4px; border-bottom:1px solid var(--edge); }
|
||
.kbd-table tr:last-child td { border-bottom:none; }
|
||
.kbd-table td:first-child { width:100px; white-space:nowrap; }
|
||
kbd { background:var(--panel); border:1px solid var(--edge); border-bottom-width:2px; border-radius:5px; padding:2px 7px; font-family:"Courier New",monospace; font-size:12px; color:var(--txt); }
|
||
.setlist-fields textarea { width:100%; background:var(--panel); color:var(--txt); border:1px solid var(--edge); border-radius:8px; padding:8px; font-size:12px; resize:none; overflow:hidden; min-height:34px; box-sizing:border-box; }
|
||
.play { background:#2e7d32; border-color:#2e7d32; color:#fff; padding:3px 10px; }
|
||
.stop { background:#c0392b; border-color:#c0392b; color:#fff; padding:3px 10px; }
|
||
.menu { position:absolute; top:36px; right:0; background:var(--panel-2); border:1px solid var(--edge); border-radius:10px; padding:6px; display:flex; flex-direction:column; gap:4px; box-shadow:0 12px 30px rgba(0,0,0,.5); z-index:70; min-width:150px; }
|
||
.menu[hidden] { display:none; }
|
||
.menu button { text-align:left; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="app">
|
||
<div class="device">
|
||
<div class="row" style="align-items:center; justify-content:space-between; gap:14px; margin-bottom:6px">
|
||
<div style="display:flex; align-items:center; gap:14px; min-width:0">
|
||
<a class="brand" href="https://varasys.io" target="_blank" rel="noopener"
|
||
title="VARASYS — Simplifying Complexity (varasys.io)" style="display:inline-flex; align-items:center; flex:0 0 auto">
|
||
<img class="brand-logo brand-dark" src="data:image/png;base64,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" alt="VARASYS — Simplifying Complexity" />
|
||
<img class="brand-logo brand-light" src="data:image/png;base64,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" alt="VARASYS — Simplifying Complexity" />
|
||
</a>
|
||
<h1 style="margin:0">Stackable Metronome <span class="lane-meta" id="appVersion" title="build version">v0.0.1-dev</span></h1>
|
||
</div>
|
||
<div style="display:flex; align-items:center; gap:10px">
|
||
<button id="themeBtn" title="toggle light / dark theme">☀</button>
|
||
<button id="helpBtn" title="keyboard shortcuts (?)">?</button>
|
||
</div>
|
||
</div>
|
||
<div class="kbd-legend" style="margin-bottom:12px">Space play · T tap · ←→ tempo · ↑↓ cue · ⏎ commit · N/P step · A add · ? help</div>
|
||
|
||
<!-- Transport: display + preset/tempo/volume + practice, in three columns -->
|
||
<div class="row">
|
||
<div class="card" style="flex:1">
|
||
<div class="row" style="gap:22px; align-items:flex-start">
|
||
<div style="flex:0 0 260px; min-width:230px">
|
||
<div class="display">
|
||
<div class="big" id="bpmDisplay">120</div>
|
||
<div class="dtimers" id="dtimers">
|
||
<span title="elapsed (stopwatch)">⏱ <span id="elapsedVal">0:00</span></span>
|
||
<span id="countWrap" title="time countdown" hidden>⏳ <span id="countVal" class="tval">0:00</span></span>
|
||
<span id="barWrap" title="bars remaining in this segment" hidden>▦ <span id="barVal" class="tval">0</span></span>
|
||
</div>
|
||
<div class="ctx" id="ctxDisplay"> </div>
|
||
</div>
|
||
<div class="btnrow" style="margin-top:10px"><button class="primary" id="startBtn">▶ Start</button><button id="tapBtn">Tap</button><span id="saveItemWrap" style="display:inline-flex" title="Select a set-list item to enable Save"><button id="saveItemBtn" disabled>💾 Save</button></span></div>
|
||
</div>
|
||
|
||
<div style="flex:1; min-width:200px">
|
||
<div class="nowplaying">
|
||
<div class="np-label">Now loaded</div>
|
||
<div class="np-name" id="npName">Free play</div>
|
||
<div class="np-sub" id="npSub"></div>
|
||
<div class="np-desc" id="npDesc"></div>
|
||
</div>
|
||
<div class="knob"><label>Tempo (BPM) <b id="bpmVal">120</b></label><input type="range" id="bpm" min="30" max="300" value="120"></div>
|
||
<div class="knob" style="margin-bottom:0"><label>Master Volume <b id="volVal">70%</b></label><input type="range" id="vol" min="0" max="100" value="70"></div>
|
||
</div>
|
||
|
||
<div class="practice-col" style="flex:1; min-width:215px">
|
||
<div class="fbox toggleable" id="trainerBox">
|
||
<label class="fhead"><input type="checkbox" id="trainerOn"><span class="ftitle">Gap / mute trainer</span></label>
|
||
<div class="fbody row" style="gap:14px; align-items:center">
|
||
<label style="font-size:12px">Play <input type="number" class="num" id="playBars" min="1" max="16" value="2"></label>
|
||
<label style="font-size:12px">Mute <input type="number" class="num" id="muteBars" min="0" max="16" value="2"> bars</label>
|
||
</div>
|
||
</div>
|
||
<div class="fbox toggleable" id="rampBox">
|
||
<label class="fhead"><input type="checkbox" id="rampOn"><span class="ftitle">Tempo ramp</span></label>
|
||
<div class="fbody row" style="gap:12px 14px; align-items:center; flex-wrap:wrap">
|
||
<label style="font-size:12px">from <input type="number" class="num" id="rampStart" min="30" max="300" value="80"> BPM</label>
|
||
<label style="font-size:12px" title="negative ramps down, positive ramps up"><input type="number" class="num" id="rampAmt" min="-30" max="30" value="5"> BPM</label>
|
||
<label style="font-size:12px">every <input type="number" class="num" id="rampEvery" min="1" max="16" value="4"> bars</label>
|
||
</div>
|
||
</div>
|
||
<div class="fbox toggleable" id="timerBox">
|
||
<label class="fhead"><input type="checkbox" id="timersOn"><span class="ftitle">Timers</span><span class="hint" style="margin:0">run while playing</span></label>
|
||
<div class="fbody">
|
||
<div class="row" style="gap:10px; align-items:center">
|
||
<label style="font-size:12px">Elapsed (stopwatch)</label>
|
||
<button class="iconbtn" id="elapsedReset" title="reset elapsed">⟲</button>
|
||
</div>
|
||
<div class="row" style="gap:10px; align-items:center; margin-top:6px">
|
||
<label style="font-size:12px">Countdown <input type="text" class="txt" id="countTime" placeholder="m:ss" title="blank = off · h:mm:ss, m:ss, or plain minutes" style="width:80px; text-align:center"></label>
|
||
<button class="iconbtn" id="countReset" title="reset countdown">⟲</button>
|
||
</div>
|
||
<div class="row" style="gap:10px; align-items:center; margin-top:6px">
|
||
<label style="font-size:12px">Bars <input type="number" class="num" id="segBarsIn" min="0" max="999" value="0" title="segment length in bars (0 = manual). With Continue on, auto-advances to the next item at the bar boundary." style="width:64px"></label>
|
||
<span class="hint" style="margin:0">0 = manual</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row" style="align-items:center; gap:12px; margin:14px 0 8px">
|
||
<h2 style="font-size:11px; text-transform:uppercase; letter-spacing:1.4px; color:var(--muted); margin:0">Meter lanes</h2>
|
||
<span class="hint" style="margin:0; flex:1">Each beat splits into <i>subdivision</i> pads — click a pad to cycle <b>accent → normal → ghost → mute</b>. Pick a <i>swing</i> subdivision for a triplet feel.</span>
|
||
</div>
|
||
<div id="meters"></div>
|
||
<div style="margin-top:10px"><button class="add" id="addMeterBtn" title="add meter lane (A)">+</button></div>
|
||
|
||
<!-- (presets moved into the Transport card; set lists live in the slide-out tray;
|
||
status now shows under the BPM in the display) -->
|
||
</div>
|
||
|
||
<!-- Set-list panel: docked beside the metronome; drawer on narrow screens -->
|
||
<aside id="routineTray">
|
||
<div class="tray-head">
|
||
<h2 style="margin:0">Set Lists</h2>
|
||
<div style="display:flex; gap:6px; position:relative">
|
||
<button class="x" id="trayMenuBtn" title="log & backup" style="margin-left:0">⋯</button>
|
||
<div id="trayMenu" class="menu" hidden>
|
||
<button id="shareSettingsBtn">🔗 Share settings link</button>
|
||
<button id="shareSetlistBtn">🔗 Share set-list link</button>
|
||
<button id="exportBtn">⭳ Export all (file)</button>
|
||
<button id="importBtn">⭱ Import file…</button>
|
||
<input type="file" id="importFile" accept="application/json" style="display:none">
|
||
<button id="clearLogBtn">🗑 Clear log</button>
|
||
<button id="resetAllBtn" style="color:#ff7b6b">♻ Reset everything…</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- editable set-list selector: rename the active list in place; ▾ switches / creates -->
|
||
<div class="lane-row" style="margin-bottom:8px; position:relative">
|
||
<input type="text" class="txt" id="slTitle" placeholder="set list title" style="flex:1; text-align:left">
|
||
<button id="slMenuBtn" title="switch or create a set list" aria-haspopup="true">▾</button>
|
||
<button class="x" id="delSetlistBtn" title="delete set list" style="margin-left:0">✕</button>
|
||
<div id="slMenu" class="menu" hidden style="top:38px; left:0; right:auto; max-height:240px; overflow:auto"></div>
|
||
</div>
|
||
<div class="setlist-fields">
|
||
<textarea id="slDesc" placeholder="description / notes" rows="1"></textarea>
|
||
</div>
|
||
<label class="mini-check" title="when a playing item reaches the end of its countdown or its bar-length, auto-advance to the next item (smooth cutover at the next bar) — give items a countdown or bar count to auto-play a whole song/set" style="margin:8px 0 6px"><input type="checkbox" id="continueMode"> Continue — auto-advance (countdown / bars)</label>
|
||
<div id="itemList"></div>
|
||
<div class="lane-row" style="margin:10px 0 6px">
|
||
<input type="text" class="txt" id="itemName" placeholder="item name" style="flex:1; min-width:110px; text-align:left">
|
||
<button id="addItemBtn">+ Add current settings</button>
|
||
</div>
|
||
<div class="hint" style="margin-top:6px"><kbd>Alt+↑/↓</kbd> reorder · 💾 save settings to an item.</div>
|
||
|
||
<div id="logView" style="margin-top:18px"></div>
|
||
</aside>
|
||
</div><!-- /#app -->
|
||
|
||
<div id="shortcutsOverlay" class="overlay" hidden>
|
||
<div class="overlay-box">
|
||
<div class="tray-head"><h2 style="margin:0">Keyboard shortcuts</h2><button class="x" id="shortcutsClose" style="margin-left:0">✕</button></div>
|
||
<table class="kbd-table">
|
||
<tr><td><kbd>Space</kbd></td><td>Play / stop (works everywhere except while typing in a text field)</td></tr>
|
||
<tr><td><kbd>T</kbd></td><td>Tap tempo</td></tr>
|
||
<tr><td><kbd>←</kbd> <kbd>→</kbd></td><td>Tempo ±1 BPM (<kbd>⇧</kbd> ±10)</td></tr>
|
||
<tr><td><kbd>A</kbd></td><td>Add meter lane</td></tr>
|
||
<tr><td><kbd>↑</kbd> <kbd>↓</kbd> <kbd>Home</kbd> <kbd>End</kbd></td><td>Move the cue cursor (crosses set lists)</td></tr>
|
||
<tr><td><kbd>PgUp</kbd> <kbd>PgDn</kbd></td><td>Cue the previous / next set list</td></tr>
|
||
<tr><td><kbd>Enter</kbd></td><td>Commit the cued item — switches on the next <b>bar</b> (smooth)</td></tr>
|
||
<tr><td><kbd>⇧Enter</kbd></td><td>Commit now — switches on the next <b>beat</b> (rude)</td></tr>
|
||
<tr><td><kbd>N</kbd> / <kbd>P</kbd></td><td>Load next / previous immediately (rude quick-step)</td></tr>
|
||
<tr><td><kbd>⌥↑</kbd> <kbd>⌥↓</kbd></td><td>Reorder the cued item</td></tr>
|
||
<tr><td><kbd>1</kbd>–<kbd>9</kbd></td><td>Enable / silence lane 1–9</td></tr>
|
||
<tr><td><kbd>?</kbd></td><td>This help</td></tr>
|
||
<tr><td><kbd>Esc</kbd></td><td>Close tray / help · cancel an armed switch</td></tr>
|
||
</table>
|
||
<div class="help-about">
|
||
<p>Source: <a href="https://git.varasys.io/VARASYS/metronome" target="_blank" rel="noopener">git.varasys.io/VARASYS/metronome</a></p>
|
||
<p><b>Your set lists, items and practice log live only in this browser</b> (localStorage) — nothing is uploaded. To move or share them, use the set-list <b>⋯</b> menu: <b>Share set-list link</b> copies a link encoding the whole set list (open it elsewhere to import a copy); <b>Share settings link</b> shares just the loaded item; <b>Export all / Import file</b> back up everything as a JSON file.</p>
|
||
<p>This is a single-page app — save this page (<kbd>Ctrl/⌘+S</kbd>) and open the file to run it fully offline, no server needed. One catch when running from a local <code>file://</code>: it <b>won't auto-save your set list</b> between sessions, so export a backup (set-list <b>⋯</b> menu → <b>Export all</b>) to keep your work.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Share dialog: copyable link -->
|
||
<div id="shareOverlay" class="overlay" hidden>
|
||
<div class="overlay-box">
|
||
<div class="tray-head"><h2 id="shareTitle" style="margin:0">Share</h2><button class="x" id="shareClose" title="close" style="margin-left:0">✕</button></div>
|
||
<textarea id="shareUrl" readonly rows="3"></textarea>
|
||
<div class="btnrow" style="margin-top:8px"><button id="shareCopy">Copy link</button><button id="shareOpen">Open ↗</button></div>
|
||
<div class="hint" id="shareNote"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
"use strict";
|
||
|
||
// Build version. deploy.sh rewrites this line: a clean commit tagged v<VERSION>
|
||
// stamps the formal "X.Y.Z"; any other build stamps "X.Y.Z-dev.<ts>.<sha>[.dirty]".
|
||
// The literal below is the fallback shown when viewing the un-deployed source.
|
||
const APP_VERSION = "0.0.1-dev";
|
||
|
||
/* =========================================================================
|
||
STATE
|
||
========================================================================= */
|
||
const state = { bpm: 120, volume: 0.7, running: false };
|
||
const trainer = { on: false, playBars: 2, muteBars: 2 };
|
||
const ramp = { on: false, startBpm: 80, amount: 5, everyBars: 4 };
|
||
|
||
let meters = []; // array of meter-lane objects
|
||
let meterSeq = 0; // id counter
|
||
|
||
/* =========================================================================
|
||
GROUPING (PORTS TO FIRMWARE)
|
||
"2+2+3" -> groups, beatsPerBar, and the beat indices that start a group.
|
||
========================================================================= */
|
||
function parseGroups(str) {
|
||
const parts = String(str).split(/[^0-9]+/).map((s) => parseInt(s, 10)).filter((n) => n >= 1 && n <= 12);
|
||
let total = 0; const groups = [];
|
||
for (const p of parts) { if (total + p > 12) break; groups.push(p); total += p; }
|
||
if (!groups.length) groups.push(4);
|
||
const beatsPerBar = groups.reduce((a, b) => a + b, 0);
|
||
const groupStarts = new Set(); let acc = 0;
|
||
for (const g of groups) { groupStarts.add(acc); acc += g; }
|
||
return { groups, beatsPerBar, groupStarts };
|
||
}
|
||
|
||
/* =========================================================================
|
||
AUDIO (Web Audio look-ahead scheduler = stand-in for the RP2040 timer)
|
||
========================================================================= */
|
||
let audioCtx = null, masterGain = null, noiseBuf = null;
|
||
const SAMPLES = {
|
||
kick: "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B/8S/xr/Jf8v/zr/RP9O/1n/Y/9v/3j/gv+M/5b/oP+r/7X/v//H/9H/2f/j/+3/9f/9/wUADQAVAB0AJQAsADQAPABEAEsAUwBaAGAAaABtAHUAfACEAIsAkwCaAKAApwCuALQAuwDAAMYAzQDSANgA3QDkAOcA7QDyAPcA+gD+AAMBBAEIAQsBDgERARUBGAEbARwBHgEhASIBIgEjASYBJgElAScBJgEmASUBJQEjASABHgEeARsBGQEXARMBEQENAQoBBQEBAf8A+QD1AO8A7ADoAOIA3gDZANMAzwDIAMMAvwC4ALIArQCmAKAAmQCUAIsAhgB/AHgAcQBpAGIAWABRAEcAQAA2AC4AJQAbABMACwADAPr/8P/o/+D/1v/O/8X/vv+1/6v/o/+c/5T/jv+G/37/ev90/27/aP9j/1//Wv9X/1P/UP9P/0z/Sv9I/0f/Rv9F/0T/Qv9D/0L/Qv9C/0T/Rf9F/0X/R/9J/0v/Tf9Q/1L/VP9W/1b/Wf9b/13/X/9g/2L/Zf9n/2r/bP9u/3H/c/92/3n/e/9+/4P/hv+J/4z/j/+U/5f/m/+e/6H/pP+n/6v/rv+x/7T/t/+6/73/wP/B/8P/xv/H/8f/yf/K/8r/zP/L/8v/y//K/8r/yf/J/8j/xv/F/8T/wf+//73/u/+5/7j/tf+z/7L/r/+s/6n/p/+l/6L/oP+d/5r/l/+T/5H/j/+L/4j/hv+D/4D/fv98/3n/d/92/3b/c/9z/3L/cv9x/3L/cv9y/3T/df93/3j/e/9+/4D/hP+H/4v/jf+R/5T/l/+a/57/of+l/6j/q/+v/7L/tv+6/7z/wP/D/8f/yv/P/9P/1//a/93/4v/m/+r/7v/x//b/+v/9/wEABQAIAAwAEAAVABkAHQAhACUAKQAuADIANgA7AD8ARABIAE0AUgBVAFkAXgBiAGUAaQBtAHAAdAB5AHwAfwCCAIUAiACMAI4AkQCVAJcAmgCcAJ4AoACiAKQApwCoAKoArACtAK8AsACyALMAswC0ALYAtwC3ALcAuAC4ALgAuAC3ALYAtwC1ALUAswCyALAArgCsAKoAqAClAKIAoACdAJoAlwCUAJEAjQCKAIcAgwB/AHsAeABzAG8AawBnAGMAXgBZAFQAUABLAEcAQgA+ADoANQAxACwAJwAjAB8AGgAWABEADQAIAAQAAAD9//n/9v/y/+7/6//o/+X/4P/d/9v/2P/V/9L/0P/M/8r/yP/G/8T/wv/A/7//vf+8/7v/uf+4/7f/tv+1/7T/tP+z/7L/sv+y/7L/sf+x/7L/sf+x/7L/sv+y/7L/s/+z/7P/tP+1/7X/tv+2/7f/uP+4/7n/uv+6/7v/vP+9/77/vv+//8H/wv/C/8P/xP/G/8f/yP/K/8v/zP/N/8//0f/S/9T/1f/W/9j/2v/b/93/3//h/+P/5f/n/+n/6v/s/+7/8P/x//P/9f/2//j/+f/7//z//v///wAAAAABAAIAAwAEAAUABgAGAAcABwAIAAkACQAJAAoACgAKAAoACgAKAAoACgAJAAkACQAJAAgABwAHAAYABgAFAAUABAADAAIAAgABAAAAAAAAAP/////+//3//f/8//z//P/7//v/+//7//r/+v/6//r/+v/6//r/+v/6//r/+v/6//v/+//7//v/+//7//v//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//P/8//z//f/9//3//f/9//3//f/9//3//v/+//7//v/+//7//v/+//7///////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||
snare: "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",
|
||
hatClosed: "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VwBjAIsAlgCcAAUAmwCPAGcAYQD7/83/TwAQABYALAAnAHsAQgCz/3D/1P+j/4L/IP+u/4P/v/+E/9X/qv/L/5X/4P9x/0UAof+C/w8AVADm/woAKQDs/1gACgBCAFIAXADn/wUAGQAPABQA+//x/20AIgAJABMAxf8TAAkA8v/G/8b/IQAwALj/0f9tAO3//P+U/9b/7v+2//L/qP/S/6T/9//8/5f/qv+8/4L/lP95/7n/z//m/xYAWAD8/wAARgAnAAQA/P8vAB4AVQBRAGEAXQBlAEMAOgDw/0YAZwD8/0EAPQCKALMAVQAQACQAKABTAFcAPwAXAA8A5f8AABcA5f/m/+n/of/1/9f/wP/b//X/rv/j/7P/2P/G/6X/9v8kAOv/rv/2//n/tv+6/7f/ov+p/+z/5f/D/+L/7P8QAA0AAADc//D/KwAAAPP/IwBrABkAEABAACYAHwA1AEsALwAGAFkAQAAkABsAGwBXAFcARAD7/zUAOAAjACUACAAlANj/8v/h/9n/2f8LAL7/9f/H/8//0P/Y/6X/y//b/+b/+/+//7j/AgD7/xYADADq/+D/QAATANn/DgAAABUAJgAjAAIACQAeAPP/9/85ACIAFgDo/xgABAAaAAIACgAiADEA8P8OAAoAEAAeAA4A/P/+//3/CwDx//f/CQAXACIA+/8LAOz/FAAqAAwAEQAFABwAAQAUABIA///k/xIACQD4/+j//P/x/wEA+v/s////AADt//L////1/wQA9f8HAAgABgD6/xAABAAHABQAEADv////8P/8//3/AADy/////v8JAOD/8v8DAAkA8//3//P/4v/z//b/8f/3//L/+v/2/+D/+P8DAAIA/v/r//z/EQD+//P/CQAHAA4AEAAKAAoABwAPAAwACgAUAA4ADQAIAA0AEAAJAAcABwAHAAUABQAHAAYACQALAAkAAQAAAAQAAQD//wAA/v///wAA///+/wAAAAD//wAAAAAAAAAAAAAAAAAAAAA=",
|
||
crash: "UklGRmisAABXQVZFZm10IBAAAAABAAEAIlYAAESsAAACABAAZGF0YUSsAAB4/27/af9p/2T/Yv9f/1v/Vv9W/1H/TP9M/0n/Rf9F/0D/QP87/zv/OP80/zH/Kv8i/yD/Hv8b/xb/Ef8P/wj/AP/2/vL+7f7t/ur+7f7t/ur+4f7U/sP+pv6S/nz+ev6J/qj+t/6r/oT+Xf42/vn9lf63/sr9hv2S/pAChAQlBcH9nQRDCCQAUAGyAuz9dAZUB5AKcQQQB1UKNQgjBUoF3QhdAq8IDwOdBK0CHwFL/Yr5I/cM8+z78O89/LwBEvd1ANn9wf0E8Dz5xfw07vjxmfDD9P71b+5P7aztS/Lp8JH4u/qX+4ECBfSV9dP5Nv9C9L8F+AdSBj0MWQUFBM8L7QI8CMMJLQf5DGYVfwJJDHQQnBa5HEEUnQ+sEGoRqw0iFEMFQg4P/88KEQskE60BQgI1CZgExA8n/MEL+f/8+BYV2fWf/xLuqOq9+OL6FO0t7mTyDfnC79vmKPBS70r4L/V889X/0fr691j2FPX5/pv4r/O/7BD5vgGc9AX0nwJH/vrvqfgqDo8cuQLFC40BmxkfC4oI9BQQExMAew6vCeDyAw+8C3gOKAS7HjEWLwVnBAr+xgXoBMQGeP4JCJIKHhCY//gJqwHeAuHttgkUDpj3b/ly/I0LGfeT7UP56PRi9wcAa/OD8cgAW/f65pr+LAMz32AHH/mQ89sASPlkAQ33vPU/AGP5/gGJBGr4LQUcBrf/9QcA/3H5LgnK/VAKoQvH8TIGjAdhAa3+Kg/TET/9kAOLAsQPnQ85BcEMUQ3NCvQAEgfJBc8LNwakDP8PKAR1FhMLsA2sDwQJlQ5B+hML7QP3DYj9xROm/yfsjQH29AgPlfYv7UkANvYnCvkDovnB6r34HwDr72TzDPzk7hT4jveL8g8D4AEj92z3YPgl/rX0bNglBEYHEf1uARciLh6T7CcevhQcBi8Yhhb7Fh7/Fv6fNUch9vzFFfoQqV3+NI8drzAuFT4llhn7Kl0Vyw77KJgtXB4yELgEOyo4M0PkLhbCBxkFmRxZETwmERWKHQEH6+8pAEP4eQhO36DxHu5+8iDryvxa9IvUFNeb3Pjek9e+3onMfdAy5o/IXcIKz/zhJ9/+z5rO7sl53FXJ2MYG2qPVKO/Y3b/hNMadB+v/LglIB1zmLe1V/BAQmPX7Agsk1AlUEUc07TZU7gAD2lXaBL4nYxMT/Ng3ohmGDOofbhU0P9AtJUGwKQUOwgb9+r0ayRD3EEA0BtPIIQoMuO06KAXX1RBQCpAW8PaU+SgOY/oc71PiWflFDXH5tvl2xkfrNO6p2OgEMsZO/a38uPcg/lzp/d7Q4ojzxu0U7IMHctUvzpTexeeQC+rrkeaUE+/obvYh2ojzYR0+5XI5zI3lZA79j9JDGqHq2BE2GKUcm+Uw8dcOqvGbJQPZaTTzBtMGW+XgCfT9reFhCwUVzCdT64AF2QwKAgMFpfuUyKfSJDA41bvwDfm+8fMSMcMS0f/5nyyu7GfNmTLck1zdzPBtEtsVbdPuCXDVlObAJ1TwAQhJwx8dUvjAOrrYvxecKjgAF9JDG9PJ2Snl9FC/AQ9vJPD2tgmA24ARp+1tCfb++Brm4R3rqwtA9toQW+My5dHoZS4q+OoJHA/Y21IdXN57GaM99+EE0l9Qtxb54HEHOSOwDsvspfLROYPvYgM++dHw/frm9eEGZgCQH7LzuPryD7Mv4eNvJF46Mf3K5mP5+Bo1+nABaQSi95kKTd29EQgGItRoJUJHAAEA1/UklDoRNBMKziTK8kQMdx7aK9c1ENNz9z0pNuNp/7QVAuC+J5AD/wdc+SYTGD2K3e7xaO/LIzfvxhdXCab+cBNVt3Mpn/UY3xEeouSlJgD+xxv8BIWy7T6c1yUMlBv3NCMOOPP/JUPRexj4CLv7vgIH1pAXicy4S1T62CVD+kYKjv47GM/z3AwRKlLdvwU/82HwlwJfF4Dj6vOM9vHc2xQJGy3bMnOt3hobhQap9gIcZiiwuL4p2R+C2OYYetYQJFH0NASIRmfXSi7rENS3sANx7v7pHSk+I5AWgSfr2njjaSCN/foHUNb1+Wf43v1JFUPJg/qN09kVz8okE7fsAw/E42IEQM60CFoqyvPAJVPqvfeR7x8bJAAt8MECbQoM/goC4zU024LjtQ/U/XgjWunt4h/pnVSLuGv+Z+vsHLUDaQslDMLSCQpx+WYLg91rMxMSIchh8LIpxeeB6Z/2h+WxEI71KTwm+djRmehsNbrjReSdBCgFt+KJDwg4S+ht+voPRDJ5tT0VTfvY8cD7ZrayPDfdBxOx2g0EDQZO60gGmhg9xHEX8OKZHZPaPg5WLpj42ObZ/iToB/7UzcnuYQDx/BYXFP+n7ZrWNP+HB13CvCCP+0H5ACDDChARbxDM+JsbWQab5s8U1QYF9oMxwAhe8DAl6e7aDkLzuvcHE8MJ+u4w8XHv3A166TD7nCCL4T0U6avOB+z80wjb81znDhwZu+Mp0ceWJd/IB+l4A6znE/IP7ScBrg2u/5YIwx1PEPXl7/O9L78YuPCwFnYH4RirDFznEeArOojcqw0262QU8f04/4DtWyvL95bHydiX6iQchw4T3usZh+2CzkMSqe1p6xb0tx+19ZklsfrpLzDfdAeu9u0ftwLjFEcCrPg65oAI6QUYAs4a9fjn5f71txQ1JonrWvT3BkYRUuX4E4j7VQpE3kMI1PTACgL8fOBWDR3ejv/5Cw0hRtUNIsLuIfvsHirsKCTbCNwqIQg0//P7Ui6kBnwUkfpQABHeS/D/EhIakeSbB6ry7wCK8F8BYgUr+dDF2R0g49b83wd8/I7EoxKvCPcDsuGsBTv+tQN8CtwDhhar62IFRP2QBD38Qhcw8MEfEuTjKK/9g+jBDilGnAyWB3DqXgfUCbQSQPYWH8r9XQK2+Pr6NQD476/fYfLL9LIgtc//7kQBNgS89tsmYgIIBGX5evaEKZP/JxW5ACT6df+dIsroVxuBCTjhKhCM7WT9jAaUHnHueAT09Rv28QEhJYDZZw2wDbHbOxdp60UESQOI/Djofhx2BKcIngh8+3nvlPFC/Sr1L/jvC9HlBwqt/L4KQv5EFsH9ed5Y9e8XkgsCAUke1hI99Qgu0fk4OyjkWv1U2SotBwEqDq7Ohv1p/mLsuQJtCNICf/S17I3mFg5i//36cw73/5IJCON97cf7pATz75D9hgNb/58FfDLb8yz0qxaUBzsXDP51/rnoWAFe8b78OCtpDXr+qvvSDkDkj/K6BrD/I/c6/XbsABR4A2gSJ+jB84rug/Ib4S7+XxXvARoIvOLJ92cFQDSS8VgNB/x/Fk8EBRcB+Lj5rgNhEgkU5Pi89TsjOfYfALH5Uf63/cP+pvUb/xv1PQtz/7oicN6B9J/qfvp67PINGgnD9SU3XQVV8yv7IQn4EYkMm9tq9wkAkAH5/jL4pva++5oOwwKGAav9CgOF50UDSg97Bs4FBPs0BDoIDfdC9H4JPAbfBeUAIupRDsv26Awe7GAjgRUBBR4EhPWOAtH7e/em9KAcKwdf/xkiWPZ0+37xJAA6/STpt/OZ+tLzvN9RDyMEcQ5X8h4GLOliA4/5uwpL8JjsX/XbHzEOIRGYK6T+BveVFQUNTPU26xcFhwdID9QBfQ8kAW38ifUbAnwV/tnk+BHry/fI/jcdjgJc/bMGfwMkAFLTavCtC5MNSPvZAgcWbPdrCcbtMAnU9HYa+95r8WIChgkJ+2T8lB74+/8Z/PZdDaPyJwO08tcMHfNYGIrv7NxwFIASXQ7vAFzn+fVtANLfMPtZ+eLeRvpFECIfhv8O/AIJpQdb7iH5FALWAK8JGvw6APr6xxPQIQD2RetcCfkO9//kBo/55g+SDJkH/fy0CnfzxAXC78H01umvAan/HvUECEn1AArKAUkA6QgB5oH7W+yoChTr+vn87d/57vsE8NwC+wFkDGD2WAI18rMFExU5JTULZw0v9+UKxA8jD1/9GAuRB+Ia8vasD+z9Vfxq8DoJnAH0FjPr7Aoi1QjkYvfuB7fzcPEvBTTtLP3Y8Q0PpgJN+Xz+OALv/ZfxP/Eh+NQMbR5Z9zj83PfWHJH3Xvi0+rUNkguMGVAUOQSMDqP0mv53/J4LwvBO9FAB0P9Q6Fz7Kf5l+M8Cxfq3/croUe6K2zH2iey/9vsC5QCeCFr7avrP8ssPGvuBFQMDbhZrFGcXlQQUBd0J2BniCdHxwwnV+Mb3HPgqDDj8dRZCC48QG9lm9OP9fADo6aHy9/jf74gIKftNCBjyLv0E8XP+4e4y+IoH2/s37+0MuxGCITDx7gf6+CT7tvoiC8EpMAdlBFQHLRDqKvgT3gKI3/ARLOz4+kX3eA3x/GAH1vJRBLYHvBb+4DTlyvByAAICZQUUAjn3d/Df+SgG1ukS7EP3iPHcA0bwWRGICJcM8vdKEOPr+/KpGuwA8vdK7AEHG/4MF4gJjRSF+lYYw/2vE0r3/gst7ksJvgw7DNUFbfqm/8Pqifc6/fwGxfvYBt37cPKn+moRkAot7QT8JvAF6pb63wf37Df5TfgcD3XzcRjz+RsWYPbw97YQOxiiDl8BHAj7/cL4cuneDTcdbQBz9FME6wOVFroGVgYd89z+Lv6nBXXy3fvI/of3OvpH9W4BdPqE/wzoe+1wCU35TQfX/joJLfBc+ZEGvQdODU3uCgxFA+kIR/Sg+RT0CiGKETwIOvz8DVIGaQLe6cMDvBaj824Bdwh8AdjuR/9J/7z+lu7fBWAFRP2VDR8HfvpCAXzpev2XCiD+4QTO9zzxvPQC+6gfeA41/J/2nggL+xwcvfCwAr/2GhKGACoNdfUp/An8UgZqB68KefEf+rH5lvrr7aIEsfmUB48Rf+yyADb+xg9x9n/+qAqMBt70j/t+CqH8EQrEBJvxMu4C86IHWwPhBdz+FgJ8FFr8m/iF+JEFBvgDA4v/mQmpBKsBRfV6AFwHCgtS74L2gvZWD6j7nvsl7T4IjfEn9P8Ru/zm+G70kgH3AxUAVBGNAYfs8/rSFxQNwgee8P7/8/FS/FgDIxFC/sLxJ/0CAGoPOvyU8t0ISAji+6b+M/2QF8f4GP2nB3gN2f+ABVz6yvysCDDwoO4mE8YOLgrjAzn4/fuW7YIFRwL0/5z9U/+D8JcBVQHQBucIhASi9iwEzBDIAAj2wf69D3IKa/4K97gEQPdS8qn1kv1T9EAFVv9U+qgM5QHZCmT9wfTC7jYEFwj5/WXskAE9AF77VgTdEZEGwfOe+moHmv8x9SYTCgULCC8NoQPWAPoR3/kNBLL1APwRA64Du/qHD1MChPNh8FEZ5g83+K3zUQW4+KEBz/7TBVn62f8Y9Ar0hP5gBIjpTvz0Ad36YfPvA0Hy0wgjBk8P4w7L6mL25g/RAI4EpPVmAPz3HwAiCu0DgfwdAsoBRgoCCir/WP/i/KgMmxL+Fej+vAHbCY4EZfbC8B8H9gkj90MP8gJ68nD7r/Nn9dHxa/TjAwcBuv9V8d7+APXM+Pb9Ef5R9rD24f4LEOP+JgYTALkdTwS+FNL9Cgy3Az8A4vswABP8/Aa9+FAJpPgCCcD5Aw8LB/UOJvlp/8X86P2t+7wDqAGv8dPkzfyu/7UOk/aO9Y/6+ww9CrEJcfY++SXtOvGPANz3ietgBRjz/AR/AzsFkiCF+FAJdwk2DMwAXBJpAW8SD//aD1X0LP1CBPsBPua3AdDuuAWpBKb9rf6hA/8Ibfs3+yIKXAc79bvyDvIV74YJRvvcAyr35/EF9dX1iPzPCwoDcf+x7jYNIRDUDH0GbAOk947/fu/nCXEQxfvMCK8RdxQEB/4YUgiv+n/0XvvCB/D4zvjL/qPzifcK9pTdXACc/qDxyvLw9kcC0gON+hP6WwViDmb6uPbO99H6yggYC5P3LP6g+qQNSgRz/uwBZPVyEdgHKA5+8Y0BgwodFuT5ug5sBF0C2QCgE3D8JAmX/nkR4u+oAnsEvgL37TX8SfIe+MbtugSl+SvoG+uc6K/9FxGo3y7obfwvDSYQQQefBHoDwhFrDIIOf/6HB6cHnPOO/iUC6gpv9/AGbAZtAMcJTPXp92z3sgo//JkHBvf4Cq75u/xz91QHN/lx+af3bflV++D9+/0J+1f7OgrGAkr4N/FE/b8DXxSB/ej1gQF+CMEVWRApCwXqp/hs/6sVDhKT+AnxNAeFB24E0v4x/dP3e/jt7SIBu/wE8Jv4Hfyh9I0IUhNPG9cM/AOM97YHOP75DJQATgBrCjMLigi1/v8F9P2DCHABjO1hAQcCVQw79ljzI+3V9x0At/UV+envYOyv8NvxlwCbCToIAwOK++AAhQUsC5wCRvnN7Gn+7gjHEXr/hfigB1wKchUTFYAF/e/0/TYEORh5B7r45v92D5MFFfls9gsGOAtJ9XH32vZA98P+fABlBp/3a+rl/LHv0fnq6mAGyff79KQMqAF9/8v+2AgWASUCXxVXFL4MDwSFBUD2YBC9BZEGwPq0/KT3DgHmA0ICaPwN7qD7bgykDI8IxPfK+yD/0QmoAKD4YQsl7WL0XPOtCZkKLP6Y+CMEoPpKGSkAQfDW+9X3yvPNDGjxoPmuBIYDGfiBCg8DbgJf/JYRgAdR9hn43AOOAyESiAuS+wLy2Ph8ASn86e5h6bP2/walCK8TKhAR/lYDDvpBCPgAigdjB0z1+f6CBnAKrwjOCPn2bvX5AiD2VQHJ9yoECgPLAwfzhwRO/3f8rQnJ7tsA//nBAVz58v6iBwoL+/SV/4kNPQIsBNID1vrn8Rj7DQXNAvcGCfs18eb/5AiEDFj+Z/bO92v8ZQ6mDQX9uPnF/XMD/A8KBDn3gO6P74r4bgLHB2v7iwHE9qv+8fElD7v8OAJ1/5wC+Q62CLf8K/kEB8MNnw5pAYcE3P5/Arz/RfU5B68K1PynD8YFlPtt8q4HVBji/Mn3gPrd77D23gBs9t/4iP1t8Fz95v+OA+L7aQFv8Er5K/naB+UM6/8183ABMQssAZgP8v8i/gnv2AnkELoXYAX29G7+DgHqExIOSQtxBiz2wPy9+kIBdPlD+lMD0RQ5Ef702PDK81b/RvlS+fwFJPK5/PH6AgHU8eLysvUNBaT1yfkCAPv7eAVNB6YYbg2DCS33wwHg/JkAyfjq+9v89gCQDU8ExBEqBjb0JwKPBoL3DQ8E+xUA0fxW/3z8f/0w+rX1kPRwAMr8GwzjAq7/zfZV/YoIoQG/BWIDauPN/aIGw/MP6/37wgdwAbIKUhOF+RQEogV0CIr6ugYfCL79wAg7DGELt/XF8Wfui/ytCZIBrfxL5inz+faODyQTUAqP+sj0qQOa/h0BzfTsAHIBD/7dCan4UhCQFO8Bdgai+C4BOvziEbz+Hfw6/CT76PYNBmgJP/t077r39REQ8bT7hQX3BMj9HwE/APT8kgBQ8fb7KuOo6i33SQ2bB9IM8/n78iT8nAviCNMG8fJf/AQJHxspCq0JlfbZ9McQKAX8EL78FgHV9p76dQGHBbMGSPrzBifqV/GZ/OwHV/yH+B3zrvftAuAIcf/3/4X6h/eT9eIS5wi/BUb73fFiBVD7LgKgEugD4fYR9OMDvAM2DcX9APZ/9QcBdg/jDcYE0ANF+PQALwNWAzgKOP+h8gHvePWrBLcBKQCu9xX6G/Z9+FwACAXe/9PtfPxRBBEDhgNfDRkOIAxDEiD3Nv/b+ij4hPUz/b0QO/+t+6j+7BLp+vnzovheBk8PywMt+JbwXwElBA/+PPn3/zb0z/F69qsC7f7MCKUIQBk7BewTZgIY/mrvGvmr/j/8uwphCif1lvBlBl0CpRH7Ag/1FvSP+oMHxv87//bzpv/7+/AQDgmc/zzwWPPE7Z8W6wQADbUDUwQU//QCBghV/Yj8j/FO/xX8R/6G/qUHpv/eAV8AQQjPC54AYfABBrT7HQv0ARMBhftq91/0UPrh9E79IP8D9Vv/chHJ+fwEW//YCJf7fAyaAlkHWgJsBI70iPqjAHQIFAxOFJz8pvNu9h8Hpg7ZFpgGw/RS+nr8KQtuBJ/1W/i39SD36vH1934AkQef9RkEmgwH/bACZ/YD+GXkjv7hBYMTPwJU+e/10v9T/zcIfwML+zkH4wLwEHIIxA5QAPwGXw2LA14JjwB4/3fyJACyA7QSIg0YCwj3/gH282j7luQT8QT8Lw6E9QQJwu/68Gr4ZgDu+oAFZAHK/IMAcPOy/Yj6LAuACKEB7w3XAhT/Q++BArkL+BSWCEsLFAKtAUAQGAvZ/EfzGvpk/HwAzQON++TwOP+7+pER/v4j9kv8pfCQAoYUKveP+4n1mgQwCdMGh/fnCR3zMfUd+6cFpfqTBbz9bANYAUcO9v3wBbfyYf23CioPZQcA9RHy/P9vD6H9W/beAbYHffa7+RH96/ng/KsCpAPC91P+GvmMBjAJUQ41+lL8BPz8/4v9l/6dBUAGof018z3/xAYTCH0EhANF9cYEQwg6CQLzg/pQ/RgJEQAmCCkB4fhx947++PxFBs/+KA5UBTYNsAUkALcBE/v1+OT4suvTB7z2PwHN/DMK+/7l/MIFTP7yBWQDqvzx8Sb5VwdrAcgLB/5l9mPvBgfHCNv9zwD1BGH6Qv+OD7T9tPKq+e3/BPz2/D/zCwhY/eMEJwHJDrwOTA/N/wX91QblC9kK0AWJAyf1hPS+Aqr57fRJC9cCcAlU+vkCl/yS/eP/ofRK+GP7X/xK+P359eW5/C/1BPvZ/VUMSPo57dD29AsPDNwP+QzjC3n7mgPgCOEG0v2K+nz+ZgGFBqYEFwUmB4EAfget/asCRAEkCj4F+BHhAjH29gCX/uYGlfPk+Z/tw/JJ/m/3SvZX+gwB7P0L+zgDtfR++Uf1NPgu/BD5kP/xCFUB3v2VDFsEgwkQCO8KvgrxALH44QZPBaH/bAP3EFMNPgYT8yAFdAl1/+MDlwDWANb5yP8XBwzyOPU//mf3wfXb853v0PhT/pr2Uf4DBOYDXPvj/7D01vuQ7GL1A/8NGgsJg/xFA2wEWgwaCbwN1gi5/jMAgwlmCtoRsA0X+Mb/PQxV/m/52fRa8sDwEwDcBZ772vauBcH9b/pb5Wz3OADL/tf/mwfr9wr9aBPI/iLyaPnN9noDFPY1/fL3NAXB/ysJDAuzGdQMVf678Q8EoAeHDmsCkAOiBTMMbQgJCvwFv/ab+c38oPkvBgH6QfmV9GH8yvxt+9wDLgKc88fuhPaM+S8E/v/v/e3/SfVTAmIFHwe775f8rPpN+sYMSQr4CaEDVQkYAhMIOANrC4kCkAIx/dADagY3EdwCjQgHAj0D5fwBBkYAFgJL8V/0p/DV+CcCXwK17STz4/aUCSP49/Zs7qT2qPHgAYEJTAIp8zH0zPr0CroFqQ7CBS0I4wH7CX4HPg4Y+74V3RCGDDj1mQA4AjH/ngBT/SwBLgvDDRH/yvs8+5b4LANmAR8Lkv3K8RPoMvpY/Xn46ffc9u32dfVr/Xb4p/np7ev5QgIwCPsJ/gIe/3j/rf5SB5UMdRUm+HgYngBCDIv93QaJ/goNtgn+C64NrQAnAjwH9PPY+Gz1BgZ19Yv9AflT/pIAiwDj/kAE8wc3+BPz1vEg9TL5nvOMBigHbP8uAEnzQgJW95X9xPYeBJYHJhKMBZwK4f85BowGPg7sCHv6he7GAiINFgxVCRMLlwLsAX8ECgM68q/xPenp+vj68v+E9PP7X/yXAQgD6ffX9FTw6v3U/RH80v9uA1oJ6gFEC7IMzg4UBBv+0v6iBFEEegKqCXULthA0Bj/7DAFhAdoFQPX28d7zRPTB/8r8UQSWBWoHWv24Bvf/ofRF9Zv4oPA3+5L9iQVKB4z4YvXX/n78MQIgBLH5+PpQ+u8BmQehC/QMJ/0vA0HyxgSUCUoGLP9CBPIFFgFWBTwTCQrQAz39Pf99+CoEpfxm+gX2l/wz/qQEpgLqCa7/qPup/+4HnPyw/hj0X/049ab/+/6mA+r04/Z89Ef2aPuN/az4hv/l/Cf+8gKYELUXdAcC/Qf8hgCiBVr+tPrK/VX9DQ6cAvsKthESDjj8vALeAYECgfTx/LD1QQDjAR8Krv8vBv/wsfui7TP81fa2B74A+wBK+UIBfgeXCywEw/tH/rX3vAKe+i7yRP7H+NQCTgJXEur7Pf16/lD8cP0/Alj99/gI/9gGbv6BCW8FRw5O/A0Eq/7X9/n+Q/r2/V4GHgNZ+mP5pfo4CwgDafPD9Vn51wRtCl4IpAw6/D0ASAVEAu32lu7j/rL8/wZL/VcHlf77/O8CVAgTCcAAQP8J+mj6wQKr/ar8v/9QAaj9AAsuAqv1ZgEI/x/6pvar/6/9+QRh+p4ByvrvA5wA/QnHCPgJfvv6+EL9nAJf/f7/MPxrAl/8cwQ9/gsGEvYu/PX22f+TBkUFQP9CAeEF+/1JDPcGXPyT9SvxcgGNAEkAEQF3+8/+XAeeAG7+dQOD+0n8FAItBSkKkA5KB6cIVgaQAQX/Svg/++33nvLvAJL8ogU++uP+gf7f9vb8LfquA3j/Sf8x9RT1BPpu/3r+hARtB6sB3gISB5MDEg8RAIEAUghuDqEMVwAO/ET0zvgu/mMJmQh++uzy2vjKAAsPqf+kBLTxRvvY+2H9BfY9/Ar9u/of/SgOOwTFCTT43wY79PQDDP2h/fn2NgT6+o8AYwaEC+4HOP5hAOsGCANcEasNJQT0/XL6MQRfA979Yv6c64Tsv/dK99sJ9gm1A/n18Pfo9WAEaf7p+OP0Qv5q+X8MnQbZDCL9Bgel+2QDyvo9/sUAz/RrAqQPxg8rCY4FZ/6+/fL/yvqaBO0PJwAK/1DzEgQPBIQCzQo5+DQFWvtfAsL5kfkw+d79NQBc86P6Hf4r+tQC1vM2//L3sv9u/ZMExfpYAn0NjwkqBf4BWAJxBMH+0g1gB7gFUfS/Dkz/+gcK/zMCa/y5AHb4o/PS6lz6afUz/X77DP2iB90JdgQKBav+of9h/Z8FK/w4/KT1+wC4BmQCCQc0/579CfMK/5gOiAmR+GUEnP7RCWEKnAO8BEICgAX8Ayz9R/eZ8TwIbg00B1z9LP6S/Pj84wGO95r1s+9y+vz44PCY/zMDKQoFDFgBz/uj/Ib0WQXY+HT5pP/zBnAUeRA5BB8I2QJB/EP4+/G9+Zn5G/2U+0cCeQnNDN4Cu/y4+U34W/cM8+QPexHOBwj2yQQSDmoP8wbDANLzJvgYAZ4SUvzjAkvzj/mU/AUBmv3rBCf0IvPg/PsMDgBa/i7xDAChA84IbvZ99iD2iPoE+mD3ivqL/HENuQiK+3r2LQc7DekFqwLIAd/22QCRBQ4U0g0TCqj85/svBr8YLAwhBlzy8PgU9igEGfVG+mvy/PWG/N0G1wStCw3t1/a48Ej5CQDbCA7ziwHL9RYEkQhJA1kPe/m0/YP7RwImCfAGMPn0/WUHZgg0DeIKzf2I8H8ChwZs97r2JPwyCPcGQAXLBO0FegLmA9H8R/5K95f0vvvlAbb4zPID+Fr+zAaKB8Dyjefl8X0G7wxUCEoFngg1C8AJExOODegBO/XB9R0JTgoHDMr7h/dVC+MCG/2+DOXyTgL68HzxoPiQ/6X6M/T+AeD9f/66A1//sv/r7nD9IfEiCnr/qQO8/fIC5/t8+z3+FQr2AqPzg/psA1AA5gX/Bmv99ghECqIOZAJrAJb4DwQM/pYQbRHsCpf7jQAzACwEYARQ/cLuRffu8Qb3WP+U+uH4FfzB8978GPxDDwH6r/wB+K39VQKhCroEegKIARP9UwtbEIIOyQfz+TX9oAjBA0wDJQKj837w9P8n/rsHGwIoBZH33fla9HH/Sf1NCc8JFPja9rH6XAmmDD3+JfZ19T768fpTCzMCzAAv9aIObg7HBkoFy/7A/Nb71Q78BkEKqvyC9SX/CgUEByACx/pv92f1NASxCEv6rf7AAMcH1wFo+mr6lvnW8ID3VfwS98gBKQG+/m35wwBqD6QEDA00BPkBvARY/bX/5AUrCJr/Bf0n/a73ywVLCZIKp+8zAf/5UAG4B/sUx/hZ+vXvxAdm/VH+FfkQ7/7zGP7jA/ESYQDT+E7+KwkjBV759v6n+ED3IvVA/8IPHgbI/OP9+PozCT4GVgUp++j/Fwil+wcCNgMlBYsBg/ulAMX8VgYK/xMJ1AEBBkUE1AloBy/49ffU8xL5iwLYEPv+Le0182PxoPgq+DgBLvsw794ACPd2B48IIAKl+owHmgTyBOoJqggbASD2CQesEU0JWQU4AjAALPRN+WYB/A0IBIsBivjw+CQKmQBwAED4gfMK63gChP1rC7n92/yp9ToBKg6ABjMBKgOu9pP1gf6jAOUJYAWE/Rb1RfWeAHwCCQDw+Kv1IAOjCFISXwCYAy780v3Z/eQH6wWC9qP8//ja+GcDAAEkChX54PMu8Xr/VfJC/gD94QSl+fYC1/+gEQwNLvv6BXAC5AZECyAEPf/m9kYHFAw0By8G7/yD+sPza/EV/NEIbPbg+lMD6v3S/eb4Uu/l/JPrjPhc+i4CjAV+CQb64Ptf/WwE3v1bA7v8G/aX814HXAfJDtsIzQHuByX+UgBfAnj/NPjsAGEKmxH9EtL+HwkUBcP7Tfk9AyICPPpL8yz2Y/oiC2cD8PbD6XPrqvreAJHwsfBKBYb/lgawBPkMLRIy+hf5qwO2BuYDXAHhBKwPQQhNCQUBBAgVAD76y/Xm/24EGwSIAQf71vqS9Ib+zgUTAav11QOA8Hr0+vib+5IMwwvS/+nvmP9fAGYC/PfW8G/3DP59DXz9mQqyAcH+lQItB1MLHwv3BR/6xQBLE1cTcQ4f+akE3AK5CdwE1AJY/zf4hPOe/M4GEgaE/vT1HfGP+Y727Pvt/68BGfWpBsUBofTL9IsDSfwh+UD4UABMDr4L1vv7/D/9AP4eA5D9KQKk/0f2bP9k/0cM1hOiB5IAdQAgBRAJ4gjfB3gFDAPG/2oFCxE4DRT+HvWX8jDxT/Z6/bUCCAMpApz0m/n8BRr8e/dZ7x/w7wJQCj/+XAHq/eIAJwzhDMgBDADx/e8CXf9L+wH6kQc3EbwLgQlh82/5XQR/A54B+voRA5wNDQXJBdAFDQcU//QBPAkIBDjz5++r9L8Dy/8W9SD1Nv/w+Vf61f+i93cBmv/C+TYDpgPOB0YIqQ2iBOUBmv44/6cGqwTVAxb9tPrBArQJAQ4+Dgf+kv2u/wEI+Agx86j0cPRuA1oJiwFJ/Ez/nvqn+Wz2TALkBrL9hPW78Pn/dwEd/CEHGvqa/QT6hPb+/vcFoPuc/y8E/P+UCXkInAJWBaQF5wo8CPQLjQrwBeUBkwPHCWcD1QXY+Br7U/VK+S77fAIK/XrzG/OQ9C0HQgMi/v4Cve4G+h37MwOnBZUBXPxX+5wKPxSRBuv/r/qi+Ln9aAlFDUoFJvnB9fX5DQQQE18Ddf3lAVAAJf+S/DP9oPvN/bIBqvviCREDiQLL/kv8/vW7+a0JPf55+5n7KPnf+MUBxwkNBrf/KPYP/5X+7wHrBRUAZPyFB6cGvgkYCR/9X/W9+Az+twKQA/YI4/4x9ML5BAf5AjP+KO6r81H1ZgglBFj+UwQjBBH8xAb3AxcHxAROAGz3ufuJAkL96gLwBKP9l/vUAUAGXPoR/bTyVvUWAY4NRQ56CgP/SPuU+8X6PfzXBToAhgE4/uoAd/3pB2sJo/1cAHj1yP76+oj97/KD8lL4+vdfA8IG9//4+Vj0N/jc/nYQoBGGCXoD6gkJBwALwwLRCPX53v3LBRgAYPYE7wT6zQNrATMDsgITC3gEXPtE8fjwgPk3BywMkP999Wjxu/ldAi/3N/tt+Tv3wwGzBpH6hAIl/4b+CANTBCACJvoiA2Xsjf32Cg4ShRLlFccJqQQlAi0HGQa7/BkG6AN6AGEBkPz0/s31D/aP+2H9cPyS+4z47fTX94b1if9LCT0ARQMTARP6SPtS8T/yPPsRAaYErAVV/hj+gwpM/9P43gL7/OAKcQ1HAjj+hP+g+BcGuwro//8FbgOOAtb7swToA80BWAPTBVr+s/ek96n1ZPPJ+Rz6pgGR95T5RPOt9EP4uf7N/EEHNASS+3YGrgfvAcYFpftWAxIE0wj4CJgNcghR/1wAcgF/AoAFfP1I+h0ByP57BFgL8Phc+VYDTv4xA7IDmfm47Xvv2fSu9037xv9J/TgBxgN69hgApfsh+oL4O/c8+nEGIAX/B0QCz/1wAuMCYQGXDAwBSAcuCRYOUAutC94MdhFiDOD69/9tB5//Evc29Nn02f0oBIUIzPqC96X5ZgH4AOf7CvRR9q71fP5MBSIATPde8P35GwRpBGAFHvf1+L36kAHNA18MYAd6C+/91gfcBAIBXQW+/TT/DgjwDvgHjgQ7BOwHcP2B+7wBkAooBH0E7QOf9g34hv/5/oj7avkq9zoBIP9q97f+Q/rjARsB+f8VCfkDuwBg+Sv69AJwAlj+egAfB4cHkQZE/PIDRQV6ANUDFvOX+4P8Ovwr/IL/R/6WBiQJzAhr/s3/ewUbDXILuQJiA+b3RPOl/DwHIASq+m4E2/10CL8FIQYx/VfyOfm7B/gAofwB+tf/Iv/SBJn7mgRGAJwAlvgU9sv/YPhwAb4ArQAvAyEIlgW5C8QEhfc6ARsDNBCVDqwGfgfPAnX+cQZCAUUFTv/n/J/1AflQAdP4yv3DAI/6Jgf0DTj+zPJE8fX2D/6Y/7oGcghI+ej1gPkvBcsDTfm3Ag76QgKYBJ8O/ATj/1X7iAiTDsoBfgmwAkv9i/VpARkEJQRtCoAFfAFYAwn8FAM4AmP77f8g9Sj3Ef7d+13+qfUM9FX9SQMg9ELzffjA/MP+QQo/DC0GpAJpA2L+9gCaA0oHgQI1/d36xfqWBX4AQwhi/wsHrAc5BAn8cfln9X/9yQcjBNX/6wZkAVf6H/zY+pALXgb0AosAn/av8cAA9vsm+lT6SfXb+3oBLwTDAcn5R/cHAUIO4gifBKn/AALB9pX+2gZhCPb6uwe4+acHLvwP/sz6CgK0/QkIaAk4Atz2t/0d/F775vgZ+OsFGADN/7f/Lvw9/l8LQgIf/OH0AgFM/tH7WwS7Cjf6cfZxBGYIR/1n+D/8xPhs9U/5owFxBF3/KgXY+7v7ZflXCUcBOvPp7/v+LAP4B7wEU/8RAZ8DgAaAB/cGFPZD+e/80AVRBQ8Euwq1A0b5dga+AL4Cife7+e8C2QFCAk4DJwNO/dH7e/na+ev3sgBE+/b0sP5cAegDTfp4/zcItQR69CjwZPWH97L/iwPG/5H4uQLdB1cHHgMnAbACLALvAz8Mww1hAM/8R/73BaQNQAU4/G/5dfJG/LEICAbe9WUEywQvBm8H4/1m9Bn4pvQK9GkBSPv59OL6W/8CALv65PmJ/mcEJvknAEL+6QVO/jIIzQHrBSgRSwgu/OIHyANICJAExgQzCuYPSQNwAvH72vcHARH+AP8m+sH0Y+73+NsA/v+1/lP2hPPh9ewAb/rh/7n8GPw8CAMDfQT2CVL8UvjcAykIkA08BiIKZwM9/yAENQsEEZUEifYzA0f+q/9PBKf5W/epBqEDQfpjB/z49/gk8cX6oAf2CyD+LvQV+s3/2fwK/Vr8PwLRAJL+gfzBAdL9Jgi/BdMGLP6G/iAElQRh/a/87fb2/ewKxg09AK72ovf7/cIGCgtqDxQEvgBh/Nf3HwEPA/T8QgLK+rcBkP9HAv4DSQJPBZb6CQk+Bl/9tPp19UTysv32CJYG6QZmAC/3SvaVAskGuf4l95L8LAuZCjYEevbD/BX75QEJCrX/aPDJ+RvzrgM5BcoIhgMBB+0EuATj9uv5uPrhBBb/gQJLAdT+IRCTBTj8W/cl/7z+pAUaCtcDlf++/p8DXQRnBLoFLP1S8UfzhP8NBED/3fvz+B38DwUdDDH9//pw/Eb8zwGq+vD4Fv4J+q/60gOeCOsG2QD7/o38dQO7/K39IgofCCEJFAMfB/oFKARHAQADM/2x+z/+pQc1+8n32fznBwgDiAr0/XP0Q/o5+Gr5BvkYAVMDl/vP9FP0GwTg/QL7Kv/0/+QF4wM4/8UBewWGAzoB7QPOBQsJlAhx+BH8oQLRCUb7OflMBKAJvwNHAgICtABj+k78CQC0ACr/3vyB+wf9mPig8dj41vNz9i//mQBEAdv9RvwM9CD+KQCQBIwHZA1YDMYD5PjXAnIA4/8++GIE6AF6/7EITQbRCkYAqAnxCXAJcQR0+ZX1IPd68yP3SPqd+Cf/ZP9s983zpfzW+VcHJQNTA5ABDQbVA2P7Cvby98z7WgIsAbcATP5R/q4DNgMZDRoJmgtMBTEBZ/5BAD38Cv+E/cr9/AVgBtkBg/s8+3D9fPuJ/s4GMQEC/Pr5yv2GAwgDCv7H+ST8m+/c9SP4DAKBCrgEt/0cBaoIowHb/U7/kvtpAYQE0v8y+bf1TvOq+Zf+cwNHAtcFbgIfAK/7cQRiBdoQ8QuwBJoEX/xnBEYAb/rj9qP9Bf8YCqcHVgVH/d4A2f3RB6sELgLT+Zr0Avyz+fr5V/wc+rH4Kf5f/H0DZP2o8c316wYrByX/AAAnAtUDVPpO9Er5A//PAccGz/s7A7wCWwShCrcKngiW+k7/kgG+CmQCHAdf/dQBzggOC7sACPfh9HT4Fv/Z/gn8F/cG+V8C+gVVAE4Kqvpv9wr9G/0e9qb9/P96/J8DBQG0/Kj7Z/a0/LMH+vm49j8ApgzaET/+JfQy+CcCXQOhAC79rv+JA8P+9PyNCHMNmgNS+fv9cQTm/wz89/bz+U4BeRBjEFIIb/jn+dD3ePb2/SkAkAMIBlgDqvlpAQIBFP48+iT9JP3fBhUHEPv6+B39df9wAYwFc/47AkP4OvpJ/3gDHhAFC8YDJAouCsn27/Nz9C338fu08xf5sQY6CPwEl/RU+mf/0gMrB+3/WQdy/aL4JPrm/6r7wwE+964EXwDhBbkA6P8oBF0EjQpEC1sN+Aey/kb7j/u99x/z8v6kBLf9IAXgAboFjwC2+8v/xQEIBWn/IgGR+HMEfQQA/cP9Mf/BAoH7D/ap9bUC2QNr+0b6wAcPDF0MEPoz/bkBbARr/QP/3P87ArkAQAOfBdMGZQXDArIBDAH7AmT+cfhz/igG6wS1A2AHjv8t9wf8ZP0I/4r5ofxnA0AGeAXVA6P8pfwWBKsC2f+h/q3+Ovr/+PUHuQoDD1sFXf7cBBv+0foz+8P71P01AHX8vvyH9l741vku/qEC6wT5/VXyM/xwAucAEPosBM8LLgriBwQATAQH/C4AXf8SB5oFkQheCJEI6wbXA+oC/gSc/LMFzPgsAhEAof/R/DP+Z/41+yH7v/WK+0340/db9Wn2M/uw/y77uvcm+iT9KAQ9AmwEZAGuBeoMjQsHAXMDBArRCSwNyApLALf8Fv2FCEwDYgObB5EHzQLNAbICIv1OAFP9gPg7Bd37vPOP8uv1n/c//nP3EwCT/7cAkv1DBvQBrQLoAtcBGwFt+1T3Svf890MHewYhB7P3+vrbADcJhwWxBgoCMwKWEW4MxATO+en4AgAMAdcEbv2q/NT8Pf8JB2X42QIf/SkARAGTA6D7vfe082712wFABVwAbv1rACf+vwMs/g78HPfC+RH9/fwOAUQCCv9aC1QHygkXBtYAyfkC+y4B8QCOBc4IRw5CA6YCH/wk+gb49PJe+2T/Vfw59/j8pP4S+bIBeAPS/bj48fw8+VcAS/uy/1YEyAEJAHMEaf9p/lr8jwbNAVsDeQn/Bt7+KwoXBqMK0v+l+lT3KPnw+O32W/ZQ/TwIwQ2uB4j7BPyGAuf71P0++gv6l/0//FL5Ivz4+8T5c/6e/DH2X/NABe8CQfnvAa0AlgZuAmAFvgJoAOABmwc7DWMG1AAYApoFEQpOAG8IP/zq/Mb+tQMz/B/9tfbC+Jj/OAKSAJoDAfo//Tf4awGI/RX72/pB+wwA9wPR+0D/BvkC/JD+bQfgAdEA3wT+A9kLVQpfAsQEiwHj/R/9ZAL4AFUC0fw4/hb/lvjz7unwaf6CBGIETATh/x8AjwDbAHz9Q/hI+M/83v0a+ykB+QNkAr8ELgtEDOQIPQE2AzECuwAGBYYAHwdEACsI/AO7/Or7M/v7ABUHUAC8/3gEMQG1/7793PRk/qj9W/bC9/z3Y/jE+V/+qghdD5IM5AUSBHL6Tv2a9+n3EPnA++wLPAdzBF8CsP6kBbEHKgyoAGj8+AB4AjUB+f85BhEADwLeArMEnvvP8+v4CP/vDTUIEQIOAOgEZAzbCyv6MvAb/tf/DALR/F74eAQ4/i4CIAUuCXP3Mvcn/XwBPQK4+VAA9QQjBfkDbP/L/vn2jfp7+VMDUPoI+Mf6WgEzCeQRVAbjAlsEqwJVAXwCfQSRBYYBbwWxBsECJwDF/Ev80fnK+lv1W//cAuP/0vX+9br4XQ3XAf/4HvcH/dEAOv3H+tcBAw4OCvYAogWiB4wEKf3W+7ICggPVBS4L+QLbAEb5QPjICxn/vP7xAHUCqvvw+PHz+/wPBPoITgIOAc/+iQQo9uz6xPkYAn0DRAKV/YH+Qfly85LycAPuBiz/Zvv9+4v+age8AvcEggaaBUYHeAK3Ch0MRAG2+hj+AQgZBKn1K/wJ+sP8sft4//sAWwN//5oC3APH+vn1bPYU/7YGl/5iA5YGtAHxCfH87/6l+wL+Uf+mBB0CSf2I+nn5/frfBfIDzf729Mz6o/2f/nr+DAPgCRgJNQpdDDUAs/h/8wL7TQbN/7n+xPlR/8QH3wVi/xv+i/Wb+9D1ePS9+VwByPzCBywEygn8A7/4qvpaAP35Nfx6/8H/bgT1DlIKXgkE+kb6B/ucAPP7Qv2s+VL4iQUgDykA4voG+joAvP+E/6j9WfcP9ScD0wj2CasEu/wFBOf7+Pw3+xHyKfOP+yL/EQOV/5X/2gTg/YQBFfs0+dL11voK/90GoQEkAUgGngtgBUUDyP/3/ykCJADt/gACPAYP/hUA5wrG/x0CHviD+rr/IwTx/If2+/2N/V75svw6/J/+kfpT/r/3yPyn+ZwA4QNC/6QFtADIAtMIAgIqA6sCEQB8AeYDMQSXCmQDpv5i//v7aAfCB2/4zfZ++nv6PQDl/mEAUfYh+av9cfnEBLIBpPYY/U4CiwGF+kb5x/tk/bUCzf5T/joISAioAcgAuf2LANoE8gKXCYYDYQCyAj8JTA02Bf7/Y/s9/Az+sgC3/Uf/lwD0AmwFzgfI/CL+Lv4s/Tj/MwPK+or5qwGP+Lv5pgQiA8L69fht+t/44vr89Zf07PpfArMEBwG1A0kAof8n///5UPrrBUILIA6aA24EQgRVCbsKawpABDP9VvdZ+iADbwYUBUMFPQN9BnMFjfve/ej2vPYe9x0CagbK+qP87/8j+Br7n/ck+ov+gf3l/iwCtP0//vYKEwkSBSL8ivtmABsC2QKq+jH2N/mTA2EJVwjhBbL9U/2QAXUATgIeA8X9Ef7b/SYI0P8r+jPz9vrqATUIUwR++aPzPf13CNwMygFG+wj/4AFCA4oGl/uh/jgBiwG8A7cAcgAK/UICVAccB24B/v4fAXcBmgUa/IL3QfnV/8cGUwMU/7P3mfvb/B8KNxAl/mH6M/txBAj/9AGz+Av4Xf6ZAGQBkvykBIsBXf6vASUCugRaAsj+9AJWBS4Bw/7N/RH+owCDAG0APfzg/GQBLwZ4DOwIDgDDAecK4AAuArv7vvuN++wACgRcAS7+Z/5dBIsBygCj/YEBhP/DAIwGB/6O9Z78GgBRAvT9e/qh9YL4AAD0/GsCcgsYCcIIcQQ5B77+awCy/boE9AGC9/X4RvoDBbICcf8s/0r4dQIsA/EBqP3t9Af+HgP6By77Jf5y/a7/rQKQAWsB6v30ALUMYg3eDFYGRQQPBL8DAgJxBZ797PuE/pQAMPvR+cn5c//e/jAHZv0Z/yf9T/mB/CkCeATNAmf4xPmB/G72r/L37W0A3APMBswA1wN9/4MJ2wHUAYUFLP3FAUUGAAITCAkIoQHFABkFxwizBBQDqAHQBIUG4wL7/fj6Nv7MBpkHTgHr9u31+PrQA0T7w/zY+ikBrAVj+935Q/hS+T/8Wv4lBH8BBf2j+1H/AgHrA8gAY/qV/mz/FQCxBpMD2f7N/Fj+7AfCD1QHrwDp+YX6G/+LAt4Chv1PBacGJwLe/v38GP5B/Gr3df8HAgwDVf7y/ub2G/bb+lkGYv+N/aT+p/oh+JT66gCgB4T+xPeU+176vgnGBVD7Rfbn+UMFMwxhCMYDTgNV/TkEUQIUAl0DkvyGA4cGUQWsBmv8LflO/mID0fv7+875vv64BrUCRgAA/UL9yP20+6z46fou+xj7SwiFCF768vVI+dH8WgBi/l77QfLs+goBZgoFAkf+oPq+/ggFmASBAC4C9fc7AxcITgtyCdsB7PvS/6oADgDG/lz96P5nBFoBfQP8/1L8GQUZBWEAwvgE/B/6xv9S+oH9ZgDGAosCjQn+/bL/SPhX+eT4dAYyBS79jfph/Or95f6Q/Bb1a/EO+jX6XP3j/WT98gQqBK0ADAG5ATH+V/u1/zsF1wS5AlwB7QL9BwgFPQTFASsAIwS0/fr4oPjGA+IAiAlw/noAXPnZ/bIAl/ts9UD4T/ZE/Z4KpgN6ACn6jgNbBigFn/+Q9Vn4MQR/AqYDOABMAsMCOwT/BQ0GPf1U+UcDZQYmBt4BWgBu/oT99P53AID6Sf0bAqkDwwJo/O77B/3BAXUMeQckAOv39vr9/Hz93/h2+Zf0l/2CA3oBRP4z/eP28gRmCgwLOwNc+dkAjgQtBUQCwf0VAGgIBAhnBP8GMwz/CHYH4AgVCT0ANv59A4QEsQcB+p4AJAH+/+//5vd29oPxP/1z/9P5k/eT9/X5ywPSA0v7hfve8q30x/tb/xsCswRhAK4GQAN/A2wGtwF3+5AEvQe0CfgHjAeABhoHRAntAgoMygFj+Rn3XvnK/OQFR/1rAIAHhQarBK0CcgAm+rD1bfla9C79NwYbAhYCXwKk//8FJf4b9Yb+GP4d/d4CTvy1BCwB9AGj/TX7lQG0/J76bPa9+vn/AwXtBREAVv/vA10EJf8f+rj4vAGxCCAF7vrTB7YG3w81CNsBPwLE+BP7NQHsAQL+O/ekAwgGNv/X/8sEYf1pA24C7Pr4+0/33/nlAKf6Gf/XAQD+HQDA+y7+Av5L/U4AJAB4/2cD3P5p/qb/jf31+SIBhP/J+QL9IAUdAN4AvQa8ApoE6gKIAFgDhgOw/i354fTxAU8EAwPe/UkBLQXsAIz4q/1I+vj7jAWgB7cBbv3u++3+twL6+sP72QBB/Bj+6v7d+rT94vtABVUCl/6w/2z/CgOmAw79m/uqAGwDGf/HCGkBT/iX/Z4B4wKeAOYDzf8YAM8CfwK3AIX3qvo9ABIECQnc/l74Evd5+hEBl/59A80ES/xQAUQAWfrF+vT8Uf7qABb/vvtO9af4Tv2aAsgAUf4mB1IAVf44/WwEn/6t/VUC+wvzCA4Bpv8sBG4DSQo3Bk7+FfkA/UkAFgKoANf+7vpJANkCRAJZ+mz3YPdz/ocEm/kG+sP/2/09/Ybz9v2h/XH4Rvwu/AX+RAGVAygE4Qa6A80BgfvU/fsBFgJ8+3v6c//sCBcIBgb/Bu//PwE9AHAKtQV0+rD2SPtQAD0EMf95+oH8BQGhAVr9Ofb+/fv7GQS3ClMEWgFr/eD8ywP2Alz82PtrAc8CqQOe/B8Acf+u/zMJtABzBNf/2Pnq/HADTQiPAEH80P84A5D8AfkQ+/7/WQbDA+QHcwJCAvkCEf2yC24N1wLA/EX3UfZe+dsA1QXH+6T/ZAKL/qj+HwEW/vEAzf0l/rQBGvyR+MD7C/mN+mEBWAIBBZD8Ef5ICCAF5AiCBfIMTwfxC0EKZvyv+779cv3N/WICLARFBW8FaQH+/1n5Tvy1BGcE8QjNBDAAuf4n/IX5FfKr9s/+3/nz+j321vOh/83/JABZB0IEGgBd/3r8wQKz+aj+7AFFBm8IiQOABXD9jQFgBAUEJwEeBpUD2gQECtkAKv84/Cr3K/zC+C35cfY3+Dj/Gf+bBv0I0v7LA9gJHwehAtD1YPic/B/90wbPCfz//v7y/xv9Tv9c/d78ngnr/64EZQZ5BgAA+/um/6z5bPb89u76tPzt9Xj/UgBoAHwCAQca/IbyfPxy+j8AH/3U/TMAngCjCacIoAafBGv9rQAmB94AhQiVAoEAewZuDsEMCQh3/Mb+NQC993r9Zv3P/NcBIgKf/3UD9gJw/vb7Bvlx+OL79gDq+4T+HQDG/kH6M/si/e3+UPqm/aH8RgDhAyMH2QpnBLL/zAC///H8DwTXAmEB1gCnBskHOgrNArwDpgNrAvEAr/vI/PX5F/jIAEYA4wHx/dT9c/4C/gwDbfuI/SP4qPyMBYEA0gI0+KEBNgOTA0cBRf89Aw4BUgaPBrQJiAhqBt0GYASG9f/3FQBoAFwHBgbSApr/tf8w+jX9wPta/Dr6qwJp/r34KfyE/eT3qwH2Ab78l/3O+lb41vqA+Jr/tgY+BYAIkQbsAWb6i/+6/63+PAdUBgkJ4wGMB4cGhAPr9cMCnAurBBH8bfuXAW0HzAjjDLoERAEi/oH8Jfan7eLy6/Wu94b/VwrEBGQBSPoU9Lj6O/67+wz/UwNV+9ADa/6BAXQH7AEiAKr6ufuS/DsC6P5FA8kFn/89//kEvwXw+HT4Fv6y/6H/vP0e/94CKgQVCZAEev1j+Sn7g/lv+a39vwQF/QoCZgGmAmAFEf21/8UAhvXa9hv+eAQIA6YEbAQ2BagC0Peo/WT/Tfui+YL2cwNsBcsDnvxL/OIAVQDLAkb70P/7AGH9aPmq+ej9ZwURAGsBl/3s/BX6tPp8/sMA3/iI/QMEcwPrA47/ivvSAZoDbv5oAOX96AJ0B3MF5wCGATUBcP1LAaQCDv3X/cX8n/8uAk4DzQL2Aaj+Pvni+Sn63P8x/XD8KgNdBakDsPTY+ekF7wDT+Az8LP8ABFIIUPyA+mr4f/6GArQBMQLIAYz5C/qm/lwIbQCVAokCSQIC/Y37zf9sA6wGkP/D/Bb/+f3cAtn/efsw+xYDAAOo+8P8mgXhAuz9V/s//A78Kf1J/ZX/LP7W/BgAtABbBU79mP8IBV773/cs/aH8D/5d/voFjQAbBPoG+/7P/lz9XQJJA3ACRgf4B+oAxPlT/yME+/zFAQoB7PrA/KX8cvt3/OP9uPpcAS79KfpMBVME2vj4+w8D2QJM9yb6xAXXBBIFNv+aAur7Uf7RAAIAOAN2BvgHXQJC/439uQC1A44CP/wx/UYAxv7lATwG8wnKCk8EbgPLBdcBQfxu/ub2w//NA1kHGQQx/XL6Yv53/R/7zQFsA0P4i/3S/dT+wQFdAj39X/4R/kkCUP3b/D0BHwAPAmn/FQhuBBkELATB/2n/Cv4CAKv/nwLVBhv+swRFA10FiwPN/4P8NgKrAbcBAARYAkT+wwB6/okCtwPv/Cz9XAHAAHX9lvi3/o7+XwL0/TEBTwXt/qoAOvyo/s/8KATQBIUGwwHUAFD8X/4IBGgJNQiLAVr9FgKrA5MDi/5WA0IEzQPD++MDvwRE9N/58/lZBzsCTP9s/6z43/YJ+lT6z/xF+D3/MwGa/ZD/cwITAY0ARgl4BQwDwgb/BiwElf8PA8b//ATxAY0APAcfAQcBXQVjBlsG6QWoAYYA9P8gApkAP/7Y+vsA7wDoAkP3B/xY/n/2JfWN/IX3Zfh0+WH6NQB8/NL9twJBAAz8qvuy/MgAHQBk/kT8AAFkA8YEWQfo/ycA9QbwBRIHxgUyB7oEawBm/FAAvAEOAIkCRP3Q+HD7KfqbBqH/awArALD+cwJy+/n+wf7p+az57/56/OwAhgKO/tT8AgHgAWwDzwD4+2b7qvyl/Bz6WAFMBPEK0wWN/cMBZ/+3ASwDl/tE9E784AFQCakFJAFq+nj+4AC2+vz3MPyy/IT9xv5A/2f+6gAz/Hz+U/86AGYBuvg4/3AAbwWqCBoIQAQlBdkCjgJuApP/5f0p/Lf/twOMBsUJIwUsAyoDHfs++JH5nvq3At7+h/ka/Lv8wviN+hj8wvqj/YYC1ABA+L78FQCRBx8HTgKVASkCCPiI81b4qvzj/+ME0gHSAn4AnAG+/RD7cAHMB3sHEAacAJ8Fv//PAq4EmP8sAbAElQTN/GH6S/wm+S78mgPlCQwC3v0mBh0CnP1d90T73/il+u76cfdg+En/FfrFAGT+lQMzA1MBnP/8/3gD2QJaATIFof4//rX+Ef+3/zYFwgWNAD/9UPyiBoIFrgRsA97+IgA/AHACGPzH+6H/XQM4/S35gPlf/g//OPwA/joAIgPiAHn75f09AKYEfwTVBOECsAI2BPv+OP7t/ov+uwBEAioDdf7P/VsDLgIzAEYHWALNDEUFUQMG+mP62/tz/9v83fqa/dQBMQJ1/wn5tvu2+gD+mfnxAS0I/AP+/Rv/HQCKCWoGzgdGAA77zfy3/hgKnwW+ANwD9QVOAN/5x/ou/Cz/D/+J/uj+yPxABHwCmQHKADAAMwA1AfYAVf6T/0z/BAAuAiMEjgKICL//e/rC+kT9hAPq/XT6XvrxAZkIDAp+B4j8LgAsArz9UfZF+BT/UQKo/qED9/9kAS7+Z/87BBsCHQGzBNcBugY5BOQFNgOmAyL+zvku/TX88fyd+WEARwFnBCL9AP1ABT3/J/5R/nr90gERAqgBCAN+AJj/4wHN/CkCtf9QAK8AnwP7ACX+6P7IAvUElf/oAgP/q/+LAt7/owD5/cgAGQQY/lD8ufx+AE7/yABCAyME6gDL/8L6Nf27+gz9rwCX/lL85fztA5MEX/7g/Tv/OAI4/eD8tf6m/tEA6P+cApoDtwMyBbH51Pxa/mH6pv6hALYG4wEx/pf7OP0M/Sf+LgKv/X76cANKBF0Frf6PB0AGxgVqBWcG9AC0/Xj/dgaWBZAE9P8CADv+XPwH+4f3jfywAt374/6o/er9RP1RAoUFIP98/tEAmAOx+qv0mfzt9k37kvyp/y4AnPzq+wQA7QM9BJkBQgF1/UAGygk9BGsBQAatCWwGAgG6/5j/vgKQ/1gD/gH5AssC6wMYAm8FpgKm/mH9wwITAGP7lf1J/jMBLAKn+hT+1/7e/8761Pxa/a37MwAH/cz5HPjK/DYDGADl/l/+nvtq+jL4o/0CAX4H+QSnBlYEFAKkA6gKewbmA5cAHgYKAwUEcAFTAhv/Pvni+SD+iPsMAfv9hv9d/5T5P/y5/EIDHftA9wf7Iv3N/fb9i/zr9/L/ugOEA0IDbgFhAJL8nwJOA6gCnwWjAHIBNgVf/woBtQLCBhIEwQPPAeMCpv7+/rv7aPxE/iL/wf0T/V//U/5M9jP0Ovxt/Ov2d/0W/uz6Uvkl9DX6FfuE/0AGMQufBDX7JPyJ/nwC9gEXBSMEnQd3CPwD/v2vAKgJlAnDAe4JjQooBxIEcAHI/XwAXPw4/Mr8CQCj+kH63/cw+8/72f2U+p//w/vz+5D90v3sABj8b/od+3cBZv3N/0/4xfxOA20AfADMAHkGGQNt/FEF3gKlALcA6AKxB/IFWgBk/uD8Kf4e/5X9BPwR/uABbAOzBCcDd/2y/cv+OAJ/A2oFzf6OAkcDJvod+7T8Cv+DAN78EQBrAjf5xv8OAYECMwA1ABEDrQA1/b36B/vQ9uf69AHlAtH6PvkSBoAHSQLrA63+vP1g+UsA2QP+Akn/Yv5W/9kBof/B/p8CHwiRBwcCW/9MAnUA1gDDASIAcf8UAp4AvgBfAxUA5v9h/VEDWAPS/df+WvyJ/s3+Lv1x/yn8N/mb+H78FgNs//v8Jvk1/IQDxwaGAxUAJQPwBQwD7QIhBjULjAR/BOwA1P7F+778svyp/3ABuQC3AWYJdQIh+zYCygCBACr/1Pt6AJv4gPrM+3H4tvob/vr5EPsZBdoGrQHN/s/9sP96A9cFWwPvACgGFAULBvL/r/1s/xgC2AbEB30EXAGNAWAE9gB4/04CzgcfB2QBZvsp/iIBsP8zAoD67PvNAZIBS/qo/Y72VPAQ+fn9HQC1/+oC7AEl/sv/ZQZwAzEBFgP7AjoBAwSVAi4AjQEqBbUFrgQTAQ/+GAEdADv/jv/5A6UHzQJ8ATv/ZPzW/EIDSQNr/db8WAGuBc8CfwHN/+//twF9/68ARvyS/I36g/yX/VX9igbBBD386P7SAVABzf0MAgAAmv7ZAYIEjgJu/+EEugOXAIH+NgIPApD+4vz2/PkBtgYqBe8CX/zg+3f7PwDg/Rb+lf6J/rwExgV4BWkEIAPWAPL/uPl++5n8i/4YAsD8+PpC/aYBCv6j+oP89/+Z/ET8ff89ASwBggbqAusElAfJBlIAa/zc/rL9lwBuAqgCcAJ8/uv/zQEP/nD8Kf63AqwGfQW3AU7/g/qe+tb7D/78/+P+Xf4y+ez84fSP+vj60v89AAf+LP7r/5r+owAr/Gb9NgIrByz9iPqG/FEDZgCSAfwF0APIANf/LvwY/V/+IwVXAKj9xgJbBCQIfwTh/tv8A//g/WH8j/sC/df/DANkAdX/RAF7BA8EOwKS/j3+rf5p/9L2aPpH/Sv7wPxYAo7+2/3d+Br8qvrr+S36KgOEA38BcwK0AcwAlQKVAUL9bftaAnoDFgSE/vv8xgTqApUEDQY2BYEA+/2A+dH7ivnY+hH93gNn/yv7sP6k+K/7IfoK/Yb+MwDVBTIFrwH7ALkAGwNb/3gEEQEB+SX2Ef9ZBm8IoAkbAwMEqQTQA4kFw/5B+xP8i/96A0cDYgNV/ZL7xfzW+rb5df2P+6P7gPij9GD4Ovtm/XP+iviH9yz9PPoh+lgCpv56AaQCWwQQCCIK7gklDwwNvgoYC8IHPQQTATEBiwIPBcYDofxS+a7/l/1N+8T5D/7LAmYB9/8f/Vn6mv32/Oz86flt+c751Pu9+a8ABPke9/T8SQLeAs39r/2lAOgBAAOpA/QAIP4FAyf+kAMhCasDZwONAYwEuAe2Bq0AWwOmAdz+TgBx/ykBEgVAAycCd/o3+j38Xvq3Ab//wveV9rv77QJa/pf8yPzm/94A9AIRAwYFewZbBaT+LAKQAdgHvwMdALf+m/o0/x4EQQAR/ggF9QWOBKAGhgOL/Wf+pP/MABsDQANwATECU/3V9jH9ZP4V+jX7o/v9/MD6QPiT/wf+HQCbBzYEGwFpAhEDgQI/ABQD/gNlBM4GXwMzA+8DvwMIBvgKywXe/3sEg/xu/3z8sgAeBFABvP0KAagCJf5hATv/GPw1AKYBhAIxA07+4vna+WT+m/uq+6P7LfrWANcDYAbaBZgDSQHI/pH6Bf6C/7cCMwJk/zH9JAFNB7kClQO+AjsDOAEZBF0Flf5VAV0DTgPGBHwAKfso+fz1S/uX/a3+JwD5AwMEAQUVACz+yPwP//L/HgOvAWYBrfvD/Pz/Ef4WArIAjwDtAh39rfyt+04ABgUqBTYCVQC3AFIAAPy/94/4vP++ABYCqQMs/63+I/n9+nf91AHXAcgCyACNAIP8AP8g/xgCfgBhASX/DACc/ykATv5FBSMHvwQpAjkEjwAMAjX9u/px+QP4zvlBAPX5Qfyj+gf9tvsA/Sr/AgEnABH/fAFw/Hf64ADX/ycC8AQyBzcI2QMFBG4DZgAKAkQCkP8xAngEHQAr+r/25/wiAb7+f//eAcv+9wPbAdsASvcf+iz+qAARAar57vsCAUQAYQBJ/8L6Tv9k/27+ogSq/EH52/yD+jH+CAVaAikB4Pw++S4A1AF/AeYDCAOOAgwBiwJTBJICTgLlAb78EQD5/wf+GQaBAtH8qvwYAmQAy/9e+ev/o/2B/LL+RP6h/gX1nPyS/nz8EgRTARj8aPrv/WEBMf4M/ggEbgGP+xH9vv1F+Nb79P+//67/fALkBnkHqQZ6Asb/WgFHAf8FcQUd++L77vvm/+P9nABr/Rj9EwFa/Hr+BPx0+kP4hP64BWgJSgblAHT7EvZi91D7yAGjAEz/Bf0Y/bL9DwXOCJoC1wIWAqgBCgXSAob+J/3E+cb/bv7eACMEtPqh9Zf8J/28AeH+rv+Q/Y8Aq/09/+3/Wv58AEj6NP+q+/sB+wF3AI8AJvn0/lgDwQSJBN4ALgC8AV8CNAWuA9z+1AAYAaYESgW1/n3/7AFBAJcAUAHg/UsBUwKV/YsBpfss/Vz55/meAFH+df7eARsBUvyY/3IBZwTLApwBfwQA/C34HPqSAkwFnACaAs/+C/s7/vb9w//v/hP92QKdBMAA1AGoADH/ff9R/xED1wFwA/sCZP7X/20Aw/11ADYElQFyACUCcwStANADNgKiBF8B0v9+/BYBX/9tAKH+BAAdApsGDApFBSUD2PvH+sP++/7X/uv/t//0/jgDyP9G/Nn+nP6F+437Tv68/cr74vy8AlYEw/9d/wr/AASHBYYDtAG3/oEBzwKTA38DSQLNA5ABGPuF+xH+U/3PAF8KZwXkBuYD0gMhBucAZgJ6A84GU/44AaH8rvmy/goCiPwzANn/0fyy/177j/ih/tn9HgNDB0gHXwLR/Nn81/7q/vQBlQROAgwC2f7e/+EGlgXbALf8J/2iBqYB7AA6/fz3xvds/+H/lwF8AJ77R/28/1X8egGE/z/+twDSBK3++f44A4n/DAKCBDgD/gJ1/hH+EgbcAhP9IAQvBCMGCAbOBuj9ZP+mAssCa/2+/a7/ufwf/agA7QKfAs39FgK5AcP7VPqU+ev/iwI/Aq7/fwJS+Rz4tviW+tYHtgfZAEv8OAIMABQEWwT+AikCyAPsAKH/6v5h/JD9n/5iAsAILAOk/+3+9vzz+lj/Rge4BIYB3AKJ/6j+QP+c/GT+TAIgBdkCRgCO/iL9LP119Qn6Vf73A2QDMf8pAdL+bP9H/d8FRQM6Aej/w/7IAZX+APxvBoMKSQLZ/+X9R/+Z+6r8J/4p/rICAQavAbf0H/rZAZf9XPt3+sr85PqX/OYFmwYzAwMDCgE0/436wQIeBIYBgv96AfL+0gEIA88Amv1b/2QDVAWI/Kf58/rx/UcB4AESB6YD1P1H/cj9CgEYAbr/ZgKPAL78Yfxv+cb+DP6T/8ECMwAp+w76hP2z+eP9pQC0+1v/tQTsB2kCS/us+sX9TgLeAUcE8AUqA3P/J/7w+c/+xQA1/VwANQEz/cL6qvxR/jsEmAOkBY4DPPu/9+/zYPjb+6T/q/8q/wUDMwD7/vT/3v5QAfsCdQN8AoQB6v5mAJIBNfsp/d4BOP3q+3z88/vC+TgBmAP0/Z//IgFYAz8CSQLjAwwCufwv9xT+8f2t/JIB7P1B/IT+Tv/BARoAg/tVAhwHNAX3A8MCbv8b/8r8Kfz5/mH9Efw//qD5Zvos/eb/dQBfAEIEqAFM/+3+mP8xAQkAWwOTBEwFGwJV/qv/+PwHAT8AUQJABb4AOvvu+soBVwBy/VwAqP02AlUCR//VBN7/3v42A2L+OQQPAnz8Mve8/if/P/xR/4L/HQEdABb+BwLh/pr+iwE7BJcC4vy//z8BJABiBZ4B1PxE/HwA0gEF/8/8i/0bAkwEhAPmBV8AEf2R+ab/TQjoA97/qvwK/238gPj2/WsBOQZGAKP9ZgJE/uz8KQEXBR8INAapAwn8Sf+pAyf92f9HAi4CDAFd/vv9Av51/tb6jv72/cz5cPw//V/+GwNwAm38Nv4QBqYDL/9k/T8A+f3P/ED/CAMFAeIA7P0KA58DDvxD+ZT6t/8XBrUCiABUB+oJhgD2/F8B2QJT/1oAOwVWBUQAeAPSBE8EfQX+A5X9Uf6cArMEzf2P+6EAswSf/4AFQAbS/fr3ePY3+4r48frS/w0HOAqQBFIA+/3yAhv/wvnPAF//WP+3/m/6zf8CAU7/JQOsBUcBqAGO/8z5Fv+NCUMGswZ0BvMHXwH9+Ub8UQJ/Avv+bAWDClQFNgIM/ycAwQIFAff/+/41AMP8g/rl/coBswWEA7L/mQBu/mf/Yfzn+hr7tPx6/a8BGghQAPD3rf3Q/4EBoQFaAu0DngDb/esDggUnAUQAOQVL/NH89gHP/mj7Qfxz/xH+3v6oArgEfQSx+mT90gSIAV3/kAR9BWoIHgQ4/+AB6gLBATAAWgCp/2wEq/4U/zT/Pf4C/vsAGAAv/8/9Cfw3+tH8ev1++xb+Bf3P/qgBnABA/279vP3c/3oDZwU+BnkGEQHY+xv9XPvD/YgBiwIf/FH+Hf2q/Oj+7f5d/ycApP/i/En+A/9JADEB9gBlBZYHZP+GAQUB7/xm+8j+lQQ2Ahb+tf+p/wf8+PucAVABFP8I/wn71/7v/lMCfwGX/JL9tPtY/vL+XPzW+//6gv9uA0QCowAfAVYElwJrAJf9yv30/ur+LAOQAbwBqALS/TH/wf+CA7z/Ofnc9kv95f4iAfn97QJz/tb8+f8JADsCPvly+4QDtAFr/FD95QAH/vT/GAIH/S77nP3PAZ//1/+BAm4DEgZPB1gEQv7W+mEAIATo/sH+U/1fAK8BQP+tAAABywJm/bf+3fiW+oT9oPqS/DUBNv/U/eX+wQN6ALL9sv3i+u/9sv1TBGgAu/w2A9kAw/yZAJgEsP5h/DEEZwOBAG7/sAQDBjgCzwB3AfH91PyS+7v8lf0zAdsBvgBpBFkGwQFT/Zv7mQCw/uD7qvqyAAMDIv0g/2H9d/ow+xD7o/p1/eoAUf/KAAMGfQZCAlP+wf+jAf79rQDjA9QAQP89AW0ADwRPBkkBu/rb/MgBwQMWAc/70fwxAWMGwQPF/eD7/fry94r64f4a+7b5qAHnB1AB8f2PAPsAZPwC/jX9pv/O+jP8xAR4AzAANv4IBFAAwf7y/z3+4P3P/qsC4gCQASEHzAahAxsBuAUGCF8Bq//tAg8EMAp+CnAChv3u+4v9yvup/xECuv/U+zD6o/tQ/Bn/7/0r++3+Cv7l/pn6RPw8+z3+4gcwB00GswQrALAEi//A/AICzganBoQCcwSiB0UDawFvBe0EsvyK+g//RQNjBkkCIgGv+6f5tAHDA4YCa/6U/AD8VfwiAYAHVwc7/t7/mASaAu8BOgEM/Rb9jfyVAk4CawBR/7IABf5f/AgEeQZQAR8BFv+FBfkBGQQ4C2oFy/+kAq0B6v1I+y79bv+SAFMBXAH+AlIAJf5J/yD+q/+L/gUBUQLIAlMDrQA9BKYDrQFyANn9bfxwAFEDyACyA4gKDwToA1sDAwUOAaT2/PYn/SEGPAbG//7+rfvx+jT/7wJa/hr5YfxHAtL/sgD8BdAEqAIDA+UCpAJfAm79bP8J+yP5VQLRB2wDUf96AQ4AefrM+JL+IwVBADH/CgI/Ae//zQJDBh39fvup/638rv9dAhQDi/74+58CJf/S/cH/D/+1/68BvgLsATMDmQCQArUCJACrAwgFPQL+/iL8xv6Z+4385QLnANsAZQS0Ae3/FP+SAPT/hfuD+zb+B/3n+hH/0v2i+UkCKgNOAF8AaQJkAdj7Lvtw/GYBMQTaBAACbfwP/9T+uf0KAqT+kP5TBLADBAAK/tL+2f2PADgD0v6LAe//lQGeAIT+pAIbAs8BngBQAUUD+f8Z/0v8SwHGAvv+E/wu+xgA3gHnADD6xvQa+gz8af+VAuUAcP6X/UD/HfxG+rn89v4g/xv9UwFOA74CjAS0AWv77wGgCLYGJQSJBCMElf9u/uz65v8EAK38qvxj+0v6mQCE/yIAqAGf/t7+5gXBBOD8QPer9Uv8WwNxBS8EpQAf/Bz4wPwzAPICVAXSAp/+Tv5OAu8CTv3h+PT8vgC+/dz+dQIn/j75wwGHBeECCgLhAtsBLvuT+OL5zPkN90v6+PvE+W7+BQPQ/xD63fv7/T3/rf1o/EUEfwL0/DoACgPDAI8AmgMkAFL7tf77AZAE7wHi+77+XABPBdID7/7x+qr8MwDj/lz9UABY/TgAwf+SAX8EWgFo+gz1d/wP/kn+Vv/8/1/+l/zF+9L+5f44/0P67PsYAc/+LAE4A3MDwQEbASgFUwNTASwBDvxB+R7/kwTqAHMCHAatASr/wPsaALkBhv3UAA4ADP5//dz/egHNAYsB5QDXAQUEy/9fAHX/pP9QAPAEGwTK/Jz9Vv+i+RX8mP8MAFn6ovn0/eUBpgPnADsDAgER/0cElwAX+r/4lf7yAg8FRQVYA18CH/30AAYFAAJSAB4FCgP+/wD9zwD5//T8y/5//ej9JwDe/5j/hv+fA74Bc//pBXUCawBLAPYAGPvD/FsFWwOh/079nP3v/er8ygA1AJr9hgF6AxsBPvmc/YEB7f5y+7UC+QEg/83/MAAbAgUDpAJ4At4A9v2XAgEFygFyAMMC2wCG/Kj8LP2S+5781P1aAMoAhP0b/xEDHgQRAPL+fwFWAxYBgf56/aX7DvvZADIHNgJEAJwCWAIuAAUCjASjALD+qAI/AvT/X/4RAT0Bw/vh/uIA+f56A8gDt/+t/nr/wf/7AoMHMQNt+9346fopAN4Ajv4U/hP8M/2kAxkFfwFMBWMGhgJ/AQAAnP8PAtsA1ALfBOMCX/5rAQADif70AuMCDgBu/5ABWAFoAHcBiQRABJwBhv/X/Rj8QfsAAwACdf+hAMj9CP/DACn8Afqs+QD9uf3EBZwDAv1EANf+aQJ7BMQGkQVkAgL9jf16AIb+qQRiA/v8AwUGCE8GtQPoATH+Kv9HA7ACpwd+Cv4C8/rw9+r9wwJkAucAlvoI9X33ivslAkkCMQOZAEv8df+QAfb+t/9//h/9+f8RAnMDgQJVAjH+4ACrBAYGXAdXBygEHwC5AZYFRQYKBeUAXAGV/W4CQwXX/i78vv7U/osAyAB1A4v/APwL+W37cgGJ/3H5wvkz/QkAnP5aAWUE4ADS/a3+JwBf/s8BGwPU/cX82f/BAp799vy+/dj7MPrS/h8Ba/4w+6r7AgKpBoMA4QJfAIH9tvm7+iv7ZPwRASQAwf67/L7++QIFA7gEoQOp/wr/ywIoBVoBCv2t/Uz+GABEATgAq/5r+2P6wPtVAmwEBf1B+tn+BwCt/q/6fP3C+b/4q/3L/iT7x/s9/DP8vv4bAj0A6/+m/UkCuAQ1/Vr9PwLSAWn/SQDe/60A9AL0ALIBdwHi/KMAkAJ/AUcB4AFXAE78Kv+h/uT5Pf1z/gD/Z/56/qMAmP+t/OL65wCiBbf/JPoE+7kAEwDc/lsDyAFY/pL8pgFmAFj+AAGt/Zr+FAK/BXUA5fxC/Vj92PqE/2QC+ABA/+j/ev7l+5QArQLt/6YCAgBE/Vr9ZvzI/M/7ev7T+uj9CP83+qr8vv4AAwAD7QJsA88BLgEuAIT/Z/6h/mf+FgHXAlUAQv0CAaUJEAh//swAtwI1/eX98gMJAPn+Vf3A/H/9DACXANH8z/0R/74ALAH7/VT6m/n2+lr9hvye/EH60vUj+D3+Iv8H/eX+EwE4AWsCBQGcAjEBAgJi/4b+8v8KBGkE4QVNB+UAfP2DAMoIMwl0B3gDt/5hAEkDFAKtAUL+F/ky+Hj+df9t/BX52fTR/H8E1QVkAEf/+f3s+4j69P4zAwUD/v8U/vH75PpCAZgEMQP7AiAFAQb+AvoGlgaGAJD/tf97BJgEKQKNAeP9jfsd/EL/0gSOBNn+MwAdAuwBLgJYAQIAYf1p/pr/DALn++z8gfy3/dD/SgT5BKb+DgEbAzUAOgFrAeYDAP+k/qQCCgTKAIv+rv8iAxgAIgHQBGcGsgPjAaT/hP0KAcEDRALs/c39tPwH/XwCcQQpAG0AhgLyA5ACiADk+hf6uftu/2EA4//DAZUC6vwG+SUEbAayASIAmQDFAfQD4ge6A58C6ALPATQECgQ6CEUEZ/41AcYC1wK5Ad4CtQPIAdn+mv/7AA4ByPwY/Jz+4PxHAu8A2f5Y/ZT8xv8tBeYDyAPjAaT+Sf4bAq4DtwDUANL/GPsu/MAAUQO/BQMDd/wzAkwFIP+BAdoF2wDd+lD85QEbAagBrf1++T/71wLIArr/UAC5AsP94/65AYgAcgB8/O75aPoMAMAACP/lAUkAWv7U/ssC3wRuAtQACgUGBRYEYAWkAtT9zf2m/Uj7wf44AOv/vP0//Nr5cv2lAIYDKASmAyH6avlLAJADQv77+xT/FQB8AQgDyALX/Vr7r/1dAnkGvgIf/B37Qfxt/D0COADX/Qf9uQGEA7D+NP/3A18Bi/7PAO8CnwJhAMsEmv9t+ur8JwJM/i4Aif9G+1L88v9VApUDxv4R/pf76vvjAZcCIv/n+z3/AP/5AWcFUwI1AX//1AGVApwDPQJ8Aov+HwGTA/YA1P6Z+1v3Kve4+tL++QHcAuUA1P6E/jD7AP6oADsDyACUAB0BlQHtAxUA5/vx/VgDZAKtAnoBof0O/RX8Fv38A1UCrwEEADb+6gFhAJr+UP3gAX8BHQHhA8MCpfw1+yf+sP58AZgD9gI6/Dz7OP2S/Gn+ygCaArQAMf5z/kL+1wHZAUT9E/1O/Kj+3gCPANv7eftQ+/n+ZgF6ARMAJ/2K+2b6G/7AAA8DLvvz+SH7cALUAaH8cPtZ+pL8pQCkAi4B+wHUAn/+Jf7jAVUCsgDFAWkBwwHL/kf/DQVkA+P/3P6j/AcBhAM5BWT9Vv+5AkIECAPc/wIASf/P/HX+DgEI/637vfmlAKT+nv3S/74Acvu9+lAAPQFyAHP+sv7W+2r6Wv4sAXABAgGJ/n76Iv2eATEC8QHvAFUBZwO8AtEAxf1VALwEFAX+/zkF8wYpAnX+Nf3D/+IAcwVMA60AS/xN+Q77Tv98AhH/V/xQ+3z+ev80/1j+XwF3AaYC9ABaADb/Bf4sAT8Ba/4AAIgALwOh/wkAfwHB/ZL+vAI9Anz9gf1p/g//2QHAAO3+0v2oArcC+QEwACr/+vlpAzUKjgTD+937MQK0AdkBDwNEAC783vwHAFoBZAJlBKsC4gBTAdwC6AO+AYMAlABMAm4E1wXHBzEBpP+VAZP/ngD8/zYCgQD0/Jz+0v8U/sgA+QMd/lr7V/w1AMoAf/+B/Vr7yP8AAmkEyAHbAA/+APzc/rX+nP4s/zUAqgCS++b/egJW/3cA+QMkAfz/ugOEAgIBTv5Y/qEBNv+XAGQBkgLlAG38UgAMA58CHgMzAe0EFAO+AY4EgQHl+1UASf5V+4EBxAU+BUX/Sf1LAOgD2QJyAXACFv8w/FX71P5iAgr9a/u0AI0AFP7N/A8Czf30/RsBAAGSAJMF0gF++uv48v7cAqsDfAIAAlMBhAHhBekGCAUs/8H+QAPQBGoFWgKtAW0Au/xLAMoBSQBOAGEAf/4HARQE7wAdAFgCsATSBE78d/1wAdIDDAHG//b7LgAiAMH+JQPPAlj9e/lJ/zAHFAVYAREC+wIqBfcDzQFi/4b8TvxkAb4CoQKNAXj/twCqAMkGdgZx/2T/wQExBIv+2f2SAQoDtAE2BE8E4wONAPYB4wGqAOr+awBb//kCLwOX/Mn5X//e/1z9JwFn/wQAWP5i/3oDXQQ4Arn+6P6EAl0CA/+5/NL9TP+j/VIAzQSfBcgApfvB/T0A9gDZ/rv7WvvjAcsCMAC1/54Aw/yj/EL+OAAVAHf88/lC/2IE+AD7/ej/Bf6o/cv+vvwb/Qf+Hf3s/QIBowF++x/86v35/QL9w/5R/r781vs9/sUAIgFYA/YBHQAfASMF7QKE/v7/6AJCArD/zwE1AAX95QDhAuH+4vs9/dj6if5UBpoCG/72/rIDOQURAWv9kv3v/4v8TvyeAP7+Y/qv+ur+ZP9O/wP/LvvE+GH8cwJYAqH/4ACf/mH7Av7oAbQAfPy+/Uf/qAB1A5oCWgHpBRIHHwBJ/mYAcALX/UL9Uf46+9H6Gf+cACf/i/7A/KH+XwK+AAz/5wCyAgMDiQNkAiL/u/nE+BH8vv4nA2ICWvu++xb+RQM1AHAAEQD+/mz/sv6I/XL9+f61/u3/Z/8n/g79+f1yAFUAQP+f/yf+1f/jAdYAKwBxBJoCS/wY++8AhAFO/0ICLwQeA44EOQQ4AVr9DgGNAMMBuwBfAJ/++f7lALkA0v/sAFP+7P3Z/wP/WgEAAG4CrQCQ/rIBUADh/+ABCQBE/B378v/jAhQDsAJrAej/rQCrAoT9r/sC/Tr9HQKXAQcBw/2e+2H8S/yS/Yv+9vwM/+3+pv8RABEDIAMlA5MEOAL7ABoA+f4s/l3+Xf5RAq4GrgaCBNT9jQC7AC4BgwBiBacGOgFzA4MHqAF8ASkCJAHi+wQAOwU/AcD5/ft1AnMDGwNCA04ACv3P+yz/WgA1/ST75f02/9T+Zv1kAYIFtwEs/Qf7GvsC/uH/4wS4BXoAgf7+/yQBjv8RAZ//nP8v/2kBrAVEAn/+kgB7BEMFYwZICCgF7f9VAJcC9wPeA80DsAOLA9ADVQLU/FD8mgKV/3D8HwCuA94B3v7U/fb9kAG+AnwBnP5s/6v95fslAtIEugOmAjIFFwZOAD8A2f7D/cr7zf5TBJUCrwDZ/83/9P/h/18DTgMF/uD9JAE2AmQBMwPmBFIAvv13ACMG2QDq/rIBwwMzAogBVQDMAF8BHgSJApEFFAI1/Iv8lQFFBm4E6P/h/1v/hAFHBFP9PPr0/HoAFQCj/cP/sP+3/kv8yvsI/1H/hP+O/h7/yP8n/V/84Pwn/L78Rf/DASL/gv+tACwBM/7G/uz9bgG/BQMDyPwm+pL78gOJBSIDof9o+l/8EwBf/2T94vxk/lb/nAIzAC365Pli/rX+nAB8/tf/7wJFA4v+XPxCAvwE1wUIA4T/nAE4/pr/1AFn/18A1f9M/8j+Fv9O/fj8df3x/Jj/+Py8/dj7LP7KAHj/v//lAIgBTgCt/fv9qvty+uP/vgCh/tL9uv8F/coAZAL0AIH9xQBM/p78bQDN/VX9GgCXAvIC6/8P/3UA2f4p/hsBjAQuAvkBn/8O/fT9TP4p/Sz+Jf9h/Vr9tvu5/LD/WgByATMBtQKa/c75svyQ/h/87wD0AwMDSf/qACkAtPv4++sDvwPgAdADPwEH+wT6gv9RAmsCtQLV/578rvmb+b78hv/9AP0AmP/MABUAEf35/RgAP/2e/dkCBwICAC//pv8AATMBXwC5AkUDywKh/tL/OADX/wAAWAHK/Vj+cwMWAmYAvv4V/IH8UwGuA2sCyvx6/N7+GP1A/0v98v4Y/sYCPwIa+wT8bv9aAH8CawJbBPL+3v2c/2n+sv1J/fP72/vWAP7+FfzI/BMAof7m/7IBX/5C/bX/rv87AjEDO/8R/SL+D//gABsEbgJH/9kBgQGh/mgAkwTbAOj+ofxOAUL/l/xa/Wf/Mf6+AH0DawLh/u8BIgGL/1UA1f9k/c391f/Z/qX7LP11ARIEXwEAAAD/aQLgAJX/ngDsAWv9RPzDAEcB+/xw/ML6F/q+/mn+tP3F/XIApP/o/0cC/v0M/2kBM/4p/Qj/rv9r/Wv+EQFEAQD/a/3BA7oDIgBF/0AEcwMKAooGvARJAjMA1wFgBFYDuQGQAa0AbAPCBZ8F3ALvAeoCsgCh/pT8Lv16AO/+Mf1O/oj8Avz0/Mv/f/+B/P/6HwB9A/YAeP4U/hb+O/5HBM4F2wBz/+wADgAKArUDGwPVBXMCYgNuBI7/3ftTAtoHLAJ8ALf/nP18AGYAUwIRAmcDcwT3A7kBDADv/fr6GP5kA6gB6P/c//385/uc/eD8sP6rApMDdwFcAIT+Fv/P/VH/wf4T/cz7ufyO/0z+TfsC/p/+rv/XAnr+t/5u/2v8GAHtAm7/vP6u/2v+WP0sAWEAHwDUAWIDJwJSADMCpANYAlcA6P8TAHD97PyY+BD71ABTAvEB9gKy/5z8r/se/4MADQSEBJwDAAO8ARgCLAGaAiMFhAO1ArACNgJhAFwASQO/BM0DXQW+Afb7Cfv1+Nn1DPzF/O/9qP7N/wD8/ftp/kT+kv7qAFoBiABmAQUERAIWAT8ArQE9AUcBAgFAA7kCfgAF/9YAggX9CHsGKwe+Af7+S/1E/gL+V/og/r4B7f/0Ab4CiACL/qv+PQNKB0IEOAL7AHIB2QLe/5IBqgBB/F//GAKh/47+DAJcAST9XAD5A+b/G/6m/2H76/iM+cX8Mf1Q/cH/+wCZAA4B1wL7AOr+xQBbBCAFvwToARUAcgAYAUsAcALLAkAEiQQUAp//S/3N/h7/IANiBLUCiQNhAJD9a/7q/sUBMACIAUcC6/8x/XT7kP3v/Mb+RwNXAJz8kPwK/R/55Plh/UQAXAEiAVb/FQC5/V3/TAJzBIYDwwE/AAABIv/2/gcA0QDL/+oCiQOtAcX9iPvD/Jz8qPw2/0T+j/sm+qX7WP70/Fb/qgBp/QQAvgF4/g/+JwCcA2UEZQV3AfYA6AG1/8j9qP7c/1UBZgKO/nn7nP4l/jH/cgGeAJz+OPzK/Iv/Gf9OAVgBkgKB/lf7d/qR+OD82QHIAWQAIv1y/L79ygB6ASD/gf1p/Z77g/rT+Qn7Tvy0AUoGKgOB/Wv+df0z+4/7Cv0n/ej/cf8C/Qz9xfx3/B0AmgSoAD3/twDh/3oAzAAzAdYAawGVAhYDf/06++f8M/7c/pQA6gJ7BGkDiAGQAn8Ctf/7/sH+Qv7bAMoA9v4u+3P+4wHvAQoC1wIuALv8gf37AEQBZv28AiMG9AER/Un+U/3n+97/lQLB/ZL7Tv0U/94DlQQzAsb/ZP3K/fn+cgAR/2v+k/9HAtQCVQJMAjMCdf8l/0QCnQUFBBYCzf5BAAD/lf4iAagBjQDN/Pv7IP8f/U78CP+1/lUBDAIlAt4Bof5G/Gv7jv6UACwCBAC1/3oB/P8H/jv/SQG8A1YFQAPo/8oAdwBL+639Gf+B/hP9Hft0+x/6Avvb/TH+R//hAv4DqAG7AEsA+/44AU4CkgKSAZL+EwA4AzsF3gAR/woCsgFbAw0H2wG3/uj/vAHV/04Brv++/hQDHgWYBO//ofwMAl4HNgR/AwAE9AHIAWwDUABJ/e/8WP0fAMED1wP2/gL7+Pzt/+P/qP7ZAQwDYQG3ALz+GPyc/ED/twI4A9YApgGmAWL/cgCVAkwD2QJQCKIHsP4a/NT+of8H/tkB8QEeA1ABQP8PAkn/Ef6NAAoCSgQ2BYYDtf/t/woDAAQvBSYGbARCAa7/pP81AToAuf5OAssFggZ8ApL8GP6Y/7X+LP/o/2n/RgAuAqT/4/7Z/gD/GQOhAdn/z/7Z/v38wf2GABEA5f6PAG0A8/q+/ScBIgI4AAIAgQCwBP4CsgG/BeQG3gP9ANz+6v3I/rQBhgKMBKIEAwPtAyUDpP/x/WYAHgRhAHz+L/8f/c392wCmAWL+af1tACX+xfvm+Nj7lf7v/GIC9AN//+r8jv42/m/6DvzIAa8Az/5QARgBpv1T/gD/9/+BAdsA6gJ1Ad7+awCQA1IAHQKTBtkDL//2/uP9Jvt6/Wn+Rf9XADUBBwLX/sv+cv16/OP/SQPSA7z+6gBWA0z/3gAiAlsE0P9i/w8CUf9H/bX+1/1f/Sz+5v9i/rj6PvqE/fP7B/xr/c/7B/2X/mn95f3s++r9vAGGAlD8Nfs1+hX8awJiBNf/kP7+/8P9Ifvl/c39RP4HAKECpAJtAFUAqP5hAB0C4QMCAR0A/gN1/v/6Uf9KBfkBM/7P/vT9rfsM/vv9DP4CAQ0EOAOeAIsAiwGe/Wr55fzxAEcBHgMZA2gATv9C/gz/eAKtAHABywMaAFX+y/8F/gD+BwKGA4T9OgCVAfv8S/pV/u8BKQDnAFUA7wDv/GH7yvuU/OwB4wSr/s/8ff8KBPIDQARIBbf/hv5LASAE0gIwAOH+OAIDBDQEJwNr/hv9DAKpAwkASf6h/Kb98v72/b4B4f67+2375/x++cz4z/vb/bT9mQEP/j/93P+VAU4BZAGjAdf+mP94A1kG/gEY/jUAlQIYAD0BAP5E/Bb9IgA7/qj81P7gATgBpv6w/j3/fP09/o0ABwH+/b7+IgJVAUz/EwGG/9kAv/+C/yr/M/5R/q7/+f6f/uoBegG6/yL/JAEfAGYC3ALWANL/lQRFAzoAOALBA7cB/gEgApIArf6vAHMF/gIA/3X9Tv4kAKMAXwBL/XT7Tv0H/vr4mfnD/qEAEwDIAZoDZP/O+mL/DgHe/BUASwHL/lP9jv/nAOP+6P9OA6QGnAJO/1YDegMRAXMDRQXGBJoEOQbjARgCMwHN/bT8LAE9AdQCTgIkAScAkPzL/hEBZgBR/4sA2QB1AKH/1ABF/5j/vAPGBE4CJwE7/7D+XP3+/3wCoQCGANIE1ADo/dL9w/xh+sr9iAB6ABv/Hv8fAcAAEfxf/skEMQSc/3IBZgH5/lj9sv5OAPYC2QJfA+ME6gBQ/Nn9cP40/+j/1wGcAncAc/6XAWkBCP8MAGwDMwFJAJABPQBr/Mj+TQYpCWkCcP4RAeMCUf6e/c3/vv2r/ZABFv/g/D/9Vf6J/9L+Qv2j/OX8J/8uAZoCv/9T//v+CgFH/nH/4f/8/10CrQD0Af4EQgJ1AnIBYQGIAaH/jv9aAQD+UP0D/4gAdf+jAOb/i//o/Vv/MQGBAeMBYgRzAuj/wf7XBB4Dgv+GAaIEDAEq/3cAwf4W/dT9UgBJAJIBBwFJApcBLvy7/Mj9cvwA/Gz/B/7R+cr6cP1u/pT7jfqQ/Vb/0P8rAFH+yvwu/pD/2QB4A80BwwDIApcCtQQjBVMDOACqAAMFZQd2BZUC9gHXAQwAyAHeApcB7/4YAsEDwAA1AQUCPQCqAFgCKwApAlEDmQFn/8j9G/1//REATAJYApQAAvsE/OAAIAPLBDECev4EAO3/tAEWApP/GgAgArr/tQOhAVz9Iv1M/9IBrQKGAycDuQHeAQACiP08+7//fAKLATUAaQEPAxT+7f9JArz+iPuh/z0DGAHZAqgAq/0pARQD1QNABKUApP5H/2kBMAC3/+j93v2tAO0ClQH+/V74nPzP/uj9BPxQ+wD8rf7g+sf7fAB8AnH/XAD7/m79Bf6rAa4ElQLh/sP8jf1LAX4Ar/wV/Nn90P+PAJf+/v3UAQ4B1/+aAqj+APwY+176Pf8fAI7/iAB4AnUDRAC6/yX/sv8uAqgC7AFfAAf+zf1L/IYAAwU/Ahr89v2h/gcAcP1t+yz/6AE1AOEDyAOI/TT4Ifhm/JX+f/7m/5z+5QCC/6j8Wv4/AAUCnQTVBPL+1/2E/Q78L//e/zv+4f8kALcBawBp/c75xv4ABGwEWgJOALf9FP4W/nr+BwHXA5cCjQDU/Xj/hgBf/+0D8wZUBRsBxQAPBOMCPf8U/9kAhv+DAIsBLP/Z/RH+y/7N/gAAG/9r/D/9EQDD/6r89PxY/7cAdQMnAD38+Pze/p4AIgCy/qb+Xf+cAF8DpgIu/pT8AgJsA7X/RP2e+zX9CgJOAZcAgQH+/jgB4AAU/jb+aQEK/gL8yP7+AUz/P/z8/54BrQB6AWL+OgBJ/vH7t/11/Y7+FAISBVMDWP+0/T/+SQFQAJABMQG8/VcArAcZBrIANv7v/xECiQMAA9z+dPtG+yX/EwGL/XD+egGQAe8Blf5B+/P7Wvu8/VoBJADe/CIApgEb/9j7lPzB/i7+dQBzA1MDvgFs/3gC5gUPBSEGSAWaA74BFQBr/U79OgCGAwQHKgZ1AS4CygBx+X787/86AR8AMAAEAEkATvwX+n/9Nv82/hb/BQGw/z/9S/0g/+P/R/9RAkAFtwHj/w4AoPsa+yL/HQKhAOoAyALGArX+2f9i/6b9iPyhAFUC9P6B/Tr7vfou/m4BbgPgAQcBNQHy/i//Kf2G/kQC1wFbBOkGcwK8/iIBGQOMBEIEjgIbA7wErgOk/lMB7QOJA1oAiwCvAUsATP/9AK0BOADK/Vj90v+LAdsBtAAW/2L+vgFJAF/9KfwM/4YA6gDXAeMBNv8T/Dj9oQB1ATMACP/e/oQBy/4u/fgA1AEiAiUCDgFkADH/YfuD+3L9pP9pAg8ChASHBnoCXvvA+QAAQANcAaEA/QAg/3z+sAIKBBsE5f7q/mIDbgIl//v7fvya/SICVgTiAOj/rQHj/nv60/m3/bL+Uf9VAD8CFv4J+yL9Av7t/1P/tvkJ+pz9B/5H/1P/1/8KAQUBGAKLAur+vv0d/En+Cv9u/QD+7/yQ/VUAqgDB/zUBvAGa/ZL8IvzQA0cDCP9MAgUCq/5n/nIBPQL2/eP+fAGTAwMD9AE/AbD/4wF9BAoCTP6h/tL9m/ou+13+LP7U/v797PyZAGQA7Pzg+rb74vze/GH7c/8sAUkBgQA9/5z9tPt3AJgEuQK3/8j/Fv51/yUCpAOYBFMC1wIPA5D9SPvZ/EL96v4MARkFQgTxAVIA3gFVAtsA5QE/AUkBLwO3Aub/Xf+UALQA4ADcAqv+Tv3ZAMMCoQD7AJj/GP4xAasDwwNk/A78VfyL/Gb6yvxoAPsAZgAxAUf/G/1cACwBXABH/gX+QgEAAMr7pv16/1r95v9OAeUBff/m/6v/a/7ZADsDEQJ3AeoCRQTe/0f+BAA9/1r+uQDrBHgCaABhAUQBAgAAAT0A3P/qAMsCMwCS+5L9B/3j/yACOwMsAjb/9vwM/gD/ZgBYAU4AWgHqACn+kv2r/ZX+WgFCAV8DGQP9/FX7BAAjBkUD6/+0AJwB+wLDAdT9XP1//+MElQREAKb+Bf6h/Vj++QKdBG7/l/0AA3cBn/8K/4L/bv+EA4QD+AD2AKT/Mf9fAUoETgIi/ur9lABFA8oB2f7j/Zz+aQO3AzoAf/6w/p4AUf9c/VP+Xf4i/VL82wCk/mP5YPmE/v7+8ft5+ysAKQF1AqQDhgPeAZ4BsgB6AcoA3gM6AVr9MwGEAtL+D/6vAcUBNgNMAiL/zf6rAfEBif9f/qT+XwCV/04BlwGK+qT3af3NA5MF4wN8AoQCnQSaBLQBw/3j/vQC/gOy/lr82f9E/nD+DwU+BbIBNP8PBd0G3P90+3r/IgBVAioEFgM//qj7Wvyf/jAA2QL5/zH/pgL+AoEBsv0O+z38Ef/q/rT9qPvP+0f94vyS/Gz/jQGqAAgDlAd7BN4AlwGoAOEC5QL0AXgC2wFhAVIALP63/Nz/pQD8//QB1wGa/8H+DgHEBEIBHf30/+P/Lv4i/ZD+qP0A/Pj8fAE4AoYAdQCEAe3/IP7q+3f7Wv0//jb/4P39/DH+k/8K/6j9KfvD/AUDewSjAEsA3v4M/Ob/DwPG/6P8wPsH/cP83vz9/Dj++/6ZAVEDwADb/Lz9GgCVAXr8if4/ASn+1P0dAZj/Xf5p/fgAKgTnAAcB6gJ1AJcCyAMsAqv/hv7D/uUA6P/Z/cP9gQEpATb/8v79AM3/ev/j/9QBa/2x+WT+Cv4H/K3+wwEFAu3/kgClAMv+LP74AD8B1/8zACsAPf4B+m/6Yv7b/fn9mANvBkQAGf8pAHMCJwGSAcIF3ARwASUCuQG3/13/EwE/Ai8GIQbfBGkCbv98AK4EnQUNBIYCggPUAicADvxO/rr/OvzU/hQEygAm+4/6Uf4v/+j+SwCm/0T8bfxy/fj8E/zx+7n8gf11/zUAvP/U/WT97AHWABH/1/0R/1UASf8F//f/Uf6B/icCMQPZAZkBpP8PBMcGNgVTAxkDLgI1AWkBYQGc/wr9/fqm/YT/SwG8A2QBSwCJBBQDUf79+wf+SQFLATT/y/5O/CT9if4K/TX8AvuE/Wf/IgNiA7sABwCoASMEzwFJ/63+/v4uAgP/N/uN+9kAuQLfBBYEZgBO/+j/TAK8A3r/a/5p/5wAIP/j/eX8nv1kAB0C+ACvAET+Qv/KAXoCfwIFAx0CWAJ6A3gCGP3a9/b8zwGhA6sCFP+a/94A9APPAk4BfwEKAQoBhgBO/xP9Zvuj/Qz/WgDq/sP8a/uw/8oAWP37/AkAngHvALr/WgAs/hr8P/11//n/nP8TAR0BzQFmAsUBwQGjAFcAvgJwAg/+LvwYAHACXwJVAnMCLP6h/2QC2wFfAFH/iQIUA6MBygFb/3r/R//7AOUAJwBu/kT9l/4uADoBqP7o/18A/P/sATb/YfxW/zECYQH7/ov/sP42/5wAkAHeAF//3gACAi4C+wG3AMH+mP+ZAIn+wf4a/MP7Iv2Q/0sA/v0WAXoCVwB1/mf+awGvAP7/jv9z/3cACgF/A7cDQgJz/07/cgHLAvkB3gHDAgUCIAIUA2EBTv/X/kL9LgDvAuUBvP3Y+yn+0P+L/rL+if+B/lP9gfwE/G37cv2a/dQA5gP2ALX/zf/h/uj+UwEbAUX/kAEtBWYACv1d/gAAuf7S/c3/XwDS/rf9AABYAXoAwQGEAVgDKAWmApn8dvkH+0T9n/+qAP7+vP/5/h7/4PzK/RT/wAD7AdkCJf8F/ev/UwLl/gD9aADcAmwD/gITAS4ACv61/yMFZwatAiIADgA2/pz84f8M/+/8Lv4uAl8CRf9L/TUAzwBV/rr/zwEiAbr/sP+UAGv+Nfy0+13+/gJVApD/bv8EANYAZANxBMgBrQHIAyMEdwChABYBQv7B/8sCWANmAPT/kgLDAgACqwIPA+ABKQCLAu0FIAMD/2b9/v5J/+z9+f8x/xv+SQCSAHP+Lvyv/ZD/3P8W/iL/LP4C/Xr9Qv4n/83+X/6UABEDDwL9+z76hgBCA4EBUgDI/5X+D/9pAUEAWP0d/vT/bv8CANEAvgDq/QQAqwTmA3P/WP2k/ov/lf4//iT98v4zAb8DNAQM/kL9sgBpA5UDOAERAO3+pgHvA78DCv/5/R8A4wGQAv7+8/uk/icAHQLyAn8Bkv4K/SwB4gD7/uD7Hf1k/+X+gv9R/+P9D//7AD8CyP/9/MH/df4J/Jj//QAH/r7+UwGkA8P/t/x//5cCQATvAFwBzwDsAHgDtwPv/3D9Vf3t/oYAZgCtAAD+kv4uAuMCtwInA7ACRQNpAisAq//y/83/hP9+AAoBGwGV/6v+sP/0APv8Hfwq/7z/z/75/34ALvx+/Fv/3vyb+jr9TvzY+wr+7wCy/n/9UwE7BZ0FIgB6/yQAcf82/lAAhAKkA94B8QAWAuAAawAwAKMBOQTtBeMDSwFd/4T/of/5//7/3v+IAMP/Av49/bL+/v81AZwDfQaVAvL+t//NAewApP5s/0L/5f2qAAoCeP/L/w4AVQFcAYQC6AJcACcAsv/m/zH92/zc//EBmv8f/KP7qP1z/zH/wACVA4EBLAGXAU4Aq/8u/Yv9OP+ZAFUBzQHFAN7/nAEzAzQEHgViBaIEiwNEAXMCKARuAmIC+QKLAir/i/0FAjoB+f0sASwE6gFfAY4Cqf8M/aj+GgA0/4T+7wDo/7z+1/4z/hP9ufwp/rQA+wBM/7D+GAGc/pD9/v61/tH8U/1M/ycAWv7e/G7+RAElAy8E+wFLAAwCNAR+AMb+RP3U/dQCogTeAncAKwBfABb/lQJgBO//P/5aAlUCVQDU/tv90fy5/Sr/L/8//GH8z/xV/JL8vP7vAEwCiQPNAwcCTv60+3H/LAFcAD0AhALUAXoBGwI2AtX/Xf4WAj4F0AOGAYL/Xf7F/bD/5wApAagAMf0n/M/9vP0q/2QCBQQjBHMCIwQiAs/8Vf1hABv/FfwH/msBxgKyAjYDbQCf/iwC/AQsBHAB9gDZAJwCsgPeAO/8i/0iAPQCegG7/Ib8Ef5C/ysABf+G/hv+RAAFAZP/bfzD+yn+NQCJ/yz91PsH/qb+nP9kAScAJ/yN/ScBDQROAP38sP/V/0L/XAEzAMf7r/0FA/cDqP4z/FP9pv8dArUDrQEd/U37V/wF/wr+ZP07/sgAcgBR/lAA/v6k/rcABwI2A7f/Uf7V//T9/fwU/tT+c/5F/ysAof9W/+H+Nv77/n/+1f/o/rz99P8FAz0E7wDM+9T84f9Y/3P/FgGtAA4AD//AAN7/df7m/zEC8QAi/839M/27/Pv8af54/hv+1P7AAOj/Iv1M/x8AOP8iAGsAzwDc/13+XABEAHL9yvzt/nUCfwI6AdT+Ivy8/TMAMwK5Ac3+yP8zAuUCVwCS/Yj91/6SAUcExQFa/FD9owARAIP8RP2NARYCPwAAAUf+t/x3/KgAPQNuAX3/7f77/UL9CP9VAJX9kv4CAmQCRwE6AQP/n/5T/83/twH2Adf/HQDxAQUBIP41ALsAMf9u/w//7f86ACIAnP+BABUARAD+AQwD6gDj/s39lf7N/5UB9ACO/4sA+QTTBkcCdf/NAo4F6AKoAK8B1ACjAAwBowEF/1D8w/33/3P/2/2P+4f5UvwU/0wCawHs++D7JwBuAtX/Jf9u/0T9t/8lBb0F5QEI/4sCYAWuA74BbgNMAu0CwQNzA/EBWgB3AQMFYgVuA+3+Z/9JANIBggPUAIb+7wFdAwwC2/2Z+6r8RADDAdcCk/9O/RX8SQCGA24BAADc/rz/aADvADUAyP3F/df/2wE1AWT+sP8rAF3+Mf1Y/tz/a/7c/xv/jfzb+gf+DgAq/18AVv9R/g4AhgCZAWEBKwAC/sMAswTmA2YCqALBAYgA/QDcAj0CRgAb/vz/G/9R/wIARACy/+wBQgS+ACv8mfxW/y4CcgBM/tL9f/9OA1gCkP8r/JD9AAGr/3D9Yv7IAAIBJQJOABv+GPsd/T8B9P+8/9QAR/+m/qMAUwKmAQj/lf2O/24ClwKUAMP9Hv9tAAgDQgRfAvQA7/9nA1MCuwB6/isAIAQjBH0D5wCJ/5cAEQNEAmT+dPp5+zv/9AHAAM/+AP5H/if/rQDQ/3D96v1w/v79JPwH/sv+1vsi/jMB5v9r/gD/Wv7D/VX+Z//2/pr/gwDV/yz/J/4r/PQAVQAR/4YATgAx/2H8af4AAH//KQA4AbcDvgBc/bL91P6L/1AAEwC+ALkAJwEzACL/2f0l/lj/kAF3AR0AgQHZ/Tr8+f2k/gf+Jf4RAWEBgf7U/jb+E/2h/zYCAALKAB0Auv+1/4L/Lv2B+4v+if/gAHUAaf20/b7+owEnAwgDRwITAcP//v1GAGQC4AAi/hj+AACZAE7/jv/e/Uv8GP0P/1//L/9p/xgCfgA//Az+i/6f/lcArQCu/6v+4AGHBQAC3P6BAk4D/gLGAxgBLP3U/QwDeAJu/1P/uv/xACcAUf70/V/+PwJTA8MAkP3W/Bb/fAHt/kb7Uvrg/UkA4f4g/nj+nP4H/mf/TgK5ATj+xQBHBAwG+ALc//f+zvzHAMsEXwSfAncA0P8+/1kA3AE1A8T/dgEYAg/+tfu8/RoAnf+G/p39h/xf/VT+tP3g/YP8Av5GAfkBpABo/qT8Gv12/tf/7wEyAvMAXgDgAQ4CHAFYAqcDhgJYAeoDQwQCAFQAHAPbAiT+g/3GAU8CtP93/+X+e/5MAH0BoAD2/hP8L/4q/c/8Rf+GAXD+Hv1s/4EBvwCpAMQBTgE3ACoBdwPIAlYAnQDBANEC2AKO/87//gG2AY4ByQHJASj/P//9Ad4BEADRAJcEdwFf/1f+hv3q/V3/3QFtADH+NgCzAysCU/4o/kz+2/9AAI4AbAKr/tn7hP3K/if/YQCi/7/9dP0HAPUAs/50/kn+3f+G/xf/Bf6R/AL/qAHBAMX+mv4dAeAFXwXmAG793/7NA3EDAgIxAPD9nv5LBGkErv5Y+w390wAiAfUBvQF8ANT/FAGdAhwAbP0u/xMCOAIg/+/+Cf94/l0AhwIHAGb/cP/1/10Adf8A/zf+KQAMA2wDSAGO/zr+Xf0Y//QALgAB/8kC5QTzAjAAiwDz/mP/vQH2AhMCzQHHAHf99v75AboDTwOAA9kEtgBB/af95//Z/2j/cAIrBOwCvwDL/2H9V/oL/KD/tgIXASsBrv9w/lwAhQGhAHf+EAA2AYMAoP+8/icAKQCSAZ4ELwNGAf4AZwCQAOb+nf5y/yoCxAMgAVb9ZP57/jT9Z/9l/jD9pfxV/nX/Ef4EAWYBdf5rAOMCJwOq/7b9HQB+Ab8A5QHiAUUBXAF0AlAFEwG4/RQAQgG1AOAAxgFTAkEDcwPVAZ/+4v12AQkEYQGG/0v/EP92/5L/TP65/ID9CP+yAOH/Y/uH9+X60QG7AGL/ef+y/4P+iP5y/3b+0v3f/+X/OgDwAAUCSv/i/XAAegReAkwD2AMPA1UAzf1pAEACRQIKAxMD1AAp/GP8TQGhA8AAwf0O/Zv+4QDwAX7+evxq/kEB5wIxA5oAbf4q/h//oQFiAbYATv4t/pABjAC3/qX9Jv/MALH9Wv1l/yX+zv6s/wj+wfuM/ZD+CAAWAMAAg/zn+m7/yQJCA9QAAv8nAqcCEwBm/zP/FP5n/VMAnwIEAB3+uP+eALr/BAC6/yv+Tv5S/5X/PQB5AL7/x/9n/ysAMv9C/mr+XgA9AGP9lvvR+yX/WwOxAF39D/52/Zb8Uf98AFz9+vzv/rwAvf8aAJX/F/9kAdUCDAI6AGD96//ZAfIAzgHrAp4Blv+a/wcBSgC+/Qv9R/71/qX+tv42/zT/mAGEAj8BWf2q+37/ZQFFAdn/xP+XAHUD8gWUAif+evwtAM8DNgIE/xf9FQCtAecBpQIfAuv/Pv80ARUAjfwm/RT/VgBAAE8AGwD6/X39hP0Z+6H5JPvh/mIBPgAI/jD/2f26/Hf/aAEKAOX9g/43ABUAU/85ADgB6QFmA4cC6/93/a/9/v3k/UD/8QBsAmwCtQAn/u795/6//fD+2gEZACT+gQALAvb/M/7B/zD/lP/CAYcAMf0I/HL/0gG7AdgBNwFi/5T9ff3W/+v/o/2G/zIClwHRAB0BqgHGANX+0f7I/jn+SwD+AdgBlgHrAE0CJQItAt8BNAAuATcCjwJFASoBzwCCAaEByQCo/jYA5ADC/q/+pP/iAGMCcwO4A70B8f5i/27/df4d/3f/9v+p/4YBYAHZ/+f+6f6xAI0APgDQACMBXQApAB0DEgPl/zP/awHVAQ4BPgAe//7/nwHuAxkEMgL/AF8AQwGLAdQBRwFGANsArAHbAF0AbP+jAHYCMwEWAH0AVgCo/28AKAIFAmT/sf6YAEEBeQBl/ln9d/zz/l8BlABw/sH9vP6oAK8B2gEEAYX/SP9KAZ4EywLq/84BswOGA0MC7QDcAZQBAwEAAvQBrwCQAbwCRQJ9/u79nP79/ej/TQDT/t/+zf7MAgMDKf+S/W79qf65/1b+RP6r/nn9MP7WAdwBDf+v/Xf+i/9hAH8ChwJZAuYCIgPLAucBawFlAJ8A5P9ZAegCpwFGAbMChwLK/2v/lAJDAgH/j/18/tH9o/7HANgB6f6e/U3+6f4qAJ8BDACi/4b+vgB5ApABdgAiAOIA7AMUA5UAgf83/iH92/+HAvkAvf8zAOP/VP5c/rr+E/+L/0f/kP4X/u//dAFYAugARP83/pf95v7N/6P/QP6x/Nn8CwGGAdf+bv6g/h3+pf/HAcoB9v7m/ucAHgF0AskAbADFAM8AwwB8/wz+Yf8PAWYBZAB1/tX/cgAJ/lj9D/5o/uj+IwCbAMH9Wvxc/Bj+aQA5Adf/1fz5/D7+qP95/8T/qgARALABRAFN/+X9s/18/gUCTAMnAHX9Y/+p//f/iQGeA+UC2gFPAn7/HP4F/u3/dwLUAaf+uv2v/nP/jQA+AO/9Df6S/wMCcQIbAEP+l/7B/hf+vf/cAHMAE/+L/2UBSQAl/+j9Av5R/rH+s/6T/zj+8ftt/PX8+PwU/u7+Cf6H/C39Xf8BAPsAKgK3AREAXQAyAa7+i/4d/47/hv8T/9gATgHZAM4B+wHa/1z/kgEXAoIC3QAmAMAACQIqAYD+Ff03/Wz/wQC2AKH+3/x3/cP+XgDhANIBQAAM/iP9z/7u/wX+Rv0F/5cAmgHbAEAAKf8S/jwAgwFCADYAogENACr/bwAYAdf/MgDJAWcB0P9//1D/fwDJAN0BgQFMAbACBQIfAYUAev/O/Vb/UwEnAesAXQBlAAkAaAELApT/SP4i/wMA9f8U/y7+7vxF/r4AIgHd/+b/aABEAPL/X//s/yICcgIpAs4CAgLvAO0BrgHb/2X+EP9Y/zsA8AH+AssAS//c/nYA/f9YAPD/VP6z/9oB1ADk/rr+tf7iALsC/gAc/+z+UP+H/5YAFwFdAegBagN9Ah0A1f3h/sAA9gF3AR8BNQG8AJ0A3wAKAB8AQQDvAXcDQwCx/pD+Yf0F/ucAYAJiAAj+zv7S/h//TAAk/wD+6P20AewCWgHT/03/c/8AAB0AJAAQAyECxgF2AXn/uf7KAGUCmQKCAWoAcP/w/wcBJwBB/7/+7f8OAmQDvgHg/zH/6f4V/0YAcQBPAPH+Q/68AP0ASP/s/kr/eADVAVoDbwPNAE3/q/9dALYAuwBsAaAAggBuAID/AP50/4wBAwJdARQB5gHsAOn/DgAcAIv/BQDXAKoB7/+W/TD81/2fAecCzQEHADf+o/7rAI4BIQCZ/v//vQBVAXQBPgFdAHD+fP8oAFv/uP89AGQAFv/a/Ij9sP6u/0P/Bf+C/er82f4KAKH+Sf23/sX/3gHAAl4BY/+n/oT/9P+wAQ8DVAJ6ALn/SQC7AcIBxQEpAND/vgCxAIP/KAHrAQUAYv+y/4cAnACMAPr+oPxm/Sn/dABtAJP/cf+1/gMAeQC0ACIApv7A/hX/3P8X/97/ywDv/83+HQCYAs8BLgKkAaUALwEgA1oDJgJzAL//+//RAG8BYACn/zEAiQCQAB4BPQCa/4//6/63/SL/+wAK/+78pP2t/u7+YP/F/wH/9f6C/83/hgAWAEX/cP+h/23/xgCGAdkAcP+O/rv/SgANAEwBHAIo/y/+AADuADABYwAm/6X9Yf6U/6r/vv4r/hH91f2x/6MAWQCp/13+N/4AAKEAq/8E/1IA+P8I/wAAXAA5ANsAQAGr/0T9Ov5OAOIA3P+p/iT/6wAxAY4A/P5l/Ar+dAD8ARICSf+r/vH+Tv8zAKsAKv8C/SD+kwAnAW3/0v4p/0X/b/9S/1b+mvwi/OT+3ABcAED+f/1E/xUAXgAH//3+JQAWAQoCmv8n/mwAZAJpAm8BIgCJ/lX/LgG4Afb+ff3K/doA4AGgAB0AcP+Y/z8A7v9tAH7/c/6x/lQAkQDt/5n+z/0K//j/wf8p/kf91f8lAWMAhf+x/xUAawAKAfAAhv7c/fH+1gAlASIAeP5o/xQBvQDg/3v+XP1M/nIAdQFyANr/hQCBACEAlADm/qj/x//BAaQCoAAJAfoAnf+DAMgAjQCyAHD/W/4G/1r/WP7C/hMAaAEjAIH+Wf3z/D7+Kv8J/yP+W/9dAV4AC//j/pL9Ef3Y/jkCUQILAbf/i/5K/7//7P+KABgBJ/8G/5P/GP9z/mL/ogAbAR0DtwIiAaL/B/9A/47+ev+2Af4BzQGVAJj+Hf7J/sT+VACrAAv/u/8lAUEC6AHNAIQB5QErAYMAOQBh/7P9S/5DAFYBmQK4AmsBxf+NAOv/ov6r/h3/NgBbAc8A+f9ZATMAvP7n/vX+3P0A/3IBywCa/+3+6/+lACwAQv+C/sH9M//qAIsBowCh/wwApQF1AvMCJwJNAFr/I/+b/6cASQHkAjEDFgEr/xMAZwEEAFj+T/9RAZUB6wDUAPb/F//k/oEABgGYAKj/Ef/X/kb+gACEASwBsAH3AU0BPwBQAGQA7v9Y/9n/HgFYAWUBzAETAQX/qf7K//AA4gHiADr/hf9jABkCxQKmAZMAEABuAfoBTwJXAa0AqAE2AjMC4wH/AAYA6gDoAJT/Zv8AAScBb/+UAF4BAQC5/yAA6QD//xv/0v8XALMAxQGbAXgAPP8a/2UADQAL//D+dv+F/6wAaQL2AO//oQCdAe0A7gAHAM7+jP5Z/w0BrACD/w3/S/+3/68ACgDB/qL/VgA3APgA6wEXARcBHgEwAAn+4v7y/1P/9v8fAen/Pv+fANECSgJ9/mP9Q/8lAKcAwP8a/4r/oP9oAHAAkP83/hL+c/4o/kn/jv9v/y8AGAK7AHr/MP/F/jj+w/1G/gL/mv9ZAKABnQHrAB8ABQFyAQcBbP/d/jsAqwDgAA8BBwGO/9D+YQCqAC3+b/3T/En9if6h/74AU/9Q/qL/Qf9x/eb8Y/32/hn/I/8mAAAB4P9UALoB0QFnAAUAiQDm/gX/KgB0ABQBaAF0AWABZQB0/1n+0/3n/8oAUQCB/+r/qP/4/8//Qv6F/TT+z/5e/m7+G/7c/bz+gAH1AbcAMQA5AAkASf/y/uv/Jv/E/ysBogHiAbEBwwDJ/kj+K/9+APT/Lf+Y/xkA7P6T/en+Pf+u/lr+N/18/K38of2o/z//Mv8LAHsAUAH0AIX/m/7z/1YA8QATAlICWwEqALQApwDX/0f/3P5s/lL/KwBf//n+Jf/p/oX+Iv2N/rz+2f1q/rb+af4e/9X/1ABHAW0ANP+D/hH///8JAMH/Ff/hAHUCfwGlAKr/Xv8RACoAaAHNAOX/RgDVAC8AYf/A/gH/Xv+q/wr/4f26/zQBVwAxAMwAhwDEAFUBjQAR/+3+A/8pAEQCiQKRASUAiwD9ARYB7/8LAQcBagAAAKgAmQF5ADL/6/54/jH+8/1w/vz+y/6f/s7+UP9YAL0ApP+P/df9Jf+2/zf+P/4H/53/xgABAqoBxwAUAYoAegAmAWoAhADZAQ0C9QBOARQC8gBKAND/9/8DACz/k//CANwAnAAHALX/XQAQAUwAQP4L/hP/sP+v/0YAzgAGAesATAHUAV3/Dv3W/fn/8gB6AGcAlv8Z/yEAYgAt/yr/yf/r/5//1/8hARIBcgHLAbMB8wEvAUIAPABkAFsAIADAAF0CEwOIAmMCbgFGAND/rgGTAef/h/+mABEBKgF7AKL/cf/C/6wADwCV/rP/ngBKAB0ApQB1AKT/sP9KAND+RP6r/p7/1AAdAZIAPABtAMoAEQEwATcAzv9P/4D/bwBvAa0AFAAUAYMB1wD6/2j/5P8RAX4CRwGj/4v/6f/b/9sAvgCp/w3/YwBFAGP/DP8yAFcBfAGoAYYBhf+S/mX/ff+u/84ASQH6AIAATQHNANn/gP9iACICSALvAAQATwBUAM//ygCZ/5T+5/5Q/zr/gv8b/jD9c/4GAIIAMP+z/uj+tv7+/gL/AP/x//YA3gCQAH8AswAgAMYAbwFDANb/ZQDpAG8Avf+xABsBNQATASsB7wDi/+n+Uv9x/5IAXwFtAA8ABgBCAIMAwv+U/vL+aP8v/3f/KQCIAAoAlQCFANr/w//z/2UAxv/w/xcAewABAb8AGwBiANX/hv/W/3n/BP8D/1EA/wBrANQAMgD9/u/+iP8MAOn/af8ZAAQAegAPAR8BswAVAMAAWQHqAPL/yf/DAMMAXACOAA4BvQAKAGz/4/6R/mD/WgDO/z7/NP+x/g//IQAPAVgAD/8q/1b/YQDoAKz/U/8aAKIAagBgAIEAxv62/Wz+w/7b/hz/Z/8UADgAjQC8AGn/ev8eAAQAOwDBAFMB2QAKAB0AxwBdAFQATgCY/wP/lP+3AHEAYgDu/3gAsgCx/xn/k/6e/l7/o/+4/xb/9f7n/ysAHgAxAEz/Av9e/0D/w//k/23/hv/zAGsBGgBS/zX/UP+vANABVQIDAc7/7ADEAekBcQE2AC//4v9sAL7/wf4f/rb/AwAwAKv/2v7G/iH/sf8b/5f+Cf7b/gEAwf/m/ob+m/4I/8P+b/9X/9T+i/8vAHIAAAEGAe3/CgCQALIAvwDq/3z/yf+kAG0B/AArAfAAMwAEAIkAXADb/vz+VACxAGsA9gBHAJv/Qv/b/mr+Kf5R/9X/w/86/6T/MQBD/6r+mf6n//v/vv++/+n/ev/l/0gArgBGAKQAfgGFAcYAtwA9AG//MgDqACYBEgE4AKL/Uv/O/y8AOQB0AEoAnQBtAQ8BjP/G/mD/sf/N/zgACAC8/kX/z//a/7z/HP/d/7IAFwGHABIAgv+b/64AOgEhAfP/oP8MAAwA7/+3/6P/Yv/2/5YB0wHvAFcAawCi/8D/wQDl/7H/XABNAE8Ad//y/p3/pQDDAD4A8v9p/zX/av8fAEsA/f+y/9D/8P+K/9D//P6E/ln/UQDgAGMAFACBANcAIgH2AAcAXv8GAAQBugFMAWkAgABbAKIA3QCbAEoAwv8tAJIAMgBU/9b/vwBzAGkA+/89/wP/L/77/UT+zv59/zIAgP9y//v/fP+L/7b/3P/K/5r/qP/n/9IAtQBRABkAwP9J/7L/SgCTAO4AyQAxACUAsQA4ARYByAAwAO7/n/8nAF0BTAHFAGAA1QDaAZkB+ADXAL8A/f/6/zYBxwBd/5r/YwDHAGwAz/9f/+v+P//eALkAtQD2ABsAxP/G/5QAuwCAAIMASgB1AD4Aq/9wAF4BDAFLABMAbgCZAE0ANwAeABIA3gBBARIB2f9h/xIAPADfAOEAhAChACsAeADTABAARQCbADUAdf/o/+sAOwBR/87/MgAAAEQAggDuANT/af8ZABoAXADNAFoAYQCoAKEAZwAyAPb/O/93/+v/QAA5AKb/MP+N/1oAFAAG/7T+ev8AAHf/MP/g/2cATgBoAPP/EQALABwAKgBT/3T+4v6b/x0AGwBjADAAef9RAI8Ah//a/0IAQAAxAE0ArQGWAcAAvwCZAEEAMABQAH8AkABIAC0ATwA+ASABngDz/+/+af5h/hn/5/8QAEcAAQCP/6X/1f/L//7+Iv8AAJj/ZP8+/5L+1f7N/w0ASAD4/2b/YP/x/gH/lP8uAFYAMwAMATYAH/8+/1P/nf+u/6H/2f/j/yMA6QDAAEAALQCiAAgBpwBqAKH/Mv+//4oARAC7/zr/EP97/6D/gv8R/6z+Ov/C/2UA3gDc/wj/cP90/4f/1v/X/2L/T/9g/6z/u/+4/wcAcABQAHr/j/9UAMz/KAASAFD/JP+v/3cAHwBQ/5r/EgCC/4b/DgD8/7b/TgDwAFUACgCw/3P/zf8uAC0APABGAAoAU/9N/+//HQC0/6r/8f+l/0X/9/7Y/v7+/P/3/0P/HwB6AAcAsf+r/1wA5gBKAQIBtABLAL3/AQDh/2D/Sf+8/zIATAApABEAwf+Q/7gAWADs/hL/Zf8v/z7/h//c//f/CQD4/5D/dv87/1z/JQDVAJ0AJAAeADQAFgDr/1wACwCS/xEAuwBqAFUAnAAeAH8AFwGOANP/Uf9E/8L/NgC9/7n/zP9k/3n/z//R/07/Zf/g/wkAzf/g//v/mP9bAKEAqP89/+//CQDM/5f/jf85/4D/xADvAGcAuP8y/3L/LAAwAA0AlP/E/yoACQAWAEAA8/9v//f/DgA+/zP/b//s/1gAWwA/AA4AlP92/2//Vf8EAFwA8//g/wEAiwBxAI0AowCHAEAA/f9dAD8A4v9xALYAKgAFAH4APACU/9f/UQBeAKwA3wCQADgASgAdAFwAGwAEAC0AJAAKAMX/8f98AP0ASgCG/xMAWABaAHAAtf+h/sn+6v/3AKIAHgD7/7b/+P9xAEQA8f94/+b/eABbABUABQAfAF8AkACxAPH/GP9b/7T/AwCvAPkAdQA0AH0AawCC/1v/8/+WAPEAjQBIAIsA1QAmAecAXADr/+j/y//p/77/Nf9l/2EATAAEACoAZP/Y/v3+t//7/4j/HQBWAAQA6P9BACoAsv+c/8f/9v/l/9//+f8uABUADgBdAE8A7//G/3n/Qf93//r/dQCdANsAsQCSALcAqACBAIUAkwDNAKoAOAAYAKAArwC7AEQAGQBWABwAf/+4/8//av/x/04AbgARAGb/hP8E/wH/j/+T/1r/Vf9s////awBpAAMAof/A/z4AeQDw/wv/Pf8/AGkA9f9f/0P/kf/e/y8A0/+s//f/agD5APwAewA6AFYAAQHWAMv/ev///1UAnwBmAP3/2P8JABUALABaAIT/Sv/K/1YATQBm/0H/w/8HABgARQDo/5b/q/9EAFwAHgDw/+D/AABkADkA1v+F/23/0f/r/8X/9f+aAIkA0P+J/7r/lv+b//n//P/B/47/k/+O/5n/r/+g/6r/CwAeADEACgAcAD8AjADmAMwAmQDo/5T/+f88AFcARwAyAGgAswAfAB4AngCjAB8AEwDy/7b/vv8QABoAFQDL/67/u/+b/8f/zf/N/9L/BwBoABQA8f86ABsAvP/e//D/oP8Z/yr/sP/5//T/7f8MAB4AGgDl/5j/qP/t/ykAcQBTAPT/5/8OAAIA/v8EAGgAOwBVAOgAUAC+/y4AXAAmADwAXgBfANP/oP/C/9H/BQBhAJcAfQBFAOD/kv+M/8L/9f8fAPv/k/9y/1T/av9a/37/uP+Q/8f/s/9X/0n/uf/4//H/kv9P/4f/hf9t/2b/fv+M/5n/TgBqABAAFgB5AK8AawCFAHEA/P8TAEgAOQADABkAKQADAMb/2f/8/53/wP8uAP//4//C/9//1f+r/4f/wf8cAAMArf+J/8//7v9pAA8BuwBUADcAGAD4/ycATgBiAG0AugC/AFoADQD4/0oAggBpAK8AuQBiACYA4f/8/wAA+v9kAB4Abv8e/y7/aP+R/9X/FwDV/9P/MwAUAM//rv9+//P/KwB1AE8AKAATAP//RwBxAIAAcAB4AHUAVAB6AKAAcQBlAKsAPwD2/8z/5v/H/5r/0/8IADwAdwB7AF8A9v/e/z4AVwA/AOP/mf+F/5L/FQCEAC0Akf+U/4v/l//o/zEAKwC9/9v/EgDC/6P/j//5/xwANQABAAQABQAbAGUAbgB7AFoASgBjAAcAuf+x/+b/8v8eAAoA5P+h/7P/PQBcAD8AQAAYAB4ACwAfAAwA+P8OAB0AewCDACwADwDj/8P/GwB5ADgA/P/o/xcAKgD//wwAmf9u/8P/2//t/6n/3P///+f/6v8hADYAJwDx/8f/6f8PACwATABSANb/dv+j/9z/EQA7ADQA9/+j/7//AwAKADEAVQAxAP7/+//h/7//tv/S/zMAQQANAAAAFQAEAMf/5f8xAGoAlABNABEA0f8UAD0ASwA7AB0AIgAUACgAFgDl/87/IQB/AKkAiQD9//L/IQAPAPr/LQAdALL/pf/T/8b/t/+N/6v/y//W//f/3/+G/3D/v//d/9L/3v/3/+L/3P/u/6z/pv/0/yoAdABMACEAIQBGAHsAdABiADMAVgClAKwASgAGABAAIAA6AEsANwDz/9//6f8CABYA1v+e/7T/wP/z//j/tv+T/67/BQAHAM3/s//J/0EAUAD2//b/4/+n/+n/FQDa//T/MgAkAOP/r/+9/+H/JAAyAB8A5f/N/+z/GgD//+L/HQAnAPP/sP+m/63/7f8rAEkATAAWAOv/2//Z/+3/DQA2ACwAPABLAPH/2P/P/9f/BADq/8r/zP/d/xwA/P/u/wAAuf/5/0sA7f+t/6//z//y/9f/6f/c/83/7f/e/5X/R/9l/7L/5//3/wcAxP+K/53/t//i/8H/zf/4/wQA9v/o//3/6v/n/1MAWQAoAAYABADy/yUASAAzAC0AKQAbADYANAAZABsAIwAvABAA1P/1/xsA9P/1//H/tf+3/+n/FwDd/9D/+f/2/9X/BgAhABQAEQAPAAkA8P8EAAAA6P8EACoAMgAJANr/yP/t//D/4P8EAB0ABgAbAPb/yv++/9z/3//j/+X/1P/V/xAA9v+//7r/wv8bAFAALQAYAOz/6/9HADEADQAbABMAGQAtAD8A+P/C/+f/OgA9AFUAOwD9/+j/6f8ZAAQA+/8RAAsAGwAQANL/r/+5/+X//P/Z/5z/iP+5/9H/ov+e/8X/yv/n/9n/rP+o/6z/y/8OACYAFQAAAPf/+v8LAA4AJQBHACYAKQASAO//DAAyADQALQAqACUALwAJAB0ACgDt////HgAkAPz/6v/g/8z/6v8HAPX/yP+y/8z/7////9r/0v8BACAACwDv/9H/7P8iACQACQAPAC8AQwA6ACAAFAAIAPj/BwApAB0AAADM/7j/7P/5////CwD4/9n/9/8MAAYA5P/g/w8AGwA7ADIA6f/G//D/MAAsAAUAAgAFAA4AJwA5AC0AGwAVABoAJgAbAAcAHABNADIADgAJAAAAHgAvACwAKQAeACUADgD//w4AHQAYAA0ACwABAP7/3P/N/+n/BwAAAOr/AgD4/+3/7v/6/w0AHwAyACQAAAD2//3/CQABAAAACwAUABsAIAD6/9n/5v8BABAAGgADAOf/5f/p/+j/+v8AAPv/JQA+ACQACADy/wIAIQBJAEUAJgD9/+T/6/8AABUAEgAVABoAJgAdAAIA8f/w/xsARQA4AA4A+//2/wAA9P/x//b/+P8JAA0A7v/Y/9f/+P8LABQACgDs/+f//v8UAAcA9f/n//T/CwATAA4ADAD0//z/GAAfABcAAADz//r//f/1//H/5f/k//D/8v/7/wYAGwARAAsACgAAAAgAFAAFAAAA+//3/wIACwAIAPL/6/8PABwAAQDm/97///8KABAACQD4//3/+//h/8z/2v/u/+//+//+//r/8f/w//r/9v/u/+z/8//7//v/8f/q/+r/3P/s//v///8BAO7/5v/s//3/FwATAAoACQAJABEA+//s//D/9P8FABgAGwAXAAEA+/8MABIADQALAA8AAQD5/wQAAgD9/wYADQAOAAMA9//v//n/AwADAAAA+//+////AQD2/+7/6//z//j/9P/3//D/8v/8/wgADQAEAAMAAwD+/wAAAAD6//3//v8AAAAA//8EAP3/+P/5//b///8DAP//BAAJAAAA+/8EAAsAAwAAAAAAAAACAAcACQAIAAgACQAKAAgAAQD9/wAAAwAEAAMA/P/9////AAABAPr/+v8AAP7/+v/5//3//f/8/wAAAAD///7//f/9/wAAAAD///z//v8AAAEAAgAAAP//AAD+//7/AAD+//7/AAADAAIAAAAAAAAAAQABAAAAAQADAAMAAgABAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
||
};
|
||
const sampleBuffers = {}; // decoded CC0 acoustic one-shots (VCSL, CC0); acoustic voices play these, electronic stay synth
|
||
|
||
let schedulerTimer = null;
|
||
const LOOKAHEAD_MS = 25, SCHEDULE_AHEAD = 0.12;
|
||
|
||
function ensureAudio() {
|
||
if (audioCtx) return;
|
||
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||
masterGain = audioCtx.createGain();
|
||
masterGain.gain.value = state.volume;
|
||
masterGain.connect(audioCtx.destination);
|
||
for (const k in SAMPLES) { // decode embedded one-shots once
|
||
const bin = atob(SAMPLES[k]); const u8 = new Uint8Array(bin.length);
|
||
for (let i = 0; i < bin.length; i++) u8[i] = bin.charCodeAt(i);
|
||
audioCtx.decodeAudioData(u8.buffer, (b) => { sampleBuffers[k] = b; }, () => {});
|
||
}
|
||
}
|
||
function getNoise() {
|
||
if (!noiseBuf) {
|
||
const n = Math.floor(audioCtx.sampleRate * 1.0);
|
||
noiseBuf = audioCtx.createBuffer(1, n, audioCtx.sampleRate);
|
||
const d = noiseBuf.getChannelData(0);
|
||
for (let i = 0; i < n; i++) d[i] = Math.random() * 2 - 1;
|
||
}
|
||
return noiseBuf;
|
||
}
|
||
|
||
// --- instrument voices (synthesized GM-style kit). On hardware these map 1:1 to
|
||
// real CC0/GPL General-MIDI percussion samples played via the I2S DAC;
|
||
// playInstrument() is the single swap point. level = velocity (accent/ghost). ---
|
||
function ampEnv(time, peak, dur, attack) {
|
||
const g = audioCtx.createGain();
|
||
peak = Math.max(0.0003, peak);
|
||
g.gain.setValueAtTime(0.0001, time);
|
||
g.gain.exponentialRampToValueAtTime(peak, time + (attack || 0.001));
|
||
g.gain.exponentialRampToValueAtTime(0.0001, time + dur);
|
||
return g;
|
||
}
|
||
function tone(time, type, f0, f1, dur) {
|
||
const o = audioCtx.createOscillator(); o.type = type;
|
||
o.frequency.setValueAtTime(f0, time);
|
||
if (f1 && f1 !== f0) o.frequency.exponentialRampToValueAtTime(Math.max(1, f1), time + Math.min(dur, 0.09));
|
||
o.start(time); o.stop(time + dur + 0.02); return o;
|
||
}
|
||
function noiseSrc(time, dur) { const s = audioCtx.createBufferSource(); s.buffer = getNoise(); s.start(time); s.stop(time + dur + 0.02); return s; }
|
||
function filt(type, freq, q) { const f = audioCtx.createBiquadFilter(); f.type = type; f.frequency.value = freq; if (q) f.Q.value = q; return f; }
|
||
function v_tone(time, level, type, f0, f1, dur, peak) { const o = tone(time, type, f0, f1, dur), g = ampEnv(time, peak * level, dur, 0.002); o.connect(g); g.connect(masterGain); }
|
||
function v_noise(time, level, fType, freq, q, dur, peak, attack) { const n = noiseSrc(time, dur), f = filt(fType, freq, q), g = ampEnv(time, peak * level, dur, attack); n.connect(f); f.connect(g); g.connect(masterGain); }
|
||
// 6 detuned square oscillators → bandpass + highpass = the classic 808/909 metallic hi-hat/cymbal timbre.
|
||
function metalHat(time, level, dur, hpFreq, peak) {
|
||
const fund = 40, ratios = [2, 3, 4.16, 5.43, 6.79, 8.21];
|
||
const bp = filt("bandpass", 10000, 0.8), hp = filt("highpass", hpFreq, 0), g = ampEnv(time, peak * level, dur, 0.001);
|
||
ratios.forEach((r) => { const o = audioCtx.createOscillator(); o.type = "square"; o.frequency.value = fund * r; o.start(time); o.stop(time + dur + 0.02); o.connect(bp); });
|
||
bp.connect(hp); hp.connect(g); g.connect(masterGain);
|
||
}
|
||
|
||
const DRUMS = {
|
||
beep: (t, l) => v_tone(t, l, "square", l >= 1 ? 1600 : 1100, 0, 0.04, 0.5),
|
||
kick: (t, l) => v_tone(t, l, "sine", 150, 50, 0.18, 1.0),
|
||
snare: (t, l) => { v_tone(t, l, "triangle", 190, 140, 0.12, 0.45); v_noise(t, l, "highpass", 1500, 0, 0.2, 0.8); },
|
||
rim: (t, l) => { const o = tone(t, "square", 1700, 0, 0.04), bp = filt("bandpass", 1700, 4), g = ampEnv(t, 0.6 * l, 0.04); o.connect(bp); bp.connect(g); g.connect(masterGain); },
|
||
clap: (t, l) => { const bp = filt("bandpass", 1200, 1.4); bp.connect(masterGain); [0, 0.012, 0.024].forEach((d, i) => { const n = noiseSrc(t + d, 0.05), e = ampEnv(t + d, (i < 2 ? 0.5 : 0.85) * l, 0.06); n.connect(e); e.connect(bp); }); },
|
||
hatClosed: (t, l) => v_noise(t, l, "highpass", 7000, 0, 0.045, 0.5),
|
||
hatOpen: (t, l) => v_noise(t, l, "highpass", 7000, 0, 0.32, 0.45, 0.002),
|
||
ride: (t, l) => { v_noise(t, l, "bandpass", 6000, 0.8, 0.4, 0.32, 0.002); v_tone(t, l, "square", 5200, 0, 0.1, 0.13); },
|
||
crash: (t, l) => v_noise(t, l, "highpass", 4000, 0, 0.8, 0.5, 0.002),
|
||
tomLow: (t, l) => v_tone(t, l, "sine", 150, 100, 0.25, 0.9),
|
||
tomMid: (t, l) => v_tone(t, l, "sine", 220, 150, 0.23, 0.9),
|
||
tomHigh: (t, l) => v_tone(t, l, "sine", 300, 210, 0.20, 0.9),
|
||
tambourine:(t, l) => v_noise(t, l, "highpass", 8000, 0, 0.12, 0.5),
|
||
cowbell: (t, l) => { const sum = audioCtx.createGain(), bp = filt("bandpass", 2640, 1.2), g = ampEnv(t, 0.8 * l, 0.3); [540, 800].forEach((f) => tone(t, "square", f, 0, 0.3).connect(sum)); sum.connect(bp); bp.connect(g); g.connect(masterGain); },
|
||
woodblock: (t, l) => v_tone(t, l, "triangle", 1800, 1500, 0.06, 0.8),
|
||
claves: (t, l) => v_tone(t, l, "sine", 2500, 0, 0.045, 0.85),
|
||
jamblock: (t, l) => { const o = tone(t, "square", 2600, 2000, 0.045), bp = filt("bandpass", 2000, 6), g = ampEnv(t, 0.8 * l, 0.045); o.connect(bp); bp.connect(g); g.connect(masterGain); },
|
||
// --- electronic drum-machine voices (synthesized — these machines ARE synths in reality) ---
|
||
kick808: (t, l) => { v_tone(t, l, "sine", 120, 45, 0.7, 1.0); v_noise(t, l * 0.5, "highpass", 2000, 0, 0.008, 0.4, 0.001); }, // long boom + click
|
||
snare808: (t, l) => { v_tone(t, l, "triangle", 178, 168, 0.16, 0.4); v_tone(t, l, "triangle", 331, 320, 0.12, 0.18); v_noise(t, l, "highpass", 1000, 0, 0.16, 0.7); },
|
||
clap808: (t, l) => { const bp = filt("bandpass", 1100, 1.3); bp.connect(masterGain); [0, 0.01, 0.02, 0.032].forEach((d, i) => { const n = noiseSrc(t + d, 0.05), e = ampEnv(t + d, (i < 3 ? 0.5 : 0.85) * l, 0.05); n.connect(e); e.connect(bp); }); },
|
||
hat808: (t, l) => metalHat(t, l, 0.045, 7000, 0.4),
|
||
openHat808: (t, l) => metalHat(t, l, 0.34, 7000, 0.38),
|
||
cowbell808: (t, l) => { const sum = audioCtx.createGain(), bp = filt("bandpass", 2640, 1.2), g = ampEnv(t, 0.8 * l, 0.3); [540, 800].forEach((f) => tone(t, "square", f, 0, 0.3).connect(sum)); sum.connect(bp); bp.connect(g); g.connect(masterGain); },
|
||
tom808: (t, l) => v_tone(t, l, "sine", 120, 78, 0.34, 0.9),
|
||
kick909: (t, l) => { v_tone(t, l, "sine", 110, 46, 0.26, 1.0); v_tone(t, l, "triangle", 280, 60, 0.035, 0.5); v_noise(t, l * 0.6, "highpass", 3000, 0, 0.01, 0.5, 0.001); }, // punchy + click
|
||
snare909: (t, l) => { v_tone(t, l, "triangle", 190, 162, 0.09, 0.28); v_noise(t, l, "highpass", 1200, 0, 0.2, 0.85); },
|
||
clap909: (t, l) => { const bp = filt("bandpass", 1000, 1.0); bp.connect(masterGain); [0, 0.009, 0.018].forEach((d) => { const n = noiseSrc(t + d, 0.05), e = ampEnv(t + d, 0.6 * l, 0.05); n.connect(e); e.connect(bp); }); const tail = noiseSrc(t + 0.018, 0.2), te = ampEnv(t + 0.018, 0.35 * l, 0.2, 0.001); tail.connect(te); te.connect(bp); },
|
||
hat909: (t, l) => metalHat(t, l, 0.05, 9000, 0.4),
|
||
ride909: (t, l) => { metalHat(t, l, 0.5, 6000, 0.3); v_noise(t, l, "bandpass", 7000, 0.7, 0.18, 0.18, 0.002); },
|
||
crash909: (t, l) => { metalHat(t, l, 0.9, 5000, 0.34); v_noise(t, l, "highpass", 4000, 0, 0.9, 0.4, 0.002); },
|
||
};
|
||
const VOICES = [
|
||
["beep", "beep"], ["kick", "kick"], ["snare", "snare"], ["rim", "rim/stick"], ["clap", "clap"],
|
||
["hatClosed", "hat closed"], ["hatOpen", "hat open"], ["ride", "ride"], ["crash", "crash"],
|
||
["tomLow", "tom low"], ["tomMid", "tom mid"], ["tomHigh", "tom high"], ["tambourine", "tambourine"],
|
||
["cowbell", "cowbell"], ["woodblock", "wood block"], ["claves", "claves"], ["jamblock", "jam block"],
|
||
["kick808", "808 kick"], ["snare808", "808 snare"], ["clap808", "808 clap"], ["hat808", "808 hat"], ["openHat808", "808 open hat"], ["cowbell808", "808 cowbell"], ["tom808", "808 tom"],
|
||
["kick909", "909 kick"], ["snare909", "909 snare"], ["clap909", "909 clap"], ["hat909", "909 hat"], ["ride909", "909 ride"], ["crash909", "909 crash"],
|
||
];
|
||
function playInstrument(type, time, level) {
|
||
const buf = sampleBuffers[type];
|
||
if (buf) { const s = audioCtx.createBufferSource(); s.buffer = buf; const g = audioCtx.createGain(); g.gain.value = level; s.connect(g); g.connect(masterGain); s.start(time); return; }
|
||
(DRUMS[type] || DRUMS.beep)(time, level);
|
||
}
|
||
|
||
/* =========================================================================
|
||
SCHEDULER (PORTS TO FIRMWARE)
|
||
========================================================================= */
|
||
// Master clock: counts bars off the FIRST lane, used by trainer + ramp.
|
||
let masterBeatTime = 0, masterBeat = 0;
|
||
let muteWindows = []; // {start,end} time ranges silenced by the trainer
|
||
|
||
function masterBeatsPerBar() { return meters.length ? meters[0].beatsPerBar : 4; }
|
||
|
||
function advanceMaster(ahead) {
|
||
const mbpb = masterBeatsPerBar();
|
||
while (masterBeatTime < ahead) {
|
||
if (masterBeat % mbpb === 0) {
|
||
const barIndex = Math.floor(masterBeat / mbpb);
|
||
if (barIndex > 0 && ramp.on && (barIndex % ramp.everyBars === 0)) setBpm(state.bpm + ramp.amount);
|
||
if (trainer.on) {
|
||
const cycle = trainer.playBars + trainer.muteBars;
|
||
if (cycle > 0 && (barIndex % cycle) >= trainer.playBars) {
|
||
muteWindows.push({ start: masterBeatTime, end: masterBeatTime + mbpb * (60 / state.bpm) });
|
||
}
|
||
}
|
||
segBarCount = barIndex; // whole bars elapsed in this segment
|
||
if (segBars > 0 && barIndex >= segBars && !pendingSwitch && state.running) { // bar-count auto-advance
|
||
const nx = nextLoadedTarget();
|
||
if (nx) { pendingSwitch = { sl: nx.sl, item: nx.item, atTime: masterBeatTime, reason: "auto" }; break; } // cut at this downbeat
|
||
}
|
||
}
|
||
masterBeat++;
|
||
masterBeatTime += 60 / state.bpm;
|
||
}
|
||
if (audioCtx) muteWindows = muteWindows.filter((w) => w.end > audioCtx.currentTime - 1);
|
||
}
|
||
function isMutedAt(t) { return muteWindows.some((w) => t >= w.start && t < w.end); }
|
||
|
||
function scheduleMeterTick(m, time) {
|
||
const spb = m.stepsPerBeat;
|
||
const barLen = m.beatsPerBar * spb;
|
||
const tickInBar = ((m.tick % barLen) + barLen) % barLen;
|
||
m.vq.push({ time, step: tickInBar, bar: Math.floor(m.tick / barLen) }); // playhead (per step) + measure (advance even when muted)
|
||
if (!m.enabled || isMutedAt(time)) return;
|
||
const lvl = m.beatsOn[tickInBar] | 0; // dynamics: 0 mute · 1 normal · 2 accent · 3 ghost
|
||
if (!lvl) return;
|
||
playInstrument(m.sound, time, lvl === 2 ? 1.0 : lvl === 3 ? 0.25 : 0.6);
|
||
}
|
||
|
||
// Reference bar = lane 1's bar; poly lanes fit their beats evenly into it.
|
||
function refBarDur() { return (meters.length ? meters[0].beatsPerBar : 4) * (60 / state.bpm); }
|
||
const SWING_RATIO = 2 / 3; // triplet swing: the off-beat lands on the last triplet
|
||
function laneStepDur(m, tick) {
|
||
if (m.poly) return refBarDur() / (m.beatsPerBar * m.stepsPerBeat); // true ratio polyrhythm (no swing)
|
||
const beat = 60 / state.bpm;
|
||
if (m.swing && m.stepsPerBeat % 2 === 0) { // swing even subdivisions (8ths, 16ths): long–short pairs
|
||
const pairDur = beat / (m.stepsPerBeat / 2);
|
||
return ((tick % m.stepsPerBeat) % 2) === 0 ? SWING_RATIO * pairDur : (1 - SWING_RATIO) * pairDur;
|
||
}
|
||
return beat / m.stepsPerBeat; // straight: shared even grid
|
||
}
|
||
|
||
function scheduler() {
|
||
const ahead = audioCtx.currentTime + SCHEDULE_AHEAD;
|
||
// While a switch is armed, never advance/schedule past its boundary — so no audio
|
||
// is committed beyond it. advanceMaster may also arm an auto-switch and stop at the boundary.
|
||
advanceMaster(pendingSwitch ? Math.min(ahead, pendingSwitch.atTime) : ahead);
|
||
const cap = pendingSwitch ? Math.min(ahead, pendingSwitch.atTime) : ahead;
|
||
for (const m of meters) {
|
||
while (m.nextTime < cap) {
|
||
scheduleMeterTick(m, m.nextTime);
|
||
m.nextTime += laneStepDur(m, m.tick); // duration of the step just scheduled (swing makes pairs uneven)
|
||
m.tick++;
|
||
}
|
||
}
|
||
// Boundary reached → swap to the new segment seamlessly (scheduler keeps running).
|
||
if (pendingSwitch && masterBeatTime >= pendingSwitch.atTime - 1e-9) performCutover(pendingSwitch);
|
||
}
|
||
|
||
/* =========================================================================
|
||
TRANSPORT
|
||
========================================================================= */
|
||
function start() {
|
||
ensureAudio(); audioCtx.resume();
|
||
state.running = true;
|
||
if (ramp.on) setBpm(ramp.startBpm); // ramp begins from its start BPM
|
||
const t0 = audioCtx.currentTime + 0.08;
|
||
for (const m of meters) { m.tick = 0; m.nextTime = t0; m.vq = []; m.vqPtr = 0; m.currentStep = -1; m.currentBar = 0; }
|
||
masterBeat = 0; masterBeatTime = t0; muteWindows = [];
|
||
schedulerTimer = setInterval(scheduler, LOOKAHEAD_MS);
|
||
scheduler(); syncStartBtn();
|
||
}
|
||
function stop() {
|
||
state.running = false;
|
||
clearInterval(schedulerTimer); schedulerTimer = null;
|
||
pendingSwitch = null; segBarCount = 0; // drop any armed switch so it can't fire on next start
|
||
for (const m of meters) m.currentStep = -1;
|
||
syncStartBtn();
|
||
}
|
||
|
||
/* ----- gap-free cutover -----------------------------------------------------
|
||
One mechanism, two quantize targets: "beat" (rude/now) and "bar" (smooth).
|
||
Arming records a future boundary time; the scheduler caps outgoing audio at it
|
||
and rebuilds the meters there — schedulerTimer never stops, so the downbeat is
|
||
continuous (this replaces the old gappy stop()+start() switch). */
|
||
function nextBeatBoundaryTime() { return masterBeatTime; } // time of the next (unscheduled) beat
|
||
function nextBarBoundaryTime() {
|
||
const mbpb = masterBeatsPerBar();
|
||
const toNext = ((mbpb - (masterBeat % mbpb)) % mbpb) || mbpb; // beats until the next downbeat (≥ 1 bar away if on it)
|
||
return masterBeatTime + toNext * (60 / state.bpm);
|
||
}
|
||
function armSwitch(sl, item, reason, quantize) {
|
||
if (!setlists[sl] || !setlists[sl].items[item]) return;
|
||
if (!state.running) { loadItem(item, sl); return; } // not playing → load immediately
|
||
let bt = quantize === "bar" ? nextBarBoundaryTime() : nextBeatBoundaryTime();
|
||
const unit = (quantize === "bar" ? masterBeatsPerBar() : 1) * (60 / state.bpm);
|
||
while (bt <= audioCtx.currentTime + SCHEDULE_AHEAD) bt += unit; // defer past already-committed audio
|
||
pendingSwitch = { sl, item, atTime: bt, reason: reason || "commit" };
|
||
updateCtx();
|
||
}
|
||
function performCutover(ps) {
|
||
const bt = ps.atTime;
|
||
logFinalize(); // close out the outgoing segment's log entry
|
||
pendingSwitch = null;
|
||
applySetup(setlists[ps.sl].items[ps.item]); // rebuilds meters, sets bpm/ramp/trainer/segBars, resets segBarCount
|
||
if (ramp.on) setBpm(ramp.startBpm); // each segment's ramp starts fresh (like start())
|
||
setLoaded(ps.sl, ps.item);
|
||
for (const m of meters) { m.tick = 0; m.nextTime = bt; m.vq = []; m.vqPtr = 0; m.currentStep = -1; m.currentBar = 0; } // first tick on the boundary
|
||
masterBeat = 0; masterBeatTime = bt; muteWindows = [];
|
||
nowPlaying = { at: Date.now(), name: setlists[ps.sl].items[ps.item].name };
|
||
if (activeSL !== loadedSL) { activeSL = loadedSL; renderSetlists(); } else renderItems();
|
||
renderLog(); updateCtx();
|
||
}
|
||
function setBpm(v) {
|
||
state.bpm = Math.max(30, Math.min(300, Math.round(v)));
|
||
bpm.value = state.bpm; bpmVal.textContent = state.bpm; bpmDisplay.textContent = state.bpm;
|
||
}
|
||
|
||
/* =========================================================================
|
||
METER LANES (dynamic add/remove)
|
||
========================================================================= */
|
||
function laneColor(id) { return `hsl(${(id * 67) % 360} 70% 62%)`; }
|
||
|
||
function addMeter(groupsStr = "4", stepsPerBeat = 4, sound = "beep", beatsOn = null, poly = false, swing = false) {
|
||
const id = ++meterSeq;
|
||
const p = parseGroups(groupsStr);
|
||
const m = {
|
||
id, groupsStr, groups: p.groups, beatsPerBar: p.beatsPerBar, groupStarts: p.groupStarts,
|
||
stepsPerBeat, sound, enabled: true, poly: !!poly, swing: !!swing, color: laneColor(id),
|
||
beatsOn: beatsOn ? beatsOn.slice() : [], // per-STEP dynamics mask (one entry per pad: 0 mute / 1 normal / 2 accent)
|
||
tick: 0, nextTime: 0, vq: [], vqPtr: 0, currentStep: -1, currentBar: 0,
|
||
el: null, stripEl: null, barEl: null,
|
||
};
|
||
// Tell recomputeLane the resolution the incoming mask was authored at, so it can
|
||
// remap/expand it: matches steps → per-step (new), matches beats → legacy per-beat.
|
||
if (m.beatsOn.length === p.beatsPerBar * stepsPerBeat) { m._maskBpb = p.beatsPerBar; m._maskSpb = stepsPerBeat; }
|
||
else if (m.beatsOn.length === p.beatsPerBar) { m._maskBpb = p.beatsPerBar; m._maskSpb = 1; }
|
||
else { m._maskBpb = 0; m._maskSpb = 1; } // empty/unknown → recompute fills all-on
|
||
if (state.running) { m.nextTime = audioCtx.currentTime + 0.05; }
|
||
meters.push(m);
|
||
buildLaneCard(m);
|
||
renumberLanes();
|
||
updateCtx();
|
||
}
|
||
|
||
function removeMeter(id) {
|
||
const i = meters.findIndex((m) => m.id === id);
|
||
if (i < 0) return;
|
||
meters[i].el.remove();
|
||
meters.splice(i, 1);
|
||
renumberLanes();
|
||
updateCtx();
|
||
}
|
||
|
||
// lane labels track position (1-based) so number-key shortcuts line up with what's shown
|
||
function renumberLanes() { meters.forEach((m, i) => { if (m.titleEl) m.titleEl.textContent = i + 1; }); }
|
||
function setLaneEnabled(m, on) {
|
||
m.enabled = on;
|
||
const cb = m.el && m.el.querySelector(`#m${m.id}_enable`); if (cb) cb.checked = on;
|
||
if (m.el) m.el.querySelector(".lane-row").classList.toggle("lane-off", !on);
|
||
}
|
||
|
||
function buildLaneCard(m) {
|
||
const card = document.createElement("div");
|
||
card.className = "meter-card";
|
||
card.innerHTML = `
|
||
<div class="lane-row">
|
||
<span class="lane-title" id="m${m.id}_title" style="color:${m.color}">${m.id}</span>
|
||
<input type="checkbox" class="lane-enable" id="m${m.id}_enable" title="enable / silence this lane" checked>
|
||
<input type="text" class="txt grp" id="m${m.id}_group" value="${m.groupsStr}" spellcheck="false" title="grouping, e.g. 2+2+3">
|
||
<span class="sum" id="m${m.id}_sum"></span>
|
||
<select class="cmp" id="m${m.id}_sub" title="subdivision — sets how many pads each beat splits into; “swing” delays the off-beats">
|
||
<option value="1">♩ quarter</option><option value="2">♪ eighth</option>
|
||
<option value="3">3·triplet</option><option value="4">16th</option><option value="6">6·sext</option>
|
||
<option value="2s">♪ swing 8th</option><option value="4s">swing 16th</option>
|
||
</select>
|
||
<select class="cmp" id="m${m.id}_sound" title="sound">${VOICES.map(([v, n]) => `<option value="${v}">${n}</option>`).join("")}</select>
|
||
<div class="strip" id="m${m.id}_strip"></div>
|
||
<span class="bar" id="m${m.id}_bar">—</span>
|
||
<label class="mini-check" title="polyrhythm: fit these beats evenly into lane 1's bar"><input type="checkbox" id="m${m.id}_poly"> poly</label>
|
||
<button class="x" id="m${m.id}_remove" title="remove lane">✕</button>
|
||
</div>`;
|
||
document.getElementById("meters").appendChild(card);
|
||
m.el = card;
|
||
m.stripEl = card.querySelector(`#m${m.id}_strip`);
|
||
m.barEl = card.querySelector(`#m${m.id}_bar`);
|
||
m.titleEl = card.querySelector(`#m${m.id}_title`);
|
||
|
||
// wire controls
|
||
const $c = (sel) => card.querySelector(sel);
|
||
$c(`#m${m.id}_group`).addEventListener("input", (e) => { m.groupsStr = e.target.value; recomputeLane(m); });
|
||
const sub = $c(`#m${m.id}_sub`); sub.value = m.swing ? (m.stepsPerBeat + "s") : String(m.stepsPerBeat);
|
||
sub.addEventListener("change", (e) => { const v = e.target.value; m.swing = /s$/.test(v); m.stepsPerBeat = parseInt(v, 10) || 1; recomputeLane(m); });
|
||
const sel = $c(`#m${m.id}_sound`); sel.value = m.sound;
|
||
sel.addEventListener("change", (e) => m.sound = e.target.value);
|
||
const polyCb = $c(`#m${m.id}_poly`); polyCb.checked = m.poly;
|
||
polyCb.addEventListener("change", (e) => m.poly = e.target.checked);
|
||
const enCb = $c(`#m${m.id}_enable`); enCb.checked = m.enabled;
|
||
enCb.addEventListener("change", (e) => setLaneEnabled(m, e.target.checked));
|
||
card.querySelector(".lane-row").classList.toggle("lane-off", !m.enabled);
|
||
$c(`#m${m.id}_remove`).addEventListener("click", () => removeMeter(m.id));
|
||
|
||
recomputeLane(m);
|
||
}
|
||
|
||
// Per-step dynamics levels: 0 mute · 1 normal · 2 accent · 3 ghost. (Ghost is the new
|
||
// value 3 so set lists saved at the 3-level stage — 0/1/2 — keep their meaning, no migration.)
|
||
const stepDefault = (s) => (s === 0 ? 2 : 1); // default: first step of each beat accented, rest normal
|
||
const NEXT_LEVEL = { 2: 1, 1: 3, 3: 0, 0: 2 }; // click cycle: accent → normal → ghost → mute → accent
|
||
function normLevel(v, dflt) { // coerce a stored value to a level
|
||
if (v === true) return dflt === 2 ? 2 : 1; // legacy boolean "on" → keep accent on downbeats
|
||
if (v === false) return 0;
|
||
if (v == null) return dflt;
|
||
const n = v | 0; return n >= 3 ? 3 : n >= 2 ? 2 : n >= 1 ? 1 : 0;
|
||
}
|
||
function recomputeLane(m) {
|
||
const p = parseGroups(m.groupsStr);
|
||
m.groups = p.groups; m.beatsPerBar = p.beatsPerBar; m.groupStarts = p.groupStarts;
|
||
// Remap the dynamics mask to step resolution (beats × subdivision = one pad each),
|
||
// preserving levels where they line up and defaulting new pads (first-of-beat accent, rest normal).
|
||
const spb = m.stepsPerBeat;
|
||
const prev = m.beatsOn || [], oldBpb = m._maskBpb || 0, oldSpb = m._maskSpb || 1;
|
||
const next = [];
|
||
for (let b = 0; b < m.beatsPerBar; b++) {
|
||
for (let s = 0; s < spb; s++) {
|
||
let val = stepDefault(s);
|
||
if (b < oldBpb) { // this beat existed before
|
||
if (oldSpb === spb) val = normLevel(prev[b * oldSpb + s], stepDefault(s)); // same resolution → step-for-step
|
||
else if (s === 0) val = normLevel(prev[b * oldSpb], 2); // resolution changed → keep the downbeat; new subs default
|
||
}
|
||
next.push(val);
|
||
}
|
||
}
|
||
m.beatsOn = next; m._maskBpb = m.beatsPerBar; m._maskSpb = spb;
|
||
m.el.querySelector(`#m${m.id}_sum`).textContent = "=" + m.beatsPerBar;
|
||
buildLaneStrip(m);
|
||
}
|
||
|
||
function buildLaneStrip(m) { // one pad per STEP (beats × subdivision)
|
||
m.stripEl.innerHTML = "";
|
||
const spb = m.stepsPerBeat, total = m.beatsPerBar * spb;
|
||
for (let i = 0; i < total; i++) {
|
||
const b = Math.floor(i / spb), s = i % spb;
|
||
const cell = document.createElement("div");
|
||
cell.className = "led";
|
||
cell.textContent = (s === 0) ? (b + 1) : ""; // label downbeats; subdivisions blank
|
||
cell.style.cursor = "pointer";
|
||
cell.title = "click: accent → normal → ghost → mute · beat " + (b + 1) + (s ? " · sub " + (s + 1) : "");
|
||
cell.addEventListener("click", () => { m.beatsOn[i] = NEXT_LEVEL[m.beatsOn[i] | 0]; renderLaneStrip(m); });
|
||
m.stripEl.appendChild(cell);
|
||
}
|
||
}
|
||
|
||
function renderLaneStrip(m) {
|
||
const cells = m.stripEl.children, spb = m.stepsPerBeat;
|
||
for (let i = 0; i < cells.length; i++) {
|
||
const cell = cells[i];
|
||
const b = Math.floor(i / spb), s = i % spb, onBeat = (s === 0);
|
||
const lvl = m.beatsOn[i] | 0, gs = onBeat && m.groupStarts.has(b);
|
||
let cls = "led";
|
||
if (!onBeat) cls += " sub"; // subdivision pad (smaller/dimmer)
|
||
else if (i > 0 && !gs) cls += " beatstart"; // gap between beats within a group
|
||
if (lvl >= 1) cls += " on"; // normal / accent / ghost → lit
|
||
if (gs) cls += " groupstart"; // group divider (layout only)
|
||
if (lvl === 2) cls += " accent"; // accented step (▲)
|
||
else if (lvl === 3) cls += " ghost"; // ghost note (faint ·)
|
||
cell.className = cls;
|
||
cell.style.setProperty("--lc", m.color);
|
||
if (state.running && i === m.currentStep) cell.classList.add("playhead");
|
||
}
|
||
if (m.barEl) m.barEl.textContent = state.running ? "bar " + (m.currentBar + 1) : "—";
|
||
}
|
||
|
||
/* =========================================================================
|
||
PRESETS (localStorage)
|
||
========================================================================= */
|
||
const LS = { presets: "metronome.presets", setlists: "metronome.setlists", logs: "metronome.logs", seeded: "metronome.seeded", continue: "metronome.continue", timers: "metronome.timers" };
|
||
function lsGet(k, fb) { try { const v = localStorage.getItem(k); return v ? JSON.parse(v) : fb; } catch (e) { return fb; } }
|
||
function lsSet(k, v) { try { localStorage.setItem(k, JSON.stringify(v)); return true; } catch (e) { console.warn("localStorage unavailable", e); return false; } }
|
||
|
||
function snapshotLanes() { return meters.map((m) => ({ groupsStr: m.groupsStr, stepsPerBeat: m.stepsPerBeat, sound: m.sound, enabled: m.enabled, poly: m.poly, swing: !!m.swing, beatsOn: m.beatsOn.slice() })); }
|
||
function applyLanes(lanes) {
|
||
while (meters.length) removeMeter(meters[0].id);
|
||
for (const c of lanes) {
|
||
addMeter(c.groupsStr, c.stepsPerBeat, c.sound, c.beatsOn, c.poly, c.swing);
|
||
const m = meters[meters.length - 1];
|
||
setLaneEnabled(m, c.enabled !== undefined ? !!c.enabled : (c.mute === undefined ? true : !c.mute)); // back-compat with old "mute"
|
||
}
|
||
}
|
||
// (Presets removed — set-list items are now the single "saved setup" mechanism.)
|
||
|
||
/* =========================================================================
|
||
SET LISTS + PRACTICE LOG
|
||
A set list = { title, description, items:[{name, bpm, lanes, ...}] }.
|
||
▶ on an item loads its settings and starts; N advances to the next item.
|
||
Each played item is logged (timestamp, name, duration, BPM, conditions).
|
||
========================================================================= */
|
||
let setlists = lsGet(LS.setlists, []);
|
||
let activeSL = 0; // VIEWED set list (the one shown in the panel)
|
||
let activeItem = -1; // loaded item index within loadedSL (-1 = none / free play)
|
||
let loadedSL = 0; // set list the loaded/playing item lives in (may differ from the viewed one)
|
||
let cuedSL = -1, cuedItem = -1; // cue cursor — non-destructive browse pointer (-1 = none)
|
||
let pendingSwitch = null; // armed cutover: { sl, item, atTime, reason }
|
||
let segBars = 0; // bar-length of the loaded segment (0 = manual, no auto-advance)
|
||
let segBarCount = 0; // whole bars elapsed in the current segment
|
||
let nowPlaying = null; // { at, name } for duration logging
|
||
let historyName = null; // item whose past-session history is shown
|
||
let continueMode = lsGet(LS.continue, false); // auto-advance to next item when countdown ends
|
||
let timersOn = lsGet(LS.timers, true); // master switch for the elapsed/countdown timers
|
||
|
||
function currentSetup() { return { bpm: state.bpm, lanes: snapshotLanes(), trainer: { ...trainer }, ramp: { ...ramp }, countMs: timers.totalMs, bars: segBars }; }
|
||
function applySetup(s) {
|
||
setBpm(s.bpm); applyLanes(s.lanes);
|
||
if (s.trainer) Object.assign(trainer, s.trainer);
|
||
if (s.ramp) Object.assign(ramp, s.ramp);
|
||
timers.totalMs = s.countMs || 0; timers.remainingMs = timers.totalMs; // per-item time countdown
|
||
segBars = s.bars || 0; segBarCount = 0; // per-item bar-length + counter
|
||
syncPracticeUI(); updateCtx();
|
||
}
|
||
function syncPracticeUI() {
|
||
$("trainerOn").checked = trainer.on; $("playBars").value = trainer.playBars; $("muteBars").value = trainer.muteBars;
|
||
$("rampOn").checked = ramp.on; $("rampStart").value = ramp.startBpm; $("rampAmt").value = ramp.amount; $("rampEvery").value = ramp.everyBars;
|
||
$("countTime").value = timers.totalMs > 0 ? fmtClock(timers.totalMs) : "";
|
||
$("segBarsIn").value = segBars || 0;
|
||
refreshFeatureBoxes(); renderTimers();
|
||
}
|
||
function refreshFeatureBoxes() {
|
||
$("trainerBox").classList.toggle("on", trainer.on);
|
||
$("rampBox").classList.toggle("on", ramp.on);
|
||
$("timerBox").classList.toggle("on", timersOn);
|
||
}
|
||
function fmtDur(sec) { sec = Math.round(sec); const m = Math.floor(sec / 60); return m + ":" + String(sec % 60).padStart(2, "0"); }
|
||
function getSL() { return setlists[activeSL]; } // the VIEWED list
|
||
function loadedItem() { const sl = setlists[loadedSL]; return (sl && activeItem >= 0) ? sl.items[activeItem] : null; }
|
||
function saveSetlists() { lsSet(LS.setlists, setlists); }
|
||
|
||
// --- set list CRUD ---
|
||
function newSetlist() {
|
||
setlists.push({ title: "Set list " + (setlists.length + 1), description: "", items: [] });
|
||
activeSL = setlists.length - 1; saveSetlists(); renderSetlists(); // view the new list; loaded item keeps playing in its own
|
||
}
|
||
function deleteSetlist() {
|
||
if (!setlists.length || !confirm("Delete this set list?")) return;
|
||
const removed = activeSL;
|
||
setlists.splice(removed, 1);
|
||
const adj = (n) => n > removed ? n - 1 : n;
|
||
if (loadedSL === removed) { activeItem = -1; loadedSL = Math.max(0, removed - 1); } else loadedSL = adj(loadedSL);
|
||
if (cuedSL === removed) { cuedSL = -1; cuedItem = -1; } else cuedSL = adj(cuedSL);
|
||
if (pendingSwitch) { if (pendingSwitch.sl === removed) pendingSwitch = null; else pendingSwitch.sl = adj(pendingSwitch.sl); }
|
||
activeSL = Math.max(0, removed - 1); saveSetlists(); renderSetlists();
|
||
}
|
||
function addItem(name) {
|
||
const sl = getSL(); if (!sl) return;
|
||
sl.items.push({ name: name || ("Item " + (sl.items.length + 1)), ...currentSetup() });
|
||
setLoaded(activeSL, sl.items.length - 1); // the captured item becomes the loaded one
|
||
saveSetlists(); renderItems();
|
||
}
|
||
function removeItem(i) {
|
||
const sl = getSL(); if (!sl) return;
|
||
sl.items.splice(i, 1);
|
||
if (activeSL === loadedSL) { if (activeItem === i) activeItem = -1; else if (activeItem > i) activeItem--; }
|
||
if (activeSL === cuedSL) { if (cuedItem === i) cuedItem = Math.min(cuedItem, sl.items.length - 1); else if (cuedItem > i) cuedItem--; }
|
||
saveSetlists(); renderItems();
|
||
}
|
||
function moveItem(i, d) { const sl = getSL(); const j = i + d; if (j < 0 || j >= sl.items.length) return; [sl.items[i], sl.items[j]] = [sl.items[j], sl.items[i]]; saveSetlists(); }
|
||
function moveCuedItem(d) { // keyboard reorder of the cued item (Alt+↑/↓), within the viewed list
|
||
if (cuedSL !== activeSL || cuedItem < 0) return;
|
||
const sl = getSL(); const j = cuedItem + d; if (j < 0 || j >= sl.items.length) return;
|
||
moveItem(cuedItem, d);
|
||
if (loadedSL === activeSL) { if (activeItem === cuedItem) activeItem = j; else if (activeItem === j) activeItem = cuedItem; }
|
||
cuedItem = j; renderItems();
|
||
}
|
||
|
||
// Record the loaded item + sync the cue + history (state only; no audio, no applySetup).
|
||
function setLoaded(sl, i) {
|
||
loadedSL = sl; activeItem = i;
|
||
const it = setlists[sl] && setlists[sl].items[i];
|
||
if (it) historyName = it.name;
|
||
cuedSL = sl; cuedItem = i; // the cue follows the loaded item
|
||
}
|
||
|
||
// --- load: clicking / N / P loads. While playing this is a gap-free RUDE (next-beat) cutover. ---
|
||
function loadItem(i, sl = activeSL) {
|
||
if (!setlists[sl] || !setlists[sl].items[i]) return;
|
||
if (state.running) { armSwitch(sl, i, "load", "beat"); return; } // playing → next beat, no gap
|
||
applySetup(setlists[sl].items[i]);
|
||
setLoaded(sl, i);
|
||
if (activeSL !== sl) { activeSL = sl; renderSetlists(); } else renderItems();
|
||
renderLog();
|
||
}
|
||
function nextItem() { // N — quick-step within the loaded list (rude when playing)
|
||
if (activeItem < 0) { loadItem(0, activeSL); return; }
|
||
const sl = setlists[loadedSL]; if (sl && activeItem + 1 < sl.items.length) loadItem(activeItem + 1, loadedSL);
|
||
}
|
||
function prevItem() { const sl = setlists[loadedSL]; if (sl && activeItem - 1 >= 0) loadItem(activeItem - 1, loadedSL); }
|
||
|
||
// --- cue cursor (browse without loading); commits via Enter/Shift+Enter ---
|
||
function setCue(sl, item) {
|
||
if (sl < 0 || sl >= setlists.length || !setlists[sl].items.length) return;
|
||
cuedSL = sl; cuedItem = Math.max(0, Math.min(item, setlists[sl].items.length - 1));
|
||
if (activeSL !== sl) { activeSL = sl; renderSetlists(); } else renderItems(); // viewed list follows the cue
|
||
}
|
||
function ensureCue() { // seed the cue on first nav (from the loaded item, else the viewed list)
|
||
if (cuedSL >= 0 && cuedItem >= 0 && setlists[cuedSL] && setlists[cuedSL].items[cuedItem]) return;
|
||
if (activeItem >= 0 && setlists[loadedSL]) { cuedSL = loadedSL; cuedItem = activeItem; } else { cuedSL = activeSL; cuedItem = 0; }
|
||
}
|
||
function cueNext() { ensureCue(); if (cuedItem + 1 < setlists[cuedSL].items.length) setCue(cuedSL, cuedItem + 1); else for (let j = cuedSL + 1; j < setlists.length; j++) if (setlists[j].items.length) return setCue(j, 0); }
|
||
function cuePrev() { ensureCue(); if (cuedItem - 1 >= 0) setCue(cuedSL, cuedItem - 1); else for (let j = cuedSL - 1; j >= 0; j--) if (setlists[j].items.length) return setCue(j, setlists[j].items.length - 1); }
|
||
function cueFirst() { for (let j = 0; j < setlists.length; j++) if (setlists[j].items.length) return setCue(j, 0); }
|
||
function cueLast() { for (let j = setlists.length - 1; j >= 0; j--) if (setlists[j].items.length) return setCue(j, setlists[j].items.length - 1); }
|
||
function cueSetlist(d) { ensureCue(); for (let j = cuedSL + d; j >= 0 && j < setlists.length; j += d) if (setlists[j].items.length) return setCue(j, 0); }
|
||
|
||
// The item after the loaded one, crossing into the next non-empty list (for auto-advance). null = end.
|
||
function nextLoadedTarget() {
|
||
const sl = setlists[loadedSL]; if (!sl || activeItem < 0) return null;
|
||
if (activeItem + 1 < sl.items.length) return { sl: loadedSL, item: activeItem + 1 };
|
||
for (let j = loadedSL + 1; j < setlists.length; j++) if (setlists[j].items.length) return { sl: j, item: 0 };
|
||
return null;
|
||
}
|
||
function updateItem() { // Save — overwrite the LOADED item with current settings (keeps its name)
|
||
const sl = setlists[loadedSL]; if (!sl || activeItem < 0 || !sl.items[activeItem]) return;
|
||
sl.items[activeItem] = { name: sl.items[activeItem].name, ...currentSetup() };
|
||
saveSetlists(); renderItems();
|
||
}
|
||
|
||
// Start/stop go through here so internal restarts don't create stray log entries.
|
||
function toggleTransport() {
|
||
if (state.running) { logFinalize(); stop(); }
|
||
else { start(); const it = loadedItem(); if (it) nowPlaying = { at: Date.now(), name: it.name }; }
|
||
renderItems();
|
||
}
|
||
|
||
// --- now-playing info on the main screen (replaces the old preset dropdown) ---
|
||
function renderNowPlaying() {
|
||
const it = loadedItem(); // the LOADED item (may live in a list you're not viewing)
|
||
$("saveItemBtn").disabled = !it; // single save button targets the loaded set-list item
|
||
// A disabled <button> swallows hover, so its title never shows — set it on the wrapper
|
||
// span too, and explain *why* it's disabled when no item is loaded.
|
||
const saveTip = it
|
||
? "Save the current settings to “" + it.name + "” (set-list item " + (activeItem + 1) + ")"
|
||
: "Load a set-list item to enable Save — it overwrites that item with your current settings";
|
||
$("saveItemBtn").title = $("saveItemWrap").title = saveTip;
|
||
if (!it) {
|
||
const vsl = getSL();
|
||
$("npName").textContent = "Free play";
|
||
$("npSub").textContent = "No set-list item loaded — edit the lanes freely.";
|
||
$("npDesc").textContent = (vsl && vsl.description) ? "“" + vsl.title + "” — " + vsl.description : "";
|
||
return;
|
||
}
|
||
const lsl = setlists[loadedSL];
|
||
$("npName").textContent = (activeItem + 1) + ". " + it.name;
|
||
$("npSub").textContent = it.bpm + " BPM · " + it.lanes.map((l) => l.sound + " " + l.groupsStr + (l.poly ? "~" : "") + (l.enabled === false ? " (off)" : "")).join(" · ");
|
||
$("npDesc").textContent = ((lsl && lsl.title) || "") + (lsl && lsl.description ? " — " + lsl.description : "");
|
||
}
|
||
|
||
// --- render ---
|
||
function autoGrow(el) { if (!el) return; el.style.height = "auto"; el.style.height = (el.scrollHeight || 0) + "px"; }
|
||
function buildSlMenu() { // the ▾ dropdown: every list + "+ New" as the last item
|
||
const menu = $("slMenu"); if (!menu) return;
|
||
menu.innerHTML = "";
|
||
setlists.forEach((sl, i) => {
|
||
const b = document.createElement("button");
|
||
b.textContent = (i === activeSL ? "● " : "") + (sl.title || ("Set list " + (i + 1)));
|
||
b.onclick = () => { $("slMenu").hidden = true; activeSL = i; renderSetlists(); }; // view only
|
||
menu.appendChild(b);
|
||
});
|
||
const nb = document.createElement("button");
|
||
nb.textContent = "+ New set list";
|
||
nb.style.cssText = "border-top:1px solid var(--edge); margin-top:2px; padding-top:6px;";
|
||
nb.onclick = () => { $("slMenu").hidden = true; newSetlist(); };
|
||
menu.appendChild(nb);
|
||
}
|
||
function renderSetlists() {
|
||
const has = setlists.length > 0;
|
||
$("slTitle").disabled = $("slDesc").disabled = $("addItemBtn").disabled = $("delSetlistBtn").disabled = !has;
|
||
if (!has) { $("slTitle").value = ""; $("slDesc").value = ""; autoGrow($("slDesc")); buildSlMenu(); renderItems(); return; }
|
||
if (activeSL >= setlists.length) activeSL = setlists.length - 1;
|
||
const sl = getSL();
|
||
$("slTitle").value = sl.title || "";
|
||
$("slDesc").value = sl.description || ""; autoGrow($("slDesc"));
|
||
buildSlMenu(); renderItems();
|
||
}
|
||
function renderItems() {
|
||
const box = $("itemList"); box.innerHTML = ""; const sl = getSL();
|
||
if (!sl) { box.innerHTML = '<div class="hint">Create a set list, then “Add current settings” to capture items.</div>'; renderNowPlaying(); return; }
|
||
if (!sl.items.length) { box.innerHTML = '<div class="hint">No items yet — set up the metronome and “Add current settings”.</div>'; renderNowPlaying(); return; }
|
||
sl.items.forEach((it, i) => {
|
||
const row = document.createElement("div");
|
||
row.className = "ex-item"
|
||
+ (activeSL === loadedSL && i === activeItem ? " active" : "") // loaded/playing (green)
|
||
+ (activeSL === cuedSL && i === cuedItem ? " cued" : ""); // cue cursor (amber)
|
||
row.title = "Click to load · ↑↓ to cue · Enter to commit · Alt+↑/↓ to reorder";
|
||
row.innerHTML = `<span class="nm">${i + 1}. ${it.name}${it.bars ? ` <span class="lane-meta">${it.bars} bars</span>` : ""}</span>
|
||
<span class="meta">${it.bpm} · ${it.lanes.map((l) => l.groupsStr).join("/")}</span>
|
||
<span class="row-actions">
|
||
<button class="x iconbtn" data-act="del" title="remove this item">✕</button>
|
||
</span>`;
|
||
row.onclick = () => loadItem(i, activeSL);
|
||
row.querySelector('[data-act=del]').onclick = (e) => { e.stopPropagation(); removeItem(i); };
|
||
box.appendChild(row);
|
||
});
|
||
renderNowPlaying();
|
||
}
|
||
|
||
// --- practice log (flat entries, one per played item) ---
|
||
function logFinalize() {
|
||
if (!nowPlaying) return;
|
||
const logs = lsGet(LS.logs, []);
|
||
logs.unshift({ at: nowPlaying.at, name: nowPlaying.name, durationSec: (Date.now() - nowPlaying.at) / 1000, bpm: state.bpm, lanes: snapshotLanes() });
|
||
lsSet(LS.logs, logs); nowPlaying = null; renderLog();
|
||
}
|
||
// Show history for the item being (or last) played, so the user can compare
|
||
// today's BPM/duration against previous days for that specific task.
|
||
function renderLog() {
|
||
const box = $("logView"); box.innerHTML = "";
|
||
if (!historyName) { box.innerHTML = '<div class="hint">Play a set-list item to see its history — compare BPM & duration across days.</div>'; return; }
|
||
const entries = lsGet(LS.logs, []).filter((e) => e.name === historyName);
|
||
|
||
const head = document.createElement("div"); head.className = "log-head";
|
||
head.innerHTML = `<span class="log-head-nm">History — ${historyName}</span>`;
|
||
if (entries.length) {
|
||
const clr = document.createElement("button"); clr.className = "iconbtn"; clr.textContent = "Clear all";
|
||
clr.title = "delete all history for this item";
|
||
clr.onclick = () => clearItemHistory();
|
||
head.appendChild(clr);
|
||
}
|
||
box.appendChild(head);
|
||
|
||
if (!entries.length) {
|
||
const h = document.createElement("div"); h.className = "hint"; h.textContent = "No past sessions for this item yet.";
|
||
box.appendChild(h); return;
|
||
}
|
||
entries.forEach((e) => {
|
||
const row = document.createElement("div"); row.className = "hist-row";
|
||
const txt = document.createElement("span"); txt.className = "hist-txt";
|
||
txt.textContent = `${new Date(e.at).toLocaleString()} · ${fmtDur(e.durationSec)} @ ${e.bpm}bpm`;
|
||
const del = document.createElement("button"); del.className = "hist-del"; del.textContent = "✕";
|
||
del.title = "delete this entry";
|
||
del.onclick = () => deleteHistoryEntry(e.at);
|
||
row.appendChild(txt); row.appendChild(del); box.appendChild(row);
|
||
});
|
||
}
|
||
function deleteHistoryEntry(at) { // remove one session by its timestamp
|
||
const logs = lsGet(LS.logs, []).filter((e) => !(e.at === at && e.name === historyName));
|
||
lsSet(LS.logs, logs); renderLog();
|
||
}
|
||
function clearItemHistory() { // clear every session for the current item
|
||
if (!historyName) return;
|
||
if (!confirm("Clear all history for “" + historyName + "”? (other items, set lists & presets are kept)")) return;
|
||
const logs = lsGet(LS.logs, []).filter((e) => e.name !== historyName);
|
||
lsSet(LS.logs, logs); renderLog();
|
||
}
|
||
function clearLog() { if (confirm("Clear the practice log? (set lists & presets are kept)")) { lsSet(LS.logs, []); renderLog(); } }
|
||
function resetAll() {
|
||
if (!confirm("Reset EVERYTHING?\n\nThis permanently deletes all saved data on this device — presets, set lists, practice log and theme — and reloads the app to first-run state (demos restored). This cannot be undone.")) return;
|
||
try { localStorage.clear(); } catch (e) {}
|
||
location.replace(location.origin + location.pathname); // reload clean, no hash
|
||
}
|
||
|
||
// --- backup: export / import everything (presets + set lists + logs) ---
|
||
function exportAll() {
|
||
const data = { version: 2, exported: new Date().toISOString(), presets: lsGet(LS.presets, {}), setlists: lsGet(LS.setlists, []), logs: lsGet(LS.logs, []) };
|
||
const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
|
||
const a = document.createElement("a");
|
||
a.href = URL.createObjectURL(blob);
|
||
a.download = "metronome-backup-" + new Date().toISOString().slice(0, 10) + ".json";
|
||
a.click(); URL.revokeObjectURL(a.href);
|
||
}
|
||
function importAll(file) {
|
||
const reader = new FileReader();
|
||
reader.onload = () => {
|
||
try {
|
||
const d = JSON.parse(reader.result);
|
||
if (d.presets) lsSet(LS.presets, d.presets);
|
||
if (d.setlists) { lsSet(LS.setlists, d.setlists); setlists = d.setlists; activeSL = 0; activeItem = -1; }
|
||
if (d.logs) lsSet(LS.logs, d.logs);
|
||
renderSetlists(); renderLog();
|
||
alert("Imported " + Object.keys(d.presets || {}).length + " presets, " + (d.setlists || []).length + " set lists, " + (d.logs || []).length + " log entries.");
|
||
} catch (e) { alert("Import failed: " + e.message); }
|
||
};
|
||
reader.readAsText(file);
|
||
}
|
||
|
||
/* =========================================================================
|
||
SHARE LANGUAGE (compact, human-readable; encodes settings/set lists in URLs)
|
||
Patch: v1;t<bpm>;vol<pct>;<lane>;…[;tr<play>/<mute>][;rmp<start>/<step>/<every>]
|
||
Lane: <sound>:<grouping>[/<sub>][=<pattern x/.>][~ poly][! disabled]
|
||
========================================================================= */
|
||
function laneCfgToStr(c) {
|
||
let s = c.sound + ":" + c.groupsStr;
|
||
const spb = c.stepsPerBeat || 1;
|
||
if (spb !== 1 || c.swing) s += "/" + spb + (c.swing ? "s" : ""); // "/2s" = swung eighths
|
||
const on = c.beatsOn || []; // per-step dynamics: one char per pad (X accent / x normal / . mute)
|
||
const isDefault = on.length && on.every((v, i) => (v | 0) === ((i % spb) === 0 ? 2 : 1));
|
||
if (on.length && !isDefault) s += "=" + on.map((v) => (v === 3 ? "g" : v >= 2 ? "X" : v >= 1 ? "x" : ".")).join("");
|
||
if (c.poly) s += "~";
|
||
if (c.enabled === false) s += "!"; // "!" = silenced / disabled
|
||
return s;
|
||
}
|
||
function laneStrToCfg(tok) {
|
||
let poly = false, disabled = false;
|
||
while (/[~!]$/.test(tok)) { if (tok.endsWith("!")) disabled = true; else poly = true; tok = tok.slice(0, -1); }
|
||
const ci = tok.indexOf(":"); if (ci < 0) return null;
|
||
let sound = tok.slice(0, ci), rest = tok.slice(ci + 1), pattern = null;
|
||
const eq = rest.indexOf("="); if (eq >= 0) { pattern = rest.slice(eq + 1); rest = rest.slice(0, eq); }
|
||
let groupsStr = rest, sub = 1, swing = false; const sl = rest.indexOf("/");
|
||
if (sl >= 0) { groupsStr = rest.slice(0, sl); const sp = rest.slice(sl + 1); swing = /s$/i.test(sp); sub = parseInt(sp, 10) || 1; }
|
||
const bpb = parseGroups(groupsStr).beatsPerBar;
|
||
// pattern levels: X=accent(2), x/1=normal(1), . / anything else = mute(0); no pattern → default (first of each beat accented)
|
||
const beatsOn = pattern ? pattern.split("").map((ch) => ch === "X" ? 2 : ch === "g" ? 3 : (ch === "x" || ch === "1") ? 1 : 0)
|
||
: Array.from({ length: bpb * sub }, (_, i) => ((i % sub) === 0 ? 2 : 1));
|
||
if (!DRUMS[sound]) sound = "beep";
|
||
return { groupsStr, stepsPerBeat: sub, sound, beatsOn, poly, swing, enabled: !disabled };
|
||
}
|
||
function setupToPatch(s) {
|
||
const parts = ["v1", "t" + s.bpm];
|
||
if (s.volume != null) parts.push("vol" + Math.round(s.volume * 100));
|
||
if (s.countMs > 0) parts.push("cd" + Math.round(s.countMs / 1000));
|
||
if (s.bars > 0) parts.push("b" + s.bars);
|
||
(s.lanes || []).forEach((c) => parts.push(laneCfgToStr(c)));
|
||
if (s.trainer && s.trainer.on) parts.push("tr" + s.trainer.playBars + "/" + s.trainer.muteBars);
|
||
if (s.ramp && s.ramp.on) parts.push("rmp" + s.ramp.startBpm + "/" + s.ramp.amount + "/" + s.ramp.everyBars);
|
||
return parts.join(";");
|
||
}
|
||
function patchToSetup(str) {
|
||
const s = { bpm: 120, volume: null, countMs: 0, bars: 0, lanes: [], trainer: { on: false, playBars: 2, muteBars: 2 }, ramp: { on: false, startBpm: 80, amount: 5, everyBars: 4 } };
|
||
for (let tok of String(str).split(";")) {
|
||
tok = tok.trim(); if (!tok || tok === "v1") continue;
|
||
if (tok.includes(":")) { const c = laneStrToCfg(tok); if (c) s.lanes.push(c); } // lanes contain ":" → matched first
|
||
else if (tok.startsWith("vol")) s.volume = (parseInt(tok.slice(3), 10) || 0) / 100;
|
||
else if (tok.startsWith("cd")) s.countMs = (parseInt(tok.slice(2), 10) || 0) * 1000;
|
||
else if (tok.startsWith("b")) s.bars = parseInt(tok.slice(1), 10) || 0; // segment bar-length
|
||
else if (tok.startsWith("tr")) { const [p, m] = tok.slice(2).split("/"); s.trainer = { on: true, playBars: +p || 1, muteBars: +m || 0 }; }
|
||
else if (tok.startsWith("rmp")) { const [a, b, c] = tok.slice(3).split("/"); s.ramp = { on: true, startBpm: +a || 80, amount: +b || 0, everyBars: +c || 1 }; }
|
||
else if (tok.startsWith("t")) s.bpm = parseInt(tok.slice(1), 10) || 120;
|
||
}
|
||
return s;
|
||
}
|
||
function currentPatch() { return setupToPatch({ bpm: state.bpm, volume: state.volume, lanes: snapshotLanes(), trainer, ramp }); }
|
||
function setVolume(pct) {
|
||
state.volume = Math.max(0, Math.min(1, pct / 100));
|
||
$("vol").value = Math.round(state.volume * 100); volVal.textContent = Math.round(state.volume * 100) + "%";
|
||
if (masterGain && audioCtx) masterGain.gain.setTargetAtTime(state.volume, audioCtx.currentTime, 0.01);
|
||
}
|
||
function applyPatch(str) { const s = patchToSetup(str); if (s.volume != null) setVolume(s.volume * 100); applySetup(s); }
|
||
|
||
// base64url(JSON) for set lists — safely carries free-text titles/names
|
||
function b64u(str) { return btoa(unescape(encodeURIComponent(str))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); }
|
||
function unb64u(s) { s = s.replace(/-/g, "+").replace(/_/g, "/"); return decodeURIComponent(escape(atob(s))); }
|
||
function setlistToCode(sl) { return b64u(JSON.stringify({ t: sl.title, d: sl.description, i: sl.items.map((it) => ({ n: it.name, p: setupToPatch(it) })) })); }
|
||
function codeToSetlist(code) {
|
||
const o = JSON.parse(unb64u(code));
|
||
return { title: o.t || "Shared set list", description: o.d || "", items: (o.i || []).map((x) => ({ name: x.n || "Item", ...patchToSetup(x.p) })) };
|
||
}
|
||
|
||
function shareLink(hashPart) { return location.origin + location.pathname + "#" + hashPart; }
|
||
function openShare(title, url, note) {
|
||
$("shareTitle").textContent = title;
|
||
$("shareUrl").value = url;
|
||
$("shareNote").textContent = note || "";
|
||
$("shareOverlay").hidden = false;
|
||
}
|
||
function shareSettings() { openShare("Share settings", shareLink("p=" + currentPatch()), "Encodes tempo, lanes & practice settings."); }
|
||
function shareSetlist() {
|
||
const sl = getSL(); if (!sl) return alert("No set list selected to share.");
|
||
openShare("Share “" + (sl.title || "set list") + "”", shareLink("sl=" + setlistToCode(sl)), "Shares the whole set list (each item's settings).");
|
||
}
|
||
|
||
// Apply a shared link on load. Returns true if it set the metronome state.
|
||
function applyHashShare() {
|
||
const h = location.hash || "";
|
||
try {
|
||
if (h.startsWith("#p=")) { applyPatch(decodeURIComponent(h.slice(3))); history.replaceState(null, "", location.pathname); return true; }
|
||
if (h.startsWith("#sl=")) {
|
||
const sl = codeToSetlist(decodeURIComponent(h.slice(4)));
|
||
setlists.push(sl); activeSL = setlists.length - 1; saveSetlists(); renderSetlists();
|
||
if (sl.items[0]) { applySetup(sl.items[0]); activeItem = 0; historyName = sl.items[0].name; }
|
||
history.replaceState(null, "", location.pathname);
|
||
alert("Imported set list: " + sl.title + " (" + sl.items.length + " items)");
|
||
return true;
|
||
}
|
||
} catch (e) { console.warn("ignored bad share link", e); }
|
||
return false;
|
||
}
|
||
|
||
// Demo set list (each item authored in the share language — also exercises the parser).
|
||
const SEED_SETLISTS = [
|
||
{ title: "🥁 Styles", description: "Grooves & feels — load one, press Space, and click pads to shape the accents.", items: [
|
||
["Four-on-the-floor", "t120;kick:4;snare:4=.x.x;hatClosed:4/2"],
|
||
["Swing ride", "t150;ride:4/2s;kick:4=X..x;snare:4=.x.x"],
|
||
// Purdie half-time shuffle: triplet grid, backbeat on 3, snare ghosts (normal) around it
|
||
["Purdie half-time shuffle", "t92;kick:4/3=X....x...x..;snare:4/3=..gg.gX.gg.g;hatClosed:4/3=X.xX.xX.xX.x"],
|
||
// Samba in 2/4 (16ths): surdo strong on beat 2, steady ganzá, tamborim teleco-teco
|
||
["Samba (2/4)", "t104;tomLow:2/4=x...X...;hatClosed:2/4;woodblock:2/4=X.xx.xX."],
|
||
// Nañigo / 6/8 bembé bell over a 12/8 grid, low drum on the two main pulses
|
||
["Nañigo (6/8 bembé)", "t130;cowbell:4/3=X.xx.x.xx.x.;kick:4/3=X.....X.....;hatClosed:4/3=..x..x..x..x"],
|
||
["6/8 groove", "t100;kick:3+3=x..x..;snare:3+3=...x..;hatClosed:3+3/2"],
|
||
["7/8 (2+2+3)", "t130;kick:2+2+3=x..x..x;hatClosed:2+2+3/2"],
|
||
["5/4 (3+2)", "t112;kick:3+2=x..x.;snare:3+2=..x..;hatClosed:3+2/2"],
|
||
] },
|
||
{ title: "🎯 Practice", description: "Polyrhythms, independence and tempo / gap tools.", items: [
|
||
["5 over 4 polyrhythm", "t100;kick:4;claves:5~"],
|
||
["3 over 2 hemiola", "t96;woodblock:2;cowbell:3~"],
|
||
["2 & 4 & 3 over one bar", "t100;kick:3;cowbell:2~;claves:4~"],
|
||
["Triplet hats", "t100;kick:4;snare:4=.x.x;hatClosed:4/3"],
|
||
["Accents — cycle the pads", "t92;kick:4=X..X;snare:4=.X.X;hatClosed:4/2"],
|
||
["Tempo builder 80↑", "t80;woodblock:4;rmp80/4/4"],
|
||
["Gap trainer (play 2 / rest 2)", "t100;kick:4;hatClosed:4/2;tr2/2"],
|
||
] },
|
||
];
|
||
|
||
/* =========================================================================
|
||
VISUALS
|
||
========================================================================= */
|
||
function drawLoop() {
|
||
if (audioCtx) {
|
||
const now = audioCtx.currentTime;
|
||
for (const m of meters) {
|
||
while (m.vqPtr < m.vq.length && m.vq[m.vqPtr].time <= now) { m.currentStep = m.vq[m.vqPtr].step; m.currentBar = m.vq[m.vqPtr].bar; m.vqPtr++; }
|
||
if (m.vqPtr > 512) { m.vq = m.vq.slice(m.vqPtr); m.vqPtr = 0; }
|
||
}
|
||
updateStatus(now);
|
||
}
|
||
for (const m of meters) renderLaneStrip(m);
|
||
tickTimers();
|
||
requestAnimationFrame(drawLoop);
|
||
}
|
||
|
||
/* =========================================================================
|
||
PRACTICE TIMERS — advance only while the metronome is running
|
||
========================================================================= */
|
||
const timers = { elapsedMs: 0, totalMs: 0, remainingMs: 0, last: 0 }; // countdown off by default
|
||
function fmtClock(ms) { const neg = ms < 0; const s = Math.round(Math.abs(ms) / 1000); return (neg ? "-" : "") + Math.floor(s / 60) + ":" + String(s % 60).padStart(2, "0"); }
|
||
// Parse a countdown duration: blank = off; "h:mm:ss" / "m:ss" (seconds-last); a plain number = minutes.
|
||
function parseTime(str) {
|
||
str = (str || "").trim(); if (!str) return 0;
|
||
if (!str.includes(":")) { const m = parseFloat(str); return isFinite(m) && m > 0 ? Math.round(m * 60000) : 0; }
|
||
const p = str.split(":").map((x) => parseInt(x, 10) || 0);
|
||
let h = 0, m = 0, s = 0;
|
||
if (p.length >= 3) { h = p[0]; m = p[1]; s = p[2]; } else { m = p[0]; s = p[1]; }
|
||
const ms = ((h * 60 + m) * 60 + s) * 1000;
|
||
return ms > 0 ? ms : 0;
|
||
}
|
||
function tickTimers() {
|
||
const now = Date.now();
|
||
const dt = timers.last ? Math.min(now - timers.last, 1000) : 0; // clamp so backgrounded gaps don't jump
|
||
timers.last = now;
|
||
if (timersOn && state.running) {
|
||
timers.elapsedMs += dt;
|
||
if (timers.totalMs > 0) {
|
||
const before = timers.remainingMs;
|
||
timers.remainingMs -= dt;
|
||
// time countdown hit 0 → auto-advance (smooth). Bar-length segments use the
|
||
// bar counter instead (handled in advanceMaster), so only fire when segBars===0.
|
||
if (before > 0 && timers.remainingMs <= 0 && continueMode && segBars === 0 && !pendingSwitch) {
|
||
const nx = nextLoadedTarget();
|
||
if (nx) armSwitch(nx.sl, nx.item, "auto", "bar");
|
||
}
|
||
// otherwise it keeps counting past 0 into negative (overtime); never stops the metronome
|
||
}
|
||
}
|
||
renderTimers();
|
||
}
|
||
function renderTimers() {
|
||
$("dtimers").hidden = !timersOn;
|
||
if (!timersOn) return;
|
||
$("elapsedVal").textContent = fmtClock(timers.elapsedMs);
|
||
const off = timers.totalMs <= 0;
|
||
$("countWrap").hidden = off; // hide time countdown when off
|
||
if (!off) {
|
||
const cd = $("countVal");
|
||
cd.textContent = fmtClock(timers.remainingMs);
|
||
cd.classList.toggle("over", timers.remainingMs <= 0); // overtime
|
||
cd.classList.toggle("low", timers.remainingMs > 0 && timers.remainingMs <= 10000); // almost up
|
||
}
|
||
// bar countdown — bars remaining in the current segment (audible bar from lane 1, not the look-ahead master clock)
|
||
const showBars = state.running && segBars > 0;
|
||
$("barWrap").hidden = !showBars;
|
||
if (showBars) {
|
||
const elapsed = meters.length ? meters[0].currentBar : segBarCount;
|
||
const remaining = Math.max(0, segBars - elapsed);
|
||
const bv = $("barVal");
|
||
bv.textContent = remaining;
|
||
bv.classList.toggle("low", remaining <= 1);
|
||
}
|
||
}
|
||
|
||
// Status shows in the display, under the BPM. Stopped → meter count; running →
|
||
// bar + trainer/ramp flags (kept short for the narrow display column).
|
||
function updateStatus() {
|
||
if (!state.running) {
|
||
ctxDisplay.textContent = meters.length ? (meters.length + " meter" + (meters.length > 1 ? "s" : "") + " · ready") : "no meters";
|
||
ctxDisplay.classList.remove("muted-cue");
|
||
return;
|
||
}
|
||
const mbpb = masterBeatsPerBar();
|
||
const barIndex = Math.floor(Math.max(0, masterBeat - 1) / mbpb);
|
||
const muted = trainer.on && isMutedAt(audioCtx.currentTime);
|
||
let s = "▶ bar " + (barIndex + 1);
|
||
if (trainer.on) s += muted ? " · mute — count!" : " · play";
|
||
if (ramp.on) s += " · ramp";
|
||
if (pendingSwitch) { // a switch is armed → show the target
|
||
const it = setlists[pendingSwitch.sl] && setlists[pendingSwitch.sl].items[pendingSwitch.item];
|
||
s += " · → " + (it ? it.name : "next");
|
||
}
|
||
ctxDisplay.textContent = s;
|
||
ctxDisplay.classList.toggle("muted-cue", muted || !!pendingSwitch);
|
||
}
|
||
function updateCtx() { updateStatus(); }
|
||
|
||
/* =========================================================================
|
||
UI WIRING
|
||
========================================================================= */
|
||
const $ = (id) => document.getElementById(id);
|
||
function syncStartBtn() {
|
||
if (state.running) { startBtn.textContent = "■ Stop"; startBtn.classList.add("on"); }
|
||
else { startBtn.textContent = "▶ Start"; startBtn.classList.remove("on"); }
|
||
}
|
||
function toggleShortcuts(show) { const o = $("shortcutsOverlay"); o.hidden = (show === undefined) ? !o.hidden : !show; }
|
||
const THEMES = ["system", "light", "dark"];
|
||
function effectiveTheme(pref) { return pref === "system" ? (matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark") : pref; }
|
||
function themePref() { try { const p = localStorage.getItem("metronome.theme"); return (p === "light" || p === "dark" || p === "system") ? p : "system"; } catch (e) { return "system"; } }
|
||
function applyTheme(pref) {
|
||
try { localStorage.setItem("metronome.theme", pref); } catch (e) {}
|
||
document.documentElement.dataset.theme = effectiveTheme(pref);
|
||
$("themeBtn").textContent = pref === "system" ? "🖥" : pref === "light" ? "☀" : "🌙";
|
||
$("themeBtn").title = "Theme: " + pref + " (click to cycle: system → light → dark)";
|
||
}
|
||
$("themeBtn").addEventListener("click", () => applyTheme(THEMES[(THEMES.indexOf(themePref()) + 1) % THEMES.length]));
|
||
matchMedia("(prefers-color-scheme: light)").addEventListener("change", () => { if (themePref() === "system") applyTheme("system"); });
|
||
applyTheme(themePref());
|
||
$("startBtn").addEventListener("click", () => toggleTransport());
|
||
let _taps = [];
|
||
function tapTempo() {
|
||
const now = performance.now();
|
||
_taps = _taps.filter((t) => now - t < 2000);
|
||
_taps.push(now);
|
||
if (_taps.length >= 2) {
|
||
let sum = 0; for (let i = 1; i < _taps.length; i++) sum += _taps[i] - _taps[i - 1];
|
||
setBpm(60000 / (sum / (_taps.length - 1)));
|
||
}
|
||
}
|
||
$("tapBtn").addEventListener("click", tapTempo);
|
||
$("saveItemBtn").addEventListener("click", () => {
|
||
if (activeItem < 0) return;
|
||
updateItem();
|
||
const b = $("saveItemBtn"), t = b.textContent; b.textContent = "✓ Saved"; setTimeout(() => { b.textContent = t; }, 900);
|
||
});
|
||
$("bpm").addEventListener("input", (e) => setBpm(+e.target.value));
|
||
$("vol").addEventListener("input", (e) => {
|
||
state.volume = +e.target.value / 100; volVal.textContent = e.target.value + "%";
|
||
if (masterGain) masterGain.gain.setTargetAtTime(state.volume, audioCtx.currentTime, 0.01);
|
||
});
|
||
$("trainerOn").addEventListener("change", (e) => { trainer.on = e.target.checked; refreshFeatureBoxes(); });
|
||
$("playBars").addEventListener("input", (e) => trainer.playBars = +e.target.value);
|
||
$("muteBars").addEventListener("input", (e) => trainer.muteBars = +e.target.value);
|
||
$("rampOn").addEventListener("change", (e) => { ramp.on = e.target.checked; refreshFeatureBoxes(); });
|
||
$("rampStart").addEventListener("input", (e) => ramp.startBpm = +e.target.value);
|
||
$("rampAmt").addEventListener("input", (e) => ramp.amount = +e.target.value);
|
||
$("rampEvery").addEventListener("input", (e) => ramp.everyBars = +e.target.value);
|
||
$("addMeterBtn").addEventListener("click", () => addMeter("4", 1, "claves"));
|
||
$("countTime").addEventListener("input", (e) => { timers.totalMs = parseTime(e.target.value); timers.remainingMs = timers.totalMs; renderTimers(); });
|
||
$("elapsedReset").addEventListener("click", () => { timers.elapsedMs = 0; renderTimers(); });
|
||
$("countReset").addEventListener("click", () => { timers.remainingMs = timers.totalMs; renderTimers(); });
|
||
$("segBarsIn").addEventListener("input", (e) => { segBars = Math.max(0, parseInt(e.target.value, 10) || 0); renderTimers(); });
|
||
$("continueMode").addEventListener("change", (e) => { continueMode = e.target.checked; lsSet(LS.continue, continueMode); });
|
||
$("timersOn").addEventListener("change", (e) => { timersOn = e.target.checked; lsSet(LS.timers, timersOn); refreshFeatureBoxes(); renderTimers(); });
|
||
$("trayMenuBtn").addEventListener("click", (e) => { e.stopPropagation(); $("trayMenu").hidden = !$("trayMenu").hidden; });
|
||
document.addEventListener("click", (e) => { const m = $("trayMenu"); if (m && !m.hidden && !m.contains(e.target) && e.target.id !== "trayMenuBtn") m.hidden = true; });
|
||
$("delSetlistBtn").addEventListener("click", deleteSetlist);
|
||
$("slMenuBtn").addEventListener("click", (e) => { e.stopPropagation(); buildSlMenu(); $("slMenu").hidden = !$("slMenu").hidden; });
|
||
document.addEventListener("click", (e) => { const m = $("slMenu"); if (m && !m.hidden && !m.contains(e.target) && e.target.id !== "slMenuBtn") m.hidden = true; });
|
||
$("slTitle").addEventListener("input", (e) => { const sl = getSL(); if (sl) { sl.title = e.target.value; saveSetlists(); } }); // rename the active list in place
|
||
$("slDesc").addEventListener("input", (e) => { const sl = getSL(); if (sl) { sl.description = e.target.value; saveSetlists(); } autoGrow(e.target); });
|
||
$("addItemBtn").addEventListener("click", () => { addItem($("itemName").value.trim()); $("itemName").value = ""; });
|
||
$("helpBtn").addEventListener("click", () => toggleShortcuts());
|
||
$("shortcutsClose").addEventListener("click", () => toggleShortcuts(false));
|
||
$("shortcutsOverlay").addEventListener("click", (e) => { if (e.target.id === "shortcutsOverlay") toggleShortcuts(false); });
|
||
$("exportBtn").addEventListener("click", () => { $("trayMenu").hidden = true; exportAll(); });
|
||
$("importBtn").addEventListener("click", () => { $("trayMenu").hidden = true; $("importFile").click(); });
|
||
$("importFile").addEventListener("change", (e) => { if (e.target.files[0]) importAll(e.target.files[0]); e.target.value = ""; });
|
||
$("clearLogBtn").addEventListener("click", () => { $("trayMenu").hidden = true; clearLog(); });
|
||
$("resetAllBtn").addEventListener("click", () => { $("trayMenu").hidden = true; resetAll(); });
|
||
$("shareSettingsBtn").addEventListener("click", () => { $("trayMenu").hidden = true; shareSettings(); });
|
||
$("shareSetlistBtn").addEventListener("click", () => { $("trayMenu").hidden = true; shareSetlist(); });
|
||
$("shareClose").addEventListener("click", () => $("shareOverlay").hidden = true);
|
||
$("shareOverlay").addEventListener("click", (e) => { if (e.target.id === "shareOverlay") $("shareOverlay").hidden = true; });
|
||
$("shareCopy").addEventListener("click", async () => { try { await navigator.clipboard.writeText($("shareUrl").value); const b = $("shareCopy"); b.textContent = "Copied!"; setTimeout(() => b.textContent = "Copy link", 1200); } catch (e) { $("shareUrl").select(); } });
|
||
$("shareOpen").addEventListener("click", () => window.open($("shareUrl").value, "_blank"));
|
||
window.addEventListener("keydown", (e) => {
|
||
const t = e.target, tag = t ? t.tagName : "", type = (t && t.type ? String(t.type) : "").toLowerCase();
|
||
// Text entry is sacred — never hijack typing in a text field.
|
||
if (t && (t.isContentEditable || tag === "TEXTAREA" ||
|
||
(tag === "INPUT" && /^(text|number|search|email|url|tel|password)$/.test(type)))) return;
|
||
const k = e.key;
|
||
if (e.altKey && (k === "ArrowUp" || k === "ArrowDown")) { e.preventDefault(); moveCuedItem(k === "ArrowUp" ? -1 : 1); return; } // reorder cued item
|
||
// Enter = commit the cued item. Smooth (next bar) by default; Shift+Enter = rude (next beat).
|
||
// (shiftKey is NOT in the modifier guard below, so Shift+Enter reaches here.)
|
||
if (k === "Enter") {
|
||
if (tag === "BUTTON" || tag === "A" || tag === "SELECT") return; // let focused controls keep Enter
|
||
e.preventDefault();
|
||
if (cuedSL >= 0 && cuedItem >= 0) armSwitch(cuedSL, cuedItem, "commit", e.shiftKey ? "beat" : "bar");
|
||
return;
|
||
}
|
||
if (e.metaKey || e.ctrlKey || e.altKey) return;
|
||
// Transport: Space always = play/stop. preventDefault so it never scrolls the
|
||
// page, toggles a focused checkbox, or re-fires a focused button.
|
||
if (k === " " || e.code === "Space") { e.preventDefault(); toggleTransport(); return; }
|
||
// A focused slider / dropdown uses these keys natively — leave it alone.
|
||
const arrowCtrl = tag === "SELECT" || (tag === "INPUT" && type === "range");
|
||
// ← / → : tempo (±1, Shift ±10).
|
||
if (k === "ArrowRight") { if (arrowCtrl) return; e.preventDefault(); setBpm(state.bpm + (e.shiftKey ? 10 : 1)); return; }
|
||
if (k === "ArrowLeft") { if (arrowCtrl) return; e.preventDefault(); setBpm(state.bpm - (e.shiftKey ? 10 : 1)); return; }
|
||
// ↑ ↓ Home End : move the cue cursor; PgUp/PgDn : cue across set lists. (Enter commits.)
|
||
if (k === "ArrowUp") { if (arrowCtrl) return; e.preventDefault(); cuePrev(); return; }
|
||
if (k === "ArrowDown") { if (arrowCtrl) return; e.preventDefault(); cueNext(); return; }
|
||
if (k === "Home") { if (arrowCtrl) return; e.preventDefault(); cueFirst(); return; }
|
||
if (k === "End") { if (arrowCtrl) return; e.preventDefault(); cueLast(); return; }
|
||
if (k === "PageUp") { if (arrowCtrl) return; e.preventDefault(); cueSetlist(-1); return; }
|
||
if (k === "PageDown") { if (arrowCtrl) return; e.preventDefault(); cueSetlist(1); return; }
|
||
if (k === "t" || k === "T") { tapTempo(); return; }
|
||
if (k === "a" || k === "A") { addMeter("4", 1, "claves"); return; }
|
||
if (k === "p" || k === "P") { prevItem(); return; } // rude quick-step (next beat while playing)
|
||
if (k === "n" || k === "N") { nextItem(); return; }
|
||
if (k === "?") { toggleShortcuts(true); return; }
|
||
if (k === "Escape") {
|
||
if (!$("shareOverlay").hidden) $("shareOverlay").hidden = true;
|
||
else if (!$("shortcutsOverlay").hidden) toggleShortcuts(false);
|
||
else if (pendingSwitch) { pendingSwitch = null; updateCtx(); } // cancel an armed switch
|
||
return;
|
||
}
|
||
if (k >= "1" && k <= "9") { const m = meters[+k - 1]; if (m) setLaneEnabled(m, !m.enabled); }
|
||
});
|
||
|
||
/* init */
|
||
// Seed the demo set lists. Versioned + additive: a newer SEED_VERSION adds any
|
||
// seed list whose title isn't already present, without clobbering the user's lists
|
||
// (and won't re-add one they've deleted at the same version).
|
||
const SEED_VERSION = 2;
|
||
if ((lsGet(LS.seeded, 0) | 0) < SEED_VERSION) {
|
||
for (const s of SEED_SETLISTS) {
|
||
if (!setlists.some((x) => x.title === s.title)) {
|
||
setlists.push({ title: s.title, description: s.description, items: s.items.map(([n, p]) => ({ name: n, ...patchToSetup(p) })) });
|
||
}
|
||
}
|
||
if (activeSL >= setlists.length) activeSL = Math.max(0, setlists.length - 1);
|
||
saveSetlists();
|
||
lsSet(LS.seeded, SEED_VERSION);
|
||
}
|
||
// a shared link (#p=… settings / #sl=… set list) sets the state; otherwise default lanes
|
||
if (!applyHashShare()) {
|
||
addMeter("4", 1, "kick"); // reference bar
|
||
addMeter("5", 1, "claves", null, true); // 5 fit into the bar → true 5:4 polyrhythm
|
||
}
|
||
renderSetlists();
|
||
renderLog();
|
||
updateCtx();
|
||
refreshFeatureBoxes();
|
||
$("continueMode").checked = continueMode;
|
||
$("timersOn").checked = timersOn;
|
||
$("appVersion").textContent = "v" + APP_VERSION;
|
||
requestAnimationFrame(drawLoop);
|
||
</script>
|
||
</body>
|
||
</html>
|