emberwick 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/chart/core/Layers.js","../src/chart/core/Loop.js","../src/chart/motion/Tween.js","../src/chart/core/TimeScale.js","../src/chart/core/PriceScale.js","../src/chart/core/palette.js","../src/chart/motion/LiveCandle.js","../src/chart/motion/Inertia.js","../src/chart/core/formatters.js","../src/chart/render/grid.js","../src/chart/render/candles.js","../src/chart/render/crosshair.js","../src/chart/core/Chart.js","../src/chart/data/DataFeed.js","../src/chart/data/RandomFeed.js","../src/chart/index.js"],"sourcesContent":["/**\n * Layers — stacked canvases sharing one coordinate space.\n *\n * Why: the crosshair repaints on every pointer move, the candles do not.\n * Separate canvases mean moving the cursor never touches candle pixels.\n * All contexts are pre-scaled by devicePixelRatio, so every renderer draws\n * in CSS pixels and gets crisp output on retina.\n */\nexport class Layers {\n constructor(container, names) {\n this.container = container\n this.names = names\n this.canvas = {}\n this.ctx = {}\n this.width = 0\n this.height = 0\n this.dpr = 0\n this.onResize = null\n\n if (getComputedStyle(container).position === 'static') {\n container.style.position = 'relative'\n }\n\n names.forEach((name, i) => {\n const c = document.createElement('canvas')\n Object.assign(c.style, {\n position: 'absolute',\n left: '0',\n top: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: String(i + 1),\n })\n container.appendChild(c)\n this.canvas[name] = c\n this.ctx[name] = c.getContext('2d')\n })\n\n this._ro = new ResizeObserver(() => this.measure())\n this._ro.observe(container)\n this.measure()\n }\n\n measure() {\n const r = this.container.getBoundingClientRect()\n const w = Math.max(1, Math.floor(r.width))\n const h = Math.max(1, Math.floor(r.height))\n const dpr = Math.min(window.devicePixelRatio || 1, 2)\n if (w === this.width && h === this.height && dpr === this.dpr) return\n this.width = w\n this.height = h\n this.dpr = dpr\n for (const n of this.names) {\n const c = this.canvas[n]\n c.width = Math.floor(w * dpr)\n c.height = Math.floor(h * dpr)\n this.ctx[n].setTransform(dpr, 0, 0, dpr, 0, 0)\n }\n if (this.onResize) this.onResize(w, h)\n }\n\n /** Flatten all layers into a single canvas (for toImage/export). */\n composite() {\n const out = document.createElement('canvas')\n out.width = Math.floor(this.width * this.dpr)\n out.height = Math.floor(this.height * this.dpr)\n const c = out.getContext('2d')\n for (const n of this.names) c.drawImage(this.canvas[n], 0, 0)\n return out\n }\n\n destroy() {\n this._ro.disconnect()\n for (const n of this.names) this.canvas[n].remove()\n this.canvas = {}\n this.ctx = {}\n }\n}\n","/**\n * Loop — ONE requestAnimationFrame loop for the whole chart, driven by\n * dirty flags. 500 feed ticks between two frames still cost one repaint.\n *\n * The frame callback returns `true` while animation is in flight, which is\n * what keeps the loop running; otherwise it idles at zero CPU until something\n * calls invalidate().\n */\nexport class Loop {\n constructor(onFrame) {\n this.onFrame = onFrame\n this.fps = 0\n this._raf = 0\n this._dirty = new Set()\n this._last = 0\n this._running = false\n this._frames = 0\n this._fpsAt = 0\n this._tick = this._tick.bind(this)\n }\n\n invalidate(...layers) {\n if (!layers.length) this._dirty.add('all')\n else for (const l of layers) this._dirty.add(l)\n this._schedule()\n }\n\n start() {\n if (this._running) return\n this._running = true\n this._last = performance.now()\n this._fpsAt = this._last\n this.invalidate('all')\n }\n\n stop() {\n this._running = false\n if (this._raf) cancelAnimationFrame(this._raf)\n this._raf = 0\n }\n\n _schedule() {\n if (this._raf || !this._running) return\n this._raf = requestAnimationFrame(this._tick)\n }\n\n _tick(now) {\n this._raf = 0\n if (!this._running) return\n const dt = Math.min(Math.max(now - this._last, 1), 64)\n this._last = now\n\n this._frames++\n if (now - this._fpsAt >= 500) {\n this.fps = Math.round((this._frames * 1000) / (now - this._fpsAt))\n this._frames = 0\n this._fpsAt = now\n }\n\n const dirty = this._dirty\n this._dirty = new Set()\n\n let wantMore = false\n try {\n wantMore = this.onFrame(dirty, dt, now) === true\n } catch (e) {\n console.error('[Emberwick] frame error', e)\n }\n if (wantMore || this._dirty.size) this._schedule()\n }\n}\n","// Motion primitives. Everything animated in Emberwick goes through one of these\n// two classes so there is exactly one place that owns easing behaviour.\n\nexport const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3)\nexport const easeInOutCubic = (t) =>\n t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2\n\n/**\n * Smoothed — exponential smoothing toward a target that may move every frame.\n * Frame-rate independent: the same visual speed at 30fps and 144fps.\n * Use for values that are continuously re-targeted (autoscale, live candle, zoom).\n */\nexport class Smoothed {\n constructor(value = 0, tau = 90) {\n this.value = value\n this.target = value\n this.tau = tau\n }\n\n set(target) {\n this.target = target\n }\n\n /** Snap with no animation. */\n jump(v) {\n this.value = v\n this.target = v\n }\n\n get settled() {\n const eps = 1e-9 + Math.abs(this.target) * 1e-6\n return Math.abs(this.target - this.value) <= eps\n }\n\n /** @returns {boolean} true while still moving (caller keeps the loop alive) */\n tick(dt) {\n if (this.settled) {\n this.value = this.target\n return false\n }\n this.value += (this.target - this.value) * (1 - Math.exp(-dt / this.tau))\n return true\n }\n}\n\n/**\n * Tween — fixed-duration one-shot, for discrete events (a candle being born).\n */\nexport class Tween {\n constructor(duration = 200, ease = easeOutCubic) {\n this.duration = duration\n this.ease = ease\n this.t = duration\n }\n\n restart() {\n this.t = 0\n }\n\n get done() {\n return this.t >= this.duration\n }\n\n get progress() {\n return this.ease(Math.min(1, this.t / this.duration))\n }\n\n tick(dt) {\n if (this.done) return false\n this.t += dt\n return true\n }\n}\n","import { Smoothed } from '../motion/Tween.js'\n\nconst clamp = (v, a, b) => (v < a ? a : v > b ? b : v)\n\n/**\n * TimeScale — maps bar index <-> x pixels.\n *\n * Two smoothed values define the view:\n * spacing : px per bar (zoom)\n * right : float bar index sitting at the right edge of the plot\n *\n * Both are Smoothed, so a wheel zoom eases instead of stepping, and new bars\n * glide in rather than jumping. Dragging uses jump() so the chart stays glued\n * to the pointer — easing a drag feels like lag, not smoothness.\n */\nexport class TimeScale {\n constructor({ spacing = 9, minSpacing = 0.8, maxSpacing = 160, rightOffset = 12 } = {}) {\n this.minSpacing = minSpacing\n this.maxSpacing = maxSpacing\n this.rightOffset = rightOffset\n this.width = 0\n this.barCount = 0\n this.follow = true\n this.timeframeMs = 60000\n this._spacing = new Smoothed(spacing, 65)\n this._right = new Smoothed(rightOffset, 65)\n this._initial = spacing\n }\n\n get spacing() { return this._spacing.value }\n get right() { return this._right.value }\n\n resize(w) { this.width = Math.max(1, w) }\n\n setBarCount(n) {\n const grew = n > this.barCount\n this.barCount = n\n if (this.follow) {\n // target the new last bar; Smoothed turns this into a glide\n const t = n - 1 + this.rightOffset\n if (grew) this._right.set(t)\n else this._right.jump(t)\n }\n }\n\n x(i) { return this.width - (this._right.value - i) * this._spacing.value }\n\n /** Centre-x of bar i (bars are drawn centred on their slot). */\n index(x) { return this._right.value - (this.width - x) / this._spacing.value }\n\n barWidth() {\n const s = this._spacing.value\n // leave a gap between candles, but never thinner than a hairline\n return Math.max(1, Math.floor(s * 0.72))\n }\n\n visibleRange() {\n const first = Math.floor(this.index(0)) - 1\n const last = Math.ceil(this.index(this.width)) + 1\n return {\n from: clamp(first, 0, Math.max(0, this.barCount - 1)),\n to: clamp(last, 0, Math.max(0, this.barCount - 1)),\n }\n }\n\n _clampRight(v) {\n const max = this.barCount - 1 + this.rightOffset + this.width / this._spacing.target\n const min = Math.min(4, this.barCount - 1 + this.rightOffset)\n return clamp(v, min, max)\n }\n\n /** Immediate pan, in pixels. Positive dx drags content right (back in time). */\n panBy(dxPx) {\n if (!dxPx) return false\n const next = this._clampRight(this._right.value - dxPx / this._spacing.value)\n this._right.jump(next)\n this.follow = false\n return true\n }\n\n /** Zoom by `factor`, keeping the bar under `x` pinned. */\n zoomAt(x, factor) {\n const s0 = this._spacing.target\n const s1 = clamp(s0 * factor, this.minSpacing, this.maxSpacing)\n if (Math.abs(s1 - s0) < 1e-9) return false\n\n // While following realtime, pin the right edge instead of the cursor so the\n // latest candle stays put — that is what traders expect.\n const anchorX = this.follow ? this.width : x\n const r0 = this._right.target\n const idx = r0 - (this.width - anchorX) / s0\n const r1 = idx + (this.width - anchorX) / s1\n\n this._spacing.set(s1)\n this._right.set(this._clampRight(r1))\n return true\n }\n\n snapToRealtime() {\n this.follow = true\n this._right.set(this.barCount - 1 + this.rightOffset)\n }\n\n reset() {\n this._spacing.set(this._initial)\n this.snapToRealtime()\n }\n\n /** True while the view is still easing. */\n tick(dt) {\n const a = this._spacing.tick(dt)\n const b = this._right.tick(dt)\n return a || b\n }\n\n get settled() { return this._spacing.settled && this._right.settled }\n}\n","import { Smoothed } from '../motion/Tween.js'\n\nconst clamp = (v, a, b) => (v < a ? a : v > b ? b : v)\n\n/**\n * PriceScale — maps price <-> y pixels, with animated autoscale.\n *\n * Bounds live in *transformed* space (identity for linear, log for log), so\n * switching modes is a one-line change and the easing still behaves.\n * The whole point of smoothing here: when a spike arrives the range glides to\n * its new bounds instead of the chart snapping and losing the reader.\n */\nexport class PriceScale {\n constructor({ mode = 'linear', tau = 120, marginTop = 0.12, marginBottom = 0.12 } = {}) {\n this.mode = mode\n this.marginTop = marginTop\n this.marginBottom = marginBottom\n this.auto = true\n this.top = 0\n this.height = 1\n this._lo = new Smoothed(0, tau)\n this._hi = new Smoothed(1, tau)\n this._primed = false\n }\n\n _fwd(v) { return this.mode === 'log' ? Math.log(Math.max(v, 1e-9)) : v }\n _inv(v) { return this.mode === 'log' ? Math.exp(v) : v }\n\n setMode(mode) {\n if (mode === this.mode) return\n const lo = this._inv(this._lo.value)\n const hi = this._inv(this._hi.value)\n this.mode = mode\n this._lo.jump(this._fwd(lo))\n this._hi.jump(this._fwd(hi))\n }\n\n layout(top, height) {\n this.top = top\n this.height = Math.max(1, height)\n }\n\n get lo() { return this._inv(this._lo.value) }\n get hi() { return this._inv(this._hi.value) }\n\n y(price) {\n const a = this._lo.value\n const b = this._hi.value\n const t = (this._fwd(price) - a) / (b - a || 1)\n return this.top + this.height * (1 - t)\n }\n\n price(y) {\n const a = this._lo.value\n const b = this._hi.value\n const t = 1 - (y - this.top) / this.height\n return this._inv(a + t * (b - a))\n }\n\n /** Fit visible bars. `extra` lets the forming candle influence the range. */\n fit(bars, from, to, extra) {\n if (!this.auto || !bars.length) return\n let min = Infinity\n let max = -Infinity\n for (let i = from; i <= to; i++) {\n const b = bars[i]\n if (!b) continue\n if (b.low < min) min = b.low\n if (b.high > max) max = b.high\n }\n if (extra) {\n if (extra.low < min) min = extra.low\n if (extra.high > max) max = extra.high\n }\n if (!isFinite(min) || !isFinite(max)) return\n\n let a = this._fwd(min)\n let b = this._fwd(max)\n let pad = (b - a) * this.marginTop\n if (!(pad > 0)) pad = Math.abs(b) * 0.01 || 1\n a -= pad\n b += (b - a) * 0 + pad\n\n this._lo.set(a)\n this._hi.set(b)\n if (!this._primed) {\n this._lo.jump(a)\n this._hi.jump(b)\n this._primed = true\n }\n }\n\n /** Manual axis-drag scaling around the vertical centre. */\n scaleBy(factor) {\n this.auto = false\n const a = this._lo.target\n const b = this._hi.target\n const mid = (a + b) / 2\n const half = ((b - a) / 2) * clamp(factor, 0.2, 5)\n this._lo.set(mid - half)\n this._hi.set(mid + half)\n }\n\n resetAuto() {\n this.auto = true\n }\n\n tick(dt) {\n const a = this._lo.tick(dt)\n const b = this._hi.tick(dt)\n return a || b\n }\n}\n","export const defaultTheme = {\n background: '#0b0e14',\n grid: 'rgba(255,255,255,0.045)',\n axisLine: 'rgba(255,255,255,0.10)',\n text: '#8b93a7',\n textStrong: '#e6e9ef',\n up: '#26a69a',\n down: '#ef5350',\n upFill: '#26a69a',\n downFill: '#ef5350',\n wickUp: '#26a69a',\n wickDown: '#ef5350',\n volumeUp: 'rgba(38,166,154,0.30)',\n volumeDown: 'rgba(239,83,80,0.30)',\n crosshair: 'rgba(255,255,255,0.32)',\n labelBg: '#2a3040',\n labelText: '#e6e9ef',\n tagText: '#06080d',\n font: '11px ui-sans-serif, -apple-system, \"Segoe UI\", Roboto, sans-serif',\n priceAxisWidth: 68,\n timeAxisHeight: 26,\n}\n\nexport const lightTheme = {\n ...defaultTheme,\n background: '#ffffff',\n grid: 'rgba(0,0,0,0.06)',\n axisLine: 'rgba(0,0,0,0.14)',\n text: '#6b7280',\n textStrong: '#111827',\n labelBg: '#374151',\n volumeUp: 'rgba(38,166,154,0.25)',\n volumeDown: 'rgba(239,83,80,0.25)',\n crosshair: 'rgba(0,0,0,0.35)',\n tagText: '#ffffff',\n}\n","import { Smoothed, Tween } from './Tween.js'\n\n/**\n * LiveCandle — makes the forming (rightmost) candle *flow* instead of snapping.\n *\n * A raw feed tick replaces close/high/low instantly, which reads as a jitter.\n * Here every component eases toward the incoming value, and a brand new candle\n * plays a short grow-from-centre animation as it scrolls in.\n */\nexport class LiveCandle {\n constructor(tau = 55) {\n this.enabled = true\n this.o = new Smoothed(0, tau)\n this.h = new Smoothed(0, tau)\n this.l = new Smoothed(0, tau)\n this.c = new Smoothed(0, tau)\n this.vol = new Smoothed(0, tau * 2)\n this.spawn = new Tween(240)\n this._has = false\n this._time = null\n }\n\n setTarget(bar) {\n if (!bar) {\n this._has = false\n return\n }\n if (!this._has || bar.time !== this._time) {\n // New candle: start collapsed at its open, then animate outward.\n this.o.jump(bar.open)\n this.h.jump(bar.open)\n this.l.jump(bar.open)\n this.c.jump(bar.open)\n this.vol.jump(0)\n this.spawn.restart()\n this._time = bar.time\n this._has = true\n }\n this.o.set(bar.open)\n this.h.set(bar.high)\n this.l.set(bar.low)\n this.c.set(bar.close)\n this.vol.set(bar.volume || 0)\n }\n\n reset() {\n this._has = false\n this._time = null\n }\n\n /** @returns {boolean} true while animating */\n tick(dt) {\n if (!this._has) return false\n let moving = false\n if (this.o.tick(dt)) moving = true\n if (this.h.tick(dt)) moving = true\n if (this.l.tick(dt)) moving = true\n if (this.c.tick(dt)) moving = true\n if (this.vol.tick(dt)) moving = true\n if (this.spawn.tick(dt)) moving = true\n return moving\n }\n\n /** Interpolated view of `bar`, or `bar` itself when disabled. */\n read(bar) {\n if (!this._has || !this.enabled || bar.time !== this._time) return bar\n const o = this.o.value\n const c = this.c.value\n return {\n time: bar.time,\n open: o,\n close: c,\n // keep the wick consistent while values chase each other\n high: Math.max(this.h.value, o, c),\n low: Math.min(this.l.value, o, c),\n volume: this.vol.value,\n _spawn: this.spawn.progress,\n }\n }\n}\n","/**\n * Inertia — momentum panning with friction decay.\n * sample() while dragging, release() on pointer up, then tick() each frame\n * until it returns 0.\n */\nexport class Inertia {\n constructor({ friction = 0.92, min = 0.015 } = {}) {\n this.friction = friction\n this.min = min\n this.v = 0 // px per ms\n this.active = false\n }\n\n sample(dx, dt) {\n if (dt <= 0) return\n const instant = dx / dt\n // low-pass so one jittery frame doesn't define the throw\n this.v = this.v * 0.6 + instant * 0.4\n this.active = false\n }\n\n release() {\n if (Math.abs(this.v) > this.min) this.active = true\n }\n\n stop() {\n this.v = 0\n this.active = false\n }\n\n /** @returns {number} px to pan this frame (0 when idle) */\n tick(dt) {\n if (!this.active) return 0\n const dx = this.v * dt\n this.v *= Math.pow(this.friction, dt / 16.6667)\n if (Math.abs(this.v) < this.min) this.stop()\n return dx\n }\n}\n","/** \"Nice\" step size (1/2/5 x 10^n) covering `span` in about `count` steps. */\nexport function niceStep(span, count) {\n const raw = span / Math.max(1, count)\n if (!(raw > 0) || !isFinite(raw)) return 1\n const mag = Math.pow(10, Math.floor(Math.log10(raw)))\n const n = raw / mag\n const s = n < 1.5 ? 1 : n < 3 ? 2 : n < 7 ? 5 : 10\n return s * mag\n}\n\nexport function priceTicks(lo, hi, count) {\n const step = niceStep(hi - lo, count)\n const ticks = []\n const start = Math.ceil(lo / step) * step\n for (let v = start; v <= hi + step * 1e-9; v += step) ticks.push(v)\n return { ticks, step }\n}\n\nexport function decimalsFor(step) {\n if (!isFinite(step) || step <= 0) return 2\n if (step >= 100) return 0\n if (step >= 1) return 2\n return Math.min(8, Math.ceil(-Math.log10(step)) + 1)\n}\n\n/** Bar-index step that keeps time labels at least `minPx` apart. */\nexport function niceBarStep(minBars) {\n const opts = [1, 2, 5, 10, 15, 20, 30, 60, 120, 240, 480, 960, 1920, 3840, 7680]\n for (const o of opts) if (o >= minBars) return o\n return Math.ceil(minBars / 1000) * 1000\n}\n\nconst p2 = (n) => String(n).padStart(2, '0')\n\nexport function fmtAxisTime(ms, tfMs) {\n const d = new Date(ms)\n if (tfMs >= 864e5) return `${d.getDate()} ${d.toLocaleString('en', { month: 'short' })}`\n if (d.getHours() === 0 && d.getMinutes() === 0) {\n return `${d.getDate()} ${d.toLocaleString('en', { month: 'short' })}`\n }\n return `${p2(d.getHours())}:${p2(d.getMinutes())}`\n}\n\nexport function fmtDateTime(ms) {\n const d = new Date(ms)\n return `${d.getFullYear()}-${p2(d.getMonth() + 1)}-${p2(d.getDate())} ${p2(d.getHours())}:${p2(d.getMinutes())}`\n}\n\nexport function fmtVolume(v) {\n if (!isFinite(v)) return '—'\n if (v >= 1e9) return (v / 1e9).toFixed(2) + 'B'\n if (v >= 1e6) return (v / 1e6).toFixed(2) + 'M'\n if (v >= 1e3) return (v / 1e3).toFixed(1) + 'K'\n return String(Math.round(v))\n}\n","import { priceTicks, decimalsFor, niceBarStep, fmtAxisTime } from '../core/formatters.js'\n\n/** Background, grid, and both axes. Repaints only when the view changes. */\nexport function drawGrid(ctx, s) {\n const { theme, ts, ps, plot, bars, width, height } = s\n\n ctx.clearRect(0, 0, width, height)\n ctx.fillStyle = theme.background\n ctx.fillRect(0, 0, width, height)\n\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n\n // ---- price grid + labels -------------------------------------------------\n const rows = Math.max(2, Math.floor(plot.h / 58))\n const { ticks, step } = priceTicks(ps.lo, ps.hi, rows)\n const dec = decimalsFor(step)\n\n ctx.strokeStyle = theme.grid\n ctx.lineWidth = 1\n ctx.beginPath()\n for (const v of ticks) {\n const y = Math.round(ps.y(v)) + 0.5\n if (y < plot.y || y > plot.y + plot.h) continue\n ctx.moveTo(0, y)\n ctx.lineTo(plot.w, y)\n }\n ctx.stroke()\n\n ctx.fillStyle = theme.text\n ctx.textAlign = 'left'\n for (const v of ticks) {\n const y = Math.round(ps.y(v))\n if (y < plot.y + 6 || y > plot.y + plot.h - 6) continue\n ctx.fillText(v.toFixed(dec), plot.w + 8, y)\n }\n\n // ---- time grid + labels --------------------------------------------------\n if (bars.length) {\n const minBars = Math.ceil(74 / Math.max(0.0001, ts.spacing))\n const stepBars = niceBarStep(minBars)\n const { from, to } = ts.visibleRange()\n const first = Math.ceil(from / stepBars) * stepBars\n\n ctx.strokeStyle = theme.grid\n ctx.beginPath()\n for (let i = first; i <= to; i += stepBars) {\n const x = Math.round(ts.x(i)) + 0.5\n if (x < 0 || x > plot.w) continue\n ctx.moveTo(x, 0)\n ctx.lineTo(x, plot.h)\n }\n ctx.stroke()\n\n ctx.fillStyle = theme.text\n ctx.textAlign = 'center'\n const ty = plot.h + theme.timeAxisHeight / 2\n for (let i = first; i <= to; i += stepBars) {\n const bar = bars[i]\n if (!bar) continue\n const x = Math.round(ts.x(i))\n if (x < 28 || x > plot.w - 28) continue\n ctx.fillText(fmtAxisTime(bar.time, ts.timeframeMs), x, ty)\n }\n }\n\n // ---- axis separators -----------------------------------------------------\n ctx.strokeStyle = theme.axisLine\n ctx.beginPath()\n ctx.moveTo(plot.w + 0.5, 0)\n ctx.lineTo(plot.w + 0.5, plot.h)\n ctx.moveTo(0, plot.h + 0.5)\n ctx.lineTo(width, plot.h + 0.5)\n ctx.stroke()\n}\n","import { decimalsFor, priceTicks } from '../core/formatters.js'\n\n/**\n * Candles + volume. Everything here is culled to the visible index range —\n * 500k bars loaded still costs only the ~200 on screen.\n */\nexport function drawCandles(ctx, s) {\n const { theme, ts, ps, plot, bars, width, height, live, volumeRatio } = s\n\n ctx.clearRect(0, 0, width, height)\n if (!bars.length) return\n\n const { from, to } = ts.visibleRange()\n const bw = ts.barWidth()\n const half = bw / 2\n const thin = bw <= 2\n\n // ---- volume strip --------------------------------------------------------\n const volH = plot.h * volumeRatio\n const volTop = plot.y + plot.h - volH\n let vmax = 0\n for (let i = from; i <= to; i++) {\n const b = bars[i]\n if (b && b.volume > vmax) vmax = b.volume\n }\n if (vmax > 0) {\n for (let i = from; i <= to; i++) {\n let b = bars[i]\n if (!b) continue\n if (live && i === bars.length - 1) b = live\n const x = ts.x(i)\n if (x < -bw || x > plot.w + bw) continue\n const h = (b.volume / vmax) * volH * 0.9\n ctx.fillStyle = b.close >= b.open ? theme.volumeUp : theme.volumeDown\n ctx.fillRect(Math.round(x - half), volTop + (volH - h), Math.max(1, bw), h)\n }\n }\n\n // ---- candles -------------------------------------------------------------\n for (let i = from; i <= to; i++) {\n let b = bars[i]\n if (!b) continue\n const isLast = i === bars.length - 1\n if (live && isLast) b = live\n\n const x = ts.x(i)\n if (x < -bw || x > plot.w + bw) continue\n\n const up = b.close >= b.open\n const color = up ? theme.up : theme.down\n const yO = ps.y(b.open)\n const yC = ps.y(b.close)\n const yH = ps.y(b.high)\n const yL = ps.y(b.low)\n\n // grow-from-centre on a freshly opened candle\n let scale = 1\n if (live && isLast && typeof b._spawn === 'number') scale = 0.35 + 0.65 * b._spawn\n\n const cx = Math.round(x) + (bw % 2 ? 0.5 : 0)\n\n // wick\n ctx.strokeStyle = up ? theme.wickUp : theme.wickDown\n ctx.lineWidth = Math.max(1, Math.min(2, bw * 0.16))\n ctx.beginPath()\n ctx.moveTo(cx, yH)\n ctx.lineTo(cx, yL)\n ctx.stroke()\n\n if (thin) continue\n\n // body\n const top = Math.min(yO, yC)\n const bodyH = Math.max(1, Math.abs(yC - yO))\n const w = Math.max(1, bw * scale)\n ctx.fillStyle = color\n ctx.fillRect(Math.round(x - w / 2), Math.round(top), Math.round(w), Math.round(bodyH))\n }\n\n // ---- last price line -----------------------------------------------------\n const lastBar = live || bars[bars.length - 1]\n if (lastBar) {\n const y = Math.round(ps.y(lastBar.close)) + 0.5\n if (y > plot.y && y < plot.y + plot.h) {\n const up = lastBar.close >= lastBar.open\n ctx.save()\n ctx.setLineDash([3, 3])\n ctx.strokeStyle = up ? theme.up : theme.down\n ctx.lineWidth = 1\n ctx.globalAlpha = 0.7\n ctx.beginPath()\n ctx.moveTo(0, y)\n ctx.lineTo(plot.w, y)\n ctx.stroke()\n ctx.restore()\n\n const { step } = priceTicks(ps.lo, ps.hi, Math.max(2, Math.floor(plot.h / 58)))\n const label = lastBar.close.toFixed(decimalsFor(step))\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n ctx.textAlign = 'left'\n const tw = ctx.measureText(label).width\n ctx.fillStyle = up ? theme.up : theme.down\n ctx.fillRect(plot.w + 1, y - 9, tw + 14, 18)\n ctx.fillStyle = theme.tagText\n ctx.fillText(label, plot.w + 8, y)\n }\n }\n}\n","import { decimalsFor, priceTicks, fmtDateTime } from '../core/formatters.js'\n\n/**\n * Crosshair lives alone on the top canvas: moving the pointer repaints only\n * these few pixels, never the candles underneath.\n */\nexport function drawCrosshair(ctx, s) {\n const { theme, ts, ps, plot, bars, width, height, cursor, magnet } = s\n\n ctx.clearRect(0, 0, width, height)\n if (!cursor || !bars.length) return\n if (cursor.x < 0 || cursor.x > plot.w || cursor.y < 0 || cursor.y > plot.h) return\n\n const i = Math.round(ts.index(cursor.x))\n const bar = bars[i]\n\n let x = cursor.x\n let y = cursor.y\n if (bar) {\n x = ts.x(i) // snap to the bar slot\n if (magnet) {\n // magnet to the nearest OHLC value\n const cands = [bar.open, bar.high, bar.low, bar.close]\n let best = null\n let bestD = Infinity\n for (const p of cands) {\n const py = ps.y(p)\n const d = Math.abs(py - cursor.y)\n if (d < bestD) { bestD = d; best = py }\n }\n if (bestD < 22) y = best\n }\n }\n\n ctx.save()\n ctx.setLineDash([4, 4])\n ctx.strokeStyle = theme.crosshair\n ctx.lineWidth = 1\n ctx.beginPath()\n ctx.moveTo(Math.round(x) + 0.5, 0)\n ctx.lineTo(Math.round(x) + 0.5, plot.h)\n ctx.moveTo(0, Math.round(y) + 0.5)\n ctx.lineTo(plot.w, Math.round(y) + 0.5)\n ctx.stroke()\n ctx.restore()\n\n ctx.font = theme.font\n ctx.textBaseline = 'middle'\n\n // price tag\n const { step } = priceTicks(ps.lo, ps.hi, Math.max(2, Math.floor(plot.h / 58)))\n const priceLabel = ps.price(y).toFixed(decimalsFor(step))\n ctx.textAlign = 'left'\n const pw = ctx.measureText(priceLabel).width\n ctx.fillStyle = theme.labelBg\n ctx.fillRect(plot.w + 1, y - 9, pw + 14, 18)\n ctx.fillStyle = theme.labelText\n ctx.fillText(priceLabel, plot.w + 8, y)\n\n // time tag\n if (bar) {\n const t = fmtDateTime(bar.time)\n ctx.textAlign = 'center'\n const tw = ctx.measureText(t).width\n const bx = Math.min(Math.max(x, tw / 2 + 6), plot.w - tw / 2 - 6)\n ctx.fillStyle = theme.labelBg\n ctx.fillRect(bx - tw / 2 - 7, plot.h + 3, tw + 14, 18)\n ctx.fillStyle = theme.labelText\n ctx.fillText(t, bx, plot.h + 12)\n }\n}\n\n","import { Layers } from './Layers.js'\nimport { Loop } from './Loop.js'\nimport { TimeScale } from './TimeScale.js'\nimport { PriceScale } from './PriceScale.js'\nimport { defaultTheme } from './palette.js'\nimport { LiveCandle } from '../motion/LiveCandle.js'\nimport { Inertia } from '../motion/Inertia.js'\nimport { drawGrid } from '../render/grid.js'\nimport { drawCandles } from '../render/candles.js'\nimport { drawCrosshair } from '../render/crosshair.js'\n\n/**\n * Chart — the orchestrator. Owns the bar store, the scales, the input\n * handling and the frame composition. Framework-free by design: this file\n * touches nothing but DOM and Canvas, which is what lets the same core ship\n * as a React component, a Web Component, or a plain script tag.\n */\nexport class Chart {\n constructor(container, options = {}) {\n if (!container) throw new Error('Chart: container element is required')\n\n this.container = container\n this.theme = { ...defaultTheme, ...(options.theme || {}) }\n this.options = {\n volumeRatio: 0.18,\n magnet: true,\n animate: true,\n ...options,\n }\n\n this.bars = []\n this.feed = null\n this._unsub = null\n this._loadingHistory = false\n this._exhausted = false\n this._listeners = { crosshair: new Set(), visibleRange: new Set() }\n\n this.layers = new Layers(container, ['base', 'main', 'overlay'])\n this.ts = new TimeScale(options.timeScale)\n this.ps = new PriceScale(options.priceScale)\n this.live = new LiveCandle()\n this.live.enabled = this.options.animate !== false\n this.inertia = new Inertia()\n\n this.cursor = null\n this.plot = { x: 0, y: 0, w: 1, h: 1 }\n\n this.loop = new Loop((dirty, dt) => this._frame(dirty, dt))\n this.layers.onResize = () => {\n this._layout()\n this.loop.invalidate('all')\n }\n\n this._layout()\n this._bindEvents()\n this.loop.start()\n }\n\n // ---------------------------------------------------------------- layout --\n _layout() {\n const { width, height } = this.layers\n const w = Math.max(1, width - this.theme.priceAxisWidth)\n const h = Math.max(1, height - this.theme.timeAxisHeight)\n this.plot = { x: 0, y: 0, w, h }\n this.ts.resize(w)\n this.ps.layout(0, h)\n }\n\n // ------------------------------------------------------------------ data --\n setData(bars) {\n this.bars = Array.isArray(bars) ? bars.slice() : []\n this._exhausted = false\n if (this.bars.length > 1) {\n this.ts.timeframeMs = this.bars[1].time - this.bars[0].time\n }\n this.ts.setBarCount(this.bars.length)\n this.ts.snapToRealtime()\n this.live.reset()\n this.ps._primed = false\n this.loop.invalidate('all')\n }\n\n /** Merge a tick into the forming candle (animated). */\n update(bar) {\n if (!bar) return\n const n = this.bars.length\n if (n && this.bars[n - 1].time === bar.time) {\n this.bars[n - 1] = bar\n } else {\n this.append(bar)\n return\n }\n this.live.setTarget(bar)\n this.loop.invalidate('main')\n }\n\n /** Open a new candle; the previous one is now closed. */\n append(bar) {\n if (!bar) return\n const n = this.bars.length\n if (n && bar.time <= this.bars[n - 1].time) {\n this.bars[n - 1] = bar\n } else {\n this.bars.push(bar)\n this.ts.setBarCount(this.bars.length)\n }\n this.live.setTarget(bar)\n this.loop.invalidate('main')\n }\n\n async setFeed(feed) {\n this.detachFeed()\n this.feed = feed\n if (!feed) return\n this.ts.timeframeMs = feed.timeframe || this.ts.timeframeMs\n const bars = await feed.getBars({\n symbol: feed.symbol,\n timeframe: feed.timeframe,\n to: null,\n limit: this.options.initialBars || 1500,\n })\n this.setData(bars)\n if (typeof feed.prime === 'function') feed.prime(bars[bars.length - 1])\n this._unsub = feed.subscribe((msg) => {\n if (!msg || !msg.bar) return\n if (msg.type === 'append') this.append(msg.bar)\n else this.update(msg.bar)\n })\n }\n\n detachFeed() {\n if (this._unsub) this._unsub()\n this._unsub = null\n this.feed = null\n }\n\n async _maybeLoadHistory() {\n if (this._loadingHistory || this._exhausted || !this.feed) return\n const { from } = this.ts.visibleRange()\n if (from > 80 || !this.bars.length) return\n\n this._loadingHistory = true\n try {\n const oldest = this.bars[0].time\n const older = await this.feed.getBars({\n symbol: this.feed.symbol,\n timeframe: this.feed.timeframe,\n to: oldest,\n limit: 1000,\n })\n if (!older || !older.length) {\n this._exhausted = true\n } else {\n const added = older.filter((b) => b.time < oldest)\n if (!added.length) {\n this._exhausted = true\n } else {\n this.bars = added.concat(this.bars)\n // keep the view pinned to the same bars: indices all shifted right\n const wasFollowing = this.ts.follow\n this.ts.barCount = this.bars.length\n this.ts._right.jump(this.ts._right.value + added.length)\n this.ts._right.set(this.ts._right.target + added.length)\n this.ts.follow = wasFollowing\n this.loop.invalidate('all')\n }\n }\n } catch (e) {\n console.error('[Emberwick] history load failed', e)\n this._exhausted = true\n } finally {\n this._loadingHistory = false\n }\n }\n\n // ---------------------------------------------------------------- events --\n _bindEvents() {\n const el = this.container\n el.style.touchAction = 'none'\n el.style.cursor = 'crosshair'\n\n let dragging = false\n let mode = null\n let lastX = 0\n let lastY = 0\n let lastT = 0\n let moved = false\n const pointers = new Map()\n let pinchDist = 0\n\n const localPos = (e) => {\n const r = el.getBoundingClientRect()\n return { x: e.clientX - r.left, y: e.clientY - r.top }\n }\n\n this._onDown = (e) => {\n pointers.set(e.pointerId, localPos(e))\n if (pointers.size === 2) {\n const [a, b] = [...pointers.values()]\n pinchDist = Math.hypot(a.x - b.x, a.y - b.y)\n dragging = false\n return\n }\n const p = localPos(e)\n dragging = true\n moved = false\n mode = p.x > this.plot.w ? 'price' : p.y > this.plot.h ? 'time' : 'pan'\n lastX = p.x\n lastY = p.y\n lastT = performance.now()\n this.inertia.stop()\n el.setPointerCapture(e.pointerId)\n }\n\n this._onMove = (e) => {\n const p = localPos(e)\n if (pointers.has(e.pointerId)) pointers.set(e.pointerId, p)\n\n if (pointers.size === 2) {\n const [a, b] = [...pointers.values()]\n const d = Math.hypot(a.x - b.x, a.y - b.y)\n if (pinchDist > 0 && d > 0) {\n const mid = (a.x + b.x) / 2\n this.ts.zoomAt(mid, d / pinchDist)\n this.loop.invalidate('all')\n }\n pinchDist = d\n return\n }\n\n this.cursor = p\n this._emitCrosshair(p)\n this.loop.invalidate('overlay')\n\n if (!dragging) return\n const now = performance.now()\n const dt = now - lastT\n const dx = p.x - lastX\n const dy = p.y - lastY\n if (Math.abs(dx) > 1 || Math.abs(dy) > 1) moved = true\n\n if (mode === 'pan') {\n this.ts.panBy(dx)\n this.inertia.sample(dx, dt)\n this.loop.invalidate('all')\n this._maybeLoadHistory()\n } else if (mode === 'price') {\n this.ps.scaleBy(1 + dy / 220)\n this.loop.invalidate('all')\n } else if (mode === 'time') {\n this.ts.zoomAt(this.plot.w, 1 - dx / 260)\n this.loop.invalidate('all')\n }\n\n lastX = p.x\n lastY = p.y\n lastT = now\n }\n\n this._onUp = (e) => {\n pointers.delete(e.pointerId)\n if (pointers.size < 2) pinchDist = 0\n if (dragging && mode === 'pan' && moved) {\n this.inertia.release()\n this.loop.invalidate('all')\n }\n dragging = false\n mode = null\n try { el.releasePointerCapture(e.pointerId) } catch (_) {}\n }\n\n this._onLeave = () => {\n this.cursor = null\n this._emitCrosshair(null)\n this.loop.invalidate('overlay')\n }\n\n this._onWheel = (e) => {\n e.preventDefault()\n const r = el.getBoundingClientRect()\n const x = e.clientX - r.left\n const factor = Math.pow(0.999, e.deltaY)\n this.ts.zoomAt(x, factor)\n this.loop.invalidate('all')\n this._maybeLoadHistory()\n }\n\n this._onDbl = () => {\n this.ts.reset()\n this.ps.resetAuto()\n this.loop.invalidate('all')\n }\n\n this._onKey = (e) => {\n const step = e.shiftKey ? 120 : 40\n if (e.key === 'ArrowLeft') { this.ts.panBy(step); this.loop.invalidate('all'); this._maybeLoadHistory() }\n else if (e.key === 'ArrowRight') { this.ts.panBy(-step); this.loop.invalidate('all') }\n else if (e.key === '+' || e.key === '=') { this.ts.zoomAt(this.plot.w / 2, 1.2); this.loop.invalidate('all') }\n else if (e.key === '-' || e.key === '_') { this.ts.zoomAt(this.plot.w / 2, 0.8); this.loop.invalidate('all') }\n else return\n e.preventDefault()\n }\n\n el.addEventListener('pointerdown', this._onDown)\n el.addEventListener('pointermove', this._onMove)\n el.addEventListener('pointerup', this._onUp)\n el.addEventListener('pointercancel', this._onUp)\n el.addEventListener('pointerleave', this._onLeave)\n el.addEventListener('wheel', this._onWheel, { passive: false })\n el.addEventListener('dblclick', this._onDbl)\n el.addEventListener('keydown', this._onKey)\n if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '0')\n }\n\n _emitCrosshair(p) {\n if (!this._listeners.crosshair.size) return\n let payload = null\n if (p && this.bars.length && p.x <= this.plot.w && p.y <= this.plot.h) {\n const i = Math.round(this.ts.index(p.x))\n const bar = this.bars[i]\n if (bar) payload = { index: i, bar, price: this.ps.price(p.y) }\n }\n for (const fn of this._listeners.crosshair) fn(payload)\n }\n\n subscribe(event, fn) {\n const set = this._listeners[event]\n if (!set) throw new Error(`Chart: unknown event \"${event}\"`)\n set.add(fn)\n return () => set.delete(fn)\n }\n\n // ----------------------------------------------------------------- frame --\n _frame(dirty, dt) {\n let animating = false\n\n if (this.ts.tick(dt)) animating = true\n\n const dx = this.inertia.tick(dt)\n if (dx) {\n this.ts.panBy(dx)\n animating = true\n this._maybeLoadHistory()\n }\n\n if (this.live.tick(dt)) animating = true\n\n const { from, to } = this.ts.visibleRange()\n const lastIdx = this.bars.length - 1\n const liveBar = this.bars.length ? this.live.read(this.bars[lastIdx]) : null\n const liveVisible = liveBar && to >= lastIdx ? liveBar : null\n\n this.ps.fit(this.bars, from, to, liveVisible)\n if (this.ps.tick(dt)) animating = true\n\n const redrawAll = animating || dirty.has('all') || dirty.has('base') || dirty.has('main')\n const state = {\n theme: this.theme,\n ts: this.ts,\n ps: this.ps,\n plot: this.plot,\n bars: this.bars,\n width: this.layers.width,\n height: this.layers.height,\n live: liveVisible,\n volumeRatio: this.options.volumeRatio,\n cursor: this.cursor,\n magnet: this.options.magnet,\n }\n\n if (redrawAll) {\n drawGrid(this.layers.ctx.base, state)\n drawCandles(this.layers.ctx.main, state)\n }\n if (redrawAll || dirty.has('overlay')) {\n drawCrosshair(this.layers.ctx.overlay, state)\n }\n\n return animating\n }\n\n // ------------------------------------------------------------------- api --\n get fps() { return this.loop.fps }\n\n setTheme(theme) {\n this.theme = { ...this.theme, ...theme }\n this._layout()\n this.loop.invalidate('all')\n }\n\n setPriceMode(mode) {\n this.ps.setMode(mode)\n this.loop.invalidate('all')\n }\n\n setAnimate(on) {\n this.live.enabled = !!on\n this.loop.invalidate('all')\n }\n\n setMagnet(on) {\n this.options.magnet = !!on\n this.loop.invalidate('overlay')\n }\n\n snapToRealtime() {\n this.ts.snapToRealtime()\n this.ps.resetAuto()\n this.loop.invalidate('all')\n }\n\n toImage() {\n return this.layers.composite().toDataURL('image/png')\n }\n\n destroy() {\n const el = this.container\n el.removeEventListener('pointerdown', this._onDown)\n el.removeEventListener('pointermove', this._onMove)\n el.removeEventListener('pointerup', this._onUp)\n el.removeEventListener('pointercancel', this._onUp)\n el.removeEventListener('pointerleave', this._onLeave)\n el.removeEventListener('wheel', this._onWheel)\n el.removeEventListener('dblclick', this._onDbl)\n el.removeEventListener('keydown', this._onKey)\n this.detachFeed()\n this.loop.stop()\n this.layers.destroy()\n this._listeners.crosshair.clear()\n this._listeners.visibleRange.clear()\n this.bars = []\n }\n}\n\n","/**\n * DataFeed — THE seam of this library.\n *\n * The chart core never knows where bars come from. Anything that implements\n * this interface can drive it: a REST endpoint, a WebSocket, a Lambda behind\n * API Gateway, a CSV in memory, or the bundled RandomFeed.\n *\n * Bar shape (the only contract that matters):\n * { time: number (ms epoch), open, high, low, close, volume }\n * Bars MUST be ascending by time and de-duplicated by the feed.\n *\n * Implement:\n * getBars({ symbol, timeframe, to, limit }) -> Promise<Bar[]>\n * Historical bars ENDING at `to` (exclusive). Return [] when exhausted;\n * the chart stops asking for more history once it sees an empty page.\n * subscribe(handler) -> unsubscribe fn\n * handler({ type: 'update'|'append', bar }) where\n * 'update' = the forming candle changed (animates)\n * 'append' = a new candle opened (previous one is now closed)\n */\nexport class DataFeed {\n constructor({ symbol = 'DEMO', timeframe = 60000 } = {}) {\n this.symbol = symbol\n this.timeframe = timeframe\n }\n\n // eslint-disable-next-line no-unused-vars\n async getBars({ symbol, timeframe, to, limit }) {\n throw new Error('DataFeed.getBars() not implemented')\n }\n\n // eslint-disable-next-line no-unused-vars\n subscribe(handler) {\n return () => {}\n }\n\n destroy() {}\n}\n\n/** Deterministic PRNG so a given seed always renders the same chart. */\nexport function mulberry32(seed) {\n let a = seed >>> 0\n return function () {\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n","import { DataFeed, mulberry32 } from './DataFeed.js'\n\n/**\n * RandomFeed — a plausible synthetic market. One implementation of DataFeed,\n * nothing more: swapping in a real provider is writing another class, with\n * zero changes to the chart core.\n *\n * Generates a GBM-ish random walk with volatility clustering and a volume\n * profile, then drives a live forming candle from sub-bar ticks.\n */\nexport class RandomFeed extends DataFeed {\n constructor({\n symbol = 'EMBR',\n timeframe = 60000,\n seed = 7,\n start = 100,\n volatility = 0.0022,\n drift = 0.00002,\n ticksPerSecond = 8,\n speed = 1,\n } = {}) {\n super({ symbol, timeframe })\n this.seed = seed\n this.start = start\n this.volatility = volatility\n this.drift = drift\n this.ticksPerSecond = ticksPerSecond\n this.speed = speed\n\n this._rnd = mulberry32(seed)\n this._handlers = new Set()\n this._timer = null\n this._forming = null\n this._last = start\n this._vol = volatility\n this._anchorTime = Math.floor(Date.now() / timeframe) * timeframe\n }\n\n _gauss() {\n // Box-Muller\n let u = 0\n let v = 0\n while (u === 0) u = this._rnd()\n while (v === 0) v = this._rnd()\n return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v)\n }\n\n _step(price) {\n // volatility clusters: vol mean-reverts but gets kicked by shocks\n const shock = this._gauss()\n this._vol += (this.volatility - this._vol) * 0.02 + Math.abs(shock) * this.volatility * 0.015\n this._vol = Math.min(this._vol, this.volatility * 6)\n return Math.max(0.01, price * (1 + this.drift + shock * this._vol))\n }\n\n _makeBar(time, open) {\n let c = open\n const n = 14\n let hi = open\n let lo = open\n for (let i = 0; i < n; i++) {\n c = this._step(c)\n if (c > hi) hi = c\n if (c < lo) lo = c\n }\n const range = Math.max(1e-9, hi - lo)\n const volume = Math.round(\n (300 + this._rnd() * 900) * (1 + (range / open) * 260)\n )\n return { time, open, high: hi, low: lo, close: c, volume }\n }\n\n /**\n * Historical bars ending just before `to`. Walks BACKWARDS from a synthetic\n * anchor, so paging further left keeps producing coherent history.\n */\n async getBars({ to, limit = 1500, timeframe = this.timeframe } = {}) {\n const end = to == null ? this._anchorTime : to\n const bars = []\n // generate forward from an earlier point for realistic shape, then slice\n const startTime = end - limit * timeframe\n const gen = mulberry32(this.seed ^ Math.floor(startTime / timeframe))\n const saved = this._rnd\n this._rnd = gen\n\n let price = this.start * (1 + (gen() - 0.5) * 0.04)\n for (let i = 0; i < limit; i++) {\n const t = startTime + i * timeframe\n const bar = this._makeBar(t, price)\n price = bar.close\n bars.push(bar)\n }\n this._rnd = saved\n\n if (to == null) {\n this._last = bars.length ? bars[bars.length - 1].close : this.start\n }\n return bars\n }\n\n subscribe(handler) {\n this._handlers.add(handler)\n if (!this._timer) this._start()\n return () => {\n this._handlers.delete(handler)\n if (!this._handlers.size) this.stop()\n }\n }\n\n _emit(msg) {\n for (const h of this._handlers) h(msg)\n }\n\n _start() {\n const interval = Math.max(16, 1000 / this.ticksPerSecond)\n this._timer = setInterval(() => this._tick(), interval)\n }\n\n /** Seed the live candle from wherever history ended. */\n prime(lastBar) {\n if (lastBar) {\n this._last = lastBar.close\n this._forming = { ...lastBar }\n }\n }\n\n _tick() {\n const tf = this.timeframe / this.speed\n const now = Date.now()\n const slot = Math.floor(now / tf) * tf\n\n if (!this._forming || this._forming.time !== slot) {\n const open = this._last\n this._forming = { time: slot, open, high: open, low: open, close: open, volume: 0 }\n this._emit({ type: 'append', bar: { ...this._forming } })\n return\n }\n\n const next = this._step(this._last)\n this._last = next\n const f = this._forming\n f.close = next\n if (next > f.high) f.high = next\n if (next < f.low) f.low = next\n f.volume += Math.round(20 + this._rnd() * 120)\n this._emit({ type: 'update', bar: { ...f } })\n }\n\n setSpeed(s) { this.speed = s }\n\n setTicksPerSecond(n) {\n this.ticksPerSecond = n\n if (this._timer) { this.stop(); this._start() }\n }\n\n setPaused(paused) {\n if (paused) this.stop()\n else if (!this._timer && this._handlers.size) this._start()\n }\n\n get paused() { return !this._timer }\n\n stop() {\n if (this._timer) clearInterval(this._timer)\n this._timer = null\n }\n\n destroy() {\n this.stop()\n this._handlers.clear()\n }\n}\n","/**\n * Emberwick — public API surface.\n *\n * This file is the future package entry point. Nothing below imports a\n * framework, so the same build drops into React, Vue, Svelte or a script tag.\n *\n * import { createChart, RandomFeed } from './chart/index.js'\n * const chart = createChart(el, { theme: { background: '#000' } })\n * await chart.setFeed(new RandomFeed({ timeframe: 60000 }))\n */\nexport { Chart } from './core/Chart.js'\nexport { TimeScale } from './core/TimeScale.js'\nexport { PriceScale } from './core/PriceScale.js'\nexport { defaultTheme, lightTheme } from './core/palette.js'\nexport { DataFeed, mulberry32 } from './data/DataFeed.js'\nexport { RandomFeed } from './data/RandomFeed.js'\nexport { Smoothed, Tween, easeOutCubic, easeInOutCubic } from './motion/Tween.js'\nexport { Inertia } from './motion/Inertia.js'\nexport { LiveCandle } from './motion/LiveCandle.js'\n\nimport { Chart } from './core/Chart.js'\n\n/** Preferred entry point. */\nexport function createChart(container, options) {\n return new Chart(container, options)\n}\n\nexport const version = '0.1.0'\n\n"],"names":["clamp","b"],"mappings":"AAQO,MAAM,OAAO;AAAA,EAClB,YAAY,WAAW,OAAO;AAC5B,SAAK,YAAY;AACjB,SAAK,QAAQ;AACb,SAAK,SAAS,CAAA;AACd,SAAK,MAAM,CAAA;AACX,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,WAAW;AAEhB,QAAI,iBAAiB,SAAS,EAAE,aAAa,UAAU;AACrD,gBAAU,MAAM,WAAW;AAAA,IAC7B;AAEA,UAAM,QAAQ,CAAC,MAAM,MAAM;AACzB,YAAM,IAAI,SAAS,cAAc,QAAQ;AACzC,aAAO,OAAO,EAAE,OAAO;AAAA,QACrB,UAAU;AAAA,QACV,MAAM;AAAA,QACN,KAAK;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,eAAe;AAAA,QACf,QAAQ,OAAO,IAAI,CAAC;AAAA,MAC5B,CAAO;AACD,gBAAU,YAAY,CAAC;AACvB,WAAK,OAAO,IAAI,IAAI;AACpB,WAAK,IAAI,IAAI,IAAI,EAAE,WAAW,IAAI;AAAA,IACpC,CAAC;AAED,SAAK,MAAM,IAAI,eAAe,MAAM,KAAK,QAAO,CAAE;AAClD,SAAK,IAAI,QAAQ,SAAS;AAC1B,SAAK,QAAO;AAAA,EACd;AAAA,EAEA,UAAU;AACR,UAAM,IAAI,KAAK,UAAU,sBAAqB;AAC9C,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,KAAK,CAAC;AACzC,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,MAAM,CAAC;AAC1C,UAAM,MAAM,KAAK,IAAI,OAAO,oBAAoB,GAAG,CAAC;AACpD,QAAI,MAAM,KAAK,SAAS,MAAM,KAAK,UAAU,QAAQ,KAAK,IAAK;AAC/D,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,MAAM;AACX,eAAW,KAAK,KAAK,OAAO;AAC1B,YAAM,IAAI,KAAK,OAAO,CAAC;AACvB,QAAE,QAAQ,KAAK,MAAM,IAAI,GAAG;AAC5B,QAAE,SAAS,KAAK,MAAM,IAAI,GAAG;AAC7B,WAAK,IAAI,CAAC,EAAE,aAAa,KAAK,GAAG,GAAG,KAAK,GAAG,CAAC;AAAA,IAC/C;AACA,QAAI,KAAK,SAAU,MAAK,SAAS,GAAG,CAAC;AAAA,EACvC;AAAA;AAAA,EAGA,YAAY;AACV,UAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,QAAI,QAAQ,KAAK,MAAM,KAAK,QAAQ,KAAK,GAAG;AAC5C,QAAI,SAAS,KAAK,MAAM,KAAK,SAAS,KAAK,GAAG;AAC9C,UAAM,IAAI,IAAI,WAAW,IAAI;AAC7B,eAAW,KAAK,KAAK,MAAO,GAAE,UAAU,KAAK,OAAO,CAAC,GAAG,GAAG,CAAC;AAC5D,WAAO;AAAA,EACT;AAAA,EAEA,UAAU;AACR,SAAK,IAAI,WAAU;AACnB,eAAW,KAAK,KAAK,MAAO,MAAK,OAAO,CAAC,EAAE,OAAM;AACjD,SAAK,SAAS,CAAA;AACd,SAAK,MAAM,CAAA;AAAA,EACb;AACF;ACtEO,MAAM,KAAK;AAAA,EAChB,YAAY,SAAS;AACnB,SAAK,UAAU;AACf,SAAK,MAAM;AACX,SAAK,OAAO;AACZ,SAAK,SAAS,oBAAI,IAAG;AACrB,SAAK,QAAQ;AACb,SAAK,WAAW;AAChB,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,QAAQ,KAAK,MAAM,KAAK,IAAI;AAAA,EACnC;AAAA,EAEA,cAAc,QAAQ;AACpB,QAAI,CAAC,OAAO,OAAQ,MAAK,OAAO,IAAI,KAAK;AAAA,QACpC,YAAW,KAAK,OAAQ,MAAK,OAAO,IAAI,CAAC;AAC9C,SAAK,UAAS;AAAA,EAChB;AAAA,EAEA,QAAQ;AACN,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW;AAChB,SAAK,QAAQ,YAAY,IAAG;AAC5B,SAAK,SAAS,KAAK;AACnB,SAAK,WAAW,KAAK;AAAA,EACvB;AAAA,EAEA,OAAO;AACL,SAAK,WAAW;AAChB,QAAI,KAAK,KAAM,sBAAqB,KAAK,IAAI;AAC7C,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,YAAY;AACV,QAAI,KAAK,QAAQ,CAAC,KAAK,SAAU;AACjC,SAAK,OAAO,sBAAsB,KAAK,KAAK;AAAA,EAC9C;AAAA,EAEA,MAAM,KAAK;AACT,SAAK,OAAO;AACZ,QAAI,CAAC,KAAK,SAAU;AACpB,UAAM,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,KAAK,OAAO,CAAC,GAAG,EAAE;AACrD,SAAK,QAAQ;AAEb,SAAK;AACL,QAAI,MAAM,KAAK,UAAU,KAAK;AAC5B,WAAK,MAAM,KAAK,MAAO,KAAK,UAAU,OAAS,MAAM,KAAK,OAAO;AACjE,WAAK,UAAU;AACf,WAAK,SAAS;AAAA,IAChB;AAEA,UAAM,QAAQ,KAAK;AACnB,SAAK,SAAS,oBAAI,IAAG;AAErB,QAAI,WAAW;AACf,QAAI;AACF,iBAAW,KAAK,QAAQ,OAAO,IAAI,GAAG,MAAM;AAAA,IAC9C,SAAS,GAAG;AACV,cAAQ,MAAM,2BAA2B,CAAC;AAAA,IAC5C;AACA,QAAI,YAAY,KAAK,OAAO,KAAM,MAAK,UAAS;AAAA,EAClD;AACF;ACnEY,MAAC,eAAe,CAAC,MAAM,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;AAC5C,MAAC,iBAAiB,CAAC,MAC7B,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,IAAI;AAOnD,MAAM,SAAS;AAAA,EACpB,YAAY,QAAQ,GAAG,MAAM,IAAI;AAC/B,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,IAAI,QAAQ;AACV,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGA,KAAK,GAAG;AACN,SAAK,QAAQ;AACb,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,IAAI,UAAU;AACZ,UAAM,MAAM,OAAO,KAAK,IAAI,KAAK,MAAM,IAAI;AAC3C,WAAO,KAAK,IAAI,KAAK,SAAS,KAAK,KAAK,KAAK;AAAA,EAC/C;AAAA;AAAA,EAGA,KAAK,IAAI;AACP,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,KAAK;AAClB,aAAO;AAAA,IACT;AACA,SAAK,UAAU,KAAK,SAAS,KAAK,UAAU,IAAI,KAAK,IAAI,CAAC,KAAK,KAAK,GAAG;AACvE,WAAO;AAAA,EACT;AACF;AAKO,MAAM,MAAM;AAAA,EACjB,YAAY,WAAW,KAAK,OAAO,cAAc;AAC/C,SAAK,WAAW;AAChB,SAAK,OAAO;AACZ,SAAK,IAAI;AAAA,EACX;AAAA,EAEA,UAAU;AACR,SAAK,IAAI;AAAA,EACX;AAAA,EAEA,IAAI,OAAO;AACT,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AAAA,EAEA,IAAI,WAAW;AACb,WAAO,KAAK,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,QAAQ,CAAC;AAAA,EACtD;AAAA,EAEA,KAAK,IAAI;AACP,QAAI,KAAK,KAAM,QAAO;AACtB,SAAK,KAAK;AACV,WAAO;AAAA,EACT;AACF;ACtEA,MAAMA,UAAQ,CAAC,GAAG,GAAG,MAAO,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAa7C,MAAM,UAAU;AAAA,EACrB,YAAY,EAAE,UAAU,GAAG,aAAa,KAAK,aAAa,KAAK,cAAc,GAAE,IAAK,CAAA,GAAI;AACtF,SAAK,aAAa;AAClB,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,QAAQ;AACb,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,cAAc;AACnB,SAAK,WAAW,IAAI,SAAS,SAAS,EAAE;AACxC,SAAK,SAAS,IAAI,SAAS,aAAa,EAAE;AAC1C,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,IAAI,UAAU;AAAE,WAAO,KAAK,SAAS;AAAA,EAAM;AAAA,EAC3C,IAAI,QAAQ;AAAE,WAAO,KAAK,OAAO;AAAA,EAAM;AAAA,EAEvC,OAAO,GAAG;AAAE,SAAK,QAAQ,KAAK,IAAI,GAAG,CAAC;AAAA,EAAE;AAAA,EAExC,YAAY,GAAG;AACb,UAAM,OAAO,IAAI,KAAK;AACtB,SAAK,WAAW;AAChB,QAAI,KAAK,QAAQ;AAEf,YAAM,IAAI,IAAI,IAAI,KAAK;AACvB,UAAI,KAAM,MAAK,OAAO,IAAI,CAAC;AAAA,UACtB,MAAK,OAAO,KAAK,CAAC;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,EAAE,GAAG;AAAE,WAAO,KAAK,SAAS,KAAK,OAAO,QAAQ,KAAK,KAAK,SAAS;AAAA,EAAM;AAAA;AAAA,EAGzE,MAAM,GAAG;AAAE,WAAO,KAAK,OAAO,SAAS,KAAK,QAAQ,KAAK,KAAK,SAAS;AAAA,EAAM;AAAA,EAE7E,WAAW;AACT,UAAM,IAAI,KAAK,SAAS;AAExB,WAAO,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,IAAI,CAAC;AAAA,EACzC;AAAA,EAEA,eAAe;AACb,UAAM,QAAQ,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC,IAAI;AAC1C,UAAM,OAAO,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,CAAC,IAAI;AACjD,WAAO;AAAA,MACL,MAAMA,QAAM,OAAO,GAAG,KAAK,IAAI,GAAG,KAAK,WAAW,CAAC,CAAC;AAAA,MACpD,IAAIA,QAAM,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,WAAW,CAAC,CAAC;AAAA,IACvD;AAAA,EACE;AAAA,EAEA,YAAY,GAAG;AACb,UAAM,MAAM,KAAK,WAAW,IAAI,KAAK,cAAc,KAAK,QAAQ,KAAK,SAAS;AAC9E,UAAM,MAAM,KAAK,IAAI,GAAG,KAAK,WAAW,IAAI,KAAK,WAAW;AAC5D,WAAOA,QAAM,GAAG,KAAK,GAAG;AAAA,EAC1B;AAAA;AAAA,EAGA,MAAM,MAAM;AACV,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,OAAO,KAAK,YAAY,KAAK,OAAO,QAAQ,OAAO,KAAK,SAAS,KAAK;AAC5E,SAAK,OAAO,KAAK,IAAI;AACrB,SAAK,SAAS;AACd,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,OAAO,GAAG,QAAQ;AAChB,UAAM,KAAK,KAAK,SAAS;AACzB,UAAM,KAAKA,QAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AAC9D,QAAI,KAAK,IAAI,KAAK,EAAE,IAAI,KAAM,QAAO;AAIrC,UAAM,UAAU,KAAK,SAAS,KAAK,QAAQ;AAC3C,UAAM,KAAK,KAAK,OAAO;AACvB,UAAM,MAAM,MAAM,KAAK,QAAQ,WAAW;AAC1C,UAAM,KAAK,OAAO,KAAK,QAAQ,WAAW;AAE1C,SAAK,SAAS,IAAI,EAAE;AACpB,SAAK,OAAO,IAAI,KAAK,YAAY,EAAE,CAAC;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,iBAAiB;AACf,SAAK,SAAS;AACd,SAAK,OAAO,IAAI,KAAK,WAAW,IAAI,KAAK,WAAW;AAAA,EACtD;AAAA,EAEA,QAAQ;AACN,SAAK,SAAS,IAAI,KAAK,QAAQ;AAC/B,SAAK,eAAc;AAAA,EACrB;AAAA;AAAA,EAGA,KAAK,IAAI;AACP,UAAM,IAAI,KAAK,SAAS,KAAK,EAAE;AAC/B,UAAM,IAAI,KAAK,OAAO,KAAK,EAAE;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,UAAU;AAAE,WAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AAAA,EAAQ;AACtE;AClHA,MAAM,QAAQ,CAAC,GAAG,GAAG,MAAO,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAU7C,MAAM,WAAW;AAAA,EACtB,YAAY,EAAE,OAAO,UAAU,MAAM,KAAK,YAAY,MAAM,eAAe,KAAI,IAAK,CAAA,GAAI;AACtF,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,eAAe;AACpB,SAAK,OAAO;AACZ,SAAK,MAAM;AACX,SAAK,SAAS;AACd,SAAK,MAAM,IAAI,SAAS,GAAG,GAAG;AAC9B,SAAK,MAAM,IAAI,SAAS,GAAG,GAAG;AAC9B,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,KAAK,GAAG;AAAE,WAAO,KAAK,SAAS,QAAQ,KAAK,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC,IAAI;AAAA,EAAE;AAAA,EACvE,KAAK,GAAG;AAAE,WAAO,KAAK,SAAS,QAAQ,KAAK,IAAI,CAAC,IAAI;AAAA,EAAE;AAAA,EAEvD,QAAQ,MAAM;AACZ,QAAI,SAAS,KAAK,KAAM;AACxB,UAAM,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK;AACnC,UAAM,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK;AACnC,SAAK,OAAO;AACZ,SAAK,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;AAC3B,SAAK,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;AAAA,EAC7B;AAAA,EAEA,OAAO,KAAK,QAAQ;AAClB,SAAK,MAAM;AACX,SAAK,SAAS,KAAK,IAAI,GAAG,MAAM;AAAA,EAClC;AAAA,EAEA,IAAI,KAAK;AAAE,WAAO,KAAK,KAAK,KAAK,IAAI,KAAK;AAAA,EAAE;AAAA,EAC5C,IAAI,KAAK;AAAE,WAAO,KAAK,KAAK,KAAK,IAAI,KAAK;AAAA,EAAE;AAAA,EAE5C,EAAE,OAAO;AACP,UAAM,IAAI,KAAK,IAAI;AACnB,UAAM,IAAI,KAAK,IAAI;AACnB,UAAM,KAAK,KAAK,KAAK,KAAK,IAAI,MAAM,IAAI,KAAK;AAC7C,WAAO,KAAK,MAAM,KAAK,UAAU,IAAI;AAAA,EACvC;AAAA,EAEA,MAAM,GAAG;AACP,UAAM,IAAI,KAAK,IAAI;AACnB,UAAM,IAAI,KAAK,IAAI;AACnB,UAAM,IAAI,KAAK,IAAI,KAAK,OAAO,KAAK;AACpC,WAAO,KAAK,KAAK,IAAI,KAAK,IAAI,EAAE;AAAA,EAClC;AAAA;AAAA,EAGA,IAAI,MAAM,MAAM,IAAI,OAAO;AACzB,QAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,OAAQ;AAChC,QAAI,MAAM;AACV,QAAI,MAAM;AACV,aAAS,IAAI,MAAM,KAAK,IAAI,KAAK;AAC/B,YAAMC,KAAI,KAAK,CAAC;AAChB,UAAI,CAACA,GAAG;AACR,UAAIA,GAAE,MAAM,IAAK,OAAMA,GAAE;AACzB,UAAIA,GAAE,OAAO,IAAK,OAAMA,GAAE;AAAA,IAC5B;AACA,QAAI,OAAO;AACT,UAAI,MAAM,MAAM,IAAK,OAAM,MAAM;AACjC,UAAI,MAAM,OAAO,IAAK,OAAM,MAAM;AAAA,IACpC;AACA,QAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,GAAG,EAAG;AAEtC,QAAI,IAAI,KAAK,KAAK,GAAG;AACrB,QAAI,IAAI,KAAK,KAAK,GAAG;AACrB,QAAI,OAAO,IAAI,KAAK,KAAK;AACzB,QAAI,EAAE,MAAM,GAAI,OAAM,KAAK,IAAI,CAAC,IAAI,QAAQ;AAC5C,SAAK;AACL,UAAM,IAAI,KAAK,IAAI;AAEnB,SAAK,IAAI,IAAI,CAAC;AACd,SAAK,IAAI,IAAI,CAAC;AACd,QAAI,CAAC,KAAK,SAAS;AACjB,WAAK,IAAI,KAAK,CAAC;AACf,WAAK,IAAI,KAAK,CAAC;AACf,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AAAA;AAAA,EAGA,QAAQ,QAAQ;AACd,SAAK,OAAO;AACZ,UAAM,IAAI,KAAK,IAAI;AACnB,UAAM,IAAI,KAAK,IAAI;AACnB,UAAM,OAAO,IAAI,KAAK;AACtB,UAAM,QAAS,IAAI,KAAK,IAAK,MAAM,QAAQ,KAAK,CAAC;AACjD,SAAK,IAAI,IAAI,MAAM,IAAI;AACvB,SAAK,IAAI,IAAI,MAAM,IAAI;AAAA,EACzB;AAAA,EAEA,YAAY;AACV,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,KAAK,IAAI;AACP,UAAM,IAAI,KAAK,IAAI,KAAK,EAAE;AAC1B,UAAM,IAAI,KAAK,IAAI,KAAK,EAAE;AAC1B,WAAO,KAAK;AAAA,EACd;AACF;AChHY,MAAC,eAAe;AAAA,EAC1B,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AAAA,EACT,MAAM;AAAA,EACN,gBAAgB;AAAA,EAChB,gBAAgB;AAClB;AAEY,MAAC,aAAa;AAAA,EACxB,GAAG;AAAA,EACH,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,SAAS;AACX;AC1BO,MAAM,WAAW;AAAA,EACtB,YAAY,MAAM,IAAI;AACpB,SAAK,UAAU;AACf,SAAK,IAAI,IAAI,SAAS,GAAG,GAAG;AAC5B,SAAK,IAAI,IAAI,SAAS,GAAG,GAAG;AAC5B,SAAK,IAAI,IAAI,SAAS,GAAG,GAAG;AAC5B,SAAK,IAAI,IAAI,SAAS,GAAG,GAAG;AAC5B,SAAK,MAAM,IAAI,SAAS,GAAG,MAAM,CAAC;AAClC,SAAK,QAAQ,IAAI,MAAM,GAAG;AAC1B,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,UAAU,KAAK;AACb,QAAI,CAAC,KAAK;AACR,WAAK,OAAO;AACZ;AAAA,IACF;AACA,QAAI,CAAC,KAAK,QAAQ,IAAI,SAAS,KAAK,OAAO;AAEzC,WAAK,EAAE,KAAK,IAAI,IAAI;AACpB,WAAK,EAAE,KAAK,IAAI,IAAI;AACpB,WAAK,EAAE,KAAK,IAAI,IAAI;AACpB,WAAK,EAAE,KAAK,IAAI,IAAI;AACpB,WAAK,IAAI,KAAK,CAAC;AACf,WAAK,MAAM,QAAO;AAClB,WAAK,QAAQ,IAAI;AACjB,WAAK,OAAO;AAAA,IACd;AACA,SAAK,EAAE,IAAI,IAAI,IAAI;AACnB,SAAK,EAAE,IAAI,IAAI,IAAI;AACnB,SAAK,EAAE,IAAI,IAAI,GAAG;AAClB,SAAK,EAAE,IAAI,IAAI,KAAK;AACpB,SAAK,IAAI,IAAI,IAAI,UAAU,CAAC;AAAA,EAC9B;AAAA,EAEA,QAAQ;AACN,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,KAAK,IAAI;AACP,QAAI,CAAC,KAAK,KAAM,QAAO;AACvB,QAAI,SAAS;AACb,QAAI,KAAK,EAAE,KAAK,EAAE,EAAG,UAAS;AAC9B,QAAI,KAAK,EAAE,KAAK,EAAE,EAAG,UAAS;AAC9B,QAAI,KAAK,EAAE,KAAK,EAAE,EAAG,UAAS;AAC9B,QAAI,KAAK,EAAE,KAAK,EAAE,EAAG,UAAS;AAC9B,QAAI,KAAK,IAAI,KAAK,EAAE,EAAG,UAAS;AAChC,QAAI,KAAK,MAAM,KAAK,EAAE,EAAG,UAAS;AAClC,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,KAAK,KAAK;AACR,QAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,WAAW,IAAI,SAAS,KAAK,MAAO,QAAO;AACnE,UAAM,IAAI,KAAK,EAAE;AACjB,UAAM,IAAI,KAAK,EAAE;AACjB,WAAO;AAAA,MACL,MAAM,IAAI;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA;AAAA,MAEP,MAAM,KAAK,IAAI,KAAK,EAAE,OAAO,GAAG,CAAC;AAAA,MACjC,KAAK,KAAK,IAAI,KAAK,EAAE,OAAO,GAAG,CAAC;AAAA,MAChC,QAAQ,KAAK,IAAI;AAAA,MACjB,QAAQ,KAAK,MAAM;AAAA,IACzB;AAAA,EACE;AACF;AC1EO,MAAM,QAAQ;AAAA,EACnB,YAAY,EAAE,WAAW,MAAM,MAAM,MAAK,IAAK,IAAI;AACjD,SAAK,WAAW;AAChB,SAAK,MAAM;AACX,SAAK,IAAI;AACT,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,OAAO,IAAI,IAAI;AACb,QAAI,MAAM,EAAG;AACb,UAAM,UAAU,KAAK;AAErB,SAAK,IAAI,KAAK,IAAI,MAAM,UAAU;AAClC,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,UAAU;AACR,QAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAK,MAAK,SAAS;AAAA,EACjD;AAAA,EAEA,OAAO;AACL,SAAK,IAAI;AACT,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA,EAGA,KAAK,IAAI;AACP,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,UAAM,KAAK,KAAK,IAAI;AACpB,SAAK,KAAK,KAAK,IAAI,KAAK,UAAU,KAAK,OAAO;AAC9C,QAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAK,MAAK,KAAI;AAC1C,WAAO;AAAA,EACT;AACF;ACrCO,SAAS,SAAS,MAAM,OAAO;AACpC,QAAM,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK;AACpC,MAAI,EAAE,MAAM,MAAM,CAAC,SAAS,GAAG,EAAG,QAAO;AACzC,QAAM,MAAM,KAAK,IAAI,IAAI,KAAK,MAAM,KAAK,MAAM,GAAG,CAAC,CAAC;AACpD,QAAM,IAAI,MAAM;AAChB,QAAM,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAChD,SAAO,IAAI;AACb;AAEO,SAAS,WAAW,IAAI,IAAI,OAAO;AACxC,QAAM,OAAO,SAAS,KAAK,IAAI,KAAK;AACpC,QAAM,QAAQ,CAAA;AACd,QAAM,QAAQ,KAAK,KAAK,KAAK,IAAI,IAAI;AACrC,WAAS,IAAI,OAAO,KAAK,KAAK,OAAO,MAAM,KAAK,KAAM,OAAM,KAAK,CAAC;AAClE,SAAO,EAAE,OAAO,KAAI;AACtB;AAEO,SAAS,YAAY,MAAM;AAChC,MAAI,CAAC,SAAS,IAAI,KAAK,QAAQ,EAAG,QAAO;AACzC,MAAI,QAAQ,IAAK,QAAO;AACxB,MAAI,QAAQ,EAAG,QAAO;AACtB,SAAO,KAAK,IAAI,GAAG,KAAK,KAAK,CAAC,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC;AACrD;AAGO,SAAS,YAAY,SAAS;AACnC,QAAM,OAAO,CAAC,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,MAAM,MAAM,IAAI;AAC/E,aAAW,KAAK,KAAM,KAAI,KAAK,QAAS,QAAO;AAC/C,SAAO,KAAK,KAAK,UAAU,GAAI,IAAI;AACrC;AAEA,MAAM,KAAK,CAAC,MAAM,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AAEpC,SAAS,YAAY,IAAI,MAAM;AACpC,QAAM,IAAI,IAAI,KAAK,EAAE;AACrB,MAAI,QAAQ,MAAO,QAAO,GAAG,EAAE,QAAO,CAAE,IAAI,EAAE,eAAe,MAAM,EAAE,OAAO,QAAO,CAAE,CAAC;AACtF,MAAI,EAAE,eAAe,KAAK,EAAE,WAAU,MAAO,GAAG;AAC9C,WAAO,GAAG,EAAE,QAAO,CAAE,IAAI,EAAE,eAAe,MAAM,EAAE,OAAO,QAAO,CAAE,CAAC;AAAA,EACrE;AACA,SAAO,GAAG,GAAG,EAAE,SAAQ,CAAE,CAAC,IAAI,GAAG,EAAE,WAAU,CAAE,CAAC;AAClD;AAEO,SAAS,YAAY,IAAI;AAC9B,QAAM,IAAI,IAAI,KAAK,EAAE;AACrB,SAAO,GAAG,EAAE,YAAW,CAAE,IAAI,GAAG,EAAE,SAAQ,IAAK,CAAC,CAAC,IAAI,GAAG,EAAE,SAAS,CAAC,IAAI,GAAG,EAAE,UAAU,CAAC,IAAI,GAAG,EAAE,WAAU,CAAE,CAAC;AAChH;AC3CO,SAAS,SAAS,KAAK,GAAG;AAC/B,QAAM,EAAE,OAAO,IAAI,IAAI,MAAM,MAAM,OAAO,WAAW;AAErD,MAAI,UAAU,GAAG,GAAG,OAAO,MAAM;AACjC,MAAI,YAAY,MAAM;AACtB,MAAI,SAAS,GAAG,GAAG,OAAO,MAAM;AAEhC,MAAI,OAAO,MAAM;AACjB,MAAI,eAAe;AAGnB,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC;AAChD,QAAM,EAAE,OAAO,SAAS,WAAW,GAAG,IAAI,GAAG,IAAI,IAAI;AACrD,QAAM,MAAM,YAAY,IAAI;AAE5B,MAAI,cAAc,MAAM;AACxB,MAAI,YAAY;AAChB,MAAI,UAAS;AACb,aAAW,KAAK,OAAO;AACrB,UAAM,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,IAAI;AAChC,QAAI,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,EAAG;AACvC,QAAI,OAAO,GAAG,CAAC;AACf,QAAI,OAAO,KAAK,GAAG,CAAC;AAAA,EACtB;AACA,MAAI,OAAM;AAEV,MAAI,YAAY,MAAM;AACtB,MAAI,YAAY;AAChB,aAAW,KAAK,OAAO;AACrB,UAAM,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC;AAC5B,QAAI,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,EAAG;AAC/C,QAAI,SAAS,EAAE,QAAQ,GAAG,GAAG,KAAK,IAAI,GAAG,CAAC;AAAA,EAC5C;AAGA,MAAI,KAAK,QAAQ;AACf,UAAM,UAAU,KAAK,KAAK,KAAK,KAAK,IAAI,MAAQ,GAAG,OAAO,CAAC;AAC3D,UAAM,WAAW,YAAY,OAAO;AACpC,UAAM,EAAE,MAAM,GAAE,IAAK,GAAG,aAAY;AACpC,UAAM,QAAQ,KAAK,KAAK,OAAO,QAAQ,IAAI;AAE3C,QAAI,cAAc,MAAM;AACxB,QAAI,UAAS;AACb,aAAS,IAAI,OAAO,KAAK,IAAI,KAAK,UAAU;AAC1C,YAAM,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,IAAI;AAChC,UAAI,IAAI,KAAK,IAAI,KAAK,EAAG;AACzB,UAAI,OAAO,GAAG,CAAC;AACf,UAAI,OAAO,GAAG,KAAK,CAAC;AAAA,IACtB;AACA,QAAI,OAAM;AAEV,QAAI,YAAY,MAAM;AACtB,QAAI,YAAY;AAChB,UAAM,KAAK,KAAK,IAAI,MAAM,iBAAiB;AAC3C,aAAS,IAAI,OAAO,KAAK,IAAI,KAAK,UAAU;AAC1C,YAAM,MAAM,KAAK,CAAC;AAClB,UAAI,CAAC,IAAK;AACV,YAAM,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC;AAC5B,UAAI,IAAI,MAAM,IAAI,KAAK,IAAI,GAAI;AAC/B,UAAI,SAAS,YAAY,IAAI,MAAM,GAAG,WAAW,GAAG,GAAG,EAAE;AAAA,IAC3D;AAAA,EACF;AAGA,MAAI,cAAc,MAAM;AACxB,MAAI,UAAS;AACb,MAAI,OAAO,KAAK,IAAI,KAAK,CAAC;AAC1B,MAAI,OAAO,KAAK,IAAI,KAAK,KAAK,CAAC;AAC/B,MAAI,OAAO,GAAG,KAAK,IAAI,GAAG;AAC1B,MAAI,OAAO,OAAO,KAAK,IAAI,GAAG;AAC9B,MAAI,OAAM;AACZ;ACpEO,SAAS,YAAY,KAAK,GAAG;AAClC,QAAM,EAAE,OAAO,IAAI,IAAI,MAAM,MAAM,OAAO,QAAQ,MAAM,gBAAgB;AAExE,MAAI,UAAU,GAAG,GAAG,OAAO,MAAM;AACjC,MAAI,CAAC,KAAK,OAAQ;AAElB,QAAM,EAAE,MAAM,GAAE,IAAK,GAAG,aAAY;AACpC,QAAM,KAAK,GAAG,SAAQ;AACtB,QAAM,OAAO,KAAK;AAClB,QAAM,OAAO,MAAM;AAGnB,QAAM,OAAO,KAAK,IAAI;AACtB,QAAM,SAAS,KAAK,IAAI,KAAK,IAAI;AACjC,MAAI,OAAO;AACX,WAAS,IAAI,MAAM,KAAK,IAAI,KAAK;AAC/B,UAAM,IAAI,KAAK,CAAC;AAChB,QAAI,KAAK,EAAE,SAAS,KAAM,QAAO,EAAE;AAAA,EACrC;AACA,MAAI,OAAO,GAAG;AACZ,aAAS,IAAI,MAAM,KAAK,IAAI,KAAK;AAC/B,UAAI,IAAI,KAAK,CAAC;AACd,UAAI,CAAC,EAAG;AACR,UAAI,QAAQ,MAAM,KAAK,SAAS,EAAG,KAAI;AACvC,YAAM,IAAI,GAAG,EAAE,CAAC;AAChB,UAAI,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,GAAI;AAChC,YAAM,IAAK,EAAE,SAAS,OAAQ,OAAO;AACrC,UAAI,YAAY,EAAE,SAAS,EAAE,OAAO,MAAM,WAAW,MAAM;AAC3D,UAAI,SAAS,KAAK,MAAM,IAAI,IAAI,GAAG,UAAU,OAAO,IAAI,KAAK,IAAI,GAAG,EAAE,GAAG,CAAC;AAAA,IAC5E;AAAA,EACF;AAGA,WAAS,IAAI,MAAM,KAAK,IAAI,KAAK;AAC/B,QAAI,IAAI,KAAK,CAAC;AACd,QAAI,CAAC,EAAG;AACR,UAAM,SAAS,MAAM,KAAK,SAAS;AACnC,QAAI,QAAQ,OAAQ,KAAI;AAExB,UAAM,IAAI,GAAG,EAAE,CAAC;AAChB,QAAI,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,GAAI;AAEhC,UAAM,KAAK,EAAE,SAAS,EAAE;AACxB,UAAM,QAAQ,KAAK,MAAM,KAAK,MAAM;AACpC,UAAM,KAAK,GAAG,EAAE,EAAE,IAAI;AACtB,UAAM,KAAK,GAAG,EAAE,EAAE,KAAK;AACvB,UAAM,KAAK,GAAG,EAAE,EAAE,IAAI;AACtB,UAAM,KAAK,GAAG,EAAE,EAAE,GAAG;AAGrB,QAAI,QAAQ;AACZ,QAAI,QAAQ,UAAU,OAAO,EAAE,WAAW,SAAU,SAAQ,OAAO,OAAO,EAAE;AAE5E,UAAM,KAAK,KAAK,MAAM,CAAC,KAAK,KAAK,IAAI,MAAM;AAG3C,QAAI,cAAc,KAAK,MAAM,SAAS,MAAM;AAC5C,QAAI,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC;AAClD,QAAI,UAAS;AACb,QAAI,OAAO,IAAI,EAAE;AACjB,QAAI,OAAO,IAAI,EAAE;AACjB,QAAI,OAAM;AAEV,QAAI,KAAM;AAGV,UAAM,MAAM,KAAK,IAAI,IAAI,EAAE;AAC3B,UAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,EAAE,CAAC;AAC3C,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK;AAChC,QAAI,YAAY;AAChB,QAAI,SAAS,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,KAAK,MAAM,GAAG,GAAG,KAAK,MAAM,CAAC,GAAG,KAAK,MAAM,KAAK,CAAC;AAAA,EACvF;AAGA,QAAM,UAAU,QAAQ,KAAK,KAAK,SAAS,CAAC;AAC5C,MAAI,SAAS;AACX,UAAM,IAAI,KAAK,MAAM,GAAG,EAAE,QAAQ,KAAK,CAAC,IAAI;AAC5C,QAAI,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG;AACrC,YAAM,KAAK,QAAQ,SAAS,QAAQ;AACpC,UAAI,KAAI;AACR,UAAI,YAAY,CAAC,GAAG,CAAC,CAAC;AACtB,UAAI,cAAc,KAAK,MAAM,KAAK,MAAM;AACxC,UAAI,YAAY;AAChB,UAAI,cAAc;AAClB,UAAI,UAAS;AACb,UAAI,OAAO,GAAG,CAAC;AACf,UAAI,OAAO,KAAK,GAAG,CAAC;AACpB,UAAI,OAAM;AACV,UAAI,QAAO;AAEX,YAAM,EAAE,KAAI,IAAK,WAAW,GAAG,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;AAC9E,YAAM,QAAQ,QAAQ,MAAM,QAAQ,YAAY,IAAI,CAAC;AACrD,UAAI,OAAO,MAAM;AACjB,UAAI,eAAe;AACnB,UAAI,YAAY;AAChB,YAAM,KAAK,IAAI,YAAY,KAAK,EAAE;AAClC,UAAI,YAAY,KAAK,MAAM,KAAK,MAAM;AACtC,UAAI,SAAS,KAAK,IAAI,GAAG,IAAI,GAAG,KAAK,IAAI,EAAE;AAC3C,UAAI,YAAY,MAAM;AACtB,UAAI,SAAS,OAAO,KAAK,IAAI,GAAG,CAAC;AAAA,IACnC;AAAA,EACF;AACF;ACtGO,SAAS,cAAc,KAAK,GAAG;AACpC,QAAM,EAAE,OAAO,IAAI,IAAI,MAAM,MAAM,OAAO,QAAQ,QAAQ,WAAW;AAErE,MAAI,UAAU,GAAG,GAAG,OAAO,MAAM;AACjC,MAAI,CAAC,UAAU,CAAC,KAAK,OAAQ;AAC7B,MAAI,OAAO,IAAI,KAAK,OAAO,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,OAAO,IAAI,KAAK,EAAG;AAE5E,QAAM,IAAI,KAAK,MAAM,GAAG,MAAM,OAAO,CAAC,CAAC;AACvC,QAAM,MAAM,KAAK,CAAC;AAElB,MAAI,IAAI,OAAO;AACf,MAAI,IAAI,OAAO;AACf,MAAI,KAAK;AACP,QAAI,GAAG,EAAE,CAAC;AACV,QAAI,QAAQ;AAEV,YAAM,QAAQ,CAAC,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK;AACrD,UAAI,OAAO;AACX,UAAI,QAAQ;AACZ,iBAAW,KAAK,OAAO;AACrB,cAAM,KAAK,GAAG,EAAE,CAAC;AACjB,cAAM,IAAI,KAAK,IAAI,KAAK,OAAO,CAAC;AAChC,YAAI,IAAI,OAAO;AAAE,kBAAQ;AAAG,iBAAO;AAAA,QAAG;AAAA,MACxC;AACA,UAAI,QAAQ,GAAI,KAAI;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,KAAI;AACR,MAAI,YAAY,CAAC,GAAG,CAAC,CAAC;AACtB,MAAI,cAAc,MAAM;AACxB,MAAI,YAAY;AAChB,MAAI,UAAS;AACb,MAAI,OAAO,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC;AACjC,MAAI,OAAO,KAAK,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC;AACtC,MAAI,OAAO,GAAG,KAAK,MAAM,CAAC,IAAI,GAAG;AACjC,MAAI,OAAO,KAAK,GAAG,KAAK,MAAM,CAAC,IAAI,GAAG;AACtC,MAAI,OAAM;AACV,MAAI,QAAO;AAEX,MAAI,OAAO,MAAM;AACjB,MAAI,eAAe;AAGnB,QAAM,EAAE,KAAI,IAAK,WAAW,GAAG,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;AAC9E,QAAM,aAAa,GAAG,MAAM,CAAC,EAAE,QAAQ,YAAY,IAAI,CAAC;AACxD,MAAI,YAAY;AAChB,QAAM,KAAK,IAAI,YAAY,UAAU,EAAE;AACvC,MAAI,YAAY,MAAM;AACtB,MAAI,SAAS,KAAK,IAAI,GAAG,IAAI,GAAG,KAAK,IAAI,EAAE;AAC3C,MAAI,YAAY,MAAM;AACtB,MAAI,SAAS,YAAY,KAAK,IAAI,GAAG,CAAC;AAGtC,MAAI,KAAK;AACP,UAAM,IAAI,YAAY,IAAI,IAAI;AAC9B,QAAI,YAAY;AAChB,UAAM,KAAK,IAAI,YAAY,CAAC,EAAE;AAC9B,UAAM,KAAK,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,KAAK,IAAI,CAAC;AAChE,QAAI,YAAY,MAAM;AACtB,QAAI,SAAS,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,EAAE;AACrD,QAAI,YAAY,MAAM;AACtB,QAAI,SAAS,GAAG,IAAI,KAAK,IAAI,EAAE;AAAA,EACjC;AACF;ACrDO,MAAM,MAAM;AAAA,EACjB,YAAY,WAAW,UAAU,IAAI;AACnC,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,sCAAsC;AAEtE,SAAK,YAAY;AACjB,SAAK,QAAQ,EAAE,GAAG,cAAc,GAAI,QAAQ,SAAS,GAAG;AACxD,SAAK,UAAU;AAAA,MACb,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,GAAG;AAAA,IACT;AAEI,SAAK,OAAO,CAAA;AACZ,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,kBAAkB;AACvB,SAAK,aAAa;AAClB,SAAK,aAAa,EAAE,WAAW,oBAAI,OAAO,cAAc,oBAAI,IAAG,EAAE;AAEjE,SAAK,SAAS,IAAI,OAAO,WAAW,CAAC,QAAQ,QAAQ,SAAS,CAAC;AAC/D,SAAK,KAAK,IAAI,UAAU,QAAQ,SAAS;AACzC,SAAK,KAAK,IAAI,WAAW,QAAQ,UAAU;AAC3C,SAAK,OAAO,IAAI,WAAU;AAC1B,SAAK,KAAK,UAAU,KAAK,QAAQ,YAAY;AAC7C,SAAK,UAAU,IAAI,QAAO;AAE1B,SAAK,SAAS;AACd,SAAK,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAC;AAEpC,SAAK,OAAO,IAAI,KAAK,CAAC,OAAO,OAAO,KAAK,OAAO,OAAO,EAAE,CAAC;AAC1D,SAAK,OAAO,WAAW,MAAM;AAC3B,WAAK,QAAO;AACZ,WAAK,KAAK,WAAW,KAAK;AAAA,IAC5B;AAEA,SAAK,QAAO;AACZ,SAAK,YAAW;AAChB,SAAK,KAAK,MAAK;AAAA,EACjB;AAAA;AAAA,EAGA,UAAU;AACR,UAAM,EAAE,OAAO,OAAM,IAAK,KAAK;AAC/B,UAAM,IAAI,KAAK,IAAI,GAAG,QAAQ,KAAK,MAAM,cAAc;AACvD,UAAM,IAAI,KAAK,IAAI,GAAG,SAAS,KAAK,MAAM,cAAc;AACxD,SAAK,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAC;AAC9B,SAAK,GAAG,OAAO,CAAC;AAChB,SAAK,GAAG,OAAO,GAAG,CAAC;AAAA,EACrB;AAAA;AAAA,EAGA,QAAQ,MAAM;AACZ,SAAK,OAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,UAAU,CAAA;AACjD,SAAK,aAAa;AAClB,QAAI,KAAK,KAAK,SAAS,GAAG;AACxB,WAAK,GAAG,cAAc,KAAK,KAAK,CAAC,EAAE,OAAO,KAAK,KAAK,CAAC,EAAE;AAAA,IACzD;AACA,SAAK,GAAG,YAAY,KAAK,KAAK,MAAM;AACpC,SAAK,GAAG,eAAc;AACtB,SAAK,KAAK,MAAK;AACf,SAAK,GAAG,UAAU;AAClB,SAAK,KAAK,WAAW,KAAK;AAAA,EAC5B;AAAA;AAAA,EAGA,OAAO,KAAK;AACV,QAAI,CAAC,IAAK;AACV,UAAM,IAAI,KAAK,KAAK;AACpB,QAAI,KAAK,KAAK,KAAK,IAAI,CAAC,EAAE,SAAS,IAAI,MAAM;AAC3C,WAAK,KAAK,IAAI,CAAC,IAAI;AAAA,IACrB,OAAO;AACL,WAAK,OAAO,GAAG;AACf;AAAA,IACF;AACA,SAAK,KAAK,UAAU,GAAG;AACvB,SAAK,KAAK,WAAW,MAAM;AAAA,EAC7B;AAAA;AAAA,EAGA,OAAO,KAAK;AACV,QAAI,CAAC,IAAK;AACV,UAAM,IAAI,KAAK,KAAK;AACpB,QAAI,KAAK,IAAI,QAAQ,KAAK,KAAK,IAAI,CAAC,EAAE,MAAM;AAC1C,WAAK,KAAK,IAAI,CAAC,IAAI;AAAA,IACrB,OAAO;AACL,WAAK,KAAK,KAAK,GAAG;AAClB,WAAK,GAAG,YAAY,KAAK,KAAK,MAAM;AAAA,IACtC;AACA,SAAK,KAAK,UAAU,GAAG;AACvB,SAAK,KAAK,WAAW,MAAM;AAAA,EAC7B;AAAA,EAEA,MAAM,QAAQ,MAAM;AAClB,SAAK,WAAU;AACf,SAAK,OAAO;AACZ,QAAI,CAAC,KAAM;AACX,SAAK,GAAG,cAAc,KAAK,aAAa,KAAK,GAAG;AAChD,UAAM,OAAO,MAAM,KAAK,QAAQ;AAAA,MAC9B,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,IAAI;AAAA,MACJ,OAAO,KAAK,QAAQ,eAAe;AAAA,IACzC,CAAK;AACD,SAAK,QAAQ,IAAI;AACjB,QAAI,OAAO,KAAK,UAAU,WAAY,MAAK,MAAM,KAAK,KAAK,SAAS,CAAC,CAAC;AACtE,SAAK,SAAS,KAAK,UAAU,CAAC,QAAQ;AACpC,UAAI,CAAC,OAAO,CAAC,IAAI,IAAK;AACtB,UAAI,IAAI,SAAS,SAAU,MAAK,OAAO,IAAI,GAAG;AAAA,UACzC,MAAK,OAAO,IAAI,GAAG;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,aAAa;AACX,QAAI,KAAK,OAAQ,MAAK,OAAM;AAC5B,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,oBAAoB;AACxB,QAAI,KAAK,mBAAmB,KAAK,cAAc,CAAC,KAAK,KAAM;AAC3D,UAAM,EAAE,KAAI,IAAK,KAAK,GAAG,aAAY;AACrC,QAAI,OAAO,MAAM,CAAC,KAAK,KAAK,OAAQ;AAEpC,SAAK,kBAAkB;AACvB,QAAI;AACF,YAAM,SAAS,KAAK,KAAK,CAAC,EAAE;AAC5B,YAAM,QAAQ,MAAM,KAAK,KAAK,QAAQ;AAAA,QACpC,QAAQ,KAAK,KAAK;AAAA,QAClB,WAAW,KAAK,KAAK;AAAA,QACrB,IAAI;AAAA,QACJ,OAAO;AAAA,MACf,CAAO;AACD,UAAI,CAAC,SAAS,CAAC,MAAM,QAAQ;AAC3B,aAAK,aAAa;AAAA,MACpB,OAAO;AACL,cAAM,QAAQ,MAAM,OAAO,CAAC,MAAM,EAAE,OAAO,MAAM;AACjD,YAAI,CAAC,MAAM,QAAQ;AACjB,eAAK,aAAa;AAAA,QACpB,OAAO;AACL,eAAK,OAAO,MAAM,OAAO,KAAK,IAAI;AAElC,gBAAM,eAAe,KAAK,GAAG;AAC7B,eAAK,GAAG,WAAW,KAAK,KAAK;AAC7B,eAAK,GAAG,OAAO,KAAK,KAAK,GAAG,OAAO,QAAQ,MAAM,MAAM;AACvD,eAAK,GAAG,OAAO,IAAI,KAAK,GAAG,OAAO,SAAS,MAAM,MAAM;AACvD,eAAK,GAAG,SAAS;AACjB,eAAK,KAAK,WAAW,KAAK;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AACV,cAAQ,MAAM,mCAAmC,CAAC;AAClD,WAAK,aAAa;AAAA,IACpB,UAAC;AACC,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA;AAAA,EAGA,cAAc;AACZ,UAAM,KAAK,KAAK;AAChB,OAAG,MAAM,cAAc;AACvB,OAAG,MAAM,SAAS;AAElB,QAAI,WAAW;AACf,QAAI,OAAO;AACX,QAAI,QAAQ;AACZ,QAAI,QAAQ;AACZ,QAAI,QAAQ;AACZ,QAAI,QAAQ;AACZ,UAAM,WAAW,oBAAI,IAAG;AACxB,QAAI,YAAY;AAEhB,UAAM,WAAW,CAAC,MAAM;AACtB,YAAM,IAAI,GAAG,sBAAqB;AAClC,aAAO,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,GAAG,EAAE,UAAU,EAAE,IAAG;AAAA,IACtD;AAEA,SAAK,UAAU,CAAC,MAAM;AACpB,eAAS,IAAI,EAAE,WAAW,SAAS,CAAC,CAAC;AACrC,UAAI,SAAS,SAAS,GAAG;AACvB,cAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,OAAM,CAAE;AACpC,oBAAY,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAC3C,mBAAW;AACX;AAAA,MACF;AACA,YAAM,IAAI,SAAS,CAAC;AACpB,iBAAW;AACX,cAAQ;AACR,aAAO,EAAE,IAAI,KAAK,KAAK,IAAI,UAAU,EAAE,IAAI,KAAK,KAAK,IAAI,SAAS;AAClE,cAAQ,EAAE;AACV,cAAQ,EAAE;AACV,cAAQ,YAAY,IAAG;AACvB,WAAK,QAAQ,KAAI;AACjB,SAAG,kBAAkB,EAAE,SAAS;AAAA,IAClC;AAEA,SAAK,UAAU,CAAC,MAAM;AACpB,YAAM,IAAI,SAAS,CAAC;AACpB,UAAI,SAAS,IAAI,EAAE,SAAS,EAAG,UAAS,IAAI,EAAE,WAAW,CAAC;AAE1D,UAAI,SAAS,SAAS,GAAG;AACvB,cAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,OAAM,CAAE;AACpC,cAAM,IAAI,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AACzC,YAAI,YAAY,KAAK,IAAI,GAAG;AAC1B,gBAAM,OAAO,EAAE,IAAI,EAAE,KAAK;AAC1B,eAAK,GAAG,OAAO,KAAK,IAAI,SAAS;AACjC,eAAK,KAAK,WAAW,KAAK;AAAA,QAC5B;AACA,oBAAY;AACZ;AAAA,MACF;AAEA,WAAK,SAAS;AACd,WAAK,eAAe,CAAC;AACrB,WAAK,KAAK,WAAW,SAAS;AAE9B,UAAI,CAAC,SAAU;AACf,YAAM,MAAM,YAAY,IAAG;AAC3B,YAAM,KAAK,MAAM;AACjB,YAAM,KAAK,EAAE,IAAI;AACjB,YAAM,KAAK,EAAE,IAAI;AACjB,UAAI,KAAK,IAAI,EAAE,IAAI,KAAK,KAAK,IAAI,EAAE,IAAI,EAAG,SAAQ;AAElD,UAAI,SAAS,OAAO;AAClB,aAAK,GAAG,MAAM,EAAE;AAChB,aAAK,QAAQ,OAAO,IAAI,EAAE;AAC1B,aAAK,KAAK,WAAW,KAAK;AAC1B,aAAK,kBAAiB;AAAA,MACxB,WAAW,SAAS,SAAS;AAC3B,aAAK,GAAG,QAAQ,IAAI,KAAK,GAAG;AAC5B,aAAK,KAAK,WAAW,KAAK;AAAA,MAC5B,WAAW,SAAS,QAAQ;AAC1B,aAAK,GAAG,OAAO,KAAK,KAAK,GAAG,IAAI,KAAK,GAAG;AACxC,aAAK,KAAK,WAAW,KAAK;AAAA,MAC5B;AAEA,cAAQ,EAAE;AACV,cAAQ,EAAE;AACV,cAAQ;AAAA,IACV;AAEA,SAAK,QAAQ,CAAC,MAAM;AAClB,eAAS,OAAO,EAAE,SAAS;AAC3B,UAAI,SAAS,OAAO,EAAG,aAAY;AACnC,UAAI,YAAY,SAAS,SAAS,OAAO;AACvC,aAAK,QAAQ,QAAO;AACpB,aAAK,KAAK,WAAW,KAAK;AAAA,MAC5B;AACA,iBAAW;AACX,aAAO;AACP,UAAI;AAAE,WAAG,sBAAsB,EAAE,SAAS;AAAA,MAAE,SAAS,GAAG;AAAA,MAAC;AAAA,IAC3D;AAEA,SAAK,WAAW,MAAM;AACpB,WAAK,SAAS;AACd,WAAK,eAAe,IAAI;AACxB,WAAK,KAAK,WAAW,SAAS;AAAA,IAChC;AAEA,SAAK,WAAW,CAAC,MAAM;AACrB,QAAE,eAAc;AAChB,YAAM,IAAI,GAAG,sBAAqB;AAClC,YAAM,IAAI,EAAE,UAAU,EAAE;AACxB,YAAM,SAAS,KAAK,IAAI,OAAO,EAAE,MAAM;AACvC,WAAK,GAAG,OAAO,GAAG,MAAM;AACxB,WAAK,KAAK,WAAW,KAAK;AAC1B,WAAK,kBAAiB;AAAA,IACxB;AAEA,SAAK,SAAS,MAAM;AAClB,WAAK,GAAG,MAAK;AACb,WAAK,GAAG,UAAS;AACjB,WAAK,KAAK,WAAW,KAAK;AAAA,IAC5B;AAEA,SAAK,SAAS,CAAC,MAAM;AACnB,YAAM,OAAO,EAAE,WAAW,MAAM;AAChC,UAAI,EAAE,QAAQ,aAAa;AAAE,aAAK,GAAG,MAAM,IAAI;AAAG,aAAK,KAAK,WAAW,KAAK;AAAG,aAAK;MAAoB,WAC/F,EAAE,QAAQ,cAAc;AAAE,aAAK,GAAG,MAAM,CAAC,IAAI;AAAG,aAAK,KAAK,WAAW,KAAK;AAAA,MAAE,WAC5E,EAAE,QAAQ,OAAO,EAAE,QAAQ,KAAK;AAAE,aAAK,GAAG,OAAO,KAAK,KAAK,IAAI,GAAG,GAAG;AAAG,aAAK,KAAK,WAAW,KAAK;AAAA,MAAE,WACpG,EAAE,QAAQ,OAAO,EAAE,QAAQ,KAAK;AAAE,aAAK,GAAG,OAAO,KAAK,KAAK,IAAI,GAAG,GAAG;AAAG,aAAK,KAAK,WAAW,KAAK;AAAA,MAAE,MACxG;AACL,QAAE,eAAc;AAAA,IAClB;AAEA,OAAG,iBAAiB,eAAe,KAAK,OAAO;AAC/C,OAAG,iBAAiB,eAAe,KAAK,OAAO;AAC/C,OAAG,iBAAiB,aAAa,KAAK,KAAK;AAC3C,OAAG,iBAAiB,iBAAiB,KAAK,KAAK;AAC/C,OAAG,iBAAiB,gBAAgB,KAAK,QAAQ;AACjD,OAAG,iBAAiB,SAAS,KAAK,UAAU,EAAE,SAAS,MAAK,CAAE;AAC9D,OAAG,iBAAiB,YAAY,KAAK,MAAM;AAC3C,OAAG,iBAAiB,WAAW,KAAK,MAAM;AAC1C,QAAI,CAAC,GAAG,aAAa,UAAU,EAAG,IAAG,aAAa,YAAY,GAAG;AAAA,EACnE;AAAA,EAEA,eAAe,GAAG;AAChB,QAAI,CAAC,KAAK,WAAW,UAAU,KAAM;AACrC,QAAI,UAAU;AACd,QAAI,KAAK,KAAK,KAAK,UAAU,EAAE,KAAK,KAAK,KAAK,KAAK,EAAE,KAAK,KAAK,KAAK,GAAG;AACrE,YAAM,IAAI,KAAK,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,CAAC;AACvC,YAAM,MAAM,KAAK,KAAK,CAAC;AACvB,UAAI,IAAK,WAAU,EAAE,OAAO,GAAG,KAAK,OAAO,KAAK,GAAG,MAAM,EAAE,CAAC,EAAC;AAAA,IAC/D;AACA,eAAW,MAAM,KAAK,WAAW,UAAW,IAAG,OAAO;AAAA,EACxD;AAAA,EAEA,UAAU,OAAO,IAAI;AACnB,UAAM,MAAM,KAAK,WAAW,KAAK;AACjC,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,yBAAyB,KAAK,GAAG;AAC3D,QAAI,IAAI,EAAE;AACV,WAAO,MAAM,IAAI,OAAO,EAAE;AAAA,EAC5B;AAAA;AAAA,EAGA,OAAO,OAAO,IAAI;AAChB,QAAI,YAAY;AAEhB,QAAI,KAAK,GAAG,KAAK,EAAE,EAAG,aAAY;AAElC,UAAM,KAAK,KAAK,QAAQ,KAAK,EAAE;AAC/B,QAAI,IAAI;AACN,WAAK,GAAG,MAAM,EAAE;AAChB,kBAAY;AACZ,WAAK,kBAAiB;AAAA,IACxB;AAEA,QAAI,KAAK,KAAK,KAAK,EAAE,EAAG,aAAY;AAEpC,UAAM,EAAE,MAAM,GAAE,IAAK,KAAK,GAAG,aAAY;AACzC,UAAM,UAAU,KAAK,KAAK,SAAS;AACnC,UAAM,UAAU,KAAK,KAAK,SAAS,KAAK,KAAK,KAAK,KAAK,KAAK,OAAO,CAAC,IAAI;AACxE,UAAM,cAAc,WAAW,MAAM,UAAU,UAAU;AAEzD,SAAK,GAAG,IAAI,KAAK,MAAM,MAAM,IAAI,WAAW;AAC5C,QAAI,KAAK,GAAG,KAAK,EAAE,EAAG,aAAY;AAElC,UAAM,YAAY,aAAa,MAAM,IAAI,KAAK,KAAK,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM;AACxF,UAAM,QAAQ;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,IAAI,KAAK;AAAA,MACT,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,OAAO,KAAK,OAAO;AAAA,MACnB,QAAQ,KAAK,OAAO;AAAA,MACpB,MAAM;AAAA,MACN,aAAa,KAAK,QAAQ;AAAA,MAC1B,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK,QAAQ;AAAA,IAC3B;AAEI,QAAI,WAAW;AACb,eAAS,KAAK,OAAO,IAAI,MAAM,KAAK;AACpC,kBAAY,KAAK,OAAO,IAAI,MAAM,KAAK;AAAA,IACzC;AACA,QAAI,aAAa,MAAM,IAAI,SAAS,GAAG;AACrC,oBAAc,KAAK,OAAO,IAAI,SAAS,KAAK;AAAA,IAC9C;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,MAAM;AAAE,WAAO,KAAK,KAAK;AAAA,EAAI;AAAA,EAEjC,SAAS,OAAO;AACd,SAAK,QAAQ,EAAE,GAAG,KAAK,OAAO,GAAG,MAAK;AACtC,SAAK,QAAO;AACZ,SAAK,KAAK,WAAW,KAAK;AAAA,EAC5B;AAAA,EAEA,aAAa,MAAM;AACjB,SAAK,GAAG,QAAQ,IAAI;AACpB,SAAK,KAAK,WAAW,KAAK;AAAA,EAC5B;AAAA,EAEA,WAAW,IAAI;AACb,SAAK,KAAK,UAAU,CAAC,CAAC;AACtB,SAAK,KAAK,WAAW,KAAK;AAAA,EAC5B;AAAA,EAEA,UAAU,IAAI;AACZ,SAAK,QAAQ,SAAS,CAAC,CAAC;AACxB,SAAK,KAAK,WAAW,SAAS;AAAA,EAChC;AAAA,EAEA,iBAAiB;AACf,SAAK,GAAG,eAAc;AACtB,SAAK,GAAG,UAAS;AACjB,SAAK,KAAK,WAAW,KAAK;AAAA,EAC5B;AAAA,EAEA,UAAU;AACR,WAAO,KAAK,OAAO,UAAS,EAAG,UAAU,WAAW;AAAA,EACtD;AAAA,EAEA,UAAU;AACR,UAAM,KAAK,KAAK;AAChB,OAAG,oBAAoB,eAAe,KAAK,OAAO;AAClD,OAAG,oBAAoB,eAAe,KAAK,OAAO;AAClD,OAAG,oBAAoB,aAAa,KAAK,KAAK;AAC9C,OAAG,oBAAoB,iBAAiB,KAAK,KAAK;AAClD,OAAG,oBAAoB,gBAAgB,KAAK,QAAQ;AACpD,OAAG,oBAAoB,SAAS,KAAK,QAAQ;AAC7C,OAAG,oBAAoB,YAAY,KAAK,MAAM;AAC9C,OAAG,oBAAoB,WAAW,KAAK,MAAM;AAC7C,SAAK,WAAU;AACf,SAAK,KAAK,KAAI;AACd,SAAK,OAAO,QAAO;AACnB,SAAK,WAAW,UAAU,MAAK;AAC/B,SAAK,WAAW,aAAa,MAAK;AAClC,SAAK,OAAO,CAAA;AAAA,EACd;AACF;AC5ZO,MAAM,SAAS;AAAA,EACpB,YAAY,EAAE,SAAS,QAAQ,YAAY,IAAK,IAAK,IAAI;AACvD,SAAK,SAAS;AACd,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA,EAGA,MAAM,QAAQ,EAAE,QAAQ,WAAW,IAAI,MAAK,GAAI;AAC9C,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AAAA;AAAA,EAGA,UAAU,SAAS;AACjB,WAAO,MAAM;AAAA,IAAC;AAAA,EAChB;AAAA,EAEA,UAAU;AAAA,EAAC;AACb;AAGO,SAAS,WAAW,MAAM;AAC/B,MAAI,IAAI,SAAS;AACjB,SAAO,WAAY;AACjB,QAAK,IAAI,aAAc;AACvB,QAAI,IAAI,KAAK,KAAK,IAAK,MAAM,IAAK,IAAI,CAAC;AACvC,QAAK,IAAI,KAAK,KAAK,IAAK,MAAM,GAAI,KAAK,CAAC,IAAK;AAC7C,aAAS,IAAK,MAAM,QAAS,KAAK;AAAA,EACpC;AACF;ACtCO,MAAM,mBAAmB,SAAS;AAAA,EACvC,YAAY;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,QAAQ;AAAA,EACZ,IAAM,IAAI;AACN,UAAM,EAAE,QAAQ,UAAS,CAAE;AAC3B,SAAK,OAAO;AACZ,SAAK,QAAQ;AACb,SAAK,aAAa;AAClB,SAAK,QAAQ;AACb,SAAK,iBAAiB;AACtB,SAAK,QAAQ;AAEb,SAAK,OAAO,WAAW,IAAI;AAC3B,SAAK,YAAY,oBAAI,IAAG;AACxB,SAAK,SAAS;AACd,SAAK,WAAW;AAChB,SAAK,QAAQ;AACb,SAAK,OAAO;AACZ,SAAK,cAAc,KAAK,MAAM,KAAK,IAAG,IAAK,SAAS,IAAI;AAAA,EAC1D;AAAA,EAEA,SAAS;AAEP,QAAI,IAAI;AACR,QAAI,IAAI;AACR,WAAO,MAAM,EAAG,KAAI,KAAK,KAAI;AAC7B,WAAO,MAAM,EAAG,KAAI,KAAK,KAAI;AAC7B,WAAO,KAAK,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC;AAAA,EAC/D;AAAA,EAEA,MAAM,OAAO;AAEX,UAAM,QAAQ,KAAK,OAAM;AACzB,SAAK,SAAS,KAAK,aAAa,KAAK,QAAQ,OAAO,KAAK,IAAI,KAAK,IAAI,KAAK,aAAa;AACxF,SAAK,OAAO,KAAK,IAAI,KAAK,MAAM,KAAK,aAAa,CAAC;AACnD,WAAO,KAAK,IAAI,MAAM,SAAS,IAAI,KAAK,QAAQ,QAAQ,KAAK,KAAK;AAAA,EACpE;AAAA,EAEA,SAAS,MAAM,MAAM;AACnB,QAAI,IAAI;AACR,UAAM,IAAI;AACV,QAAI,KAAK;AACT,QAAI,KAAK;AACT,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAI,KAAK,MAAM,CAAC;AAChB,UAAI,IAAI,GAAI,MAAK;AACjB,UAAI,IAAI,GAAI,MAAK;AAAA,IACnB;AACA,UAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,EAAE;AACpC,UAAM,SAAS,KAAK;AAAA,OACjB,MAAM,KAAK,KAAI,IAAK,QAAQ,IAAK,QAAQ,OAAQ;AAAA,IACxD;AACI,WAAO,EAAE,MAAM,MAAM,MAAM,IAAI,KAAK,IAAI,OAAO,GAAG,OAAM;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,EAAE,IAAI,QAAQ,MAAM,YAAY,KAAK,UAAS,IAAK,IAAI;AACnE,UAAM,MAAM,MAAM,OAAO,KAAK,cAAc;AAC5C,UAAM,OAAO,CAAA;AAEb,UAAM,YAAY,MAAM,QAAQ;AAChC,UAAM,MAAM,WAAW,KAAK,OAAO,KAAK,MAAM,YAAY,SAAS,CAAC;AACpE,UAAM,QAAQ,KAAK;AACnB,SAAK,OAAO;AAEZ,QAAI,QAAQ,KAAK,SAAS,KAAK,IAAG,IAAK,OAAO;AAC9C,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAM,IAAI,YAAY,IAAI;AAC1B,YAAM,MAAM,KAAK,SAAS,GAAG,KAAK;AAClC,cAAQ,IAAI;AACZ,WAAK,KAAK,GAAG;AAAA,IACf;AACA,SAAK,OAAO;AAEZ,QAAI,MAAM,MAAM;AACd,WAAK,QAAQ,KAAK,SAAS,KAAK,KAAK,SAAS,CAAC,EAAE,QAAQ,KAAK;AAAA,IAChE;AACA,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,SAAS;AACjB,SAAK,UAAU,IAAI,OAAO;AAC1B,QAAI,CAAC,KAAK,OAAQ,MAAK,OAAM;AAC7B,WAAO,MAAM;AACX,WAAK,UAAU,OAAO,OAAO;AAC7B,UAAI,CAAC,KAAK,UAAU,KAAM,MAAK,KAAI;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,MAAM,KAAK;AACT,eAAW,KAAK,KAAK,UAAW,GAAE,GAAG;AAAA,EACvC;AAAA,EAEA,SAAS;AACP,UAAM,WAAW,KAAK,IAAI,IAAI,MAAO,KAAK,cAAc;AACxD,SAAK,SAAS,YAAY,MAAM,KAAK,MAAK,GAAI,QAAQ;AAAA,EACxD;AAAA;AAAA,EAGA,MAAM,SAAS;AACb,QAAI,SAAS;AACX,WAAK,QAAQ,QAAQ;AACrB,WAAK,WAAW,EAAE,GAAG,QAAO;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,QAAQ;AACN,UAAM,KAAK,KAAK,YAAY,KAAK;AACjC,UAAM,MAAM,KAAK,IAAG;AACpB,UAAM,OAAO,KAAK,MAAM,MAAM,EAAE,IAAI;AAEpC,QAAI,CAAC,KAAK,YAAY,KAAK,SAAS,SAAS,MAAM;AACjD,YAAM,OAAO,KAAK;AAClB,WAAK,WAAW,EAAE,MAAM,MAAM,MAAM,MAAM,MAAM,KAAK,MAAM,OAAO,MAAM,QAAQ,EAAC;AACjF,WAAK,MAAM,EAAE,MAAM,UAAU,KAAK,EAAE,GAAG,KAAK,WAAU,CAAE;AACxD;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,MAAM,KAAK,KAAK;AAClC,SAAK,QAAQ;AACb,UAAM,IAAI,KAAK;AACf,MAAE,QAAQ;AACV,QAAI,OAAO,EAAE,KAAM,GAAE,OAAO;AAC5B,QAAI,OAAO,EAAE,IAAK,GAAE,MAAM;AAC1B,MAAE,UAAU,KAAK,MAAM,KAAK,KAAK,KAAI,IAAK,GAAG;AAC7C,SAAK,MAAM,EAAE,MAAM,UAAU,KAAK,EAAE,GAAG,IAAG,CAAE;AAAA,EAC9C;AAAA,EAEA,SAAS,GAAG;AAAE,SAAK,QAAQ;AAAA,EAAE;AAAA,EAE7B,kBAAkB,GAAG;AACnB,SAAK,iBAAiB;AACtB,QAAI,KAAK,QAAQ;AAAE,WAAK,KAAI;AAAI,WAAK;IAAS;AAAA,EAChD;AAAA,EAEA,UAAU,QAAQ;AAChB,QAAI,OAAQ,MAAK,KAAI;AAAA,aACZ,CAAC,KAAK,UAAU,KAAK,UAAU,KAAM,MAAK,OAAM;AAAA,EAC3D;AAAA,EAEA,IAAI,SAAS;AAAE,WAAO,CAAC,KAAK;AAAA,EAAO;AAAA,EAEnC,OAAO;AACL,QAAI,KAAK,OAAQ,eAAc,KAAK,MAAM;AAC1C,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,UAAU;AACR,SAAK,KAAI;AACT,SAAK,UAAU,MAAK;AAAA,EACtB;AACF;ACpJO,SAAS,YAAY,WAAW,SAAS;AAC9C,SAAO,IAAI,MAAM,WAAW,OAAO;AACrC;AAEY,MAAC,UAAU;"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "emberwick",
3
+ "version": "0.1.0",
4
+ "description": "Smooth flowing candlestick charts for the web — canvas-rendered, zero-dependency, pluggable data feeds.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": [
8
+ "./webcomponent.js"
9
+ ],
10
+ "main": "./index.js",
11
+ "module": "./index.js",
12
+ "types": "./index.d.ts",
13
+ "unpkg": "./umd/emberwick.umd.js",
14
+ "jsdelivr": "./umd/emberwick.umd.js",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./index.d.ts",
18
+ "import": "./index.js"
19
+ },
20
+ "./react": {
21
+ "types": "./react.d.ts",
22
+ "import": "./react.js"
23
+ },
24
+ "./webcomponent": {
25
+ "types": "./webcomponent.d.ts",
26
+ "import": "./webcomponent.js"
27
+ },
28
+ "./umd": "./umd/emberwick.umd.js",
29
+ "./package.json": "./package.json"
30
+ },
31
+ "peerDependencies": {
32
+ "react": ">=17"
33
+ },
34
+ "peerDependenciesMeta": {
35
+ "react": {
36
+ "optional": true
37
+ }
38
+ },
39
+ "keywords": [
40
+ "candlestick",
41
+ "chart",
42
+ "charting",
43
+ "financial",
44
+ "trading",
45
+ "ohlc",
46
+ "canvas",
47
+ "realtime",
48
+ "tradingview-alternative"
49
+ ],
50
+ "engines": {
51
+ "node": ">=18"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ }
56
+ }
package/react.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ import type * as React from 'react'
2
+ import type { Bar, Chart, ChartOptions, CrosshairPayload, Feed, PriceMode, Theme } from './index.js'
3
+
4
+ export interface EmberwickChartProps
5
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
6
+ /** Static dataset. Ignored while a feed is attached and driving updates. */
7
+ data?: Bar[]
8
+ /** Data source. Passing a new instance re-loads history. */
9
+ feed?: Feed
10
+ /** Options applied at construction time only. */
11
+ options?: ChartOptions
12
+ /** Partial theme; re-applied whenever the object identity changes. */
13
+ theme?: Partial<Theme>
14
+ priceMode?: PriceMode
15
+ animate?: boolean
16
+ magnet?: boolean
17
+ onCrosshair?: (payload: CrosshairPayload | null) => void
18
+ className?: string
19
+ style?: React.CSSProperties
20
+ }
21
+
22
+ export interface EmberwickChartHandle {
23
+ /** The underlying chart instance, or null before mount / after unmount. */
24
+ readonly chart: Chart | null
25
+ }
26
+
27
+ export declare const EmberwickChart: React.ForwardRefExoticComponent<
28
+ EmberwickChartProps & React.RefAttributes<EmberwickChartHandle>
29
+ >
30
+
31
+ export default EmberwickChart
package/react.js ADDED
@@ -0,0 +1,76 @@
1
+ import { forwardRef, useRef, useEffect, useImperativeHandle, createElement } from "react";
2
+ import { createChart } from "./index.js";
3
+ const EmberwickChart = forwardRef(function EmberwickChart2(props, ref) {
4
+ const {
5
+ data,
6
+ feed,
7
+ options,
8
+ theme,
9
+ priceMode,
10
+ animate,
11
+ magnet,
12
+ onCrosshair,
13
+ className,
14
+ style,
15
+ ...rest
16
+ } = props;
17
+ const hostRef = useRef(null);
18
+ const chartRef = useRef(null);
19
+ const crosshairRef = useRef(onCrosshair);
20
+ crosshairRef.current = onCrosshair;
21
+ useEffect(() => {
22
+ const chart = createChart(hostRef.current, {
23
+ ...options || {},
24
+ ...theme ? { theme } : {},
25
+ ...animate !== void 0 ? { animate } : {},
26
+ ...magnet !== void 0 ? { magnet } : {}
27
+ });
28
+ chartRef.current = chart;
29
+ const off = chart.subscribe("crosshair", (payload) => {
30
+ const fn = crosshairRef.current;
31
+ if (fn) fn(payload);
32
+ });
33
+ return () => {
34
+ off();
35
+ chart.destroy();
36
+ chartRef.current = null;
37
+ };
38
+ }, []);
39
+ useImperativeHandle(ref, () => ({
40
+ get chart() {
41
+ return chartRef.current;
42
+ }
43
+ }), []);
44
+ useEffect(() => {
45
+ if (chartRef.current && data) chartRef.current.setData(data);
46
+ }, [data]);
47
+ useEffect(() => {
48
+ if (!chartRef.current) return;
49
+ if (feed) chartRef.current.setFeed(feed);
50
+ else chartRef.current.detachFeed();
51
+ }, [feed]);
52
+ useEffect(() => {
53
+ if (chartRef.current && theme) chartRef.current.setTheme(theme);
54
+ }, [theme]);
55
+ useEffect(() => {
56
+ if (chartRef.current && priceMode) chartRef.current.setPriceMode(priceMode);
57
+ }, [priceMode]);
58
+ useEffect(() => {
59
+ if (chartRef.current && animate !== void 0) chartRef.current.setAnimate(animate);
60
+ }, [animate]);
61
+ useEffect(() => {
62
+ if (chartRef.current && magnet !== void 0) chartRef.current.setMagnet(magnet);
63
+ }, [magnet]);
64
+ return createElement("div", {
65
+ ref: hostRef,
66
+ className,
67
+ // The chart measures its container, so it needs real dimensions.
68
+ style: { position: "relative", width: "100%", height: "100%", ...style || {} },
69
+ ...rest
70
+ });
71
+ });
72
+ export {
73
+ EmberwickChart,
74
+ EmberwickChart as default
75
+ };
76
+ //# sourceMappingURL=react.js.map
package/react.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","sources":["../src/adapters/react/EmberwickChart.js"],"sourcesContent":["import { createElement, forwardRef, useEffect, useImperativeHandle, useRef } from 'react'\nimport { createChart } from '../../chart/index.js'\n\n/**\n * React adapter.\n *\n * Deliberately written with createElement instead of JSX so the library build\n * needs no JSX transform and no react/jsx-runtime external.\n *\n * The chart instance is created ONCE and then driven imperatively by effects —\n * re-creating a canvas chart on every render would throw away the animation\n * state (and the user's pan/zoom position) on each prop change.\n *\n * <EmberwickChart feed={feed} theme={{ up: '#0f0' }} onCrosshair={fn} />\n *\n * Imperative escape hatch:\n * const ref = useRef(null)\n * <EmberwickChart ref={ref} />\n * ref.current.chart.snapToRealtime()\n */\nexport const EmberwickChart = forwardRef(function EmberwickChart(props, ref) {\n const {\n data,\n feed,\n options,\n theme,\n priceMode,\n animate,\n magnet,\n onCrosshair,\n className,\n style,\n ...rest\n } = props\n\n const hostRef = useRef(null)\n const chartRef = useRef(null)\n const crosshairRef = useRef(onCrosshair)\n\n // Keep the latest callback without re-subscribing on every render.\n crosshairRef.current = onCrosshair\n\n // --- create / destroy (once) ---------------------------------------------\n useEffect(() => {\n const chart = createChart(hostRef.current, {\n ...(options || {}),\n ...(theme ? { theme } : {}),\n ...(animate !== undefined ? { animate } : {}),\n ...(magnet !== undefined ? { magnet } : {}),\n })\n chartRef.current = chart\n\n const off = chart.subscribe('crosshair', (payload) => {\n const fn = crosshairRef.current\n if (fn) fn(payload)\n })\n\n return () => {\n off()\n chart.destroy()\n chartRef.current = null\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // --- imperative handle ----------------------------------------------------\n useImperativeHandle(ref, () => ({\n get chart() {\n return chartRef.current\n },\n }), [])\n\n // --- prop -> chart wiring -------------------------------------------------\n useEffect(() => {\n if (chartRef.current && data) chartRef.current.setData(data)\n }, [data])\n\n useEffect(() => {\n if (!chartRef.current) return\n if (feed) chartRef.current.setFeed(feed)\n else chartRef.current.detachFeed()\n }, [feed])\n\n useEffect(() => {\n if (chartRef.current && theme) chartRef.current.setTheme(theme)\n }, [theme])\n\n useEffect(() => {\n if (chartRef.current && priceMode) chartRef.current.setPriceMode(priceMode)\n }, [priceMode])\n\n useEffect(() => {\n if (chartRef.current && animate !== undefined) chartRef.current.setAnimate(animate)\n }, [animate])\n\n useEffect(() => {\n if (chartRef.current && magnet !== undefined) chartRef.current.setMagnet(magnet)\n }, [magnet])\n\n return createElement('div', {\n ref: hostRef,\n className,\n // The chart measures its container, so it needs real dimensions.\n style: { position: 'relative', width: '100%', height: '100%', ...(style || {}) },\n ...rest,\n })\n})\n\nexport default EmberwickChart\n"],"names":["EmberwickChart"],"mappings":";;AAoBY,MAAC,iBAAiB,WAAW,SAASA,gBAAe,OAAO,KAAK;AAC3E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACP,IAAM;AAEJ,QAAM,UAAU,OAAO,IAAI;AAC3B,QAAM,WAAW,OAAO,IAAI;AAC5B,QAAM,eAAe,OAAO,WAAW;AAGvC,eAAa,UAAU;AAGvB,YAAU,MAAM;AACd,UAAM,QAAQ,YAAY,QAAQ,SAAS;AAAA,MACzC,GAAI,WAAW,CAAA;AAAA,MACf,GAAI,QAAQ,EAAE,MAAK,IAAK;MACxB,GAAI,YAAY,SAAY,EAAE,QAAO,IAAK,CAAA;AAAA,MAC1C,GAAI,WAAW,SAAY,EAAE,OAAM,IAAK,CAAA;AAAA,IAC9C,CAAK;AACD,aAAS,UAAU;AAEnB,UAAM,MAAM,MAAM,UAAU,aAAa,CAAC,YAAY;AACpD,YAAM,KAAK,aAAa;AACxB,UAAI,GAAI,IAAG,OAAO;AAAA,IACpB,CAAC;AAED,WAAO,MAAM;AACX,UAAG;AACH,YAAM,QAAO;AACb,eAAS,UAAU;AAAA,IACrB;AAAA,EAEF,GAAG,CAAA,CAAE;AAGL,sBAAoB,KAAK,OAAO;AAAA,IAC9B,IAAI,QAAQ;AACV,aAAO,SAAS;AAAA,IAClB;AAAA,EACJ,IAAM,CAAA,CAAE;AAGN,YAAU,MAAM;AACd,QAAI,SAAS,WAAW,KAAM,UAAS,QAAQ,QAAQ,IAAI;AAAA,EAC7D,GAAG,CAAC,IAAI,CAAC;AAET,YAAU,MAAM;AACd,QAAI,CAAC,SAAS,QAAS;AACvB,QAAI,KAAM,UAAS,QAAQ,QAAQ,IAAI;AAAA,QAClC,UAAS,QAAQ,WAAU;AAAA,EAClC,GAAG,CAAC,IAAI,CAAC;AAET,YAAU,MAAM;AACd,QAAI,SAAS,WAAW,MAAO,UAAS,QAAQ,SAAS,KAAK;AAAA,EAChE,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACd,QAAI,SAAS,WAAW,UAAW,UAAS,QAAQ,aAAa,SAAS;AAAA,EAC5E,GAAG,CAAC,SAAS,CAAC;AAEd,YAAU,MAAM;AACd,QAAI,SAAS,WAAW,YAAY,OAAW,UAAS,QAAQ,WAAW,OAAO;AAAA,EACpF,GAAG,CAAC,OAAO,CAAC;AAEZ,YAAU,MAAM;AACd,QAAI,SAAS,WAAW,WAAW,OAAW,UAAS,QAAQ,UAAU,MAAM;AAAA,EACjF,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO,cAAc,OAAO;AAAA,IAC1B,KAAK;AAAA,IACL;AAAA;AAAA,IAEA,OAAO,EAAE,UAAU,YAAY,OAAO,QAAQ,QAAQ,QAAQ,GAAI,SAAS,CAAA,EAAG;AAAA,IAC9E,GAAG;AAAA,EACP,CAAG;AACH,CAAC;"}
@@ -0,0 +1,2 @@
1
+ (function(_,x){typeof exports=="object"&&typeof module!="undefined"?x(exports):typeof define=="function"&&define.amd?define(["exports"],x):(_=typeof globalThis!="undefined"?globalThis:_||self,x(_.Emberwick={}))})(this,function(_){"use strict";class x{constructor(t,i){this.container=t,this.names=i,this.canvas={},this.ctx={},this.width=0,this.height=0,this.dpr=0,this.onResize=null,getComputedStyle(t).position==="static"&&(t.style.position="relative"),i.forEach((e,n)=>{const h=document.createElement("canvas");Object.assign(h.style,{position:"absolute",left:"0",top:"0",width:"100%",height:"100%",pointerEvents:"none",zIndex:String(n+1)}),t.appendChild(h),this.canvas[e]=h,this.ctx[e]=h.getContext("2d")}),this._ro=new ResizeObserver(()=>this.measure()),this._ro.observe(t),this.measure()}measure(){const t=this.container.getBoundingClientRect(),i=Math.max(1,Math.floor(t.width)),e=Math.max(1,Math.floor(t.height)),n=Math.min(window.devicePixelRatio||1,2);if(!(i===this.width&&e===this.height&&n===this.dpr)){this.width=i,this.height=e,this.dpr=n;for(const h of this.names){const o=this.canvas[h];o.width=Math.floor(i*n),o.height=Math.floor(e*n),this.ctx[h].setTransform(n,0,0,n,0,0)}this.onResize&&this.onResize(i,e)}}composite(){const t=document.createElement("canvas");t.width=Math.floor(this.width*this.dpr),t.height=Math.floor(this.height*this.dpr);const i=t.getContext("2d");for(const e of this.names)i.drawImage(this.canvas[e],0,0);return t}destroy(){this._ro.disconnect();for(const t of this.names)this.canvas[t].remove();this.canvas={},this.ctx={}}}class q{constructor(t){this.onFrame=t,this.fps=0,this._raf=0,this._dirty=new Set,this._last=0,this._running=!1,this._frames=0,this._fpsAt=0,this._tick=this._tick.bind(this)}invalidate(...t){if(!t.length)this._dirty.add("all");else for(const i of t)this._dirty.add(i);this._schedule()}start(){this._running||(this._running=!0,this._last=performance.now(),this._fpsAt=this._last,this.invalidate("all"))}stop(){this._running=!1,this._raf&&cancelAnimationFrame(this._raf),this._raf=0}_schedule(){this._raf||!this._running||(this._raf=requestAnimationFrame(this._tick))}_tick(t){if(this._raf=0,!this._running)return;const i=Math.min(Math.max(t-this._last,1),64);this._last=t,this._frames++,t-this._fpsAt>=500&&(this.fps=Math.round(this._frames*1e3/(t-this._fpsAt)),this._frames=0,this._fpsAt=t);const e=this._dirty;this._dirty=new Set;let n=!1;try{n=this.onFrame(e,i,t)===!0}catch(h){console.error("[Emberwick] frame error",h)}(n||this._dirty.size)&&this._schedule()}}const F=s=>1-Math.pow(1-s,3),G=s=>s<.5?4*s*s*s:1-Math.pow(-2*s+2,3)/2;class k{constructor(t=0,i=90){this.value=t,this.target=t,this.tau=i}set(t){this.target=t}jump(t){this.value=t,this.target=t}get settled(){const t=1e-9+Math.abs(this.target)*1e-6;return Math.abs(this.target-this.value)<=t}tick(t){return this.settled?(this.value=this.target,!1):(this.value+=(this.target-this.value)*(1-Math.exp(-t/this.tau)),!0)}}class z{constructor(t=200,i=F){this.duration=t,this.ease=i,this.t=t}restart(){this.t=0}get done(){return this.t>=this.duration}get progress(){return this.ease(Math.min(1,this.t/this.duration))}tick(t){return this.done?!1:(this.t+=t,!0)}}const L=(s,t,i)=>s<t?t:s>i?i:s;class I{constructor({spacing:t=9,minSpacing:i=.8,maxSpacing:e=160,rightOffset:n=12}={}){this.minSpacing=i,this.maxSpacing=e,this.rightOffset=n,this.width=0,this.barCount=0,this.follow=!0,this.timeframeMs=6e4,this._spacing=new k(t,65),this._right=new k(n,65),this._initial=t}get spacing(){return this._spacing.value}get right(){return this._right.value}resize(t){this.width=Math.max(1,t)}setBarCount(t){const i=t>this.barCount;if(this.barCount=t,this.follow){const e=t-1+this.rightOffset;i?this._right.set(e):this._right.jump(e)}}x(t){return this.width-(this._right.value-t)*this._spacing.value}index(t){return this._right.value-(this.width-t)/this._spacing.value}barWidth(){const t=this._spacing.value;return Math.max(1,Math.floor(t*.72))}visibleRange(){const t=Math.floor(this.index(0))-1,i=Math.ceil(this.index(this.width))+1;return{from:L(t,0,Math.max(0,this.barCount-1)),to:L(i,0,Math.max(0,this.barCount-1))}}_clampRight(t){const i=this.barCount-1+this.rightOffset+this.width/this._spacing.target,e=Math.min(4,this.barCount-1+this.rightOffset);return L(t,e,i)}panBy(t){if(!t)return!1;const i=this._clampRight(this._right.value-t/this._spacing.value);return this._right.jump(i),this.follow=!1,!0}zoomAt(t,i){const e=this._spacing.target,n=L(e*i,this.minSpacing,this.maxSpacing);if(Math.abs(n-e)<1e-9)return!1;const h=this.follow?this.width:t,u=this._right.target-(this.width-h)/e+(this.width-h)/n;return this._spacing.set(n),this._right.set(this._clampRight(u)),!0}snapToRealtime(){this.follow=!0,this._right.set(this.barCount-1+this.rightOffset)}reset(){this._spacing.set(this._initial),this.snapToRealtime()}tick(t){const i=this._spacing.tick(t),e=this._right.tick(t);return i||e}get settled(){return this._spacing.settled&&this._right.settled}}const V=(s,t,i)=>s<t?t:s>i?i:s;class P{constructor({mode:t="linear",tau:i=120,marginTop:e=.12,marginBottom:n=.12}={}){this.mode=t,this.marginTop=e,this.marginBottom=n,this.auto=!0,this.top=0,this.height=1,this._lo=new k(0,i),this._hi=new k(1,i),this._primed=!1}_fwd(t){return this.mode==="log"?Math.log(Math.max(t,1e-9)):t}_inv(t){return this.mode==="log"?Math.exp(t):t}setMode(t){if(t===this.mode)return;const i=this._inv(this._lo.value),e=this._inv(this._hi.value);this.mode=t,this._lo.jump(this._fwd(i)),this._hi.jump(this._fwd(e))}layout(t,i){this.top=t,this.height=Math.max(1,i)}get lo(){return this._inv(this._lo.value)}get hi(){return this._inv(this._hi.value)}y(t){const i=this._lo.value,e=this._hi.value,n=(this._fwd(t)-i)/(e-i||1);return this.top+this.height*(1-n)}price(t){const i=this._lo.value,e=this._hi.value,n=1-(t-this.top)/this.height;return this._inv(i+n*(e-i))}fit(t,i,e,n){if(!this.auto||!t.length)return;let h=1/0,o=-1/0;for(let v=i;v<=e;v++){const a=t[v];a&&(a.low<h&&(h=a.low),a.high>o&&(o=a.high))}if(n&&(n.low<h&&(h=n.low),n.high>o&&(o=n.high)),!isFinite(h)||!isFinite(o))return;let p=this._fwd(h),u=this._fwd(o),l=(u-p)*this.marginTop;l>0||(l=Math.abs(u)*.01||1),p-=l,u+=(u-p)*0+l,this._lo.set(p),this._hi.set(u),this._primed||(this._lo.jump(p),this._hi.jump(u),this._primed=!0)}scaleBy(t){this.auto=!1;const i=this._lo.target,e=this._hi.target,n=(i+e)/2,h=(e-i)/2*V(t,.2,5);this._lo.set(n-h),this._hi.set(n+h)}resetAuto(){this.auto=!0}tick(t){const i=this._lo.tick(t),e=this._hi.tick(t);return i||e}}const A={background:"#0b0e14",grid:"rgba(255,255,255,0.045)",axisLine:"rgba(255,255,255,0.10)",text:"#8b93a7",textStrong:"#e6e9ef",up:"#26a69a",down:"#ef5350",upFill:"#26a69a",downFill:"#ef5350",wickUp:"#26a69a",wickDown:"#ef5350",volumeUp:"rgba(38,166,154,0.30)",volumeDown:"rgba(239,83,80,0.30)",crosshair:"rgba(255,255,255,0.32)",labelBg:"#2a3040",labelText:"#e6e9ef",tagText:"#06080d",font:'11px ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif',priceAxisWidth:68,timeAxisHeight:26},J={...A,background:"#ffffff",grid:"rgba(0,0,0,0.06)",axisLine:"rgba(0,0,0,0.14)",text:"#6b7280",textStrong:"#111827",labelBg:"#374151",volumeUp:"rgba(38,166,154,0.25)",volumeDown:"rgba(239,83,80,0.25)",crosshair:"rgba(0,0,0,0.35)",tagText:"#ffffff"};class H{constructor(t=55){this.enabled=!0,this.o=new k(0,t),this.h=new k(0,t),this.l=new k(0,t),this.c=new k(0,t),this.vol=new k(0,t*2),this.spawn=new z(240),this._has=!1,this._time=null}setTarget(t){if(!t){this._has=!1;return}(!this._has||t.time!==this._time)&&(this.o.jump(t.open),this.h.jump(t.open),this.l.jump(t.open),this.c.jump(t.open),this.vol.jump(0),this.spawn.restart(),this._time=t.time,this._has=!0),this.o.set(t.open),this.h.set(t.high),this.l.set(t.low),this.c.set(t.close),this.vol.set(t.volume||0)}reset(){this._has=!1,this._time=null}tick(t){if(!this._has)return!1;let i=!1;return this.o.tick(t)&&(i=!0),this.h.tick(t)&&(i=!0),this.l.tick(t)&&(i=!0),this.c.tick(t)&&(i=!0),this.vol.tick(t)&&(i=!0),this.spawn.tick(t)&&(i=!0),i}read(t){if(!this._has||!this.enabled||t.time!==this._time)return t;const i=this.o.value,e=this.c.value;return{time:t.time,open:i,close:e,high:Math.max(this.h.value,i,e),low:Math.min(this.l.value,i,e),volume:this.vol.value,_spawn:this.spawn.progress}}}class j{constructor({friction:t=.92,min:i=.015}={}){this.friction=t,this.min=i,this.v=0,this.active=!1}sample(t,i){if(i<=0)return;const e=t/i;this.v=this.v*.6+e*.4,this.active=!1}release(){Math.abs(this.v)>this.min&&(this.active=!0)}stop(){this.v=0,this.active=!1}tick(t){if(!this.active)return 0;const i=this.v*t;return this.v*=Math.pow(this.friction,t/16.6667),Math.abs(this.v)<this.min&&this.stop(),i}}function N(s,t){const i=s/Math.max(1,t);if(!(i>0)||!isFinite(i))return 1;const e=Math.pow(10,Math.floor(Math.log10(i))),n=i/e;return(n<1.5?1:n<3?2:n<7?5:10)*e}function B(s,t,i){const e=N(t-s,i),n=[],h=Math.ceil(s/e)*e;for(let o=h;o<=t+e*1e-9;o+=e)n.push(o);return{ticks:n,step:e}}function D(s){return!isFinite(s)||s<=0?2:s>=100?0:s>=1?2:Math.min(8,Math.ceil(-Math.log10(s))+1)}function Q(s){const t=[1,2,5,10,15,20,30,60,120,240,480,960,1920,3840,7680];for(const i of t)if(i>=s)return i;return Math.ceil(s/1e3)*1e3}const R=s=>String(s).padStart(2,"0");function Z(s,t){const i=new Date(s);return t>=864e5?`${i.getDate()} ${i.toLocaleString("en",{month:"short"})}`:i.getHours()===0&&i.getMinutes()===0?`${i.getDate()} ${i.toLocaleString("en",{month:"short"})}`:`${R(i.getHours())}:${R(i.getMinutes())}`}function tt(s){const t=new Date(s);return`${t.getFullYear()}-${R(t.getMonth()+1)}-${R(t.getDate())} ${R(t.getHours())}:${R(t.getMinutes())}`}function it(s,t){const{theme:i,ts:e,ps:n,plot:h,bars:o,width:p,height:u}=t;s.clearRect(0,0,p,u),s.fillStyle=i.background,s.fillRect(0,0,p,u),s.font=i.font,s.textBaseline="middle";const l=Math.max(2,Math.floor(h.h/58)),{ticks:v,step:a}=B(n.lo,n.hi,l),c=D(a);s.strokeStyle=i.grid,s.lineWidth=1,s.beginPath();for(const f of v){const d=Math.round(n.y(f))+.5;d<h.y||d>h.y+h.h||(s.moveTo(0,d),s.lineTo(h.w,d))}s.stroke(),s.fillStyle=i.text,s.textAlign="left";for(const f of v){const d=Math.round(n.y(f));d<h.y+6||d>h.y+h.h-6||s.fillText(f.toFixed(c),h.w+8,d)}if(o.length){const f=Math.ceil(74/Math.max(1e-4,e.spacing)),d=Q(f),{from:T,to:b}=e.visibleRange(),S=Math.ceil(T/d)*d;s.strokeStyle=i.grid,s.beginPath();for(let g=S;g<=b;g+=d){const r=Math.round(e.x(g))+.5;r<0||r>h.w||(s.moveTo(r,0),s.lineTo(r,h.h))}s.stroke(),s.fillStyle=i.text,s.textAlign="center";const w=h.h+i.timeAxisHeight/2;for(let g=S;g<=b;g+=d){const r=o[g];if(!r)continue;const m=Math.round(e.x(g));m<28||m>h.w-28||s.fillText(Z(r.time,e.timeframeMs),m,w)}}s.strokeStyle=i.axisLine,s.beginPath(),s.moveTo(h.w+.5,0),s.lineTo(h.w+.5,h.h),s.moveTo(0,h.h+.5),s.lineTo(p,h.h+.5),s.stroke()}function st(s,t){const{theme:i,ts:e,ps:n,plot:h,bars:o,width:p,height:u,live:l,volumeRatio:v}=t;if(s.clearRect(0,0,p,u),!o.length)return;const{from:a,to:c}=e.visibleRange(),f=e.barWidth(),d=f/2,T=f<=2,b=h.h*v,S=h.y+h.h-b;let w=0;for(let r=a;r<=c;r++){const m=o[r];m&&m.volume>w&&(w=m.volume)}if(w>0)for(let r=a;r<=c;r++){let m=o[r];if(!m)continue;l&&r===o.length-1&&(m=l);const M=e.x(r);if(M<-f||M>h.w+f)continue;const y=m.volume/w*b*.9;s.fillStyle=m.close>=m.open?i.volumeUp:i.volumeDown,s.fillRect(Math.round(M-d),S+(b-y),Math.max(1,f),y)}for(let r=a;r<=c;r++){let m=o[r];if(!m)continue;const M=r===o.length-1;l&&M&&(m=l);const y=e.x(r);if(y<-f||y>h.w+f)continue;const C=m.close>=m.open,at=C?i.up:i.down,U=n.y(m.open),W=n.y(m.close),rt=n.y(m.high),lt=n.y(m.low);let K=1;l&&M&&typeof m._spawn=="number"&&(K=.35+.65*m._spawn);const X=Math.round(y)+(f%2?.5:0);if(s.strokeStyle=C?i.wickUp:i.wickDown,s.lineWidth=Math.max(1,Math.min(2,f*.16)),s.beginPath(),s.moveTo(X,rt),s.lineTo(X,lt),s.stroke(),T)continue;const ct=Math.min(U,W),ut=Math.max(1,Math.abs(W-U)),Y=Math.max(1,f*K);s.fillStyle=at,s.fillRect(Math.round(y-Y/2),Math.round(ct),Math.round(Y),Math.round(ut))}const g=l||o[o.length-1];if(g){const r=Math.round(n.y(g.close))+.5;if(r>h.y&&r<h.y+h.h){const m=g.close>=g.open;s.save(),s.setLineDash([3,3]),s.strokeStyle=m?i.up:i.down,s.lineWidth=1,s.globalAlpha=.7,s.beginPath(),s.moveTo(0,r),s.lineTo(h.w,r),s.stroke(),s.restore();const{step:M}=B(n.lo,n.hi,Math.max(2,Math.floor(h.h/58))),y=g.close.toFixed(D(M));s.font=i.font,s.textBaseline="middle",s.textAlign="left";const C=s.measureText(y).width;s.fillStyle=m?i.up:i.down,s.fillRect(h.w+1,r-9,C+14,18),s.fillStyle=i.tagText,s.fillText(y,h.w+8,r)}}}function et(s,t){const{theme:i,ts:e,ps:n,plot:h,bars:o,width:p,height:u,cursor:l,magnet:v}=t;if(s.clearRect(0,0,p,u),!l||!o.length||l.x<0||l.x>h.w||l.y<0||l.y>h.h)return;const a=Math.round(e.index(l.x)),c=o[a];let f=l.x,d=l.y;if(c&&(f=e.x(a),v)){const w=[c.open,c.high,c.low,c.close];let g=null,r=1/0;for(const m of w){const M=n.y(m),y=Math.abs(M-l.y);y<r&&(r=y,g=M)}r<22&&(d=g)}s.save(),s.setLineDash([4,4]),s.strokeStyle=i.crosshair,s.lineWidth=1,s.beginPath(),s.moveTo(Math.round(f)+.5,0),s.lineTo(Math.round(f)+.5,h.h),s.moveTo(0,Math.round(d)+.5),s.lineTo(h.w,Math.round(d)+.5),s.stroke(),s.restore(),s.font=i.font,s.textBaseline="middle";const{step:T}=B(n.lo,n.hi,Math.max(2,Math.floor(h.h/58))),b=n.price(d).toFixed(D(T));s.textAlign="left";const S=s.measureText(b).width;if(s.fillStyle=i.labelBg,s.fillRect(h.w+1,d-9,S+14,18),s.fillStyle=i.labelText,s.fillText(b,h.w+8,d),c){const w=tt(c.time);s.textAlign="center";const g=s.measureText(w).width,r=Math.min(Math.max(f,g/2+6),h.w-g/2-6);s.fillStyle=i.labelBg,s.fillRect(r-g/2-7,h.h+3,g+14,18),s.fillStyle=i.labelText,s.fillText(w,r,h.h+12)}}class O{constructor(t,i={}){if(!t)throw new Error("Chart: container element is required");this.container=t,this.theme={...A,...i.theme||{}},this.options={volumeRatio:.18,magnet:!0,animate:!0,...i},this.bars=[],this.feed=null,this._unsub=null,this._loadingHistory=!1,this._exhausted=!1,this._listeners={crosshair:new Set,visibleRange:new Set},this.layers=new x(t,["base","main","overlay"]),this.ts=new I(i.timeScale),this.ps=new P(i.priceScale),this.live=new H,this.live.enabled=this.options.animate!==!1,this.inertia=new j,this.cursor=null,this.plot={x:0,y:0,w:1,h:1},this.loop=new q((e,n)=>this._frame(e,n)),this.layers.onResize=()=>{this._layout(),this.loop.invalidate("all")},this._layout(),this._bindEvents(),this.loop.start()}_layout(){const{width:t,height:i}=this.layers,e=Math.max(1,t-this.theme.priceAxisWidth),n=Math.max(1,i-this.theme.timeAxisHeight);this.plot={x:0,y:0,w:e,h:n},this.ts.resize(e),this.ps.layout(0,n)}setData(t){this.bars=Array.isArray(t)?t.slice():[],this._exhausted=!1,this.bars.length>1&&(this.ts.timeframeMs=this.bars[1].time-this.bars[0].time),this.ts.setBarCount(this.bars.length),this.ts.snapToRealtime(),this.live.reset(),this.ps._primed=!1,this.loop.invalidate("all")}update(t){if(!t)return;const i=this.bars.length;if(i&&this.bars[i-1].time===t.time)this.bars[i-1]=t;else{this.append(t);return}this.live.setTarget(t),this.loop.invalidate("main")}append(t){if(!t)return;const i=this.bars.length;i&&t.time<=this.bars[i-1].time?this.bars[i-1]=t:(this.bars.push(t),this.ts.setBarCount(this.bars.length)),this.live.setTarget(t),this.loop.invalidate("main")}async setFeed(t){if(this.detachFeed(),this.feed=t,!t)return;this.ts.timeframeMs=t.timeframe||this.ts.timeframeMs;const i=await t.getBars({symbol:t.symbol,timeframe:t.timeframe,to:null,limit:this.options.initialBars||1500});this.setData(i),typeof t.prime=="function"&&t.prime(i[i.length-1]),this._unsub=t.subscribe(e=>{!e||!e.bar||(e.type==="append"?this.append(e.bar):this.update(e.bar))})}detachFeed(){this._unsub&&this._unsub(),this._unsub=null,this.feed=null}async _maybeLoadHistory(){if(this._loadingHistory||this._exhausted||!this.feed)return;const{from:t}=this.ts.visibleRange();if(!(t>80||!this.bars.length)){this._loadingHistory=!0;try{const i=this.bars[0].time,e=await this.feed.getBars({symbol:this.feed.symbol,timeframe:this.feed.timeframe,to:i,limit:1e3});if(!e||!e.length)this._exhausted=!0;else{const n=e.filter(h=>h.time<i);if(!n.length)this._exhausted=!0;else{this.bars=n.concat(this.bars);const h=this.ts.follow;this.ts.barCount=this.bars.length,this.ts._right.jump(this.ts._right.value+n.length),this.ts._right.set(this.ts._right.target+n.length),this.ts.follow=h,this.loop.invalidate("all")}}}catch(i){console.error("[Emberwick] history load failed",i),this._exhausted=!0}finally{this._loadingHistory=!1}}}_bindEvents(){const t=this.container;t.style.touchAction="none",t.style.cursor="crosshair";let i=!1,e=null,n=0,h=0,o=0,p=!1;const u=new Map;let l=0;const v=a=>{const c=t.getBoundingClientRect();return{x:a.clientX-c.left,y:a.clientY-c.top}};this._onDown=a=>{if(u.set(a.pointerId,v(a)),u.size===2){const[f,d]=[...u.values()];l=Math.hypot(f.x-d.x,f.y-d.y),i=!1;return}const c=v(a);i=!0,p=!1,e=c.x>this.plot.w?"price":c.y>this.plot.h?"time":"pan",n=c.x,h=c.y,o=performance.now(),this.inertia.stop(),t.setPointerCapture(a.pointerId)},this._onMove=a=>{const c=v(a);if(u.has(a.pointerId)&&u.set(a.pointerId,c),u.size===2){const[S,w]=[...u.values()],g=Math.hypot(S.x-w.x,S.y-w.y);if(l>0&&g>0){const r=(S.x+w.x)/2;this.ts.zoomAt(r,g/l),this.loop.invalidate("all")}l=g;return}if(this.cursor=c,this._emitCrosshair(c),this.loop.invalidate("overlay"),!i)return;const f=performance.now(),d=f-o,T=c.x-n,b=c.y-h;(Math.abs(T)>1||Math.abs(b)>1)&&(p=!0),e==="pan"?(this.ts.panBy(T),this.inertia.sample(T,d),this.loop.invalidate("all"),this._maybeLoadHistory()):e==="price"?(this.ps.scaleBy(1+b/220),this.loop.invalidate("all")):e==="time"&&(this.ts.zoomAt(this.plot.w,1-T/260),this.loop.invalidate("all")),n=c.x,h=c.y,o=f},this._onUp=a=>{u.delete(a.pointerId),u.size<2&&(l=0),i&&e==="pan"&&p&&(this.inertia.release(),this.loop.invalidate("all")),i=!1,e=null;try{t.releasePointerCapture(a.pointerId)}catch{}},this._onLeave=()=>{this.cursor=null,this._emitCrosshair(null),this.loop.invalidate("overlay")},this._onWheel=a=>{a.preventDefault();const c=t.getBoundingClientRect(),f=a.clientX-c.left,d=Math.pow(.999,a.deltaY);this.ts.zoomAt(f,d),this.loop.invalidate("all"),this._maybeLoadHistory()},this._onDbl=()=>{this.ts.reset(),this.ps.resetAuto(),this.loop.invalidate("all")},this._onKey=a=>{const c=a.shiftKey?120:40;if(a.key==="ArrowLeft")this.ts.panBy(c),this.loop.invalidate("all"),this._maybeLoadHistory();else if(a.key==="ArrowRight")this.ts.panBy(-c),this.loop.invalidate("all");else if(a.key==="+"||a.key==="=")this.ts.zoomAt(this.plot.w/2,1.2),this.loop.invalidate("all");else if(a.key==="-"||a.key==="_")this.ts.zoomAt(this.plot.w/2,.8),this.loop.invalidate("all");else return;a.preventDefault()},t.addEventListener("pointerdown",this._onDown),t.addEventListener("pointermove",this._onMove),t.addEventListener("pointerup",this._onUp),t.addEventListener("pointercancel",this._onUp),t.addEventListener("pointerleave",this._onLeave),t.addEventListener("wheel",this._onWheel,{passive:!1}),t.addEventListener("dblclick",this._onDbl),t.addEventListener("keydown",this._onKey),t.hasAttribute("tabindex")||t.setAttribute("tabindex","0")}_emitCrosshair(t){if(!this._listeners.crosshair.size)return;let i=null;if(t&&this.bars.length&&t.x<=this.plot.w&&t.y<=this.plot.h){const e=Math.round(this.ts.index(t.x)),n=this.bars[e];n&&(i={index:e,bar:n,price:this.ps.price(t.y)})}for(const e of this._listeners.crosshair)e(i)}subscribe(t,i){const e=this._listeners[t];if(!e)throw new Error(`Chart: unknown event "${t}"`);return e.add(i),()=>e.delete(i)}_frame(t,i){let e=!1;this.ts.tick(i)&&(e=!0);const n=this.inertia.tick(i);n&&(this.ts.panBy(n),e=!0,this._maybeLoadHistory()),this.live.tick(i)&&(e=!0);const{from:h,to:o}=this.ts.visibleRange(),p=this.bars.length-1,u=this.bars.length?this.live.read(this.bars[p]):null,l=u&&o>=p?u:null;this.ps.fit(this.bars,h,o,l),this.ps.tick(i)&&(e=!0);const v=e||t.has("all")||t.has("base")||t.has("main"),a={theme:this.theme,ts:this.ts,ps:this.ps,plot:this.plot,bars:this.bars,width:this.layers.width,height:this.layers.height,live:l,volumeRatio:this.options.volumeRatio,cursor:this.cursor,magnet:this.options.magnet};return v&&(it(this.layers.ctx.base,a),st(this.layers.ctx.main,a)),(v||t.has("overlay"))&&et(this.layers.ctx.overlay,a),e}get fps(){return this.loop.fps}setTheme(t){this.theme={...this.theme,...t},this._layout(),this.loop.invalidate("all")}setPriceMode(t){this.ps.setMode(t),this.loop.invalidate("all")}setAnimate(t){this.live.enabled=!!t,this.loop.invalidate("all")}setMagnet(t){this.options.magnet=!!t,this.loop.invalidate("overlay")}snapToRealtime(){this.ts.snapToRealtime(),this.ps.resetAuto(),this.loop.invalidate("all")}toImage(){return this.layers.composite().toDataURL("image/png")}destroy(){const t=this.container;t.removeEventListener("pointerdown",this._onDown),t.removeEventListener("pointermove",this._onMove),t.removeEventListener("pointerup",this._onUp),t.removeEventListener("pointercancel",this._onUp),t.removeEventListener("pointerleave",this._onLeave),t.removeEventListener("wheel",this._onWheel),t.removeEventListener("dblclick",this._onDbl),t.removeEventListener("keydown",this._onKey),this.detachFeed(),this.loop.stop(),this.layers.destroy(),this._listeners.crosshair.clear(),this._listeners.visibleRange.clear(),this.bars=[]}}class ${constructor({symbol:t="DEMO",timeframe:i=6e4}={}){this.symbol=t,this.timeframe=i}async getBars({symbol:t,timeframe:i,to:e,limit:n}){throw new Error("DataFeed.getBars() not implemented")}subscribe(t){return()=>{}}destroy(){}}function E(s){let t=s>>>0;return function(){t=t+1831565813|0;let i=Math.imul(t^t>>>15,1|t);return i=i+Math.imul(i^i>>>7,61|i)^i,((i^i>>>14)>>>0)/4294967296}}class ht extends ${constructor({symbol:t="EMBR",timeframe:i=6e4,seed:e=7,start:n=100,volatility:h=.0022,drift:o=2e-5,ticksPerSecond:p=8,speed:u=1}={}){super({symbol:t,timeframe:i}),this.seed=e,this.start=n,this.volatility=h,this.drift=o,this.ticksPerSecond=p,this.speed=u,this._rnd=E(e),this._handlers=new Set,this._timer=null,this._forming=null,this._last=n,this._vol=h,this._anchorTime=Math.floor(Date.now()/i)*i}_gauss(){let t=0,i=0;for(;t===0;)t=this._rnd();for(;i===0;)i=this._rnd();return Math.sqrt(-2*Math.log(t))*Math.cos(2*Math.PI*i)}_step(t){const i=this._gauss();return this._vol+=(this.volatility-this._vol)*.02+Math.abs(i)*this.volatility*.015,this._vol=Math.min(this._vol,this.volatility*6),Math.max(.01,t*(1+this.drift+i*this._vol))}_makeBar(t,i){let e=i;const n=14;let h=i,o=i;for(let l=0;l<n;l++)e=this._step(e),e>h&&(h=e),e<o&&(o=e);const p=Math.max(1e-9,h-o),u=Math.round((300+this._rnd()*900)*(1+p/i*260));return{time:t,open:i,high:h,low:o,close:e,volume:u}}async getBars({to:t,limit:i=1500,timeframe:e=this.timeframe}={}){const n=t==null?this._anchorTime:t,h=[],o=n-i*e,p=E(this.seed^Math.floor(o/e)),u=this._rnd;this._rnd=p;let l=this.start*(1+(p()-.5)*.04);for(let v=0;v<i;v++){const a=o+v*e,c=this._makeBar(a,l);l=c.close,h.push(c)}return this._rnd=u,t==null&&(this._last=h.length?h[h.length-1].close:this.start),h}subscribe(t){return this._handlers.add(t),this._timer||this._start(),()=>{this._handlers.delete(t),this._handlers.size||this.stop()}}_emit(t){for(const i of this._handlers)i(t)}_start(){const t=Math.max(16,1e3/this.ticksPerSecond);this._timer=setInterval(()=>this._tick(),t)}prime(t){t&&(this._last=t.close,this._forming={...t})}_tick(){const t=this.timeframe/this.speed,i=Date.now(),e=Math.floor(i/t)*t;if(!this._forming||this._forming.time!==e){const o=this._last;this._forming={time:e,open:o,high:o,low:o,close:o,volume:0},this._emit({type:"append",bar:{...this._forming}});return}const n=this._step(this._last);this._last=n;const h=this._forming;h.close=n,n>h.high&&(h.high=n),n<h.low&&(h.low=n),h.volume+=Math.round(20+this._rnd()*120),this._emit({type:"update",bar:{...h}})}setSpeed(t){this.speed=t}setTicksPerSecond(t){this.ticksPerSecond=t,this._timer&&(this.stop(),this._start())}setPaused(t){t?this.stop():!this._timer&&this._handlers.size&&this._start()}get paused(){return!this._timer}stop(){this._timer&&clearInterval(this._timer),this._timer=null}destroy(){this.stop(),this._handlers.clear()}}function nt(s,t){return new O(s,t)}const ot="0.1.0";_.Chart=O,_.DataFeed=$,_.Inertia=j,_.LiveCandle=H,_.PriceScale=P,_.RandomFeed=ht,_.Smoothed=k,_.TimeScale=I,_.Tween=z,_.createChart=nt,_.defaultTheme=A,_.easeInOutCubic=G,_.easeOutCubic=F,_.lightTheme=J,_.mulberry32=E,_.version=ot,Object.defineProperty(_,Symbol.toStringTag,{value:"Module"})});
2
+ //# sourceMappingURL=emberwick.umd.js.map