diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,367 @@
+# Changelog
+
+All notable changes to `miso` are documented here.
+
+## 1.13.0.0
+
+### Added
+
+- **Native mobile backend.** `miso` can now target native mobile devices by
+  driving the [Lynx](https://lynxjs.org) dual-thread runtime instead of the
+  browser DOM. New `Miso.Native` entry point (`native` / `nativeWithContext`),
+  the `Miso.Native.Element.*` element / event / property / method vocabulary,
+  and main-thread event handlers for low-latency gestures. Gated behind the
+  `native` cabal flag (`-fnative`); web / WASM builds are unaffected.
+
+  Because the flag is off by default, the `Miso.Native.*` modules do not
+  appear in the Hackage-generated documentation — build locally with
+  `-fnative`, or see the `sample-app-native` directory for a worked example
+  with iOS and Android hosts.
+
+- **App-global `context`.** A single value shared by every `Component` in the
+  tree (miso's analogue of React Context): seed with `startAppWithContext`,
+  read with `getContext` (or the first argument to `view`), update with
+  `modifyContext` / `modifyContext_` / `putContext`, and opt components into
+  context-driven re-renders with `useContext`. `ComponentInfo` gained a
+  `componentInfoContext` lens. The motivating use case is propagating
+  settings such as locale or theme to every component without threading them
+  through `props`.
+
+- **Cookie Store API.** New `Miso.Cookie` module wrapping the browser's
+  [CookieStore API](https://developer.mozilla.org/en-US/docs/Web/API/CookieStore)
+  as `Effect` combinators — `cookieGet`, `cookieGetAll`, `cookieSet`,
+  `cookieDelete`, `cookieDeleteWith`, the `Cookie` record and `defaultCookie`
+  constructor, plus `_`-suffixed synchronous variants. `Miso.Subscription.Cookie`
+  adds `cookieChangeSub` for subscribing to `CookieChangeEvent`s. Requires a
+  secure context (HTTPS or `localhost`); on browsers without the API
+  (e.g. Firefox) the error callback fires and `cookieChangeSub` is a no-op.
+
+- **`canvasSub`.** New `Miso.Subscription.Canvas` module. `canvasSub` drives
+  a `<canvas>` in a tight `requestAnimationFrame` loop, bypassing virtual DOM
+  construction entirely — unlike `Miso.Canvas`, whose `draw` runs during the
+  diffing process on discrete events. Pair it with `onCreatedWith` /
+  `onDestroyed` and `startSub` / `stopSub` to start the loop when the canvas
+  mounts and stop it on unmount. The draw callback receives each frame's
+  high-resolution timestamp and a snapshot of the component's current model
+  (see the `Sub` change below), and the queued frame is cancelled before the
+  callback is freed on teardown.
+
+- **`Miso.Trace`.** A browser-console analogue of `Debug.Trace` for
+  debugging pure code such as `view` functions or helpers called from
+  `update`. `trace`, `traceId`, `traceWith`, `traceShow`, `traceShowId`,
+  `traceShowWith`, `traceM` and `traceShowM` log with `console.log`; the
+  `traceWarn*` and `traceError*` families log with `console.warn` and
+  `console.error` respectively, gaining the browser's severity filtering
+  and stack traces. `traceTo` generalises over any `MisoString -> IO ()`
+  console function from `Miso.FFI`. Like `Debug.Trace`, these are built on
+  `unsafePerformIO` and are a debugging aid only.
+
+- **Synchronous `Miso.Fetch` variants.** `_`-suffixed counterparts for the
+  whole surface — `getJSON_`, `postJSON_`, `postJSON'_`, `putJSON_`,
+  `getText_`, `postText_`, `putText_`, `getBlob_`, `postBlob_`, `putBlob_`,
+  `getFormData_`, `postFormData_`, `putFormData_`, `getUint8Array_`,
+  `postUint8Array_`, `putUint8Array_`, `getArrayBuffer_`, `postArrayBuffer_`,
+  `putArrayBuffer_`, `postImage_`, `putImage_`. Each blocks the calling
+  thread and returns `Either (Response error) (Response body)`. Best used
+  inside `Miso.Effect.io` / `io_` so the scheduler thread is not blocked.
+
+- **Cross-thread effects.** `runOnBG` and `runOnMain` (with the supporting
+  `Thread` type) dispatch an action's `update` onto the background (BTS) or
+  main (MTS) thread of the Lynx runtime. Off the native runtime, or when
+  already on the target thread, both behave as an ordinary `issue`.
+
+- **Main-thread event handlers.** `onMain` / `onMainWithOptions` in
+  `Miso.Event` register handlers that run directly on the main thread, for
+  low-latency gesture and animation work. `Miso.Native.MainThread` provides
+  `MainThreadRef` and the imperative operations those handlers drive.
+  `eventHandlerConvert` / `eventHandlerDecoder` and the `EventHandler` type
+  are exported for building custom handlers.
+
+- **Static components.** `mountStatic` and `mountStaticWithProps` mount a
+  `Component` through a `StaticPtr` (`SomeStaticComponent`), so the component
+  survives the dual-thread boundary; `vcomp_` / `vcomp` turn the resulting
+  pointer into a `View`. Unlike the non-static combinators these need no key —
+  the compile-time `StaticKey` supplies identity. To opt a statically mounted
+  child into `context` re-renders, set the field directly:
+  `mountStatic comp { useContext = True }`. `mountUseContext` is the
+  non-static equivalent.
+
+- **Every exported name is documented.** `cabal haddock` reported 118
+  undocumented exports across 34 modules — mostly the Lynx event payloads,
+  decoders, method parameter records and `Events` maps under
+  `Miso.Native.Element.*`. All now carry Haddock.
+
+- **Context-seeding SSR entry points.** `misoWithContext` and
+  `prerenderWithContext` hydrate a server-rendered page with an explicit
+  initial `context`; `setContext` seeds the global context for use from the
+  `ToHtml` renderer. `Miso.Reload` gained matching `liveWithContext` and
+  `reloadWithContext`.
+
+- **Lynx thread detection.** `getThreads`, `onBTS` and `onMTS` in `Miso.FFI`
+  report which thread the current code is executing on.
+
+- **CSS helpers.** `transition_` builds a single shorthand `transition`
+  declaration (so an imperative `transition: none` reset on the main thread
+  clears it as one key), and `cubicBezier` produces a `cubic-bezier(…)`
+  timing function.
+
+- **`Miso.DSL` additions.** `await` for awaiting a JS promise from Haskell,
+  and the `JSException` type (which now has an `Exception` instance).
+
+- **`DirectEvents`.** `VNode` carries a set of directly-dispatched events,
+  readable via `nodeDirectEvents`, used by the native runtime to skip the
+  scratch-node round trip.
+
+- **Types that were reachable but not exported.** Several types appeared in
+  exported signatures without being exported themselves, so callers could not
+  name them: `Consumed` (the payload of `Miso.Native.Element.List.Method`'s
+  callback), `GetTextBoundingRect` (the parameter of `getTextBoundingRect`),
+  `ListItemInfo`, `AnimationType` and `UIAppearanceDetailEventType` (field
+  types of exported Lynx event records), and `ComponentIds` (the type of
+  `ComponentState`'s `_componentChildren`). `Miso.JSON` now exports `ToJSON`
+  with both methods — `toJSONList` was hidden, so it could not be overridden
+  outside the module — along with the four generic-deriving classes missing
+  from its `Generics` group (`GToJSONRep`, `GToJSONSumNullary`,
+  `GFromJSONRep`, `GFromJSONSumNullary`). `Miso.Lens.Generic` likewise exports
+  the type-level machinery its `HasLens` instances mention (`GSet`,
+  `GetFieldType`, `TotalityCheck`, `And`, `Or`).
+
+- **`aeson` cabal flag.** When enabled (`-faeson`, off by default),
+  `Miso.JSON` keeps its API but is defined in terms of
+  [aeson](https://hackage.haskell.org/package/aeson): `Value`, `Object`, and
+  `Parser` become aeson's types, so existing aeson `ToJSON` / `FromJSON`
+  instances work directly with `Miso.Fetch`, `Miso.WebSocket`, and the event
+  decoders. Signatures are unchanged — the accessors still take `MisoString`
+  keys, `withArray` still passes the continuation a `[Value]`, `withNumber`
+  still passes a `Double`, and `Result` still carries `MisoString` error
+  messages. On the JS / WASM backends orphan instances make `JSString` a
+  first-class JSON citizen. Miso's own generic-deriving machinery (`GToJSON`
+  et al.) is not exported in this mode; aeson's `genericToJSON` / `Options` /
+  `camelTo2` are re-exported instead. CI runs the WASM integration suite in
+  both modes.
+
+- **`text` cabal flag on WASM.** When enabled (`-ftext`, off by default),
+  `MisoString` is `Data.Text.Text` instead of `JSString` on the WASM
+  backend too (previously this was only possible on the `VANILLA` / SSR
+  build). `Data.JSString` remains the FFI boundary type, so DOM writes
+  still convert `Text -> JSString` on the way out. Number formatting and
+  parsing take advantage of this to avoid unnecessary FFI round trips:
+  `toMisoString` on `Int` / `Word` / `Double` / `Float` builds `Text`
+  directly via `Data.Text.Lazy.Builder` (`decimal` / `realFloat`) instead
+  of allocating a throwaway `JSVal` via JS's `.toString()`, since GHC's
+  `Show` formatting is what these functions target on this backend
+  regardless. Likewise,
+  `fromMisoString` on `Int` / `Word` / `Double` / `Float` parses directly
+  with `Data.Text.Read` instead of round-tripping through
+  `JSString`/`parseInt`/`parseFloat`, while reproducing the JS parsers'
+  semantics: leading/trailing whitespace and trailing garbage are
+  ignored, a leading `+`/`-` is accepted, and integers with a `0x`/`0X`
+  prefix parse as hexadecimal. CI gained a `playwright-wasm-aeson-text`
+  target that runs the WASM integration suite with both the `aeson` and
+  `text` flags enabled together.
+
+### Changed
+
+- **Breaking: `View` and `Attribute` gained type parameters.**
+  `View context model action` and `Attribute model action`. This lets event
+  handlers read the current `model` and supports the native dual-thread
+  `static` handler protocol. `VNode` now carries a `DirectEvents` set, the
+  key moved into `SomeComponent (Maybe Key) …`, and `VComp` / `VCompStatic` /
+  `SomeStaticComponent` were restructured. Downstream `view` and attribute
+  signatures must be updated accordingly.
+
+- **Breaking: `Sub` gained a `model` type parameter.** `Sub action` is now
+  `Sub model action`, and a subscription receives a second argument — an
+  `IO model` that returns a snapshot of the component's current model:
+  `type Sub model action = Sink action -> IO model -> IO ()`. This lets
+  long-running subscriptions (like `canvasSub`) read the latest model
+  without threading it through actions. All bundled subscriptions were
+  updated; user-defined subscriptions that ignore the model need only accept
+  (and discard) the extra argument, e.g.
+  `tickSub sink _ = forever (threadDelay delay >> sink Tick)`. `mapSub`,
+  `createSub`, and `startSub` were updated accordingly.
+
+- **Breaking: `Miso.Binding` was removed.** The experimental lens-based
+  parent/child model synchronisation mechanism (`Binding`, `Bindings`,
+  `Precedence`, and the `bindings` field on `Component`) is gone, along with
+  its propagation phase in the scheduler. Use the new app-global `context`
+  for shared state, or asynchronous messaging via `broadcast` / `Miso.PubSub`
+  for point-to-point communication.
+
+- **Breaking: `parent` and `ROOT` were removed.** `Component` no longer
+  carries a `parent`; the `ROOT` marker that demarcated the top of the page
+  is unnecessary without it. Both are superseded by `context`.
+
+- **Breaking: `Miso.Types.keyed` was removed.** Use the keyed constructors
+  directly: `textKey` / `textKey_` for text, `fragment_` / `vfrag_` for
+  fragments, `mount_` / `vcomp_` / `mountStatic` for components, and
+  `key_` in the attribute list for element nodes.
+
+- **Breaking: runtime internals dropped from `Miso.FFI`.** `mountComponent`,
+  `unmountComponent` and `modelHydration` (and `getComponentContext` from
+  `Miso.FFI.Internal`) were documented as runtime-use-only and have been
+  removed as part of the dual-thread rework. They have no user-facing
+  replacement.
+
+- **Breaking: `autocomplete_` takes a `MisoString`.** It was
+  `Bool -> Attribute action`, which could only produce `"on"` / `"off"` and
+  could not express the many other valid values (`"email"`, `"new-password"`,
+  …). It is now `MisoString -> Attribute action`; replace `autocomplete_ True`
+  with `autocomplete_ "on"`.
+
+- **Breaking: `Miso.Util.Parser.endOfInput` was generalised** from
+  `Parser a ()` to `ParserT r [a] [] ()`. Call sites are unaffected unless
+  they carried an explicit type annotation.
+
+- **`MisoString` `length` and `take` are code-point based on WASM.** They
+  previously counted UTF-16 code units, so a string holding a single
+  astral-plane character (an emoji, say) reported a length of 2. They now
+  agree with `Data.Text` and with the GHCJS backend. Only the WASM backend
+  was affected.
+
+- **`context` no longer requires `ToJSON` / `FromJSON`.** The constraints
+  were unused — `context` is never sent across the dual-thread boundary.
+
+### Removed
+
+- **`Miso.String.QQ`.** The `misoString` QuasiQuoter for multiline
+  `MisoString` literals is gone. GHC's `MultilineStrings` extension
+  (GHC 9.12+) covers the use case directly — enable the pragma and write
+  triple-quoted `MisoString` literals. (`Miso.FFI.QQ` and `Miso.Lens.TH`,
+  the other `template-haskell`-flag modules, are unaffected.)
+
+### Fixed
+
+- **`Miso.Fetch`'s `none` response type no longer double-fires the success
+  callback.** `fetchCore` called the success callback directly for
+  `responseType == "none"` and then fell through into a second, unconditional
+  `.then` that called it again with `body: undefined`. Every `post*`/`put*`
+  variant that discards the response body (`postJSON`, `postJSON_`, `putText`,
+  `putBlob_`, etc.) dispatched its success action twice per request.
+
+- **Native: attribute removal actually removes the attribute.** The MTS
+  drawing context's `removeAttribute` called `__SetAttribute(node, key, '')`.
+  The engine's `Element::SetAttribute` (`lynx/core/renderer/dom/element.cc`)
+  only takes the removal branch when the value is lepus-empty
+  (`null`/`undefined`) — an empty string is an ordinary string value, so it
+  was stored in `updated_attr_map_` instead of being removed. Every prop
+  diffed off a native element (`dom.ts`'s `diffProps`, which routes native
+  removals through this path) was setting it to `''` rather than clearing
+  it. Now passes `null`.
+
+- **`rAFSub` now cancels the pending animation frame on unsubscribe.**
+  Release freed the `requestAnimationFrame` callback without cancelling the
+  frame already queued in the browser; the next frame then invoked a freed
+  callback and crashed the WASM RTS with `internal error: stg_ap_p_ret`.
+  `Miso.Canvas`'s `draw` also moved from a `syncCallback` to an
+  `asyncCallback`, fixing a `schedule: re-entered unsafely` crash when a
+  component unmounted mid-diff.
+
+- **Non-bubbling media events are registered in the capture phase.**
+  `durationchange`, `loadeddata`, `loadedmetadata` and `loadstart` do not
+  bubble, so their delegated listeners — registered in the bubble phase —
+  never received them and `onLoadedMetadata` and friends silently never
+  fired. They are now registered with capture, like the other non-bubbling
+  entries in `mediaEvents`.
+
+- **Native: the layout custom event is recognised under its released name.**
+  Released Lynx engines (e.g. LynxExplorer apps) emit it as `layout`, while
+  newer Lynx sources emit `layoutchange`; miso only listened for the latter,
+  so `onLayoutChange` never fired on released engines. `onLayout` /
+  `onLayoutMainWith` are added as aliases so apps can bind both when the
+  host engine version is unknown.
+
+- **Native: `consumeSlideEvent_` sends the shape Lynx expects.** Lynx parses
+  `consume-slide-event` as `[start, end]` angle-range pairs (degrees,
+  -180..180), but the binding serialised a flat list of angles instead of
+  paired ranges, a shape the engine silently ignores.
+
+- **`autocorrect_` and `spellcheck_` wrote to the wrong attribute.** Both
+  emitted `autocomplete` instead of their own attribute name. `spellcheck_`
+  additionally now emits `"true"` / `"false"` rather than `"on"` / `"off"`.
+
+- **`MOUNT` errors on a missing `domRef`** instead of synthesizing a bogus
+  parent node and failing later in the diff.
+
+- **Key-based model recovery is gated on `liveMode`,** so a component no
+  longer reuses an unrelated model outside of hot reload.
+
+- **`pendingStaticKey` / `pendingMainThread` are reset before plain `On`
+  handlers run,** preventing state from one handler leaking into the next.
+
+- **`-fssr` compiles together with `-fnative`.**
+
+- **`JSException` derives `Exception`,** so it can be `throw`n and `catch`ed
+  normally.
+
+- **Non-bubbling `mouseleave`/`pointerleave` are registered in the capture
+  phase.** Neither event bubbles per the DOM spec (unlike `mouseout` /
+  `pointerout`, which correctly bubble), but the delegated listener was
+  registered in the bubble phase, so `onMouseLeave` / `onPointerLeave`
+  handlers on any non-root element silently never fired. Same bug class as
+  the non-bubbling media events fix above, extended to these two.
+
+- **`vcomp` was misused as a synonym for `component` in `Miso.hs`'s
+  documentation.** `vcomp` builds a `VCompStatic` from a `StaticPtr` (the
+  static-component feature), not a `Component` from `model` / `update` /
+  `view` functions. The module's own "Your first Component" example and two
+  other doc snippets used `vcomp` where `component` was meant, so copying
+  them verbatim would not typecheck.
+
+- **`MisoString`'s `drop` is code-point-based on WASM, matching `take` /
+  `length`.** `take` / `length` were made code-point-based to fix
+  astral-character (e.g. emoji) miscounting, but `drop` was left on raw
+  UTF-16 slicing. Since `splitAt` is defined as `(take n xs, drop n xs)`,
+  the two disagreed on where position `n` falls for any string containing
+  an astral character before it, corrupting the split.
+
+- **`-ftext` `parseInt` mis-parses negative hex.** `"-0x1A"` checked for a
+  `0x` / `0X` prefix before stripping a sign, so it never matched and fell
+  through to a decimal parse of `"0x1A"`, silently returning `0` instead of
+  `-26`. The sign is now stripped first, then the remainder is checked for
+  a hex prefix.
+
+- **`eventJSON` decodes a null/undefined path as `null` instead of
+  crashing.** A decoder path landing on `null`/`undefined` — `relatedTarget`,
+  `currentTarget`, `form`, `list`, etc. are all legitimately null/undefined
+  on many real DOM events — hit `'length' in obj` on the nullish value and
+  threw `TypeError`, crashing event dispatch instead of decoding the field
+  as `null`. An intermediate nullish step one segment earlier had the same
+  problem; both are now handled.
+  
+- **`freeLifecycleHooks` frees a component's `mount`/`unmount` callbacks
+  again.** It read the `mount`/`unmount` fields off the component's own
+  rendered content root instead of the `VComp` wrapper node that actually
+  holds them (reachable one hop up, via the content root's `parent` link),
+  so `fromJSVal` always failed and `freeFunction` was never called. Every
+  non-root `Component` unmount — normal teardown and every GHCi hot-reload
+  cycle — leaked the closures `mountCallback`/`unmountCallback` capture,
+  which includes the whole `initialize` closure (`app`, `events`, `sink`,
+  `model`). See Note [Freeing event handler callbacks] in `Miso.Runtime`.
+
+### Performance
+
+- **Short-lived `JSVal` handles are freed eagerly in the WASM runtime.**
+  On the WASM backend every `JSVal` carries a weak pointer with a C
+  finalizer, and the RTS copies all of them at every GC — so the hundreds of
+  scratch handles `buildVTree` allocates per frame made GC pauses scale with
+  handle churn (~100 ms pauses with ~50 KB of live data in profiling). The
+  runtime now releases handles nothing else can reach via the new
+  `Miso.DSL.freeJSVal` (`GHC.Wasm.Prim.freeJSVal` on WASM, a no-op on other
+  backends), and event handler callbacks are freed when their vtree is
+  replaced. Measured on miso-mario, `C_FINALIZER_LIST` copied per GC dropped
+  from 7.3 MB to 2.3 MB. See Note [Freeing VTree handles] in `Miso.Runtime`.
+
+- **`StableName` dirty-checking extended to `context` and `props`.**
+  `modelCheck` was generalised to `dirtyCheck :: Eq a => a -> a -> Bool` and
+  applied to the remaining sites that performed a full structural `Eq` walk
+  on every check. The common case — two reads of the same `IORef` returning
+  the same heap object — now short-circuits on pointer equality, which
+  matters most for large contexts such as i18n translation maps.
+
+- **Main-thread events dispatch directly,** with no scratch-node or JS
+  round trip.
+
+- **The thread environment (`mts` / `bts` / `web`) is cached** as a static
+  global in the runtime rather than re-queried on every `initialize` /
+  `initComponent`.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2016-2018, David M. Johnson
+Copyright (c) 2016-2026, David M. Johnson
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,544 +1,426 @@
-<h1 align="center">miso</h1>
+
 <p align="center">
+
 <a href="https://haskell-miso.org">
-  <img width=10% src="https://emojipedia-us.s3.amazonaws.com/thumbs/240/apple/96/steaming-bowl_1f35c.png">
+
+<img width="15%" height="512" alt="Image" src="https://github.com/user-attachments/assets/384a1898-0aed-4662-9a03-8dbe5641228f" />
    </a>
-<p align="center">A <i>tasty</i> <a href="https://www.haskell.org/"><strong>Haskell</strong></a> front-end framework</p>
+<p align="center">:ramen: <a href="https://haskell-miso.org"><b>miso</b></a> | A library for building web and <a href="https://github.com/haskell-miso/miso-lynx">mobile</a> applications</p>
 </p>
 
-<p align="center">
-  <a href="https://haskell-miso-slack.herokuapp.com">
-	<img src="https://img.shields.io/badge/slack-miso-E01563.svg?style=flat-square" alt="Miso Slack">
-  </a>
-  <a href="http://hackage.haskell.org/package/miso">
-	<img src="https://img.shields.io/hackage/v/miso.svg?style=flat-square" alt="Hackage">
-  </a>
-  <a href="https://haskell.org">
-	<img src="https://img.shields.io/badge/language-Haskell-green.svg?style=flat-square" alt="Haskell">
+<p align="center"> 
+  <a href="https://matrix.to/#/#haskell-miso:matrix.org">
+    <img src="https://img.shields.io/badge/matrix.org-miso-FF4B33.svg?style=for-the-badge" alt="Matrix #haskell-miso:matrix.org">
   </a>
-  <a href="https://github.com/dmjio/miso/blob/master/LICENSE">
-	<img src="http://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat-square" alt="LICENSE">
+  <a href="https://www.npmjs.com/package/haskell-miso">  
+    <img src="https://img.shields.io/npm/v/haskell-miso?style=for-the-badge" />
+  </a>  
+  <a href="https://haskell-miso-cachix.cachix.org">
+    <img src="https://img.shields.io/badge/build-cachix-yellow.svg?style=for-the-badge" alt="Cachix">
   </a>
-  <a href="https://hydra.dmj.io">
-	<img src="https://img.shields.io/badge/build-Hydra-00BDFD.svg?style=flat-square" alt="Miso Hydra">
+  <a href="https://actions-badge.atrox.dev/dmjio/miso/goto?ref=master">
+    <img alt="Build Status" src="https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fdmjio%2Fmiso%2Fbadge%3Fref%3Dmaster&style=for-the-badge" />
   </a>
-  <a href="https://www.irccloud.com/invite?channel=%23haskell-miso&amp;hostname=irc.freenode.net&amp;port=6697&amp;ssl=1">
-	<img src="https://img.shields.io/badge/irc-%23haskell--miso-1e72ff.svg?style=flat-square" alt="IRC #haskell-miso">
+  <a href="http://hackage.haskell.org/package/miso">
+    <img src="https://img.shields.io/hackage/v/miso.svg?style=for-the-badge" alt="Hackage">
   </a>
 </p>
 
-**Miso** is a small "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" [Haskell](https://www.haskell.org/) front-end framework for quickly building highly interactive single-page web applications. It features a virtual-dom, diffing / patching algorithm, attribute and property normalization, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe [servant](https://haskell-servant.github.io/)-style routing and an extensible Subscription-based subsystem. Inspired by [Elm](http://elm-lang.org/), [Redux](http://redux.js.org/) and [Bobril](http://github.com/bobris/bobril). **Miso** is pure by default, but side effects (like `XHR`) can be introduced into the system via the `Effect` data type. **Miso** makes heavy use of the [GHCJS](https://github.com/ghcjs/ghcjs) FFI and therefore has minimal dependencies. **Miso** can be considered a shallow [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language) for modern web programming.
+<p align="center"> 
+Inspired by <a href="http://elm-lang.org/">Elm</a> and <a href="http://react.dev/">React</a>. See the <a href="https://github.com/haskell-miso">GitHub</a> org. <a href="https://try.haskell-miso.org">Try it</a>. Read the <a href="https://haddocks.haskell-miso.org/miso/Miso.html">docs</a>.
+</p>
 
+## Key features
+
+- [Virtual DOM](https://en.wikipedia.org/wiki/Virtual_DOM) with recursive diffing and patching algorithm
+- Attribute and property normalization, event delegation, and event batching
+- Model-View-Update paradigm
+- Pure by default 
+- SVG, 2D Canvas, and WebGL (via [three.js](https://threejs.org))
+- [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), [Server-Sent Events](https://github.com/haskell-miso/miso-sse), and [WebSocket](https://github.com/haskell-miso/miso-websocket) support
+- Type-safe client-side routing
+- An extensible subscription system for long-running effects and third-party library integration
+- Lifecycle hooks (`onCreated`, `onDestroyed`, `mount`, `unmount`)
+- [Component](https://react.dev/reference/react/Component), [Context](https://react.dev/learn/passing-data-deeply-with-context), [Fragment](https://react.dev/reference/react/Fragment) and [Props](https://react.dev/learn/passing-props-to-a-component) features.
+
+It makes heavy use of the [GHC JavaScript FFI](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html#javascript-ffi-in-the-wasm-backend) and maintains minimal dependencies. It can be considered a shallow [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language) for modern web programming. Compilation targets include [JavaScript](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/javascript.html) and [WebAssembly](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html) via [GHC](https://www.haskell.org/ghc/). Hot reload is provided through [WASM browser mode](https://www.tweag.io/blog/2025-04-17-wasm-ghci-browser/) integrated with [ghciwatch](https://github.com/MercuryTechnologies/ghciwatch).
+
+> [!TIP]
+> See the [miso organization](https://github.com/haskell-miso) on GitHub for the full ecosystem of packages and examples 🍜
+
 ## Table of Contents
-- [Quick Start](#quick-start)
-  - [Begin](#begin)
-  - [Stack](#stack)
-  - [Nix](#nix)
-  - [Cabal](#cabal)
-  - [GHCJSi Caveats](#ghcjsi-caveats)
-  - [Architecture](#architecture)
-- [Examples](#examples)
-  - [TodoMVC](#todomvc)
-  - [Flatris](#flatris)
-  - [2048](#2048)
-  - [Snake](#snake)
-  - [Mario](#mario)
-  - [Websocket](#websocket)
-  - [SSE](#sse)
-  - [XHR](#xhr)
-  - [Router](#router)
-  - [SVG](#svg)
-  - [Canvas 2D](#canvas-2d)
-  - [ThreeJS](#threejs)
-  - [Simple](#simple)
-  - [File Reader](#file-reader)
-  - [WebVR](#webvr)
+- [Playground](#playground-)
+- [Quick Start (Nix)](#quick-start-nix-)
+- [Manual Setup (GHCup / Cabal)](#manual-setup-ghcup--cabal)
+  - [cabal.project](#cabalproject)
+  - [app.cabal](#appcabal)
+  - [Main.hs](#mainhs)
+- [Hot Reload](#hot-reload-)
+- [Installation](#installation)
 - [Haddocks](#haddocks)
-  - [GHC](#ghc)
-  - [GHCJS](#ghcjs)
-- [Sample Application](#sample-application)
-- [Building examples](#building-examples)
-- [Coverage](#coverage)
-- [Isomorphic](#isomorphic)
-- [Pinning nixpkgs](#pinning-nixpkgs)
-- [Binary cache](#binary-cache)
-- [Benchmarks](#benchmarks)
+- [Wiki](#wiki)
+- [Architecture](#architecture)
+- [Examples](#examples)
+- [HTTP](#interacting-with-http-apis-)
+- [Testing](#testing-)
+- [Native](#native-)
+- [Benchmarks](#benchmarks-%EF%B8%8F)
+- [Nix](#nix-)
+  - [Pinning nixpkgs](#pinning-nixpkgs-)
+  - [Binary cache](#binary-cache)
+- [Community](#community-)
 - [Maintainers](#maintainers)
+- [Commercial](#commercial-)
 - [Contributing](#contributing)
+- [Contributors](#contributors-)
+- [Partnerships](#partnerships-)
+- [Backers](#backers)
+- [Organizations](#organizations)
+- [History](#history-)
 - [License](#license)
 
-## Quick start
-To get started quickly building applications, we recommend using the [`stack`](https://docs.haskellstack.org/en/stable/README/) or [`nix`](https://nixos.org/nix) package managers. Obtaining [`GHCJS`](https://github.com/ghcjs/ghcjs) is required as a prerequisite. `stack` and `nix` make this process easy, if you're using `cabal` we assume you have [obtained `GHCJS`](https://github.com/ghcjs/ghcjs#installation) by other means.
+## Playground 🛝
 
-All source code depicted below for the quick start app is available [here](https://github.com/dmjio/miso/tree/master/sample-app).
+An interactive playground is available at [try.haskell-miso.org](https://try.haskell-miso.org). It allows editing and running applications directly in the browser without any local toolchain setup, and is useful for experimentation and sharing minimal reproducible examples.
 
-### Begin
-We recommend using `nix` when working with `miso`, but it is just as fine to use `stack`.
-To build the sample-app with `nix`, execute the command below:
+## Quick Start (Nix) ⚡
 
-```bash
-git clone https://github.com/dmjio/miso && cd miso/sample-app && nix-build
-```
+> [!TIP]
+> The [miso-sampler](https://github.com/haskell-miso/miso-sampler) template repository includes a counter application with build scripts for WebAssembly, JavaScript, and native GHC targets.
 
-To develop with `nix` run the below command (this will put you into a shell where you can iteratively develop the project with `cabal build`).
+The following requires [Nix Flakes](https://wiki.nixos.org/wiki/Flakes). See also [Binary cache](#binary-cache) to avoid rebuilding dependencies.
 
 ```bash
-git clone https://github.com/dmjio/miso && cd miso/sample-app && nix-shell -A env
-```
-
-For more information on using `nix` w/ `miso`, see the [`nix` section below](#nix)
-
-To build the sample-app with `stack`, execute the command below:
-```bash
-git clone https://github.com/dmjio/miso && cd miso/sample-app && stack setup && stack build
-```
+# Install nix 
+curl -L https://nixos.org/nix/install | sh
 
-Note: It's important to ensure that you don't have a global `cabal-install` present on your system. This could cause build problems. If you see an error like this (below), try deleting your global `cabal-install`.
+# Enable flakes
+echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf
 
-```bash
-exit status: 1
-stderr: solver must be one of: modular
-CallStack (from HasCallStack):
-  error, called at libraries/Cabal/Cabal/Distribution/ReadE.hs:46:24 in Cabal-2.0.1.0:Distribution.ReadE
+# Clone, build and serve
+git clone https://github.com/haskell-miso/miso-sampler && cd miso-sampler
+nix develop .#wasm --command bash -c 'make && make serve'
 ```
 
+## Manual Setup (GHCup / Cabal)
 
-For more information on using `stack` w/ `miso`, see the [`stack` section below](#stack)
+To develop applications without Nix, acquire [GHC](https://www.haskell.org/ghc/) and [cabal](https://www.haskell.org/cabal/) via [GHCup](https://www.haskell.org/ghcup/).
 
+> [!TIP]
+> For users new to Haskell tooling, [GHCup](https://www.haskell.org/ghcup/) is the recommended way to install both [GHC](https://www.haskell.org/ghc/) and [cabal](https://www.haskell.org/cabal/).
 
-### Stack
-In the `miso` repository there is a [folder named `stack`](https://github.com/dmjio/miso/tree/master/stack) with "known to work" configurations for `GHCJS`. One stack file exists for both the `7.10.3` and `8.0.1` versions of `GHCJS`. In general, we recommend developing with the `7.10.3` version since it currently supports `GHCJSi` (a REPL that connects to the browser by way of a [`nodejs`](https://nodejs.org/en/) web server using [`socket.io`](https://socket.io/)) and building with the `8.0.1` version (if possible). For more information on using `stack` with `GHCJS`, please consult the [GHCJS section of the `stack` docs](https://docs.haskellstack.org/en/stable/ghcjs/).
+A minimal application requires three files:
 
-To begin, create the following directory layout
-```bash
-➜  mkdir app && touch app/{Main.hs,app.cabal,stack.yaml} && tree app
-app
-|-- Main.hs
-|-- app.cabal
-`-- stack.yaml
-```
+  - `cabal.project`
+  - `app.cabal`
+  - `Main.hs`
 
-Add a `stack.yaml` file that uses a recent version of `miso`.
-```bash
-➜  cat app/stack.yaml
-resolver: lts-6.30
-compiler: ghcjs-0.2.0.9006030_ghc-7.10.3
-compiler-check: match-exact
+### `cabal.project`
 
+```cabal
 packages:
- - '.'
-extra-deps:
- - miso-0.12.0.0
+  .
 
-setup-info:
-  ghcjs:
-	source:
-	  ghcjs-0.2.0.9006030_ghc-7.10.3:
-		 url: http://ghcjs.tolysz.org/lts-6.30-9006030.tar.gz
-		 sha1: 2371e2ffe9e8781808b7a04313e6a0065b64ee51
+source-repository-package
+  type: git
+  location: https://github.com/dmjio/miso
+  branch: master
 ```
 
-Add a `cabal` file
-```bash
-➜  cat app/*.cabal
-name:                app
-version:             0.1.0.0
-synopsis:            First miso app
-category:            Web
-build-type:          Simple
-cabal-version:       >=1.10
+> [!NOTE]
+> Pinning to a specific `tag:` or `commit:` rather than `branch: master` is recommended for reproducible builds.
 
-executable app
-  main-is:             Main.hs
-  build-depends:       base, miso
-  default-language:    Haskell2010
-```
+### `app.cabal`
 
-Add the source from [Sample Application](#sample-application) to `app/Main.hs`
+Using `cabal-version: 2.2` or later enables [common stanzas](https://vrom911.github.io/blog/common-stanzas), which allow a single `.cabal` file to target both the WASM and JS backends.
 
-Run `stack setup`. This might take a long time, since it will have to build `GHCJS`.
-```
-stack setup
-```
+```cabal
+cabal-version: 2.2
+name: app
+version: 0.1.0.0
+synopsis: Sample miso app
+category: Web
 
-Run `stack build` to get the static assets
-```
-stack build
-```
+common options
+  if arch(wasm32)
+    ghc-options:
+      -no-hs-main
+      -optl-mexec-model=reactor
+      "-optl-Wl,--export=hs_start"
+    cpp-options:
+      -DWASM
 
-See the result
-```
-open $(stack path --local-install-root)/bin/app.jsexe/index.html
-```
+  if arch(javascript)
+     ld-options:
+       -sEXPORTED_RUNTIME_METHODS=HEAP8
 
-Using GHCJSi
-```
-stack ghci
+executable app
+  import:
+    options
+  main-is:
+    Main.hs
+  build-depends:
+    base, miso
+  default-language:
+    Haskell2010
 ```
 
-If that warns with `socket.io not found, browser session not available`, you'll need to install `socket.io`
-```
-npm install socket.io
-```
+### `Main.hs`
 
-and update your `NODE_PATH`
-```
-export NODE_PATH=$(pwd)/node_modules
-```
+A counter application demonstrating the Model-View-Update pattern:
 
-Now you should be connected, and the app viewable in `GHCJSi` (open http://localhost:6400).
-```bash
-➜  stack ghci
-app-0.1.0.0: initial-build-steps (exe)
-Configuring GHCi with the following packages: app
-GHCJSi, version 0.2.0.9006020-7.10.3: http://www.github.com/ghcjs/ghcjs/  :? for help
-[1 of 1] Compiling Main             ( /Users/david/Desktop/miso/sample-app/Main.hs, interpreted )
-socket.io found, browser session available at http://localhost:6400
-Ok, modules loaded: Main.
-*Main> main
-browser connected, code runs in browser from now on
+```haskell
+----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE LambdaCase        #-}
+{-# LANGUAGE CPP               #-}
+----------------------------------------------------------------------------
+module Main where
+----------------------------------------------------------------------------
+import           Miso
+import qualified Miso.Html as H
+import           Miso.Lens
+----------------------------------------------------------------------------
+-- | Sum type for App events
+data Action
+  = AddOne
+  | SubtractOne
+  | SayHelloWorld
+  deriving (Show, Eq)
+----------------------------------------------------------------------------
+-- | Entry point for a miso application
+main :: IO ()
+main = startApp defaultEvents app
+----------------------------------------------------------------------------
+-- | WASM export, required when compiling w/ the WASM backend.
+#ifdef WASM
+foreign export javascript "hs_start" main :: IO ()
+#endif
+----------------------------------------------------------------------------
+-- | `vcomp` takes as arguments the initial model, update function, view function
+app :: App Int Action
+app = vcomp 0 updateModel viewModel
+----------------------------------------------------------------------------
+-- | Updates model, optionally introduces side effects
+updateModel :: Action -> Effect context props Int Action
+updateModel = \case
+  AddOne -> this += 1
+  SubtractOne -> this -= 1
+  SayHelloWorld -> io_ $ do
+    alert "Hello World"
+    consoleLog "Hello World"
+----------------------------------------------------------------------------
+-- | Constructs a virtual DOM from a model
+viewModel :: context -> props -> Int -> View context Action
+viewModel _context _props x = vfrag
+    [ H.button_ [ H.onClick AddOne ] [ text "+" ]
+    , text (ms x)
+    , H.button_ [ H.onClick SubtractOne ] [ text "-" ]
+    , H.br_ []
+    , H.button_ [ H.onClick SayHelloWorld ] [ text "Alert Hello World!" ]
+    ]
+----------------------------------------------------------------------------
 ```
 
-### Nix
-`Nix` is a more powerful option for building web applications with `miso` since it encompasses development workflow, configuration management, and deployment. The source code for [`haskell-miso.org`](https://github.com/dmjio/miso/tree/master/examples/haskell-miso.org) is an example of this.
-
-If unfamiliar with `nix`, we recommend [@Gabriel439](https://github.com/Gabriel439)'s ["Nix and Haskell in production"](https://github.com/Gabriel439/haskell-nix) guide.
-
-To get started, we will use the [`cabal2nix`](https://github.com/NixOS/cabal2nix) tool to convert our `Cabal` file into a `nix` derivation (named `app.nix`). We'll then write a file named `default.nix`, which is used for building our project (via `nix-build`) and development (via `nix-shell`).
-
-To begin, make the following directory layout:
-```bash
-➜  mkdir app && touch app/{Main.hs,app.cabal,default.nix,app.nix} && tree app
-app
-|-- Main.hs
-|-- app.cabal
-|-- default.nix
-`-- app.nix
-```
+## Hot Reload 🔥
 
-Add a `cabal` file
-```bash
-➜  cat app/*.cabal
-name:                app
-version:             0.1.0.0
-synopsis:            First miso app
-category:            Web
-build-type:          Simple
-cabal-version:       >=1.10
+Hot reload is supported via [WASM browser mode](https://www.tweag.io/blog/2025-04-17-wasm-ghci-browser/) and [ghciwatch](https://github.com/MercuryTechnologies/ghciwatch). This provides incremental recompilation with automatic browser refresh on file changes. See the [miso-sampler browser mode documentation](https://github.com/haskell-miso/miso-sampler/blob/main/README.md#browser-mode-) for setup instructions.
 
-executable app
-  main-is:             Main.hs
-  build-depends:       base, miso
-  default-language:    Haskell2010
-```
+## Installation
 
-Use [`cabal2nix`](https://github.com/NixOS/cabal2nix) to generate a file named `app.nix`
-that looks like below.
-```bash
-➜  cabal2nix . --compiler ghcjs > app.nix
-➜  cat app.nix
-```
+See [Installation](docs/Install.md) for platform-specific installation instructions.
 
-```nix
-{ mkDerivation, base, miso, stdenv }:
-mkDerivation {
-  pname = "app";
-  version = "0.1.0.0";
-  src = ./.;
-  isLibrary = false;
-  isExecutable = true;
-  executableHaskellDepends = [ base miso ];
-  description = "First miso app";
-  license = stdenv.lib.licenses.bsd3;
-}
-```
+## Haddocks
 
-Write a `default.nix` (which calls `app.nix`), this fetches a recent version of `miso`.
-```nix
-{ pkgs ? import ((import <nixpkgs> {}).fetchFromGitHub {
-	owner = "NixOS";
-	repo = "nixpkgs";
-	rev = "a0aeb23";
-	sha256 = "04dgg0f2839c1kvlhc45hcksmjzr8a22q1bgfnrx71935ilxl33d";
-  }){}
-}:
-let
-  result = import (pkgs.fetchFromGitHub {
-	owner = "dmjio";
-	repo = "miso";
-	sha256 = "1l1gwzzqlvvcmg70jjrwc5ijv1vb6y5ljqkh7rxxq7hkyxpjyx9q";
-	rev = "95f6bc9b1ae6230b110358a82b6a573806f272c2";
-  }) {};
-in pkgs.haskell.packages.ghcjs.callPackage ./app.nix {
-  miso = result.miso-ghcjs;
-}
-```
+Official API reference. See also the [Miso](https://haddocks.haskell-miso.org/miso/Miso.html) module for a guided entry point into the library.
 
-Build the project
-```
-nix-build
-```
+| Platform | URL |
+|------|-------------|
+| GHCJS | [Link](https://haddocks.haskell-miso.org/) |
+| GHC | [Link](http://hackage.haskell.org/package/miso) |
 
-Open the result
-```
-open ./result/bin/app.jsexe/index.html
-```
+## Wiki
 
-For development with `nix`, it's important to have `cabal` present for building. This command will make it available in your `PATH`.
-```
-nix-env -iA cabal-install -f '<nixpkgs>'
-```
+See the [DeepWiki](https://deepwiki.com/dmjio/miso) entry for an AI-assisted exploration of the source code.
 
-To be put into a shell w/ `GHCJS` and all the dependencies for this project present, use `nix-shell`.
-```
-nix-shell -A env
-```
+[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dmjio/miso)
 
-To open `GHCJSi` (`NODE_PATH` should already be set properly)
-```
-$ cabal configure --ghcjs
-$ cabal repl
-Package has never been configured. Configuring with default flags. If this
-fails, please run configure manually.
-Resolving dependencies...
-Configuring app-0.1.0.0...
-Preprocessing executable 'app' for app-0.1.0.0...
-GHCJSi, version 0.2.0-7.10.3: http://www.github.com/ghcjs/ghcjs/  :? for help
-[1 of 1] Compiling Main             ( Main.hs, interpreted )
-Ok, modules loaded: Main.
-*Main>
-browser connected, code runs in browser from now on
-```
+## Architecture
 
-### Cabal
-The latest stable version of `miso` will be available on Hackage.
-To build with cabal, we assume `ghcjs` is in your `PATH` and `ghcjs-base` is present in your `ghcjs-pkg` list.
-```bash
-cabal sandbox init
-cabal install --ghcjs
-cabal build
-open dist/build/app/app.jsexe/index.html
-```
+**miso** follows the [Model-View-Update](https://guide.elm-lang.org/architecture/) (MVU) pattern. A `Component` is parameterized by a `model` type and an `action` type. The `update` function maps actions to `Effect` values — a monad over the Reader/Writer/State stack — which can both modify the model and schedule `IO` operations. Long-running effects are expressed as `Sub`scriptions that push actions into the component via a `Sink`.
 
-### GHCJSi Caveats
-If you run `main` in `GHCJSi`, interrupt it and then run it again, you
-will end up with two copies of your app displayed above each other. As
-a workaround, you can use `clearBody >> main` which will completely
-clear the document body before rendering your application.
+For (client/server) applications, the recommended layout is a single `.cabal` file with separate executable stanzas conditioned on the compiler target. An example of this structure is the [haskell-miso.org source](https://github.com/haskell-miso/haskell-miso.org/blob/master/haskell-miso.cabal).
 
-### Architecture
-For constructing client and server applications, we recommend using one `cabal` file with two executable sections, where the `buildable` attribute set is contingent on the compiler. An example of this layout is [here](https://github.com/dmjio/miso/blob/master/examples/haskell-miso.org/haskell-miso.cabal#L16-L60). For more info on how to use `stack` with a `client`/`server` setup, see this [link](https://docs.haskellstack.org/en/stable/ghcjs/#project-with-both-client-and-server). For more information on how to use `nix` with a `client`/`server` setup, see the [nix scripts](https://github.com/dmjio/miso/blob/master/examples/haskell-miso.org/default.nix) for [https://haskell-miso.org](https://haskell-miso.org).
+> [!TIP]
+> For a worked example of a Nix-based client/server deployment, see the [nix scripts](https://github.com/haskell-miso/haskell-miso.org/blob/master/default.nix) for [haskell-miso.org](https://haskell-miso.org).
 
 ## Examples
 
-### TodoMVC
-  - [Link](https://todo-mvc.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/todo-mvc/Main.hs)
+Examples are hosted under the [haskell-miso](https://github.com/haskell-miso) GitHub organization. Each repository contains its own build instructions. The recommended approach is to build via [`nix`](https://nixos.org/nix/).
 
-### Flatris
-  - [Link](https://flatris.haskell-miso.org/) / [Source](https://github.com/ptigwe/hs-flatris/)
+> [!TIP]
+> Use [cachix](https://cachix.org) to avoid rebuilding shared dependencies: `cachix use haskell-miso-cachix`
 
-### 2048
-  - [Link](http://2048.haskell-miso.org/) / [Source](https://github.com/ptigwe/hs2048/)
+| Name                  | Description                               | Source                                                        | Demo                                                      | Author                                            |
+|-----------------------|-------------------------------------------|---------------------------------------------------------------|-----------------------------------------------------------|---------------------------------------------------|
+| **TodoMVC**           | TodoMVC reference implementation          | [Source](https://github.com/haskell-miso/miso-todomvc)        | [Demo](https://todomvc.haskell-miso.org)       | [@dmjio](https://github.com/dmjio)                |
+| **2048**              | Clone of the 2048 sliding-tile game       | [Source](https://github.com/haskell-miso/miso-2048)           | [Demo](https://2048.haskell-miso.org/)         | [@ptigwe](https://github.com/ptigwe)              |
+| **Flatris**           | Tetris variant                            | [Source](https://github.com/haskell-miso/miso-flatris)        | [Demo](https://flatris.haskell-miso.org/)      | [@ptigwe](https://github.com/ptigwe)              |
+| **Plane**             | Flappy-bird-style game                    | [Source](https://github.com/haskell-miso/miso-plane)          | [Demo](https://plane.haskell-miso.org/)        | [@Lermex](https://github.com/Lermex)              |
+| **Snake**             | Classic Snake game                        | [Source](https://github.com/haskell-miso/miso-snake)          | [Demo](https://snake.haskell-miso.org/)        | [@lbonn](https://github.com/lbonn)                |
+| **SVG**               | SVG rendering                             | [Source](https://github.com/haskell-miso/miso-svg)            | [Demo](https://svg.haskell-miso.org/)          | [@dmjio](https://github.com/dmjio)                |
+| **Fetch**             | HTTP API interaction via Fetch            | [Source](https://github.com/haskell-miso/miso-fetch)          | [Demo](https://fetch.haskell-miso.org)         | [@dmjio](https://github.com/dmjio)                |
+| **File Reader**       | FileReader API                            | [Source](https://github.com/haskell-miso/miso-filereader)     | [Demo](https://file-reader.haskell-miso.org/)  | [@dmjio](https://github.com/dmjio)                |
+| **Mario**             | Physics-based platformer                  | [Source](https://github.com/haskell-miso/miso-mario)          | [Demo](https://mario.haskell-miso.org)         | [@dmjio](https://github.com/dmjio)                |
+| **WebSocket**         | WebSocket communication                   | [Source](https://github.com/haskell-miso/miso-websocket)      | [Demo](https://websocket.haskell-miso.org)     | [@dmjio](https://github.com/dmjio)                |
+| **Router**            | Client-side routing                       | [Source](https://github.com/haskell-miso/miso-router)         | [Demo](https://router.haskell-miso.org)        | [@dmjio](https://github.com/dmjio)                |
+| **Canvas 2D**         | 2D Canvas rendering                       | [Source](https://github.com/haskell-miso/miso-canvas2d)       | [Demo](https://canvas.haskell-miso.org)        | [@dmjio](https://github.com/dmjio)                |
+| **MathML**            | MathML rendering                          | [Source](https://github.com/haskell-miso/miso-mathml)         | [Demo](https://mathml.haskell-miso.org)        | [@dmjio](https://github.com/dmjio)                |
+| **Simple**            | Counter (minimal example)                 | [Source](https://github.com/haskell-miso/miso-sampler)        | [Demo](https://counter.haskell-miso.org)       | [@dmjio](https://github.com/dmjio)                |
+| **SSE**               | Server-Sent Events                        | [Source](https://github.com/haskell-miso/miso-sse)            | [Demo](https://sse.haskell-miso.org)           | [@dmjio](https://github.com/dmjio)                |
+| **Three.js**          | 3D rendering via Three.js                 | [Source](https://github.com/haskell-miso/three-miso)          | [Demo](https://threejs.haskell-miso.org/)      | [@juliendehos](https://github.com/juliendehos)    |
+| **Space Invaders**    | Space Invaders clone                      | [Source](https://github.com/haskell-miso/miso-invaders)       | [Demo](https://space-invaders.haskell-miso.org/) | [@juliendehos](https://github.com/juliendehos)    |
+| **Audio**             | Audio playback                            | [Source](https://github.com/haskell-miso/miso-audio)          | [Demo](https://audio.haskell-miso.org/)        | [@juliendehos](https://github.com/juliendehos)    |
+| **Video**             | Video playback                            | [Source](https://github.com/haskell-miso/miso-video)          | [Demo](https://video.haskell-miso.org/)        | [@juliendehos](https://github.com/juliendehos)    |
+| **WebVR**             | WebVR via A-Frame                         | [Source](https://github.com/haskell-miso/miso-aframe)         | [Demo](https://aframe.haskell-miso.org/)       | [@dmjio](https://github.com/dmjio)                |
+| **Reactivity**        | Fine-grained reactive updates             | [Source](https://github.com/haskell-miso/miso-reactive)       | [Demo](https://reactive.haskell-miso.org/)     | [@dmjio](https://github.com/dmjio)                |
+| **Chess**             | Chess game                                | [Source](https://github.com/haskell-miso/chess)               | [Demo](https://chess.haskell-miso.org)         | [@dmjio](https://github.com/dmjio)                |
 
-### Snake
-  - [Link](http://snake.haskell-miso.org/) / [Source](https://github.com/lbonn/miso-snake)
+## Interacting with HTTP APIs 🔌
 
-### Mario
-  - [Link](https://mario.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/mario/Main.hs)
+Two approaches are supported:
 
-### Websocket
-  - [Link](https://websocket.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/websocket/Main.hs)
+  1. For simple JSON-based APIs, use the [Fetch](https://haddocks.haskell-miso.org/miso/Miso-Fetch.html) module directly.
 
-### SSE
-  - [Link](https://sse.haskell-miso.org/) / [Client](https://github.com/dmjio/miso/blob/master/examples/sse/client/Main.hs) / [Server](https://github.com/dmjio/miso/blob/master/examples/sse/server/Main.hs)
+  2. For more complex cases, define a [Servant](https://www.servant.dev/) API and derive client functions via [servant-miso-client](https://github.com/haskell-miso/servant-miso-client).
 
-### XHR
-  - [Link](https://xhr.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/xhr/Main.hs)
+     The [Fetch example](https://github.com/haskell-miso/miso-fetch) ([Demo](https://fetch.haskell-miso.org/)) demonstrates the required setup. Add the following to `cabal.project` to use `servant-miso-client`:
 
-### Router
-  - [Link](https://router.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/router/Main.hs)
+     ```
+     source-repository-package
+       type: git
+       location: https://github.com/haskell-miso/servant-miso-client
+       tag: master
+     ```
 
-### SVG
-  - [Link](https://svg.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/svg/Main.hs)
+## Testing ✅
 
-### Canvas 2D
-  - [Link](http://canvas.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/canvas2d/Main.hs)
+The test suite spans three layers:
 
-### ThreeJS
-  - [Link](http://threejs.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/three/Main.hs)
+- **Unit tests** — the TypeScript runtime (virtual DOM, diffing, event delegation) is tested with [bun](https://github.com/oven-sh/bun), covering the core `diff` engine and supporting utilities.
+- **Integration tests** — Haskell internals are exercised via a WASM test suite that runs the runtime in a headless browser environment, verifying component lifecycle, subscriptions, and state transitions.
+- **End-to-end tests** — selected applications such as [TodoMVC](https://github.com/haskell-miso/miso-todomvc) are tested end-to-end against a live browser to validate full-stack rendering and event handling.
 
-### Simple
-  - [Link](https://simple.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/exe/Main.hs)
+A full coverage report for the TypeScript layer is available at [coverage.haskell-miso.org](http://coverage.haskell-miso.org).
 
-### File Reader
-  - [Link](https://file-reader.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/file-reader/Main.hs)
+> [!NOTE]
+> To run the TypeScript tests, install [bun](https://github.com/oven-sh/bun) first.
 
-### WebVR
-  - [Link](https://fizruk.github.io/fpconf-2017-talk/miso-aframe-demo/dist/demo.jsexe/index.html) / [Source](https://github.com/fizruk/miso-aframe)
+```bash
+$ curl -fsSL https://bun.sh/install | bash
+```
+or
 
-## Haddocks
+```bash
+$ nix-env -iA bun -f '<nixpkgs>'
+```
 
-### GHCJS
-  - [Link](https://haddocks.haskell-miso.org/)
+and
 
-### GHC
-  - [Link](http://hackage.haskell.org/package/miso)
+```bash
+$ bun install && bun run test
+```
 
-## Sample application
-```haskell
--- | Haskell language pragma
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards #-}
+## Native 📱
 
--- | Haskell module declaration
-module Main where
+iOS and Android applications are supported via [LynxJS](https://lynxjs.org). See the [miso-lynx](https://github.com/haskell-miso/miso-lynx) repository for details.
 
--- | Miso framework import
-import Miso
-import Miso.String
+## Benchmarks 🏎️
 
--- | Type synonym for an application model
-type Model = Int
+[According to benchmarks](https://krausest.github.io/js-framework-benchmark/current.html), `miso` performs competitively relative to other frameworks.
 
--- | Sum type for application events
-data Action
-  = AddOne
-  | SubtractOne
-  | NoOp
-  | SayHelloWorld
-  deriving (Show, Eq)
+## Nix <img src="https://raw.githubusercontent.com/NixOS/nixos-artwork/refs/heads/master/logo/nix-snowflake-colours.svg" alt="nixos-snowflake" width="25"/>
 
--- | Entry point for a miso application
-main :: IO ()
-main = startApp App {..}
-  where
-	initialAction = SayHelloWorld -- initial action to be executed on application load
-	model         = 0             -- initial model
-	update        = updateModel   -- update function
-	view          = viewModel     -- view function
-	events        = defaultEvents -- default delegated events
-	subs          = []            -- empty subscription list
-	mountPoint    = Nothing       -- mount point for application (Nothing defaults to 'body')
+`Nix` provides a reproducible environment for building, configuring, and deploying applications. The [haskell-miso.org](https://github.com/dmjio/miso/tree/master/haskell-miso.org) source serves as a reference for this workflow.
 
--- | Updates model, optionally introduces side effects
-updateModel :: Action -> Model -> Effect Action Model
-updateModel AddOne m = noEff (m + 1)
-updateModel SubtractOne m = noEff (m - 1)
-updateModel NoOp m = noEff m
-updateModel SayHelloWorld m = m <# do
-  putStrLn "Hello World" >> pure NoOp
+### Pinning nixpkgs 📌
 
--- | Constructs a virtual DOM from a model
-viewModel :: Model -> View Action
-viewModel x = div_ [] [
-   button_ [ onClick AddOne ] [ text "+" ]
- , text (ms x)
- , button_ [ onClick SubtractOne ] [ text "-" ]
- ]
-```
+By default, `miso` uses a pinned version of [`nixpkgs`](https://github.com/dmjio/miso/blob/master/nix/nixpkgs.json) known as `pkgs`.
 
-## Building examples
+> [!NOTE]
+> `miso` also maintains a `legacyPkgs` nixpkgs pin for tools such as `nixops` and for builds using the original `GHCJS 8.6` backend.
 
-The easiest way to build the examples is with the [`nix`](https://nixos.org/nix/) package manager
-```
-git clone https://github.com/dmjio/miso && cd miso && nix-build
-```
+### Binary cache
 
-This will build all examples and documentation into a folder named `result`
-```
-➜  miso git:(master) ✗ tree result -d
-result
-|-- doc
-|   |-- x86_64-osx-ghc-8.0.2
-|   |   `-- miso-0.2.0.0
-|   |       `-- html
-|   |           `-- src
-|   `-- x86_64-osx-ghcjs-0.2.0-ghc7_10_3
-|       `-- miso-0.2.0.0
-|           `-- html
-|               `-- src
-|-- examples
-|   |-- mario.jsexe
-|   |   `-- imgs
-|   |       |-- jump
-|   |       |-- stand
-|   |       `-- walk
-|   |-- router.jsexe
-|   |-- simple.jsexe
-|   |-- tests.jsexe
-|   |-- todo-mvc.jsexe
-|   `-- websocket.jsexe
+Linux and macOS users can use a [binary cache](https://haskell-miso-cachix.cachix.org) to avoid rebuilding dependencies. Follow the setup instructions on [cachix](https://haskell-miso-cachix.cachix.org/).
+
+```bash
+$ cachix use haskell-miso-cachix
 ```
 
-To see examples, we recommend hosting them with a webserver
+For CI pipelines using GitHub Actions:
 
-```
-cd result/examples/todo-mvc.jsexe && python -m SimpleHTTPServer
-Serving HTTP on 0.0.0.0 port 8000 ...
+```yaml
+- name: Install cachix
+  uses: cachix/cachix-action@v16
+  with:
+    name: haskell-miso-cachix
 ```
 
-## Coverage
+## Community :octocat:
 
-The core algorithmic component of miso is [diff.js](https://github.com/dmjio/miso/blob/master/jsbits/diff.js). It is responsible for all DOM manipulation that occurs in a miso application and has [100% code coverage](http://coverage.haskell-miso.org). Tests and coverage made possible using [jsdom](https://github.com/jsdom/jsdom) and [jest](https://github.com/facebook/jest).
+- [Github](https://github.com/haskell-miso)
+- [Matrix](https://matrix.to/#/#haskell-miso:matrix.org)
+- [Discord](https://discord.gg/QVDtfYNSxq)
 
-To run the tests and build the coverage report:
+## Maintainers
 
-```bash
-cd miso/tests
-npm i
-npm run test
-## Or by using `yarn` instead of `npm`:
-# yarn
-# yarn test
-```
+[@dmjio](https://github.com/dmjio)
 
-## Isomorphic
+## Commercial 🚀
 
-Isomorphic javascript is a technique for increased SEO, code-sharing and perceived page load times. It works in two parts. First, the server sends a pre-rendered HTML body to the client's browser. Second, after the client javascript application loads, the pointers of the pre-rendered DOM are copied into the virtual DOM, and the application proceeds as normal. All subsequent page navigation is handled locally by the client, avoiding full-page postbacks as necessary.
+Since its launch, `miso` has been deployed across a range of domains, including quantitative finance, network security, defense research, academia, SaaS, the public sector, and non-profit organizations. The largest known deployment consisted of approximately 200,000 LOC serving over 10,000 users.
 
-The `miso` function is used to perform the pointer-copying behavior client-side.
+## Contributing
 
-For more information on how `miso` handles isomorphic javascript, we recommend [this tutorial](https://github.com/FPtje/miso-isomorphic-example).
+Contributions are welcome. [Open an issue](https://github.com/dmjio/miso/issues/new) or submit a [pull request](https://github.com/dmjio/miso/pulls).
 
-## Pinning nixpkgs
+See [CONTRIBUTING](https://github.com/dmjio/miso/blob/master/CONTRIBUTING.md) for guidelines.
 
-By default `miso` uses a known-to-work, pinned version of [`nixpkgs`](https://github.com/dmjio/miso/blob/master/default.nix#L1-L6).
-To override this to your system's version of `nixpkgs` write:
+## Contributors 🦾
 
-```
-nix-build --arg nixpkgs 'import <nixpkgs> {}'
-```
+> [!NOTE]
+> This project exists thanks to all the people who [contribute](CONTRIBUTING.md).
 
-## Binary cache
+<a href="https://github.com/dmjio/miso/graphs/contributors"><img src="https://opencollective.com/miso/contributors.svg?width=890&button=false" /></a>
 
-`nix` users on a Linux distro can take advantage of a [binary cache](https://hydra.dmj.io/nix-cache-info) for faster builds. To use the binary cache simply append `https://hydra.dmj.io/nix-cache-info` during all `nix-shell` and/or `nix-build` invocations.
+## Partnerships 🤝
 
-```bash
-nix-build --option extra-binary-caches https://hydra.dmj.io
-```
+For inquiries regarding feature sponsorship or corporate partnerships, contact <a href="mailto:support@haskell-miso.org">support@haskell-miso.org</a>.
 
-Alternatively, add `https://hydra.dmj.io` to your list of local binary caches in `nix.conf` (usually found in `/etc/nix/nix.conf`), and it will automatically be used on all invocations of `nix-build` and/or `nix-shell`.
+## Backers
 
-```
-binary-caches = https://hydra.dmj.io/ https://cache.nixos.org/
-```
+Become a [financial contributor](https://opencollective.com/miso/contribute) to help sustain the project.
 
-## Benchmarks
+<a href="https://opencollective.com/miso"><img src="https://opencollective.com/miso/individuals.svg?width=890"></a>
 
-[According to benchmarks](https://medium.com/@saurabhnanda/benchmarks-fp-languages-libraries-for-front-end-development-a11af0542f7e), `miso` is among the fastest functional programming web frameworks, second only to [Elm](http://elm-lang.org).
+## organizations
 
-<img src="https://cdn-images-1.medium.com/max/1600/1*6EjJTf1mhlTxd4QWsygCwA.png" width="500" height="600" />
+[Support this project](https://opencollective.com/miso/contribute) with your organization. Your logo will appear here with a link to your website.
 
-## Maintainers
+<a target="_blank" href="https://opencollective.com/miso/organization/0/website"><img src="https://opencollective.com/miso/organization/0/avatar.svg"></a>
 
-[@dmjio](https://github.com/dmjio)
+## History 📜
 
-## Contributing
+> **miso** is a portmanteau of ***micro*** and ***isomorphic***.
 
-Feel free to dive in! [Open an issue](https://github.com/dmjio/miso/issues/new) or submit [PRs](https://github.com/dmjio/miso/pulls).
+[miso](https://haskell-miso.org) was initiated in 2016 as a research project exploring two directions:
 
-See [CONTRIBUTING](https://github.com/dmjio/miso/blob/master/CONTRIBUTING.md) for more info.
+- Expressing the [Elm architecture](https://elm-lang.org) in [GHCJS](https://github.com/ghcjs/ghcjs) as an [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language)
+- Implementing [reconciliation](https://legacy.reactjs.org/docs/reconciliation.html#the-diffing-algorithm) and [isomorphic](https://en.wikipedia.org/wiki/Isomorphic_JavaScript) rendering techniques from the JavaScript ecosystem, within a purely functional setting.
 
+The project addresses the [JavaScript problem](https://wiki.haskell.org/The_JavaScript_Problem) in Haskell by providing component abstractions and rendering primitives familiar to practitioners of frameworks such as [React](https://reactjs.org) and [Vue.js](https://vuejs.org). The library has since expanded to include multiple rendering backends and native mobile support for [iOS](https://www.apple.com/ios/), [Android](https://www.android.com/), and [HarmonyOS](https://device.harmonyos.com/en/) via [LynxJS](https://lynxjs.org).
+
 ## License
 
-[BSD3](LICENSE) © David Johnson
+[BSD3](LICENSE) © dmjio
diff --git a/cbits/foreign.c b/cbits/foreign.c
new file mode 100644
--- /dev/null
+++ b/cbits/foreign.c
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+// dmj: like `foreign-store`, but just for a single Ptr.
+// this is used to store a StablePtr (IORef a), retrieved after a GHCi reload
+
+static void *stored_value = NULL;
+
+// Store a pointer
+void miso_x_store(void *ptr) {
+    stored_value = ptr;
+}
+
+// Get the stored pointer
+void *miso_x_get(void) {
+    return stored_value;
+}
+
+// Check if a pointer is stored (non-NULL)
+int miso_x_exists(void) {
+    return stored_value != NULL;
+}
+
+// Clear the stored pointer
+void miso_x_clear(void) {
+    stored_value = NULL;
+}
diff --git a/examples/canvas2d/Main.hs b/examples/canvas2d/Main.hs
deleted file mode 100644
--- a/examples/canvas2d/Main.hs
+++ /dev/null
@@ -1,95 +0,0 @@
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE OverloadedStrings #-}
-module Main where
-
-import Control.Monad
-import GHCJS.Types
-import JavaScript.Web.Canvas
-
-import Miso
-import Miso.String
-
-type Model = (Double, Double)
-
-data Action
-  = NoOp
-  | GetTime
-  | SetTime Model
-
-main :: IO ()
-main = do
-  [sun, moon, earth] <- replicateM 3 newImage
-  setSrc sun "https://mdn.mozillademos.org/files/1456/Canvas_sun.png"
-  setSrc moon "https://mdn.mozillademos.org/files/1443/Canvas_moon.png"
-  setSrc earth "https://mdn.mozillademos.org/files/1429/Canvas_earth.png"
-  startApp App { initialAction = GetTime
-               , update = updateModel (sun,moon,earth)
-               , ..
-               }
-  where
-    view _ = canvas_ [ id_ "canvas"
-                     , width_ "300"
-                     , height_ "300"
-                     ] []
-    model  = (0.0, 0.0)
-    subs   = []
-    events = defaultEvents
-    mountPoint = Nothing -- default to body
-
-updateModel
-  :: (Image,Image,Image)
-  -> Action
-  -> Model
-  -> Effect Action Model
-updateModel _ NoOp m = noEff m
-updateModel _ GetTime m = m <# do
-  date <- newDate
-  (s,m') <- (,) <$> getSecs date <*> getMillis date
-  pure $ SetTime (s,m')
-updateModel (sun,moon,earth) (SetTime m@(secs,millis)) _ = m <# do
-  ctx <- getCtx
-  setGlobalCompositeOperation ctx
-  clearRect 0 0 300 300 ctx
-  fillStyle 0 0 0 0.6 ctx
-  strokeStyle 0 153 255 0.4 ctx
-  save ctx
-  translate 150 150 ctx
-  flip rotate ctx $ (((2 * pi) / 60) * secs) + (((2 * pi) / 60000) * millis)
-  translate 105 0 ctx
-  fillRect 0 (-12) 50 24 ctx
-  drawImage' earth (-12) (-12) ctx
-  save ctx
-  flip rotate ctx $ (((2 * pi) / 6) * secs) + (((2 * pi) / 6000) * millis)
-  translate 0 28.5 ctx
-  drawImage' moon (-3.5) (-3.5) ctx
-  replicateM_ 2 (restore ctx)
-  beginPath ctx
-  arc 150 150 105 0 (pi * 2) False ctx
-  stroke ctx
-  drawImage sun 0 0 300 300 ctx
-  pure GetTime
-
-foreign import javascript unsafe "$1.globalCompositeOperation = 'destination-over';"
-  setGlobalCompositeOperation :: Context -> IO ()
-
-foreign import javascript unsafe "$4.drawImage($1,$2,$3);"
-  drawImage' :: Image -> Double -> Double -> Context -> IO ()
-
-foreign import javascript unsafe "$r = document.getElementById('canvas').getContext('2d');"
-  getCtx :: IO Context
-
-foreign import javascript unsafe "$r = new Image();"
-  newImage :: IO Image
-
-foreign import javascript unsafe "$1.src = $2;"
-  setSrc :: Image -> MisoString -> IO ()
-
-foreign import javascript unsafe "$r = new Date();"
-  newDate :: IO JSVal
-
-foreign import javascript unsafe "$r = $1.getSeconds();"
-  getSecs :: JSVal -> IO Double
-
-foreign import javascript unsafe "$r = $1.getMilliseconds();"
-  getMillis :: JSVal -> IO Double
-
diff --git a/examples/compose-update/Main.hs b/examples/compose-update/Main.hs
deleted file mode 100644
--- a/examples/compose-update/Main.hs
+++ /dev/null
@@ -1,108 +0,0 @@
-{-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TupleSections #-}
-{-# LANGUAGE OverloadedStrings #-}
-module Main where
-
--- This example demonstrates how you can split your update function
--- into separate update functions for parts of your model and then
--- combine them into a single update function operating on the whole
--- model which combines their effects.
-
-import Control.Monad
-import Data.Monoid
-
-import Miso
-import Miso.String
-
--- In this slightly contrived example, our model consists of two
--- counters. When one of those counters is incremented, the other is
--- decremented and the other way around.
-type Model = (Int, Int)
-
-data Action
-  = Increment
-  | Decrement
-  | NoOp
-  deriving (Show, Eq)
-
--- We are going to use 'Lens'es in this example. Since @miso@ does not
--- depend on a lens library we are going to define a couple of
--- utilities ourselves. We recommend that in your own applications,
--- you depend on a lens library such as @lens@ or @microlens@ to get
--- these definitions.
-type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
-
--- | You can find this under the same name in @lens@ and
--- @microlens@. @lens@ also provides the infix operator '%%~' as a
--- synonym for 'traverseOf'.
---
--- In this example we are only going to use this when applied to
--- 'Lens' m a' and using 'Effect Action' for the @f@ type variable. In
--- that case the specialized type signature is:
---
--- @traverseOf :: Functor f => Lens' m a -> (a -> Effect Action a) -> s -> Effect action s
-traverseOf :: Functor f => Lens s t a b -> (a -> f b) -> s -> f t
-traverseOf = id
-
--- | A lens into the first element of a tuple. Both @lens@ and
--- @microlens@ provide this under the same name.
-_1 :: Lens (a,c) (b,c) a b
-_1 f (a,c) = (,c) <$> f a
-
--- | A lens into the second element of a tuple. Both @lens@ and
--- @microlens@ provide this under the same name.
-_2 :: Lens (c,a) (c,b) a b
-_2 f (c,a) = (c,) <$> f a
-
--- | Update function for the first counter in our 'Model'.
-updateFirstCounter :: Action -> Int -> Effect Action Int
-updateFirstCounter Increment m = noEff (m + 1)
-updateFirstCounter Decrement m = noEff (m - 1)
-updateFirstCounter NoOp m = noEff m
-
--- | Update function for the second counter in our 'Model'. As we’ve
--- mentioned before, this counter is decremented when the first
--- counter is incremented and the other way around.
-updateSecondCounter :: Action -> Int -> Effect Action Int
-updateSecondCounter Increment m = noEff (m - 1)
-updateSecondCounter Decrement m = noEff (m + 1)
-updateSecondCounter NoOp m = noEff m
-
--- | This is the combined update function for both counters.
-updateModel :: Action -> Model -> Effect Action Model
-updateModel act =
-  let -- We use 'traverseOf' to lift an update function for one
-      -- counter to an update function that operates on both
-      -- counters. The lifted function leaves the other counter
-      -- untouched.
-      liftedUpdateFirst :: Model -> Effect Action Model
-      liftedUpdateFirst = traverseOf _1 (updateFirstCounter act)
-      liftedUpdateSecond :: Model -> Effect Action Model
-      liftedUpdateSecond = traverseOf _2 (updateSecondCounter act)
-  in -- Since 'Effect Action' is an instance of 'Monad', we can just
-     -- use '<=<' to compose these lifted update functions.  It might
-     -- be helpful to look at the type signature of '<=<' specialized
-     -- for 'Effect Action':
-     --
-     -- @(<=<) :: (b -> Effect Action c) -> (a -> Effect Action b) -> a -> Effect Action c
-     liftedUpdateFirst <=< liftedUpdateSecond
-
-main :: IO ()
-main = startApp App { initialAction = NoOp, ..}
-  where
-    model  = (0, 0)
-    update = updateModel
-    view   = viewModel
-    events = defaultEvents
-    subs   = []
-    mountPoint = Nothing
-
-viewModel :: Model -> View Action
-viewModel (x, y) =
-  div_
-    []
-    [ button_ [onClick Increment] [text "+"]
-    , text (ms x <> " | " <> ms y)
-    , button_ [onClick Decrement] [text "-"]
-    ]
diff --git a/examples/file-reader/Main.hs b/examples/file-reader/Main.hs
deleted file mode 100644
--- a/examples/file-reader/Main.hs
+++ /dev/null
@@ -1,92 +0,0 @@
-{-# LANGUAGE DeriveGeneric       #-}
-{-# LANGUAGE OverloadedStrings   #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators       #-}
-{-# LANGUAGE DataKinds           #-}
-{-# LANGUAGE RecordWildCards     #-}
-{-# LANGUAGE TypeFamilies        #-}
-module Main where
-
-import           Miso
-import           Miso.String
-import           Control.Concurrent.MVar
-
-import GHCJS.Types
-import GHCJS.Foreign.Callback
-
--- | Model
-data Model
-  = Model
-  { info :: MisoString
-  } deriving (Eq, Show)
-
--- | Action
-data Action
-  = ReadFile
-  | NoOp
-  | SetContent MisoString
-  deriving (Show, Eq)
-
--- | Main entry point
-main :: IO ()
-main = do
-  startApp App { model = Model ""
-               , initialAction = NoOp
-               , ..
-               }
-    where
-      mountPoint = Nothing
-      update = updateModel
-      events = defaultEvents
-      subs   = []
-      view   = viewModel
-
--- | Update your model
-updateModel :: Action -> Model -> Effect Action Model
-updateModel ReadFile m = m <# do
-  fileReaderInput <- getElementById "fileReader"
-  file <- getFile fileReaderInput
-  reader <- newReader
-  mvar <- newEmptyMVar
-  setOnLoad reader =<< do
-    asyncCallback $ do
-      r <- getResult reader
-      putMVar mvar r
-  readText reader file
-  SetContent <$> readMVar mvar
-updateModel (SetContent c) m = noEff m { info = c }
-updateModel NoOp m = noEff m
-
--- | View function, with routing
-viewModel :: Model -> View Action
-viewModel Model {..} = view
-  where
-    view = div_ [] [
-        "FileReader API example"
-      , input_ [ id_ "fileReader"
-             , type_ "file"
-             , onChange (const ReadFile)
-             ]
-      , div_ [] [ text info ]
-      ]
-
-foreign import javascript unsafe "console.log($1);"
-  consoleLog :: JSVal -> IO ()
-
-foreign import javascript unsafe "$r = new FileReader();"
-  newReader :: IO JSVal
-
-foreign import javascript unsafe "$r = document.getElementById($1);"
-  getElementById :: MisoString -> IO JSVal
-
-foreign import javascript unsafe "$r = $1.files[0];"
-  getFile :: JSVal -> IO JSVal
-
-foreign import javascript unsafe "$1.onload = $2;"
-  setOnLoad :: JSVal -> Callback (IO ()) -> IO ()
-
-foreign import javascript unsafe "$r = $1.result;"
-  getResult :: JSVal -> IO MisoString
-
-foreign import javascript unsafe "$1.readAsText($2);"
-  readText :: JSVal -> JSVal -> IO ()
diff --git a/examples/mario/Main.hs b/examples/mario/Main.hs
deleted file mode 100644
--- a/examples/mario/Main.hs
+++ /dev/null
@@ -1,148 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards   #-}
-{-# LANGUAGE MultiWayIf        #-}
-{-# LANGUAGE BangPatterns      #-}
-module Main where
-
-import           Data.Bool
-import           Data.Function
-import qualified Data.Map      as M
-import           Data.Monoid
-
-import           Miso
-import           Miso.String
-
-data Action
-  = GetArrows !Arrows
-  | Time !Double
-  | WindowCoords !(Int,Int)
-  | NoOp
-
-spriteFrames :: [MisoString]
-spriteFrames = ["0 0", "-74px 0","-111px 0","-148px 0","-185px 0","-222px 0","-259px 0","-296px 0"]
-
-main :: IO ()
-main = do
-    time <- now
-    let m = mario { time = time }
-    startApp App { model = m, initialAction = NoOp, ..}
-  where
-    update = updateMario
-    view   = display
-    events = defaultEvents
-    subs   = [ arrowsSub GetArrows
-             , windowSub WindowCoords
-             ]
-    mountPoint = Nothing
-
-data Model = Model
-    { x :: !Double
-    , y :: !Double
-    , vx :: !Double
-    , vy :: !Double
-    , dir :: !Direction
-    , time :: !Double
-    , delta :: !Double
-    , arrows :: !Arrows
-    , window :: !(Int,Int)
-    } deriving (Show, Eq)
-
-data Direction
-  = L
-  | R
-  deriving (Show,Eq)
-
-mario :: Model
-mario = Model
-    { x = 0
-    , y = 0
-    , vx = 0
-    , vy = 0
-    , dir = R
-    , time = 0
-    , delta = 0
-    , arrows = Arrows 0 0
-    , window = (0,0)
-    }
-
-updateMario :: Action -> Model -> Effect Action Model
-updateMario NoOp m = step m
-updateMario (GetArrows arrs) m = noEff newModel
-  where
-    newModel = m { arrows = arrs }
-updateMario (Time newTime) m = step newModel
-  where
-    newModel = m { delta = (newTime - time m) / 20
-                 , time = newTime
-                 }
-updateMario (WindowCoords coords) m = noEff newModel
-  where
-    newModel = m { window = coords }
-
-step :: Model -> Effect Action Model
-step m@Model{..} = k <# do Time <$> now
-  where
-    k = m & gravity delta
-          & jump arrows
-          & walk arrows
-          & physics delta
-
-jump :: Arrows -> Model -> Model
-jump Arrows{..} m@Model{..} =
-    if arrowY > 0 && vy == 0
-      then m { vy = 6 }
-      else m
-
-gravity :: Double -> Model -> Model
-gravity dt m@Model{..} =
-  m { vy = if y > 0 then vy - (dt / 4) else 0 }
-
-physics :: Double -> Model -> Model
-physics dt m@Model{..} =
-  m { x = x + dt * vx
-    , y = max 0 (y + dt * vy)
-    }
-
-walk :: Arrows -> Model -> Model
-walk Arrows{..} m@Model{..} =
-  m { vx = fromIntegral arrowX
-    , dir = if | arrowX < 0 -> L
-               | arrowX > 0 -> R
-               | otherwise -> dir
-    }
-
-display :: Model -> View action
-display m@Model{..} = marioImage
-  where
-    (h,w) = window
-    groundY = 62 - (fromIntegral (fst window) / 2)
-    marioImage =
-      div_ [ height_ $ ms h
-           , width_ $ ms w
-           ] [ div_ [ style_ (marioStyle m groundY) ] [] ]
-
-marioStyle :: Model -> Double -> M.Map MisoString MisoString
-marioStyle Model {..} gy =
-  M.fromList [ ("transform", matrix dir x $ abs (y + gy) )
-             , ("display", "block")
-             , ("width", "37px")
-             , ("height", "37px")
-             , ("background-color", "transparent")
-             , ("background-image", "url(imgs/mario.png)")
-             , ("background-repeat", "no-repeat")
-             , ("background-position", spriteFrames !! frame)
-             , bool mempty ("animation", "play 0.8s steps(8) infinite") (y == 0 && vx /= 0)
-             ]
-  where
-    frame | y > 0 = 1
-          | otherwise = 0
-
-matrix :: Direction -> Double -> Double -> MisoString
-matrix dir x y =
-  "matrix("
-     <> (if dir == L then "-1" else "1")
-     <> ",0,0,1,"
-     <> ms x
-     <> ","
-     <> ms y
-     <> ")"
diff --git a/examples/mario/imgs/mario.png b/examples/mario/imgs/mario.png
deleted file mode 100644
Binary files a/examples/mario/imgs/mario.png and /dev/null differ
diff --git a/examples/mario/index.html b/examples/mario/index.html
deleted file mode 100644
--- a/examples/mario/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <style>
-      @keyframes play { 100% { background-position: -296px; } }
-    </style>
-  </head>
-  <body>
-    <script src='all.js'></script>
-  </body>
-</html>
diff --git a/examples/router/Main.hs b/examples/router/Main.hs
deleted file mode 100644
--- a/examples/router/Main.hs
+++ /dev/null
@@ -1,91 +0,0 @@
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TypeOperators #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE CPP #-}
-module Main where
-
-import Data.Proxy
-import Servant.API
-#if MIN_VERSION_servant(0,10,0)
-import Servant.Utils.Links
-#endif
-
-import Miso
-
--- | Model
-data Model
-  = Model
-  { uri :: URI
-    -- ^ current URI of application
-  } deriving (Eq, Show)
-
--- | Action
-data Action
-  = HandleURI URI
-  | ChangeURI URI
-  | NoOp
-  deriving (Show, Eq)
-
--- | Main entry point
-main :: IO ()
-main = do
-  currentURI <- getCurrentURI
-  startApp App { model = Model currentURI, initialAction = NoOp, ..}
-  where
-    update = updateModel
-    events = defaultEvents
-    subs   = [ uriSub HandleURI ]
-    view   = viewModel
-    mountPoint = Nothing
-
--- | Update your model
-updateModel :: Action -> Model -> Effect Action Model
-updateModel (HandleURI u) m = m { uri = u } <# do
-  pure NoOp
-updateModel (ChangeURI u) m = m <# do
-  pushURI u
-  pure NoOp
-updateModel _ m = noEff m
-
--- | View function, with routing
-viewModel :: Model -> View Action
-viewModel model = view
-  where
-    view =
-      either (const the404) id
-        $ runRoute (Proxy :: Proxy API) handlers uri model
-    handlers = about :<|> home
-    home (_ :: Model) = div_ [] [
-        div_ [] [ text "home" ]
-      , button_ [ onClick goAbout ] [ text "go about" ]
-      ]
-    about (_ :: Model) = div_ [] [
-        div_ [] [ text "about" ]
-      , button_ [ onClick goHome ] [ text "go home" ]
-      ]
-    the404 = div_ [] [
-        text "the 404 :("
-      , button_ [ onClick goHome ] [ text "go home" ]
-      ]
-
--- | Type-level routes
-type API   = About :<|> Home
-type Home  = View Action
-type About = "about" :> View Action
-
--- | Type-safe links used in `onClick` event handlers to route the application
-goAbout, goHome :: Action
-(goHome, goAbout) = (goto api home, goto api about)
-  where
-#if MIN_VERSION_servant(0,10,0)
-    goto a b = ChangeURI (linkURI (safeLink a b))
-#else
-    goto a b = ChangeURI (safeLink a b)
-#endif
-    home  = Proxy :: Proxy Home
-    about = Proxy :: Proxy About
-    api   = Proxy :: Proxy API
-
diff --git a/examples/svg/Main.hs b/examples/svg/Main.hs
deleted file mode 100644
--- a/examples/svg/Main.hs
+++ /dev/null
@@ -1,82 +0,0 @@
-{-# LANGUAGE OverloadedStrings          #-}
-{-# LANGUAGE RecordWildCards            #-}
-{-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE TypeOperators              #-}
-module Main where
-
-import qualified Data.Map      as M
-
-import           Control.Arrow
-import           Miso
-import           Miso.String   (MisoString, pack, ms)
-import           Miso.Svg      hiding (height_, id_, style_, width_)
-import           Touch
-
-trunc = truncate *** truncate
-
-main :: IO ()
-main = startApp App {..}
-  where
-    initialAction = Id
-    model         = emptyModel
-    update        = updateModel
-    view          = viewModel
-    events        = M.insert (pack "mousemove") False $
-                    M.insert (pack "touchstart") False $
-                    M.insert (pack "touchmove") False defaultEvents
-    subs          = [ mouseSub HandleMouse ]
-    mountPoint    = Nothing
-
-emptyModel :: Model
-emptyModel = Model (0,0)
-
-updateModel :: Action -> Model -> Effect Action Model
-updateModel (HandleTouch (TouchEvent touch)) model =
-  model <# do
-    putStrLn "Touch did move"
-    print touch
-    return $ HandleMouse $ trunc . page $ touch
-updateModel (HandleMouse newCoords) model =
-  noEff model { mouseCoords = newCoords }
-updateModel Id model = noEff model
-
-data Action
-  = HandleMouse (Int, Int)
-  | HandleTouch TouchEvent
-  | Id
-
-newtype Model
-  = Model
-  { mouseCoords  :: (Int, Int)
-  } deriving (Show, Eq)
-
-viewModel :: Model -> View Action
-viewModel (Model (x,y)) =
-  div_ [ ] [
-    svg_ [ style_ $ M.fromList [ ("border-style", "solid")
-                               , ("height", "700px")
-                               ]
-         , width_ "auto"
-         , onTouchMove HandleTouch
-       ] [
-     g_ [] [
-     ellipse_ [ cx_ $ ms x
-              , cy_ $ ms y
-              , style_ svgStyle
-              , rx_ "100"
-              , ry_ "100"
-              ] [ ]
-     ]
-     , text_ [ x_ $ ms x
-             , y_ $ ms y
-             ] [ text $ ms $ show (x,y) ]
-   ]
- ]
-
-svgStyle :: M.Map MisoString MisoString
-svgStyle =
-  M.fromList [
-      ("fill", "yellow")
-    , ("stroke", "purple")
-    , ("stroke-width", "2")
-    ]
diff --git a/examples/svg/Touch.hs b/examples/svg/Touch.hs
deleted file mode 100644
--- a/examples/svg/Touch.hs
+++ /dev/null
@@ -1,44 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards #-}
-module Touch where
-
-import Control.Monad
-import Data.Aeson.Types
-import Debug.Trace
-import Miso
-
-data Touch = Touch
-  { identifier :: Int
-  , screen :: (Int, Int)
-  , client :: (Double, Double)
-  , page :: (Double, Double)
-  } deriving (Eq, Show)
-
-instance FromJSON Touch where
-  parseJSON =
-    withObject "touch" $ \o -> do
-      identifier <- o .: "identifier"
-      screen <- (,) <$> o .: "screenX" <*> o .: "screenY"
-      client <- (,) <$> o .: "clientX" <*> o .: "clientY"
-      page <- (,) <$> o .: "pageX" <*> o .: "pageY"
-      return Touch {..}
-
-data TouchEvent =
-  TouchEvent Touch
-  deriving (Eq, Show)
-
-instance FromJSON TouchEvent where
-  parseJSON obj = do
-    ((x:_):_) <- parseJSON obj
-    return $ TouchEvent x
-
-touchDecoder :: Decoder TouchEvent
-touchDecoder = Decoder {..}
-  where
-    decodeAt = DecodeTargets [["changedTouches"], ["targetTouches"], ["touches"]]
-    decoder = parseJSON
-
-onTouchMove :: (TouchEvent -> action) -> Attribute action
-onTouchMove = on "touchmove" touchDecoder
-
-onTouchStart = on "touchstart" touchDecoder
diff --git a/examples/three/Main.hs b/examples/three/Main.hs
deleted file mode 100644
--- a/examples/three/Main.hs
+++ /dev/null
@@ -1,154 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards   #-}
-module Main where
-
-import           Control.Monad
-import           Data.IORef
-import qualified Data.Map      as M
-import           GHCJS.Types
-
-import           Miso
-import           Miso.String
-
-data Action
-  = GetTime
-  | Init
-  | SetTime !Double
-
-withStats :: JSVal -> IO () -> IO ()
-withStats stats m = do
-  statsBegin stats >> m
-  statsEnd stats
-
-data Context = Context
-  { rotateCube :: IO ()
-  , renderScene :: IO ()
-  , stats :: JSVal
-  }
-
-initContext :: IORef Context -> IO ()
-initContext ref = do
-  canvas <- getElementById "canvas"
-  scene <- newScene
-  camera <- newCamera
-  renderer <- newRenderer canvas
-  setSize renderer
-  cube <- join $ newMesh
-    <$> newBoxGeometry 1 1 1
-    <*> newMeshBasicMaterial
-  addToScene scene cube
-  positionCamera camera 5
-  stats <- newStats
-  statsContainer <- getElementById "stats"
-  addStatsToDOM statsContainer stats
-  writeIORef ref Context {
-    stats = stats
-  , rotateCube = do
-      rotateX cube 0.1
-      rotateY cube 0.1
-  , renderScene =
-      render renderer scene camera
-  }
-
-main :: IO ()
-main = do
-  stats <- newStats
-  ref <- newIORef $ Context (pure ()) (pure ()) stats
-  m <- now
-  startApp App { model = m
-               , initialAction = Init
-               , update = updateModel ref
-               , mountPoint = Nothing
-               , ..
-               }
-    where
-      events = defaultEvents
-      view   = viewModel
-      subs   = []
-
-viewModel :: Double -> View action
-viewModel _ = div_ [] [
-    div_ [ id_ "stats"
-         , style_ $ M.singleton "position" "absolute"
-         ] []
-  , canvas_ [ id_ "canvas"
-            , width_ "400"
-            , height_ "300"
-            ] []
-  ]
-
-updateModel
-  :: IORef Context
-  -> Action
-  -> Double
-  -> Effect Action Double
-updateModel ref Init m = m <# do
-  initContext ref
-  pure GetTime
-
-updateModel ref GetTime m = m <# do
-  Context {..} <- readIORef ref
-  withStats stats $ do
-    rotateCube
-    renderScene
-  SetTime <$> now
-
-updateModel _ (SetTime m) _ =
-  m <# pure GetTime
-
-foreign import javascript unsafe "$r = new Stats();"
-  newStats :: IO JSVal
-
-foreign import javascript unsafe "$1.begin();"
-  statsBegin :: JSVal -> IO ()
-
-foreign import javascript unsafe "$1.end();"
-  statsEnd :: JSVal -> IO ()
-
-foreign import javascript unsafe "$1.showPanel(0);"
-  showPanel :: JSVal -> IO ()
-
-foreign import javascript unsafe "$r = new THREE.Scene();"
-  newScene :: IO JSVal
-
-foreign import javascript unsafe "$r = new THREE.BoxGeometry( $1, $2, $3 );"
-  newBoxGeometry :: Int -> Int -> Int -> IO JSVal
-
-foreign import javascript unsafe "$r = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );"
-  newCamera :: IO JSVal
-
-foreign import javascript unsafe "$r = new THREE.Mesh( $1, $2 );"
-  newMesh :: JSVal -> JSVal -> IO JSVal
-
-foreign import javascript unsafe "$r = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );"
-  newMeshBasicMaterial :: IO JSVal
-
-foreign import javascript unsafe "$r = new THREE.WebGLRenderer({canvas:$1, antialias : true});"
-  newRenderer :: JSVal -> IO JSVal
-
-foreign import javascript unsafe "$1.setSize( window.innerWidth, window.innerHeight );"
-  setSize :: JSVal -> IO ()
-
-foreign import javascript unsafe "$r = document.getElementById($1);"
-  getElementById :: MisoString -> IO JSVal
-
-foreign import javascript unsafe "$1.add($2);"
-  addToScene :: JSVal -> JSVal -> IO ()
-
-foreign import javascript unsafe "$1.position.z = $2;"
-  cameraZ :: JSVal -> Int -> IO ()
-
-foreign import javascript unsafe "$1.rotation.x += $2;"
-  rotateX :: JSVal -> Double -> IO ()
-
-foreign import javascript unsafe "$1.rotation.y += $2;"
-  rotateY :: JSVal -> Double -> IO ()
-
-foreign import javascript unsafe "$1.render($2, $3);"
-  render :: JSVal -> JSVal -> JSVal -> IO ()
-
-foreign import javascript unsafe "$1.position.z = $2;"
-  positionCamera :: JSVal -> Double -> IO ()
-
-foreign import javascript unsafe "$1.appendChild( $2.domElement );"
-  addStatsToDOM :: JSVal -> JSVal -> IO ()
diff --git a/examples/todo-mvc/Main.hs b/examples/todo-mvc/Main.hs
deleted file mode 100644
--- a/examples/todo-mvc/Main.hs
+++ /dev/null
@@ -1,312 +0,0 @@
-{-# LANGUAGE TypeOperators              #-}
-{-# LANGUAGE OverloadedStrings          #-}
-{-# LANGUAGE FlexibleInstances          #-}
-{-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE DataKinds                  #-}
-{-# LANGUAGE DeriveGeneric              #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-{-# LANGUAGE RecordWildCards            #-}
-{-# LANGUAGE LambdaCase                 #-}
-{-# LANGUAGE MultiParamTypeClasses      #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE ExtendedDefaultRules #-}
-module Main where
-
-import           Data.Aeson   hiding (Object)
-import           Data.Bool
-import qualified Data.Map     as M
-import           Data.Monoid
-import           GHC.Generics
-import           Miso
-import           Miso.String  (MisoString)
-import qualified Miso.String  as S
-
-default (MisoString)
-
-data Model = Model
-  { entries :: [Entry]
-  , field :: MisoString
-  , uid :: Int
-  , visibility :: MisoString
-  , step :: Bool
-  } deriving (Show, Generic, Eq)
-
-data Entry = Entry
-  { description :: MisoString
-  , completed :: Bool
-  , editing :: Bool
-  , eid :: Int
-  , focussed :: Bool
-  } deriving (Show, Generic, Eq)
-
-instance ToJSON Entry
-instance ToJSON Model
-
-instance FromJSON Entry
-instance FromJSON Model
-
-emptyModel :: Model
-emptyModel = Model
-  { entries = []
-  , visibility = "All"
-  , field = mempty
-  , uid = 0
-  , step = False
-  }
-
-newEntry :: MisoString -> Int -> Entry
-newEntry desc eid = Entry
-  { description = desc
-  , completed = False
-  , editing = False
-  , eid = eid
-  , focussed = False
-  }
-
-data Msg
-  = NoOp
-  | CurrentTime Int
-  | UpdateField MisoString
-  | EditingEntry Int Bool
-  | UpdateEntry Int MisoString
-  | Add
-  | Delete Int
-  | DeleteComplete
-  | Check Int Bool
-  | CheckAll Bool
-  | ChangeVisibility MisoString
-   deriving Show
-
-main :: IO ()
-main = startApp App { initialAction = NoOp, ..}
-  where
-    model      = emptyModel
-    update     = updateModel
-    view       = viewModel
-    events     = defaultEvents
-    mountPoint = Nothing
-    subs       = []
-
-updateModel :: Msg -> Model -> Effect Msg Model
-updateModel NoOp m = noEff m
-updateModel (CurrentTime n) m =
-  m <# do print n >> pure NoOp
-updateModel Add model@Model{..} =
-  noEff model {
-    uid = uid + 1
-  , field = mempty
-  , entries = entries <> [ newEntry field uid | not $ S.null field ]
-  }
-updateModel (UpdateField str) model = noEff model { field = str }
-updateModel (EditingEntry id' isEditing) model@Model{..} =
-  model { entries = newEntries } <# do
-    focus $ S.pack $ "todo-" ++ show id'
-    pure NoOp
-    where
-      newEntries = filterMap entries (\t -> eid t == id') $
-         \t -> t { editing = isEditing, focussed = isEditing }
-
-updateModel (UpdateEntry id' task) model@Model{..} =
-  noEff model { entries = newEntries }
-    where
-      newEntries =
-        filterMap entries ((==id') . eid) $ \t ->
-           t { description = task }
-
-updateModel (Delete id') model@Model{..} =
-  noEff model { entries = filter (\t -> eid t /= id') entries }
-
-updateModel DeleteComplete model@Model{..} =
-  noEff model { entries = filter (not . completed) entries }
-
-updateModel (Check id' isCompleted) model@Model{..} =
-   model { entries = newEntries } <# eff
-    where
-      eff =
-        putStrLn "clicked check" >>
-          pure NoOp
-
-      newEntries =
-        filterMap entries (\t -> eid t == id') $ \t ->
-          t { completed = isCompleted }
-
-updateModel (CheckAll isCompleted) model@Model{..} =
-  noEff model { entries = newEntries }
-    where
-      newEntries =
-        filterMap entries (const True) $
-          \t -> t { completed = isCompleted }
-
-updateModel (ChangeVisibility v) model =
-  noEff model { visibility = v }
-
-filterMap :: [a] -> (a -> Bool) -> (a -> a) -> [a]
-filterMap xs predicate f = go' xs
-  where
-    go' [] = []
-    go' (y:ys)
-     | predicate y = f y : go' ys
-     | otherwise   = y : go' ys
-
-viewModel :: Model -> View Msg
-viewModel m@Model{..} =
- div_
-    [ class_ "todomvc-wrapper"
-    , style_  $ M.singleton "visibility" "hidden"
-    ]
-    [ section_
-        [ class_ "todoapp" ]
-        [ viewInput m field
-        , viewEntries visibility entries
-        , viewControls m visibility entries
-        ]
-    , infoFooter
-    ]
-
-viewEntries :: MisoString -> [ Entry ] -> View Msg
-viewEntries visibility entries =
-  section_
-    [ class_ "main"
-    , style_ $ M.singleton "visibility" cssVisibility
-    ]
-    [ input_
-        [ class_ "toggle-all"
-        , type_ "checkbox"
-        , name_ "toggle"
-        , checked_ allCompleted
-        , onClick $ CheckAll (not allCompleted)
-        ]
-      , label_
-        [ for_ "toggle-all" ]
-          [ text $ S.pack "Mark all as complete" ]
-      , ul_ [ class_ "todo-list" ] $
-         flip map (filter isVisible entries) $ \t ->
-           viewKeyedEntry t
-      ]
-  where
-    cssVisibility = bool "visible" "hidden" (null entries)
-    allCompleted = all (==True) $ completed <$> entries
-    isVisible Entry {..} =
-      case visibility of
-        "Completed" -> completed
-        "Active" -> not completed
-        _ -> True
-
-viewKeyedEntry :: Entry -> View Msg
-viewKeyedEntry = viewEntry
-
-viewEntry :: Entry -> View Msg
-viewEntry Entry {..} = liKeyed_ (toKey eid)
-    [ class_ $ S.intercalate " " $
-       [ "completed" | completed ] <> [ "editing" | editing ]
-    ]
-    [ div_
-        [ class_ "view" ]
-        [ input_
-            [ class_ "toggle"
-            , type_ "checkbox"
-            , checked_ completed
-            , onClick $ Check eid (not completed)
-            ]
-        , label_
-            [ onDoubleClick $ EditingEntry eid True ]
-            [ text description ]
-        , button_
-            [ class_ "destroy"
-            , onClick $ Delete eid
-            ] []
-        ]
-    , input_
-        [ class_ "edit"
-        , value_ description
-        , name_ "title"
-        , id_ $ "todo-" <> S.ms eid
-        , onInput $ UpdateEntry eid
-        , onBlur $ EditingEntry eid False
-        , onEnter $ EditingEntry eid False
-        ]
-    ]
-
-viewControls :: Model ->  MisoString -> [ Entry ] -> View Msg
-viewControls model visibility entries =
-  footer_  [ class_ "footer"
-           , hidden_ (null entries)
-           ]
-      [ viewControlsCount entriesLeft
-      , viewControlsFilters visibility
-      , viewControlsClear model entriesCompleted
-      ]
-  where
-    entriesCompleted = length . filter completed $ entries
-    entriesLeft = length entries - entriesCompleted
-
-viewControlsCount :: Int -> View Msg
-viewControlsCount entriesLeft =
-  span_ [ class_ "todo-count" ]
-     [ strong_ [] [ text $ S.ms entriesLeft ]
-     , text (item_ <> " left")
-     ]
-  where
-    item_ = S.pack $ bool " items" " item" (entriesLeft == 1)
-
-viewControlsFilters :: MisoString -> View Msg
-viewControlsFilters visibility =
-  ul_
-    [ class_ "filters" ]
-    [ visibilitySwap "#/" "All" visibility
-    , text " "
-    , visibilitySwap "#/active" "Active" visibility
-    , text " "
-    , visibilitySwap "#/completed" "Completed" visibility
-    ]
-
-visibilitySwap :: MisoString -> MisoString -> MisoString -> View Msg
-visibilitySwap uri visibility actualVisibility =
-  li_ [  ]
-      [ a_ [ href_ uri
-           , class_ $ S.concat [ "selected" | visibility == actualVisibility ]
-           , onClick (ChangeVisibility visibility)
-           ] [ text visibility ]
-      ]
-
-viewControlsClear :: Model -> Int -> View Msg
-viewControlsClear _ entriesCompleted =
-  button_
-    [ class_ "clear-completed"
-    , prop "hidden" (entriesCompleted == 0)
-    , onClick DeleteComplete
-    ]
-    [ text $ "Clear completed (" <> S.ms entriesCompleted <> ")" ]
-
-viewInput :: Model -> MisoString -> View Msg
-viewInput _ task =
-  header_ [ class_ "header" ]
-    [ h1_ [] [ text "todos" ]
-    , input_
-        [ class_ "new-todo"
-        , placeholder_ "What needs to be done?"
-        , autofocus_ True
-        , value_ task
-        , name_ "newTodo"
-        , onInput UpdateField
-        , onEnter Add
-        ]
-    ]
-
-onEnter :: Msg -> Attribute Msg
-onEnter action =
-  onKeyDown $ bool NoOp action . (== KeyCode 13)
-
-infoFooter :: View Msg
-infoFooter =
-    footer_ [ class_ "info" ]
-    [ p_ [] [ text "Double-click to edit a todo" ]
-    , p_ []
-        [ text "Written by "
-        , a_ [ href_ "https://github.com/dmjio" ] [ text "David Johnson" ]
-        ]
-    , p_ []
-        [ text "Part of "
-        , a_ [ href_ "http://todomvc.com" ] [ text "TodoMVC" ]
-        ]
-    ]
diff --git a/examples/todo-mvc/index.html b/examples/todo-mvc/index.html
deleted file mode 100644
--- a/examples/todo-mvc/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <link rel='stylesheet' href='https://d33wubrfki0l68.cloudfront.net/css/d0175a264698385259b5f1638f2a39134ee445a0/style.css'/>
-  </head>
-  <body>
-    <script src='all.js'></script>
-  </body>
-</html>
diff --git a/examples/websocket/Main.hs b/examples/websocket/Main.hs
deleted file mode 100644
--- a/examples/websocket/Main.hs
+++ /dev/null
@@ -1,73 +0,0 @@
-{-# LANGUAGE DeriveGeneric              #-}
-{-# LANGUAGE RecordWildCards            #-}
-{-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE TypeOperators              #-}
-{-# LANGUAGE FlexibleInstances          #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-{-# LANGUAGE DataKinds                  #-}
-{-# LANGUAGE OverloadedStrings          #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE MultiParamTypeClasses      #-}
-{-# LANGUAGE ExtendedDefaultRules       #-}
-module Main where
-
-import           Data.Aeson
-import           GHC.Generics
-import           Data.Bool
-import qualified Data.Map as M
-
-import           Miso
-import           Miso.String  (MisoString)
-import qualified Miso.String  as S
-
-main :: IO ()
-main = startApp App { initialAction = Id, ..}
-  where
-    model = Model mempty mempty
-    events = defaultEvents
-    subs = [ websocketSub uri protocols HandleWebSocket ]
-    update = updateModel
-    view = appView
-    uri = URL "wss://echo.websocket.org"
-    protocols = Protocols [ ]
-    mountPoint = Nothing
-
-updateModel :: Action -> Model -> Effect Action Model
-updateModel (HandleWebSocket (WebSocketMessage (Message m))) model
-  = noEff model { received = m }
-updateModel (SendMessage msg) model = model <# do send msg >> pure Id
-updateModel (UpdateMessage m) model = noEff model { msg = Message m }
-updateModel _ model = noEff model
-
-instance ToJSON Message
-instance FromJSON Message
-
-newtype Message = Message MisoString
-  deriving (Eq, Show, Generic, Monoid)
-
-data Action
-  = HandleWebSocket (WebSocket Message)
-  | SendMessage Message
-  | UpdateMessage MisoString
-  | Id
-
-data Model = Model {
-    msg :: Message
-  , received :: MisoString
-  } deriving (Show, Eq)
-
-appView :: Model -> View Action
-appView Model{..} = div_ [ style_ $ M.fromList [("text-align", "center")] ] [
-   h1_ [style_ $ M.fromList [("font-weight", "bold")] ] [ a_ [ href_ "https://github.com/dmjio/miso" ] [ text $ S.pack "Miso Websocket Example" ] ]
- , h3_ [] [ text $ S.pack "wss://echo.websocket.org" ]
- , input_  [ type_ "text"
-           , onInput UpdateMessage
-           , onEnter (SendMessage msg)
-           ]
- , button_ [ onClick (SendMessage msg)
-           ] [ text (S.pack "Send to echo server") ]
- , div_ [ ] [ p_ [ ] [ text received | not . S.null $ received ] ]
- ]
-
-onEnter :: Action -> Attribute Action
-onEnter action = onKeyDown $ bool Id action . (== KeyCode 13)
diff --git a/examples/websocket/index.html b/examples/websocket/index.html
deleted file mode 100644
--- a/examples/websocket/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <link rel='stylesheet' href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.3/css/bulma.min.css"'/>
-  </head>
-  <body>
-    <script src='all.js'></script>
-  </body>
-</html>
diff --git a/examples/xhr/Main.hs b/examples/xhr/Main.hs
deleted file mode 100644
--- a/examples/xhr/Main.hs
+++ /dev/null
@@ -1,145 +0,0 @@
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE TypeOperators #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TypeFamilies #-}
-module Main where
-
-import           Data.Aeson
-import           Data.Aeson.Types
-import qualified Data.Map                      as M
-import           Data.Maybe
-import           GHC.Generics
-import           JavaScript.Web.XMLHttpRequest
-
-import           Miso                          hiding (defaultOptions)
-import           Miso.String
-
--- | Model
-data Model
-  = Model
-  { info :: Maybe APIInfo
-  } deriving (Eq, Show)
-
--- | Action
-data Action
-  = FetchGitHub
-  | SetGitHub APIInfo
-  | NoOp
-  deriving (Show, Eq)
-
--- | Main entry point
-main :: IO ()
-main = do
-  startApp App { model = Model Nothing
-               , initialAction = NoOp
-               , mountPoint = Nothing
-               , ..
-               }
-    where
-      update = updateModel
-      events = defaultEvents
-      subs   = []
-      view   = viewModel
-
--- | Update your model
-updateModel :: Action -> Model -> Effect Action Model
-updateModel FetchGitHub m = m <# do
-  SetGitHub <$> getGitHubAPIInfo
-updateModel (SetGitHub apiInfo) m =
-  noEff m { info = Just apiInfo }
-updateModel NoOp m = noEff m
-
--- | View function, with routing
-viewModel :: Model -> View Action
-viewModel Model {..} = view
-  where
-    view = div_ [ style_ $ M.fromList [
-                  (pack "text-align", pack "center")
-                , (pack "margin", pack "200px")
-                ]
-               ] [
-        h1_ [class_ $ pack "title" ] [ text $ pack "Miso XHR Example" ]
-      , button_ attrs [
-          text $ pack "Fetch JSON from https://api.github.com via XHR"
-          ]
-      , case info of
-          Nothing -> div_ [] [ text $ pack "No data" ]
-          Just APIInfo{..} ->
-            table_ [ class_ $ pack "table is-striped" ] [
-              thead_ [] [
-                tr_ [] [
-                  th_ [] [ text $ pack "URLs"]
-                ]
-              ]
-            , tbody_ [] [
-                tr_ [] [ td_ [] [ text current_user_url ] ]
-              , tr_ [] [ td_ [] [ text emojis_url ] ]
-              , tr_ [] [ td_ [] [ text emails_url ] ]
-              , tr_ [] [ td_ [] [ text events_url ] ]
-              , tr_ [] [ td_ [] [ text gists_url ] ]
-              , tr_ [] [ td_ [] [ text feeds_url ] ]
-              , tr_ [] [ td_ [] [ text followers_url ] ]
-              , tr_ [] [ td_ [] [ text following_url ] ]
-              ]
-            ]
-          ]
-      where
-        attrs = [ onClick FetchGitHub
-                , class_ $ pack "button is-large is-outlined"
-                ] ++ [ disabled_ True | isJust info ]
-
-data APIInfo
-  = APIInfo
-  { current_user_url :: MisoString
-  , current_user_authorizations_html_url :: MisoString
-  , authorizations_url :: MisoString
-  , code_search_url :: MisoString
-  , commit_search_url :: MisoString
-  , emails_url :: MisoString
-  , emojis_url :: MisoString
-  , events_url :: MisoString
-  , feeds_url :: MisoString
-  , followers_url :: MisoString
-  , following_url :: MisoString
-  , gists_url :: MisoString
-  , hub_url :: MisoString
-  , issue_search_url :: MisoString
-  , issues_url :: MisoString
-  , keys_url :: MisoString
-  , notifications_url :: MisoString
-  , organization_repositories_url :: MisoString
-  , organization_url :: MisoString
-  , public_gists_url :: MisoString
-  , rate_limit_url :: MisoString
-  , repository_url :: MisoString
-  , repository_search_url :: MisoString
-  , current_user_repositories_url :: MisoString
-  , starred_url :: MisoString
-  , starred_gists_url :: MisoString
-  , team_url :: MisoString
-  , user_url :: MisoString
-  , user_organizations_url :: MisoString
-  , user_repositories_url :: MisoString
-  , user_search_url :: MisoString
-  } deriving (Show, Eq, Generic)
-
-instance FromJSON APIInfo where
-  parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = camelTo '_' }
-
-getGitHubAPIInfo :: IO APIInfo
-getGitHubAPIInfo = do
-  Just resp <- contents <$> xhrByteString req
-  case eitherDecodeStrict resp :: Either String APIInfo of
-    Left s -> error s
-    Right j -> pure j
-  where
-    req = Request { reqMethod = GET
-                  , reqURI = pack "https://api.github.com"
-                  , reqLogin = Nothing
-                  , reqHeaders = []
-                  , reqWithCredentials = False
-                  , reqData = NoData
-                  }
-
diff --git a/exe/Main.hs b/exe/Main.hs
deleted file mode 100644
--- a/exe/Main.hs
+++ /dev/null
@@ -1,40 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards #-}
-module Main where
-
-import Miso
-import Miso.String
-
-type Model = Int
-
-main :: IO ()
-main = startApp App { initialAction = SayHelloWorld, ..}
-  where
-    model  = 0
-    update = updateModel
-    view   = viewModel
-    events = defaultEvents
-    mountPoint = Nothing
-    subs   = []
-
-updateModel :: Action -> Model -> Effect Action Model
-updateModel AddOne m = noEff (m + 1)
-updateModel SubtractOne m = noEff (m - 1)
-updateModel NoOp m = noEff m
-updateModel SayHelloWorld m = m <# do
-  putStrLn "Hello World!" >> pure NoOp
-
-data Action
-  = AddOne
-  | SubtractOne
-  | NoOp
-  | SayHelloWorld
-  deriving (Show, Eq)
-
-viewModel :: Int -> View Action
-viewModel x = div_ [] [
-   button_ [ onClick AddOne ] [ text "+" ]
- , text $ ms (show x)
- , button_ [ onClick SubtractOne ] [ text "-" ]
- ]
-
diff --git a/ffi/ghc/Miso/DSL/FFI.hs b/ffi/ghc/Miso/DSL/FFI.hs
new file mode 100644
--- /dev/null
+++ b/ffi/ghc/Miso/DSL/FFI.hs
@@ -0,0 +1,237 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE DeriveAnyClass     #-}
+-----------------------------------------------------------------------------
+module Miso.DSL.FFI where
+-----------------------------------------------------------------------------
+import           Control.Exception (Exception)
+import           Data.Text (Text, unpack)
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Builder as TB
+import qualified Data.Text.Lazy.Builder.Int as TBI
+import qualified Data.Text.Lazy.Builder.RealFloat as TBR
+import           Text.Read (readMaybe)
+-----------------------------------------------------------------------------
+-- | A type that represents any JS value
+data JSVal = JSVal
+-----------------------------------------------------------------------------
+-- | An exception raised by a rejected JavaScript Promise.
+--
+-- @since 1.13.0.0
+data JSException = JSException
+  deriving stock Show
+  deriving anyclass Exception
+-----------------------------------------------------------------------------
+instance Eq JSVal where
+  JSVal == JSVal = True
+-----------------------------------------------------------------------------
+toJSVal_Bool :: Bool -> IO JSVal
+toJSVal_Bool = undefined
+-----------------------------------------------------------------------------
+toJSVal_Double :: Double -> IO JSVal
+toJSVal_Double = undefined
+-----------------------------------------------------------------------------
+toJSVal_Int :: Int -> IO JSVal
+toJSVal_Int = undefined
+-----------------------------------------------------------------------------
+toJSVal_List :: [JSVal] -> IO JSVal
+toJSVal_List = undefined
+-----------------------------------------------------------------------------
+-- | The 'null' value in JS.
+jsNull :: JSVal
+jsNull = JSVal
+-----------------------------------------------------------------------------
+toJSVal_JSVal :: JSVal -> IO JSVal
+toJSVal_JSVal = undefined
+-----------------------------------------------------------------------------
+toJSVal_Char :: Char -> IO JSVal
+toJSVal_Char = undefined
+-----------------------------------------------------------------------------
+toJSVal_Float :: Float -> IO JSVal
+toJSVal_Float = undefined
+-----------------------------------------------------------------------------
+toJSVal_Text :: Text -> IO JSVal
+toJSVal_Text = undefined
+-----------------------------------------------------------------------------
+fromJSVal_Text :: JSVal -> IO (Maybe Text)
+fromJSVal_Text = undefined
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Text :: JSVal -> IO Text
+fromJSValUnchecked_Text = undefined
+-----------------------------------------------------------------------------
+fromJSVal_Char :: JSVal -> IO (Maybe Char)
+fromJSVal_Char = undefined
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Char :: JSVal -> IO Char
+fromJSValUnchecked_Char = undefined
+-----------------------------------------------------------------------------
+fromJSVal_Float :: JSVal -> IO (Maybe Float)
+fromJSVal_Float = undefined
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Float :: JSVal -> IO Float
+fromJSValUnchecked_Float = undefined
+-----------------------------------------------------------------------------
+fromJSVal_Bool :: JSVal -> IO (Maybe Bool)
+fromJSVal_Bool = undefined
+-----------------------------------------------------------------------------
+new_ffi :: JSVal -> JSVal -> IO JSVal
+new_ffi = undefined
+-----------------------------------------------------------------------------
+eval_ffi :: Text -> IO JSVal
+eval_ffi = undefined
+-----------------------------------------------------------------------------
+create_ffi :: IO JSVal
+create_ffi = undefined
+-----------------------------------------------------------------------------
+getProp_ffi :: Text -> JSVal -> IO JSVal
+getProp_ffi = undefined
+-----------------------------------------------------------------------------
+setProp_ffi :: Text -> JSVal -> JSVal -> IO ()
+setProp_ffi = undefined
+-----------------------------------------------------------------------------
+setField_ffi :: JSVal -> Text -> JSVal -> IO ()
+setField_ffi = undefined
+-----------------------------------------------------------------------------
+fromJSVal_Int :: JSVal -> IO (Maybe Int)
+fromJSVal_Int = undefined
+-----------------------------------------------------------------------------
+fromJSVal_Double :: JSVal -> IO (Maybe Double)
+fromJSVal_Double  = undefined
+-----------------------------------------------------------------------------
+getPropIndex_ffi :: Int -> JSVal -> IO JSVal
+getPropIndex_ffi  = undefined
+-----------------------------------------------------------------------------
+isNull_ffi :: JSVal -> Bool
+isNull_ffi = undefined
+-----------------------------------------------------------------------------
+isUndefined_ffi :: JSVal -> Bool
+isUndefined_ffi = undefined
+-----------------------------------------------------------------------------
+freeFunction_ffi :: JSVal -> IO ()
+freeFunction_ffi = undefined
+
+freeJSVal_ffi :: JSVal -> IO ()
+freeJSVal_ffi _ = pure ()
+-----------------------------------------------------------------------------
+-- | Schedules a callback to run before the next repaint.
+--
+-- @since 1.13.0.0
+requestAnimationFrame :: JSVal -> IO Int
+requestAnimationFrame = undefined
+-----------------------------------------------------------------------------
+-- | High-resolution timestamp where one exists, wall clock where it does not.
+now_ffi :: IO Double
+now_ffi = undefined
+-----------------------------------------------------------------------------
+-- | Cancels a frame previously scheduled with 'requestAnimationFrame'.
+--
+-- @since 1.13.0.0
+cancelAnimationFrame :: Int -> IO ()
+cancelAnimationFrame = undefined
+-----------------------------------------------------------------------------
+toJSVal_JSString :: Text -> IO JSVal
+toJSVal_JSString = undefined
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Maybe :: JSVal -> IO (Maybe JSVal)
+fromJSValUnchecked_Maybe = undefined
+-----------------------------------------------------------------------------
+fromJSVal_Maybe :: JSVal -> IO (Maybe (Maybe JSVal))
+fromJSVal_Maybe = undefined
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Bool :: JSVal -> IO Bool
+fromJSValUnchecked_Bool = undefined
+-----------------------------------------------------------------------------
+invokeFunction :: JSVal -> JSVal -> JSVal -> IO JSVal
+invokeFunction = undefined
+-----------------------------------------------------------------------------
+listProps_ffi :: JSVal -> IO JSVal
+listProps_ffi = undefined
+-----------------------------------------------------------------------------
+setPropIndex_ffi :: Int -> JSVal -> JSVal -> IO ()
+setPropIndex_ffi = undefined
+-----------------------------------------------------------------------------
+-- | The @globalThis@ object in JS.
+global :: JSVal
+global = undefined
+-----------------------------------------------------------------------------
+fromJSVal_List :: JSVal -> IO (Maybe [JSVal])
+fromJSVal_List = undefined
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Int :: JSVal -> IO Int
+fromJSValUnchecked_Int = undefined
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Double :: JSVal -> IO Double
+fromJSValUnchecked_Double = undefined
+-----------------------------------------------------------------------------
+fromJSVal_JSString :: JSVal -> IO (Maybe Text)
+fromJSVal_JSString = undefined
+-----------------------------------------------------------------------------
+-- | Awaits a JS Promise. If the promise rejects, it throws a t'JSException'.
+--
+-- @since 1.13.0.0
+await :: JSVal -> IO JSVal
+await = undefined
+-----------------------------------------------------------------------------
+-- | A asynchronous callback
+asyncCallback :: IO () -> IO JSVal
+asyncCallback = undefined
+-- | A asynchronous callback with one argument
+asyncCallback1 :: (JSVal -> IO ()) -> IO JSVal
+asyncCallback1 = undefined
+-- | A asynchronous callback with two arguments
+asyncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal
+asyncCallback2 = undefined
+-- | A asynchronous callback with three arguments
+asyncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal
+asyncCallback3 = undefined
+-----------------------------------------------------------------------------
+-- | A synchronous callback
+syncCallback :: IO () -> IO JSVal
+syncCallback = undefined
+-- | A synchronous callback with a single argument
+syncCallback1 :: (JSVal -> IO ()) -> IO JSVal
+syncCallback1 = undefined
+-- | A synchronous callback with two arguments
+syncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal
+syncCallback2 = undefined
+-- | A synchronous callback with three arguments
+syncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal
+syncCallback3 = undefined
+-----------------------------------------------------------------------------
+-- | A synchronous callback that returns a value
+syncCallback' :: IO JSVal -> IO JSVal
+syncCallback' = undefined
+-- | A synchronous callback that takes a single argument and returns a value
+syncCallback1' :: (JSVal -> IO JSVal) -> IO JSVal
+syncCallback1' = undefined
+-- | A synchronous callback that takes two arguments and returns a value
+syncCallback2' :: (JSVal -> JSVal -> IO JSVal) -> IO JSVal
+syncCallback2' = undefined
+-- | A synchronous callback that takes three arguments and returns a value
+syncCallback3' :: (JSVal -> JSVal -> JSVal -> IO JSVal) -> IO JSVal
+syncCallback3' = undefined
+-----------------------------------------------------------------------------
+parseInt :: Text -> Maybe Int
+parseInt = readMaybe . unpack
+-----------------------------------------------------------------------------
+parseDouble :: Text -> Maybe Double
+parseDouble = readMaybe . unpack
+-----------------------------------------------------------------------------
+parseWord :: Text -> Maybe Word
+parseWord = readMaybe . unpack
+-----------------------------------------------------------------------------
+parseFloat :: Text -> Maybe Float
+parseFloat = readMaybe . unpack
+-----------------------------------------------------------------------------
+toString_Int :: Int -> Text
+toString_Int = TL.toStrict . TB.toLazyText . TBI.decimal
+-----------------------------------------------------------------------------
+toString_Word :: Word -> Text
+toString_Word = TL.toStrict . TB.toLazyText . TBI.decimal
+-----------------------------------------------------------------------------
+toString_Float :: Float -> Text
+toString_Float = TL.toStrict . TB.toLazyText . TBR.realFloat
+-----------------------------------------------------------------------------
+toString_Double :: Double -> Text
+toString_Double = TL.toStrict . TB.toLazyText . TBR.realFloat
+-----------------------------------------------------------------------------
diff --git a/ffi/js/Miso/DSL/FFI.hs b/ffi/js/Miso/DSL/FFI.hs
new file mode 100644
--- /dev/null
+++ b/ffi/js/Miso/DSL/FFI.hs
@@ -0,0 +1,482 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE InterruptibleFFI  #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+-----------------------------------------------------------------------------
+module Miso.DSL.FFI
+  ( -- ** Types
+    JSVal
+  , JSString
+  , now_ffi
+    -- ** Serialization FFI
+    -- *** ToJSVal
+  , toJSVal_Char
+  , toJSVal_Bool
+  , toJSVal_Double
+  , toJSVal_Float
+  , toJSVal_Int
+  , toJSVal_List
+  , toJSVal_JSString
+  , toJSVal_Text
+    -- *** FromJSVal
+  , fromJSVal_Text
+  , fromJSValUnchecked_Text
+  , fromJSVal_Char
+  , fromJSValUnchecked_Char
+  , fromJSVal_Bool
+  , fromJSValUnchecked_Bool
+  , fromJSVal_Double
+  , fromJSValUnchecked_Double
+  , fromJSVal_Float
+  , fromJSValUnchecked_Float
+  , fromJSVal_Int
+  , fromJSValUnchecked_Int
+  , fromJSVal_List
+  , fromJSVal_JSString
+  , fromJSVal_Maybe
+  , fromJSValUnchecked_Maybe
+  -- * Callback FFI
+  , awaitPromise_ffi
+  , await
+  , asyncCallback
+  , asyncCallback1
+  , asyncCallback2
+  , asyncCallback3
+  , syncCallback
+  , syncCallback1
+  , syncCallback2
+  , syncCallback3
+  , syncCallback'
+  , syncCallback1'
+  , syncCallback2'
+  , syncCallback3'
+  -- * DSL FFI
+  , invokeFunction
+  , setProp_ffi
+  , new_ffi
+  , getProp_ffi
+  , eval_ffi
+  , setPropIndex_ffi
+  , getPropIndex_ffi
+  , create_ffi
+    -- *** Misc. FFI
+  , global
+  , isUndefined_ffi
+  , isNull_ffi
+  , jsNull
+  , freeFunction_ffi
+  , freeJSVal_ffi
+  , listProps_ffi
+  , requestAnimationFrame
+  , cancelAnimationFrame
+  -- *** String FFI
+  , parseInt
+  , parseDouble
+  , parseWord
+  , parseFloat
+  , toString_Double
+  , toString_Float
+  , toString_Word
+  , toString_Int
+  , JSException
+  ) where
+-----------------------------------------------------------------------------
+import           Data.JSString
+import           Data.Text
+import           Control.Exception (throwIO)
+-----------------------------------------------------------------------------
+import qualified GHCJS.Marshal as Marshal
+import           GHCJS.Types
+#ifdef GHCJS_NEW
+import           GHC.JS.Prim
+import qualified GHC.JS.Foreign.Callback as Callback
+#elif GHCJS_OLD
+import           GHCJS.Prim
+import qualified GHCJS.Foreign.Callback as Callback
+#endif
+-----------------------------------------------------------------------------
+foreign import javascript safe
+#ifdef GHCJS_NEW
+  "(($1,$2) => { return $1 === $2; })"
+#else
+  "$r = $1 === $2;"
+#endif
+  eq :: JSVal -> JSVal -> Bool
+-----------------------------------------------------------------------------
+instance Eq JSVal where
+  (==) = eq
+  {-# INLINE (==) #-}
+-----------------------------------------------------------------------------
+toJSVal_Bool :: Bool -> IO JSVal
+toJSVal_Bool = Marshal.toJSVal
+{-# INLINE toJSVal_Bool #-}
+-----------------------------------------------------------------------------
+toJSVal_Double :: Double -> IO JSVal
+toJSVal_Double = Marshal.toJSVal
+{-# INLINE toJSVal_Double #-}
+-----------------------------------------------------------------------------
+toJSVal_Int :: Int -> IO JSVal
+toJSVal_Int = Marshal.toJSVal
+{-# INLINE toJSVal_Int #-}
+-----------------------------------------------------------------------------
+toJSVal_List :: [JSVal] -> IO JSVal
+toJSVal_List = Marshal.toJSVal
+{-# INLINE toJSVal_List #-}
+-----------------------------------------------------------------------------
+fromJSVal_Bool :: JSVal -> IO (Maybe Bool)
+fromJSVal_Bool = Marshal.fromJSVal
+{-# INLINE fromJSVal_Bool #-}
+-----------------------------------------------------------------------------
+foreign import javascript safe
+#ifdef GHCJS_NEW
+  "(($1,$2) => { return new $1(...$2) })"
+#else
+  "$r = Reflect.construct($1, $2);"
+#endif
+  new_ffi :: JSVal -> JSVal -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { return eval($1); })"
+#else
+  "$r = eval($1);"
+#endif
+  eval_ffi :: JSString -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(() => { return {}; })"
+#else
+  "$r = {};"
+#endif
+  create_ffi :: IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1,$2) => { return $2[$1]; })"
+#else
+  "$r=$2[$1]"
+#endif
+  getProp_ffi :: JSString -> JSVal -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1,$2,$3) => { return $3[$1]=$2; })"
+#else
+  "$3[$1]=$2"
+#endif
+  setProp_ffi
+    :: JSString
+    -- ^ Key
+    -> JSVal
+    -- ^ Value
+    -> JSVal
+    -- ^ Object
+    -> IO ()
+-----------------------------------------------------------------------------
+fromJSVal_Int :: JSVal -> IO (Maybe Int)
+fromJSVal_Int = Marshal.fromJSVal
+{-# INLINE fromJSVal_Int #-}
+-----------------------------------------------------------------------------
+fromJSVal_Double :: JSVal -> IO (Maybe Double)
+fromJSVal_Double  = Marshal.fromJSVal
+{-# INLINE fromJSVal_Double #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1,$2) => { return $2[$1]; })"
+#else
+  "$r=$2[$1]"
+#endif
+  getPropIndex_ffi :: Int -> JSVal -> IO JSVal
+-----------------------------------------------------------------------------
+isNull_ffi :: JSVal -> Bool
+isNull_ffi = isNull
+{-# INLINE isNull_ffi #-}
+-----------------------------------------------------------------------------
+isUndefined_ffi :: JSVal -> Bool
+isUndefined_ffi = isUndefined
+{-# INLINE isUndefined_ffi #-}
+-----------------------------------------------------------------------------
+freeFunction_ffi :: JSVal -> IO ()
+freeFunction_ffi _ = pure ()
+{-# INLINE freeFunction_ffi #-}
+-----------------------------------------------------------------------------
+-- | No-op on GHCJS: 'JSVal's are ordinary JS references collected by the JS GC.
+freeJSVal_ffi :: JSVal -> IO ()
+freeJSVal_ffi _ = pure ()
+{-# INLINE freeJSVal_ffi #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { return requestAnimationFrame($1); })"
+#else
+  "$r = requestAnimationFrame($1);"
+#endif
+  requestAnimationFrame :: JSVal -> IO Int
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { return cancelAnimationFrame($1); })"
+#else
+  "cancelAnimationFrame($1);"
+#endif
+  cancelAnimationFrame :: Int -> IO ()
+-----------------------------------------------------------------------------
+toJSVal_JSString :: JSString -> IO JSVal
+toJSVal_JSString = Marshal.toJSVal
+{-# INLINE toJSVal_JSString #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Maybe :: JSVal -> IO (Maybe JSVal)
+fromJSValUnchecked_Maybe = Marshal.fromJSValUnchecked
+{-# INLINE fromJSValUnchecked_Maybe #-}
+-----------------------------------------------------------------------------
+fromJSVal_Maybe :: JSVal -> IO (Maybe (Maybe JSVal))
+fromJSVal_Maybe = Marshal.fromJSVal
+{-# INLINE fromJSVal_Maybe #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Bool :: JSVal -> IO Bool
+fromJSValUnchecked_Bool = Marshal.fromJSValUnchecked
+{-# INLINE fromJSValUnchecked_Bool #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1,$2,$3) => { return $1.apply($2, $3); })"
+#else
+  "$r = $1.apply($2, $3);"
+#endif
+  invokeFunction :: JSVal -> JSVal -> JSVal -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { return Object.keys($1); })"
+#else
+  "$r = Object.keys($1);"
+#endif
+  listProps_ffi :: JSVal -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1,$2,$3) => { return $3[$1]=$2; })"
+#else
+  "$3[$1]=$2"
+#endif
+  setPropIndex_ffi
+    :: Int
+    -- ^ Key
+    -> JSVal
+    -- ^ Value
+    -> JSVal
+    -- ^ Object
+    -> IO ()
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(() => { return globalThis; })"
+#else
+  "$r = globalThis"
+#endif
+  global :: JSVal
+-----------------------------------------------------------------------------
+fromJSVal_List :: JSVal -> IO (Maybe [JSVal])
+fromJSVal_List = Marshal.fromJSVal
+{-# INLINE fromJSVal_List #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Int :: JSVal -> IO Int
+fromJSValUnchecked_Int = Marshal.fromJSValUnchecked
+{-# INLINE fromJSValUnchecked_Int #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Double :: JSVal -> IO Double
+fromJSValUnchecked_Double = Marshal.fromJSValUnchecked
+{-# INLINE fromJSValUnchecked_Double #-}
+-----------------------------------------------------------------------------
+fromJSVal_JSString :: JSVal -> IO (Maybe JSString)
+fromJSVal_JSString = Marshal.fromJSVal
+{-# INLINE fromJSVal_JSString #-}
+-----------------------------------------------------------------------------
+toJSVal_Char :: Char -> IO JSVal
+toJSVal_Char = Marshal.toJSVal
+{-# INLINE toJSVal_Char #-}
+-----------------------------------------------------------------------------
+toJSVal_Float :: Float -> IO JSVal
+toJSVal_Float = Marshal.toJSVal
+{-# INLINE toJSVal_Float #-}
+-----------------------------------------------------------------------------
+toJSVal_Text :: Text -> IO JSVal
+toJSVal_Text = Marshal.toJSVal
+{-# INLINE toJSVal_Text #-}
+-----------------------------------------------------------------------------
+fromJSVal_Text :: JSVal -> IO (Maybe Text)
+fromJSVal_Text = Marshal.fromJSVal
+{-# INLINE fromJSVal_Text #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Text :: JSVal -> IO Text
+fromJSValUnchecked_Text = Marshal.fromJSValUnchecked
+{-# INLINE fromJSValUnchecked_Text #-}
+-----------------------------------------------------------------------------
+fromJSVal_Char :: JSVal -> IO (Maybe Char)
+fromJSVal_Char = Marshal.fromJSVal
+{-# INLINE fromJSVal_Char #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Char :: JSVal -> IO Char
+fromJSValUnchecked_Char = Marshal.fromJSValUnchecked
+{-# INLINE fromJSValUnchecked_Char #-}
+-----------------------------------------------------------------------------
+fromJSVal_Float :: JSVal -> IO (Maybe Float)
+fromJSVal_Float = Marshal.fromJSVal
+{-# INLINE fromJSVal_Float #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Float :: JSVal -> IO Float
+fromJSValUnchecked_Float = Marshal.fromJSValUnchecked
+{-# INLINE fromJSValUnchecked_Float #-}
+-----------------------------------------------------------------------------
+-- | Suspends the current Haskell thread and yields to the JS event loop
+-- until the given JavaScript Promise resolves or rejects.
+foreign import javascript interruptible
+#if GHCJS_NEW
+  "((promise, $c) => { promise.then(s => $c(null, s), e => $c(e, null)); })"
+#else
+  "$1.then(function(s) { $c(null, s); }, function(e) { $c(e, null); });"
+#endif
+  awaitPromise_ffi :: JSVal -> IO (JSVal, JSVal)
+
+-- | Awaits a JS Promise. If the promise rejects, it throws a t'JSException',
+-- mirroring the exact behavior of the GHC WASM backend's 'safe' imports.
+--
+-- @since 1.13.0.0
+await :: JSVal -> IO JSVal
+await promise = do
+  (err, val) <- awaitPromise_ffi promise
+  -- If the error argument is null/undefined, the promise resolved successfully
+  if isNull_ffi err || isUndefined_ffi err
+    then pure val
+    else throwIO =<< mkJSException err
+-----------------------------------------------------------------------------
+asyncCallback :: IO () -> IO JSVal
+asyncCallback x = jsval <$> Callback.asyncCallback x
+{-# INLINE asyncCallback #-}
+asyncCallback1 :: (JSVal -> IO ()) -> IO JSVal
+asyncCallback1 x = jsval <$> Callback.asyncCallback1 x
+{-# INLINE asyncCallback1 #-}
+asyncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal
+asyncCallback2 x = jsval <$> Callback.asyncCallback2 x
+{-# INLINE asyncCallback2 #-}
+asyncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal
+asyncCallback3 x = jsval <$> Callback.asyncCallback3 x
+{-# INLINE asyncCallback3 #-}
+-----------------------------------------------------------------------------
+syncCallback :: IO () -> IO JSVal
+syncCallback x = jsval <$> Callback.syncCallback Callback.ThrowWouldBlock x
+{-# INLINE syncCallback #-}
+syncCallback1 :: (JSVal -> IO ()) -> IO JSVal
+syncCallback1 x = jsval <$> Callback.syncCallback1 Callback.ThrowWouldBlock x
+{-# INLINE syncCallback1 #-}
+syncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal
+syncCallback2 x = jsval <$> Callback.syncCallback2 Callback.ThrowWouldBlock x
+{-# INLINE syncCallback2 #-}
+syncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal
+syncCallback3 x = jsval <$> Callback.syncCallback3 Callback.ThrowWouldBlock x
+{-# INLINE syncCallback3 #-}
+-----------------------------------------------------------------------------
+syncCallback' :: IO JSVal -> IO JSVal
+syncCallback' x = jsval <$> Callback.syncCallback' x
+{-# INLINE syncCallback' #-}
+syncCallback1' :: (JSVal -> IO JSVal) -> IO JSVal
+syncCallback1' x = jsval <$> Callback.syncCallback1' x
+{-# INLINE syncCallback1' #-}
+syncCallback2' :: (JSVal -> JSVal -> IO JSVal) -> IO JSVal
+syncCallback2' x = jsval <$> Callback.syncCallback2' x
+{-# INLINE syncCallback2' #-}
+syncCallback3' :: (JSVal -> JSVal -> JSVal -> IO JSVal) -> IO JSVal
+syncCallback3' x = jsval <$> Callback.syncCallback3' x
+{-# INLINE syncCallback3' #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { return parseInt($1); })"
+#else
+  "$r = parseInt($1)"
+#endif
+  parseInt_Unchecked :: JSString -> Double
+-----------------------------------------------------------------------------
+parseWord :: JSString -> Maybe Word
+parseWord string = fromIntegral <$> parseInt string
+{-# INLINE parseWord #-}
+-----------------------------------------------------------------------------
+parseInt :: JSString -> Maybe Int
+parseInt string =
+  case parseInt_Unchecked string of
+    double | isNaN double -> Nothing
+           | otherwise -> Just (round double)
+{-# INLINE parseInt #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { return parseFloat($1); })"
+#else
+  "$r = parseFloat($1)"
+#endif
+  parseDouble_Unchecked :: JSString -> Double
+-----------------------------------------------------------------------------
+parseDouble :: JSString -> Maybe Double
+parseDouble string =
+  case parseDouble_Unchecked string of
+    double | isNaN double -> Nothing
+           | otherwise -> Just double
+{-# INLINE parseDouble #-}
+-----------------------------------------------------------------------------
+parseFloat :: JSString -> Maybe Float
+parseFloat string = realToFrac <$> parseDouble string
+{-# INLINE parseFloat #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { return ($1).toString(); })"
+#else
+  "$r = String($1);"
+#endif
+  toString_Int :: Int -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { return ($1).toString(); })"
+#else
+  "$r = String($1);"
+#endif
+  toString_Double :: Double -> JSString
+-----------------------------------------------------------------------------
+-- Note: GHCJS narrows Float ops via Math.fround, so $1 already holds the
+-- f64 expansion of the f32 value (e.g. 3.140000104904175 for 3.14f). A
+-- plain `.toString()` would print that expansion; search increasing
+-- precisions until re-parsing (narrowed back to f32) recovers the
+-- original value, giving the shortest round-tripping decimal.
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { for (var p = 1; p <= 9; p++) { var s = $1.toPrecision(p); if (Math.fround(parseFloat(s)) === $1) return String(parseFloat(s)); } return String($1); })"
+#else
+  "var floatVal = $1; var floatStr; for (var floatPrec = 1; floatPrec <= 9; floatPrec++) { floatStr = floatVal.toPrecision(floatPrec); if (Math.fround(parseFloat(floatStr)) === floatVal) break; } $r = String(parseFloat(floatStr));"
+#endif
+  toString_Float :: Float -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(($1) => { return ($1).toString(); })"
+#else
+  "$r = String($1);"
+#endif
+  toString_Word :: Word -> JSString
+-----------------------------------------------------------------------------
+-- | High-resolution timestamp where one exists, wall clock where it does not.
+--
+-- @performance@ is absent on Lynx's background-thread realm, so this cannot be
+-- a bare @performance.now()@; see 'Miso.FFI.Internal.now'.
+foreign import javascript unsafe
+#if GHCJS_NEW
+  "(() => (typeof performance !== 'undefined' && performance && typeof performance.now === 'function') ? performance.now() : Date.now())"
+#else
+  "$r = (typeof performance !== 'undefined' && performance && typeof performance.now === 'function') ? performance.now() : Date.now();"
+#endif
+  now_ffi :: IO Double
+-----------------------------------------------------------------------------
diff --git a/ffi/wasm/Data/JSString.hs b/ffi/wasm/Data/JSString.hs
new file mode 100644
--- /dev/null
+++ b/ffi/wasm/Data/JSString.hs
@@ -0,0 +1,933 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE MultilineStrings  #-}
+{-# LANGUAGE UnboxedTuples     #-}
+{-# LANGUAGE BangPatterns      #-}
+{-# LANGUAGE LambdaCase        #-}
+{-# LANGUAGE MagicHash         #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-----------------------------------------------------------------------------
+module Data.JSString
+  ( -- * Types
+    JSString (..)
+    -- * Creation and elimination
+  , pack
+  , unpack
+  , singleton
+  , empty
+    -- * Basic interface
+  , cons
+  , snoc
+  , append
+  , uncons
+  , unsnoc
+  , head
+  , last
+  , tail
+  , init
+  , null
+  , length
+  , compareLength
+    -- * Transformations
+  , map
+  , intercalate
+  , intersperse
+  , transpose
+  , reverse
+  , replace
+    -- ** Case conversion
+  , toCaseFold
+  , toLower
+  , toUpper
+  , toTitle
+    -- ** Justification
+  , justifyLeft
+  , justifyRight
+  , center
+    -- * Folds
+  , foldl
+  , foldl'
+  , foldl1
+  , foldr
+  , foldr1
+    -- ** Special folds
+  , concat
+  , concatMap
+  , any
+  , all
+  , maximum
+  , minimum
+    -- * Construction
+    -- ** Scans
+  , scanl
+  , scanl1
+  , scanr
+  , scanr1
+    -- ** Accumulating maps
+  , mapAccumL
+  , mapAccumR
+    -- ** Generation and unfolding
+  , replicate
+  , unfoldr
+  , unfoldrN
+    -- * Substrings
+    -- ** Breaking strings
+  , take
+  , takeEnd
+  , drop
+  , dropEnd
+  , takeWhile
+  , takeWhileEnd
+  , dropWhile
+  , dropWhileEnd
+  , dropAround
+  , strip
+  , stripStart
+  , stripEnd
+  , splitAt
+  , breakOn
+  , breakOnEnd
+  , break
+  , span
+  , group
+  , groupBy
+  , inits
+  , tails
+  -- ** Breaking into many substrings
+  , splitOn
+  , split
+  , chunksOf
+  -- ** Breaking into lines and words
+  , lines
+  , words
+  , unlines
+  , unwords
+  -- * Predicates
+  , isPrefixOf
+  , isSuffixOf
+  , isInfixOf
+    -- ** View patterns
+  , stripPrefix
+  , stripSuffix
+  , commonPrefixes
+    -- * Searching
+  , filter
+  -- , breakOnAll
+  , find
+  , partition
+    -- * Indexing
+  , index
+  , findIndex
+  , count
+    -- * Zipping
+  , zip
+  , zipWith
+   -- * Misc
+  , textFromJSString
+  , textToJSString
+  , toJSString
+  , fromJSString
+  , toString_Double
+  , toString_Float
+  , toString_Word
+  , toString_Int
+  ) where
+-----------------------------------------------------------------------------
+import           Data.Array.Byte (ByteArray(..))
+import           Data.Text.Internal hiding (pack, empty, append)
+import           GHC.Exts
+import           GHC.IO
+import           GHC.Wasm.Prim
+import qualified Data.List as List
+import qualified Data.Text as T
+import           Prelude
+  hiding ( length, head, tail, filter, zip
+         , zipWith, unlines, unwords, null
+         , map, reverse, foldl', last, init
+         , foldl, foldl1, foldr, foldr1, concat
+         , concatMap, any, maximum, all, minimum
+         , scanl, scanl1, scanr, scanr1, replicate
+         , take, drop, takeWhile, dropWhile, splitAt
+         , break, span, lines, words
+         )
+-----------------------------------------------------------------------------
+pack :: String -> JSString
+{-# INLINE pack #-}
+pack = toJSString
+-----------------------------------------------------------------------------
+empty :: JSString
+{-# INLINE empty #-}
+empty = mempty
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return String.fromCharCode($1) + $2;
+  """ cons :: Char -> JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1 + String.fromCharCode($2);
+  """ snoc :: JSString -> Char -> JSString
+-----------------------------------------------------------------------------
+append :: JSString -> JSString -> JSString
+{-# INLINE append #-}
+append = mappend
+-----------------------------------------------------------------------------
+unsnoc :: JSString -> Maybe (JSString, Char) 
+{-# INLINE unsnoc #-}
+unsnoc s
+  | 0 <- length s = Nothing
+  | otherwise = Just (init s, last s)
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1.length === 0) throw new Error ('last: empty string');
+  return $1.slice(-1).charCodeAt();
+  """ last :: JSString -> Char
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1.length === 0) throw new Error ('init: empty string');
+  return $1.slice(0,-1);
+  """ init :: JSString -> JSString
+-----------------------------------------------------------------------------
+compareLength :: JSString -> Int -> Ordering
+{-# INLINE compareLength #-}
+compareLength str = compare (length str)
+-----------------------------------------------------------------------------
+map :: (Char -> Char) -> JSString -> JSString
+{-# INLINE map #-}
+map f s =
+  case uncons s of
+    Nothing -> mempty
+    Just (c, next) ->
+      f c `cons` map f next
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  const sep = String.fromCharCode($1)
+  if ($2.length === 0) return '';
+  else if ($2.length === 1) return $2;
+  else return $2.split('').join(sep);
+  """ intersperse :: Char -> JSString -> JSString
+-----------------------------------------------------------------------------
+transpose :: [JSString] -> [JSString]
+{-# INLINE transpose #-}
+transpose = fmap toJSString . List.transpose . fmap fromJSString
+-----------------------------------------------------------------------------
+-- | Reverses a t'Miso.String.MisoString'
+--
+-- @
+-- reverse "abc"
+-- "cba"
+-- @
+foreign import javascript unsafe
+  """
+  return [...$1].reverse().join('');
+  """ reverse :: JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $3.replace($1,$2);
+  """ replace :: JSString -> JSString -> JSString -> JSString
+-----------------------------------------------------------------------------
+toCaseFold :: JSString -> JSString
+{-# INLINE toCaseFold #-}
+toCaseFold = textToJSString . T.toCaseFold . textFromJSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1.toLowerCase();
+  """ toLower :: JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1.toUpperCase();
+  """ toUpper :: JSString -> JSString
+-----------------------------------------------------------------------------
+toTitle :: JSString -> JSString
+{-# INLINE toTitle #-}
+toTitle = textToJSString . T.toTitle . textFromJSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 <= $3.length) return $3;
+  let paddings = $1 - $3.length;
+  while (paddings > 0) {
+    $3 += String.fromCharCode($2);
+    paddings--;
+  }
+  return $3;
+  """ justifyLeft :: Int -> Char -> JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 <= $3.length) return $3;
+  let paddings = $1 - $3.length;
+  while (paddings > 0) {
+    $3 = String.fromCharCode($2) + $3;
+    paddings--;
+  }
+  return $3;
+  """ justifyRight :: Int -> Char -> JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 <= $3.length) return $3;
+  let paddings = ($1 - $3.length) / 2;
+  let left = Math.ceil(paddings);
+  let right = Math.floor(paddings);
+  while (left > 0) {
+    $3 = String.fromCharCode($2) + $3;
+    left--;
+  }
+  while (right > 0) {
+    $3 += String.fromCharCode($2);
+    right--;
+  }
+  return $3;
+  """ center :: Int -> Char -> JSString -> JSString
+-----------------------------------------------------------------------------
+foldl :: (a -> Char -> a) -> a -> JSString -> a
+{-# INLINE foldl #-}
+foldl f x ys =
+  case uncons ys of
+    Nothing -> x
+    Just (c, next) -> foldl f (f x c) next
+-----------------------------------------------------------------------------
+foldl1 :: (Char -> Char -> Char) -> JSString -> Char
+{-# INLINE foldl1 #-}
+foldl1 f xs =
+  case uncons xs of
+    Nothing -> error "foldl1: empty string"
+    Just (c,next) ->
+      foldl f c next
+-----------------------------------------------------------------------------
+foldr :: (Char -> a -> a) -> a -> JSString -> a
+{-# INLINE foldr #-}
+foldr f x ys =
+  case uncons ys of
+    Nothing -> x
+    Just (c, next) ->
+      f c (foldr f x next)
+-----------------------------------------------------------------------------
+foldr1 :: (Char -> Char -> Char) -> JSString -> Char
+{-# INLINE foldr1 #-}
+foldr1 f ys =
+  case uncons ys of
+    Nothing -> error "foldr1: empty string"
+    Just (c, next)
+      | length next == 0 -> c
+      | otherwise -> f c (foldr1 f next)
+-----------------------------------------------------------------------------
+any :: (Char -> Bool) -> JSString -> Bool
+{-# INLINE any #-}
+any f str =
+  case uncons str of
+    Nothing -> False
+    Just (c, next) ->
+      f c || any f next
+-----------------------------------------------------------------------------
+all :: (Char -> Bool) -> JSString -> Bool
+{-# INLINE all #-}
+all f str =
+  case uncons str of
+    Nothing -> True
+    Just (c, next) ->
+      f c && all f next
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1.length === 0) throw new Error ('maximum: empty string');
+
+  let max = $1[0].charCodeAt();
+  for (let i = 0; i < $1.length; i++) {
+    if (max < $1[i].charCodeAt()) {
+      max = $1[i].charCodeAt();
+    }
+  }
+  return max;
+  """ maximum :: JSString -> Char
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1.length === 0) throw new Error ('minimum: empty string');
+
+  let min = $1[0].charCodeAt();
+  for (let i = 0; i < $1.length; i++) {
+    if ($1[i].charCodeAt() < min) {
+      min = $1[i].charCodeAt();
+    }
+  }
+  return min;
+  """ minimum :: JSString -> Char
+-----------------------------------------------------------------------------
+scanl :: (Char -> Char -> Char) -> Char -> JSString -> JSString
+{-# INLINE scanl #-}
+scanl f x ys =
+  case uncons ys of
+    Nothing -> singleton x
+    Just (c, next) ->
+      x `cons` scanl f (f x c) next
+-----------------------------------------------------------------------------
+scanl1 :: (Char -> Char -> Char) -> JSString -> JSString
+{-# INLINE scanl1 #-}
+scanl1 f ys =
+  case uncons ys of
+    Nothing -> mempty
+    Just (c, next) ->
+      scanl f c next 
+-----------------------------------------------------------------------------
+scanr :: (Char -> Char -> Char) -> Char -> JSString -> JSString
+{-# INLINE scanr #-}
+scanr f q0 ys = 
+  case uncons ys of
+    Nothing -> singleton q0
+    Just (x, xs) ->
+      case uncons (scanr f q0 xs) of
+        Just (q, qss) -> do
+          let qs = q `cons` qss
+          f x q `cons` qs
+        Nothing -> error "scanr: impossible" 
+-----------------------------------------------------------------------------
+scanr1 :: (Char -> Char -> Char) -> JSString -> JSString
+{-# INLINE scanr1 #-}
+scanr1 f ys = 
+  case uncons ys of
+    Nothing -> mempty
+    Just (x, xs)
+      | length xs == 0 -> singleton x
+      | otherwise -> do
+          case uncons (scanr1 f xs) of
+            Just (q, qss) -> f x q `cons` (q `cons` qss)
+            Nothing -> error "scanr: impossible" 
+-----------------------------------------------------------------------------
+mapAccumL :: (a -> Char -> (a, Char)) -> a -> JSString -> (a, JSString)
+{-# INLINE mapAccumL #-}
+mapAccumL f x str =
+  case uncons str of
+    Nothing -> (x, str)
+    Just (c, next) -> do
+      let (a, c') = f x c
+      cons c' <$> mapAccumL f a next
+-----------------------------------------------------------------------------
+mapAccumR :: (a -> Char -> (a, Char)) -> a -> JSString -> (a, JSString)
+{-# INLINE mapAccumR #-}
+mapAccumR f x str =
+  case uncons str of
+    Nothing -> (x, str)
+    Just (c, next) ->
+      case mapAccumR f x next of
+        (a, qs) ->
+          case f a c of
+            (a', k) -> (a', k `cons` qs)
+-----------------------------------------------------------------------------
+unfoldr :: (a -> Maybe (Char, a)) -> a -> JSString
+{-# INLINE unfoldr #-}
+unfoldr f x = do
+  case f x of
+    Nothing -> mempty
+    Just (c, y) ->
+      c `cons` unfoldr f y
+-----------------------------------------------------------------------------
+unfoldrN :: Int -> (a -> Maybe (Char, a)) -> a -> JSString
+{-# INLINE unfoldrN #-}
+unfoldrN n f seed = go seed mempty
+  where
+    go x acc
+      | length acc == n = acc
+      | otherwise =
+          case f x of
+            Nothing -> mempty
+            Just (c,y) -> go y (c `cons` acc)
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 < 1) return "";
+  return Array.from($2).slice(0, $1).join('');
+  """ take :: Int -> JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 < 1) return "";
+  return $2.slice(-$1);
+  """ takeEnd :: Int -> JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 < 1) return "";
+  return $2.slice(0, -$1);
+  """ dropEnd :: Int -> JSString -> JSString
+-----------------------------------------------------------------------------
+takeWhile :: (Char -> Bool) -> JSString -> JSString
+{-# INLINE takeWhile #-}
+takeWhile f xs =
+  case uncons xs of
+    Nothing -> mempty
+    Just (c, next) ->
+      if f c
+        then c `cons` takeWhile f next
+        else mempty
+-----------------------------------------------------------------------------
+takeWhileEnd :: (Char -> Bool) -> JSString -> JSString
+{-# INLINE takeWhileEnd #-}
+takeWhileEnd f = reverse . takeWhile f . reverse
+-----------------------------------------------------------------------------
+dropWhile :: (Char -> Bool) -> JSString -> JSString
+{-# INLINE dropWhile #-}
+dropWhile f xs =
+  case uncons xs of
+    Nothing -> xs
+    Just (c, next) ->
+      if f c
+        then dropWhile f next
+        else xs
+-----------------------------------------------------------------------------
+dropWhileEnd :: (Char -> Bool) -> JSString -> JSString
+{-# INLINE dropWhileEnd #-}
+dropWhileEnd f = reverse . dropWhile f . reverse
+-----------------------------------------------------------------------------
+dropAround :: (Char -> Bool) -> JSString -> JSString
+{-# INLINE dropAround #-}
+dropAround f = dropWhile f . dropWhileEnd f
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1.trim();
+  """ strip :: JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1.trimStart();
+  """ stripStart :: JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1.trimEnd();
+  """ stripEnd :: JSString -> JSString
+-----------------------------------------------------------------------------
+splitAt :: Int -> JSString -> (JSString, JSString)
+{-# INLINE splitAt #-}
+splitAt n xs = (take n xs, drop n xs)
+-----------------------------------------------------------------------------
+breakOn :: JSString -> JSString -> (JSString, JSString)
+{-# INLINE breakOn #-}
+breakOn n _ | 0 <- length n = error "breakOn: empty needle"
+breakOn needle haystack = go (mempty, haystack)
+  where
+    go (acc, stack) =
+      if needle `isPrefixOf` stack
+        then (acc, stack)
+        else
+          case uncons stack of
+            Nothing -> (acc, stack)
+            Just (c,next) ->
+              go (acc `snoc` c, next)
+-----------------------------------------------------------------------------
+breakOnEnd :: JSString -> JSString -> (JSString, JSString)
+{-# INLINE breakOnEnd #-}
+breakOnEnd n _ | 0 <- length n = error "breakOnEnd: empty needle"
+breakOnEnd needle haystack = go (mempty, haystack)
+  where
+    go (acc, stack) =
+      if needle `isSuffixOf` stack
+        then (stack, acc)
+        else
+          case unsnoc stack of
+            Nothing -> (stack, acc)
+            Just (next, c) ->
+              go (c `cons` acc, next)
+-----------------------------------------------------------------------------
+break :: (Char -> Bool) -> JSString -> (JSString, JSString)
+{-# INLINE break #-}
+break f s = go (mempty, s)
+  where
+    go (failed, rest) =
+      case uncons rest of
+        Nothing -> (failed, rest)
+        Just (c,next) ->
+          if f c
+            then (failed, c `cons` next)
+            else go (failed `snoc` c, next)
+-----------------------------------------------------------------------------
+span :: (Char -> Bool) -> JSString -> (JSString, JSString)
+{-# INLINE span #-}
+span f s = (takeWhile f s, dropWhile f s)
+-----------------------------------------------------------------------------
+group :: JSString -> [JSString]
+{-# INLINE group #-}
+group = groupBy (==)
+-----------------------------------------------------------------------------
+groupBy :: (Char -> Char -> Bool) -> JSString -> [JSString]
+{-# INLINE groupBy #-}
+groupBy eq s' =
+  case uncons s' of
+    Nothing -> []
+    Just (c, next) -> do
+      let (ys, zs) = span (eq c) next
+      (c `cons` ys) : groupBy eq zs
+-----------------------------------------------------------------------------
+inits :: JSString -> [JSString]
+{-# INLINE inits #-}
+inits s = 
+  case unsnoc s of
+    Nothing -> [""]
+    Just (next, _) -> inits next <> [s]
+-----------------------------------------------------------------------------
+tails :: JSString -> [JSString]
+{-# INLINE tails #-}
+tails s =
+  case uncons s of
+    Nothing -> [""]
+    Just (_, next) -> s : tails next
+-----------------------------------------------------------------------------
+splitOn :: JSString -> JSString -> [JSString]
+{-# INLINE splitOn #-}
+splitOn prefix _ | 0 <- length prefix = error "splitOn: empty prefix"
+splitOn prefix str = go str mempty
+  where
+    go s acc | 0 <- length s = [acc]
+    go s acc = do
+      if prefix `isPrefixOf` s
+        then acc : go (drop (length prefix) s) mempty
+        else
+          case uncons s of
+            Nothing -> [acc]
+            Just (c,next) ->
+              go next (acc `snoc` c)
+-----------------------------------------------------------------------------
+split :: (Char -> Bool) -> JSString -> [JSString]
+{-# INLINE split #-}
+split f = go
+  where
+    go str | 0 <- length str = [empty]
+    go str = do
+      let
+        found = takeWhile (not . f) str
+        next = drop 1 (dropWhile (not . f) str)
+      found : go next
+-----------------------------------------------------------------------------
+chunksOf :: Int -> JSString -> [JSString]
+{-# INLINE chunksOf #-}
+chunksOf 0 _ = []
+chunksOf n s =
+  case (take n s, drop n s) of
+    (hd, tl) ->
+      if length tl == 0
+        then [hd]
+        else hd : chunksOf n tl
+-----------------------------------------------------------------------------
+lines :: JSString -> [JSString]
+{-# INLINE lines #-}
+lines = splitOn "\n"
+-----------------------------------------------------------------------------
+words :: JSString -> [JSString]
+{-# INLINE words #-}
+words s = go (strip s)
+  where
+    go xs | length xs == 0 = []
+    go xs = do
+      let next = dropWhile (==' ') xs
+      let payload = takeWhile (/=' ') next
+      payload : go (drop (length payload) next)
+-----------------------------------------------------------------------------
+unwords :: [JSString] -> JSString
+{-# INLINE unwords #-}
+unwords = intercalate " "
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $2.endsWith($1);
+  """ isSuffixOf :: JSString -> JSString -> Bool
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $2.includes($1);
+  """ isInfixOf :: JSString -> JSString -> Bool
+-----------------------------------------------------------------------------
+stripPrefix :: JSString -> JSString -> Maybe JSString
+{-# INLINE stripPrefix #-}
+stripPrefix prefix string
+  | not (prefix `isPrefixOf` string) = Nothing
+  | otherwise = Just (drop (length prefix) string)
+-----------------------------------------------------------------------------
+stripSuffix :: JSString -> JSString -> Maybe JSString
+{-# INLINE stripSuffix #-}
+stripSuffix suffix string
+  | not (suffix `isSuffixOf` string) = Nothing
+  | otherwise = Just (dropEnd (length suffix) string)
+-----------------------------------------------------------------------------
+commonPrefixes :: JSString -> JSString -> Maybe (JSString, JSString, JSString)
+{-# INLINE commonPrefixes #-}
+commonPrefixes ls rs | length ls == 0 || length rs == 0 = Nothing
+commonPrefixes ls' rs' = go mempty ls' rs'
+  where
+    go acc ls rs =
+      case (uncons ls, uncons rs) of
+        (Just (l,lss), Just (r,rss)) ->
+          if l == r
+            then go (acc `snoc` l) lss rss
+            else
+              if null acc
+                then Nothing
+                else Just (acc, l `cons` lss, r `cons` rss)
+        _ -> Nothing
+-----------------------------------------------------------------------------
+filter :: (Char -> Bool) -> JSString -> JSString
+{-# INLINE filter #-}
+filter f xs =
+  case uncons xs of
+    Nothing -> mempty
+    Just (c,next) ->
+      if f c
+        then c `cons` filter f next
+        else filter f next
+-----------------------------------------------------------------------------
+-- breakOnAll :: JSString -> JSString -> [(JSString, JSString)]
+-- breakOnAll = error "TODO: implement breakOnAll"
+-----------------------------------------------------------------------------
+find :: (Char -> Bool) -> JSString -> Maybe Char
+{-# INLINE find #-}
+find f xs = do
+  (c,next) <- uncons xs
+  if f c
+    then pure c
+    else find f next
+-----------------------------------------------------------------------------
+partition :: (Char -> Bool) -> JSString -> (JSString, JSString)
+{-# INLINE partition #-}
+partition f xs = (filter f xs, filter (not . f) xs)
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1.length === 0) throw new Error ('index: empty string')
+  return $1[$2].charCodeAt();
+  """ index :: JSString -> Int -> Char
+-----------------------------------------------------------------------------
+findIndex :: (Char -> Bool) -> JSString -> Maybe Int
+findIndex f xs = go xs
+  where
+    len = length xs - 1
+    go zs = do
+      (next, ys) <- uncons zs
+      if f next
+        then pure (len - length ys)
+        else go ys
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1.length === 0) throw new Error ('count: empty string')
+  return $2.split($1).length - 1;
+  """ count :: JSString -> JSString -> Int
+-----------------------------------------------------------------------------
+zip :: JSString -> JSString -> [(Char,Char)]
+{-# INLINE zip #-}
+zip l r =
+  case (uncons l, uncons r) of
+    (Just (l',ls), Just (r',rs)) ->
+      (l',r') : zip ls rs
+    _ -> []
+-----------------------------------------------------------------------------
+zipWith :: (Char -> Char -> Char) -> JSString -> JSString -> JSString
+{-# INLINE zipWith #-}
+zipWith f l r =
+  case (uncons l, uncons r) of
+    (Just (l', ls), Just (r', rs)) ->
+      f l' r' `cons` zipWith f ls rs
+    _ -> mempty
+-----------------------------------------------------------------------------
+newtype JSUint8Array = JSUint8Array JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "(new TextEncoder()).encode($1)"
+  js_str_encode :: JSString -> IO JSUint8Array
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "$1.byteLength"
+  js_buf_len :: JSUint8Array -> IO Int
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "(new Uint8Array(__exports.memory.buffer, $2, $1.byteLength)).set($1)"
+  js_from_buf :: JSUint8Array -> Ptr a -> IO ()
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "(new TextDecoder('utf-8', {fatal: true})).decode(new Uint8Array(__exports.memory.buffer, $1, $2))"
+  js_to_str :: Ptr a -> Int -> IO JSString
+-----------------------------------------------------------------------------
+textFromJSString :: JSString -> Text
+{-# INLINE textFromJSString #-}
+textFromJSString str = unsafeDupablePerformIO $ do
+  buf <- js_str_encode str
+  I# len# <- js_buf_len buf
+  IO $ \s0 -> case newByteArray# len# s0 of
+    (# s1, mba# #) -> case unIO (js_from_buf buf (Ptr (mutableByteArrayContents# mba#))) s1 of
+      (# s2, _ #) -> case unIO (freeJSVal (coerce buf)) s2 of
+        (# s3, _ #) -> case unsafeFreezeByteArray# mba# s3 of
+          (# s4, ba# #) -> (# s4, Text (ByteArray ba#) 0 (I# len#) #)
+-----------------------------------------------------------------------------
+textToJSString :: Text -> JSString
+{-# INLINE textToJSString #-}
+textToJSString (Text (ByteArray ba#) (I# off#) (I# len#)) = unsafeDupablePerformIO $
+  IO $ \s0 -> case newPinnedByteArray# len# s0 of
+    (# s1, mba# #) -> case copyByteArray# ba# off# mba# 0# len# s1 of
+      s2 -> keepAlive# mba# s2 $ unIO $ js_to_str (Ptr (mutableByteArrayContents# mba#)) $ I# len#
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1.length === 0
+  """ null :: JSString -> Bool
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 < 1 || $2.length === 0) return $2;
+  return Array.from($2).slice($1).join('');
+  """ drop :: Int -> JSString -> JSString
+-----------------------------------------------------------------------------
+foldl' :: (a -> Char -> a) -> a -> JSString -> a
+{-# INLINE foldl' #-}
+foldl' f x ys =
+  case uncons ys of
+    Nothing -> x
+    Just (c, next) -> do
+      let !z = f x c
+      foldl' f z next
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return Array.from($1).length;
+  """ length :: JSString -> Int
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $2.startsWith($1)
+  """ isPrefixOf :: JSString -> JSString -> Bool
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return String.fromCharCode($1);
+  """ singleton :: Char -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1.length === 0) throw new Error ('head: empty string');
+  return $1.slice(0).charCodeAt();
+  """ head :: JSString -> Char
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1.slice(1,$1.length)
+  """ tail :: JSString -> JSString
+-----------------------------------------------------------------------------
+uncons :: JSString -> Maybe (Char, JSString)
+{-# INLINE uncons #-}
+uncons str
+  | 0 <- length str = Nothing
+  | otherwise = Just (head str, tail str)
+-----------------------------------------------------------------------------
+unpack :: JSString -> String
+{-# INLINE unpack #-}
+unpack = fromJSString
+-----------------------------------------------------------------------------
+intercalate :: JSString -> [JSString] -> JSString
+{-# INLINE intercalate #-}
+intercalate sep = \case
+  [] -> mempty
+  [x] -> x
+  (x:xs) -> x <> sep <> intercalate sep xs
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 === $2) return 0;
+  else if ($1 > $2) return 1;
+  else return -1;
+  """ jsstringOrd :: JSString -> JSString -> Int
+-----------------------------------------------------------------------------
+concat :: [JSString] -> JSString
+{-# INLINE concat #-}
+concat = mconcat
+-----------------------------------------------------------------------------
+concatMap :: (Char -> JSString) -> JSString -> JSString
+{-# INLINE concatMap #-}
+concatMap f str =
+  case uncons str of
+    Nothing -> mempty
+    Just (c, next) -> f c <> concatMap f next
+-----------------------------------------------------------------------------
+unlines :: [JSString] -> JSString
+{-# INLINE unlines #-}
+unlines ks = concat [ snoc k '\n' | k <- ks ]
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 < 1) { return ''; }
+  else if ($1 === 1) { return $2; }
+  else {
+    const inc = $2;
+    while (--$1) {
+      $2 += inc;
+    }
+    return $2;
+  }
+  """ replicate :: Int -> JSString -> JSString
+----------------------------------------------------------------------------
+instance Ord JSString where
+  compare s1 s2 =
+    case jsstringOrd s1 s2 of
+      0 -> EQ
+      1 -> GT
+      (-1) -> LT
+      _ -> error "jsstringOrd: impossible"
+  {-# INLINE compare #-}
+----------------------------------------------------------------------------
+instance Eq JSString where
+  (==) = jsstringEq
+  {-# INLINE (==) #-}
+----------------------------------------------------------------------------
+instance Semigroup JSString where
+  (<>) = jsstringMappend
+  {-# INLINE (<>) #-}
+----------------------------------------------------------------------------
+instance Monoid JSString where
+  mempty = jsstringMempty
+  {-# INLINE mempty #-}
+----------------------------------------------------------------------------
+instance Show JSString where
+  show = show . fromJSString
+  {-# INLINE show #-}
+----------------------------------------------------------------------------
+instance IsString JSString where
+  fromString = toJSString
+  {-# INLINE fromString #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return $1 === $2"
+  jsstringEq :: JSString -> JSString -> Bool
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return $1 + $2"
+  jsstringMappend :: JSString -> JSString -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return ''"
+  jsstringMempty :: JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return ($1).toString()"
+  toString_Int :: Int -> JSString
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return ($1).toString()"
+  toString_Double :: Double -> JSString
+-----------------------------------------------------------------------------
+-- Note: $1 arrives widened to a JS (f64) Number, so a plain `.toString()`
+-- prints the full f64 expansion of the f32 value (e.g. "3.140000104904175"
+-- for 3.14f) rather than the shortest decimal that round-trips through
+-- float32. Search increasing precisions until re-parsing (narrowed back to
+-- f32 via Math.fround) recovers the original value.
+foreign import javascript unsafe
+  """
+  var x = $1;
+  for (var p = 1; p <= 9; p++) {
+    var s = x.toPrecision(p);
+    if (Math.fround(parseFloat(s)) === x) return String(parseFloat(s));
+  }
+  return String(x);
+  """
+  toString_Float :: Float -> JSString
+-----------------------------------------------------------------------------
+toString_Word :: Word -> JSString
+{-# INLINE toString_Word #-}
+toString_Word = toJSString . show
+-----------------------------------------------------------------------------
diff --git a/ffi/wasm/Miso/DSL/FFI.hs b/ffi/wasm/Miso/DSL/FFI.hs
new file mode 100644
--- /dev/null
+++ b/ffi/wasm/Miso/DSL/FFI.hs
@@ -0,0 +1,586 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP                      #-}
+{-# LANGUAGE LambdaCase               #-}
+{-# LANGUAGE TemplateHaskell          #-}
+{-# LANGUAGE MultilineStrings         #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE InterruptibleFFI  #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+-----------------------------------------------------------------------------
+module Miso.DSL.FFI
+  ( -- ** Types
+    JSVal
+  , JSString (..)
+  , now_ffi
+    -- ** Serialization FFI
+    -- *** ToJSVal
+  , toJSVal_Char
+  , toJSVal_Bool
+  , toJSVal_Double
+  , toJSVal_Float
+  , toJSVal_Int
+  , toJSVal_List
+  , toJSVal_JSString
+  , toJSVal_Text
+    -- *** FromJSVal
+  , fromJSVal_Text
+  , fromJSValUnchecked_Text
+  , fromJSVal_Char
+  , fromJSValUnchecked_Char
+  , fromJSVal_Bool
+  , fromJSValUnchecked_Bool
+  , fromJSVal_Double
+  , fromJSValUnchecked_Double
+  , fromJSVal_Float
+  , fromJSValUnchecked_Float
+  , fromJSVal_Int
+  , fromJSValUnchecked_Int
+  , fromJSVal_List
+  , fromJSValUnchecked_List
+  , fromJSVal_JSString
+  , fromJSVal_Maybe
+  , fromJSValUnchecked_Maybe
+  -- * Callback FFI
+  , await
+  , asyncCallback
+  , asyncCallback1
+  , asyncCallback2
+  , asyncCallback3
+  , syncCallback
+  , syncCallback1
+  , syncCallback2
+  , syncCallback3
+  , syncCallback'
+  , syncCallback1'
+  , syncCallback2'
+  , syncCallback3'
+  -- * DSL FFI
+  , invokeFunction
+  , setProp_ffi
+  , new_ffi
+  , getProp_ffi
+  , eval_ffi
+  , setPropIndex_ffi
+  , getPropIndex_ffi
+  , create_ffi
+    -- *** Misc. FFI
+  , global
+  , isUndefined_ffi
+  , isNull_ffi
+  , jsNull
+  , freeFunction_ffi
+  , freeJSVal_ffi
+  , requestAnimationFrame
+  , cancelAnimationFrame
+  , listProps_ffi
+  -- *** String FFI
+  , parseInt
+  , parseDouble
+  , parseWord
+  , parseFloat
+#ifdef MISO_TEXT
+  , toString_Int
+  , toString_Double
+  , toString_Float
+  , toString_Word
+#endif
+  , textFromJSString
+  , textToJSString
+  , JSException
+  ) where
+-----------------------------------------------------------------------------
+import           Data.Text (Text)
+import           Control.Monad
+import           Data.JSString (textFromJSString, textToJSString)
+#ifdef MISO_TEXT
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as TL
+import qualified Data.Text.Lazy.Builder as TB
+import qualified Data.Text.Lazy.Builder.Int as TBI
+import qualified Data.Text.Lazy.Builder.RealFloat as TBR
+import qualified Data.Text.Read as TR
+#endif
+import           Prelude hiding (length, head, tail, unlines, concat, null, drop, replicate, concatMap)
+-----------------------------------------------------------------------------
+import           GHC.Wasm.Prim
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1 === $2;
+  """ eq :: JSVal -> JSVal -> Bool
+-----------------------------------------------------------------------------
+instance Eq JSVal where
+  (==) = eq
+  {-# INLINE (==) #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  if ($1 === 0.0) return false;
+  return true;
+  """ toJSVal_Bool :: Bool -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1
+  """ toJSVal_Double :: Double -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1
+  """ toJSVal_Int :: Int -> IO JSVal
+-----------------------------------------------------------------------------
+toJSVal_List :: [JSVal] -> IO JSVal
+toJSVal_List js = do
+  arr <- newArray
+  forM_ js (pushArray arr)
+  pure arr
+{-# INLINE toJSVal_List #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return [];
+  """ newArray :: IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  $1.push($2)
+  """ pushArray :: JSVal -> JSVal -> IO ()
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1
+  """
+  toJSVal_Char :: Char -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1
+  """
+  toJSVal_Float :: Float -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1
+  """ fromJSValUnchecked_Float :: JSVal -> IO Float
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1
+  """ fromJSValUnchecked_Char :: JSVal -> IO Char
+-----------------------------------------------------------------------------
+fromJSVal_Char :: JSVal -> IO (Maybe Char)
+fromJSVal_Char x =
+  if isNullOrUndefined x
+    then pure Nothing
+    else Just <$> fromJSValUnchecked_Char x
+{-# INLINE fromJSVal_Char #-}
+-----------------------------------------------------------------------------
+toJSVal_JSString :: JSString -> IO JSVal
+toJSVal_JSString (JSString jsval) = pure jsval
+{-# INLINE toJSVal_JSString #-}
+-----------------------------------------------------------------------------
+fromJSVal_Text :: JSVal -> IO (Maybe Text)
+fromJSVal_Text x =
+  if isNullOrUndefined x
+    then pure Nothing
+    else Just <$> fromJSValUnchecked_Text x
+{-# INLINE fromJSVal_Text #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Text :: JSVal -> IO Text
+fromJSValUnchecked_Text t =
+  pure $ textFromJSString (JSString t)
+{-# INLINE fromJSValUnchecked_Text #-}
+-----------------------------------------------------------------------------
+toJSVal_Text :: Text -> IO JSVal
+toJSVal_Text t =
+  case textToJSString t of
+    JSString jsval -> pure jsval
+{-# INLINE toJSVal_Text #-}
+-----------------------------------------------------------------------------
+fromJSVal_Float :: JSVal -> IO (Maybe Float)
+fromJSVal_Float x =
+  if isNullOrUndefined x
+    then pure Nothing
+    else Just <$> fromJSValUnchecked_Float x
+{-# INLINE fromJSVal_Float #-}
+-----------------------------------------------------------------------------
+fromJSVal_Bool :: JSVal -> IO (Maybe Bool)
+fromJSVal_Bool x =
+  if isNullOrUndefined x
+    then pure Nothing
+    else Just <$> fromJSValUnchecked_Bool x
+{-# INLINE fromJSVal_Bool #-}
+-----------------------------------------------------------------------------
+fromJSVal_Int :: JSVal -> IO (Maybe Int)
+fromJSVal_Int x =
+  if isNullOrUndefined x
+    then pure Nothing
+    else Just <$> fromJSValUnchecked_Int x
+{-# INLINE fromJSVal_Int #-}
+-----------------------------------------------------------------------------
+fromJSVal_Double :: JSVal -> IO (Maybe Double)
+fromJSVal_Double x =
+  if isNullOrUndefined x
+    then pure Nothing
+    else Just <$> fromJSValUnchecked_Double x
+{-# INLINE fromJSVal_Double #-}
+-----------------------------------------------------------------------------
+fromJSVal_List :: JSVal -> IO (Maybe [JSVal])
+fromJSVal_List x = do
+  if isNullOrUndefined x
+    then pure Nothing
+    else do
+      arrayLike <- isArray x
+      if not arrayLike
+        then pure Nothing
+        else Just <$> fromJSValUnchecked_List x
+{-# INLINE fromJSVal_List #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_List :: JSVal -> IO [JSVal]
+fromJSValUnchecked_List x = do
+   len <- length x
+   forM [ 0 .. len - 1 ] (flip getPropIndex_ffi x)
+{-# INLINE fromJSValUnchecked_List #-}
+-----------------------------------------------------------------------------
+fromJSVal_JSString :: JSVal -> IO (Maybe JSString)
+fromJSVal_JSString x = do
+  if isNullOrUndefined x
+    then pure Nothing
+    else Just <$> jsstringFromJSVal x
+{-# INLINE fromJSVal_JSString #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return $1" jsstringFromJSVal :: JSVal -> IO JSString
+-----------------------------------------------------------------------------
+isNullOrUndefined :: JSVal -> Bool
+isNullOrUndefined x = isNull_ffi x || isUndefined_ffi x
+{-# INLINE isNullOrUndefined #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1 === undefined;
+  """ isUndefined_ffi :: JSVal -> Bool
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1 === null;
+  """ isNull_ffi :: JSVal -> Bool
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return null;
+  """ jsNull :: JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return globalThis" global :: JSVal
+-----------------------------------------------------------------------------
+-- | Awaits a JS Promise. If the promise rejects, it throws a t'JSException'.
+--
+-- @since 1.13.0.0
+foreign import javascript interruptible "return await $1;"
+  await :: JSVal -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper"
+  asyncCallback
+    :: IO ()
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper"
+  asyncCallback1
+    :: (JSVal -> IO ())
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper"
+  asyncCallback2
+    :: (JSVal -> JSVal -> IO ())
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper"
+  asyncCallback3
+    :: (JSVal -> JSVal -> JSVal -> IO ())
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper sync"
+  syncCallback
+    :: IO ()
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper sync"
+  syncCallback1
+    :: (JSVal -> IO ())
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper sync"
+  syncCallback2
+    :: (JSVal -> JSVal -> IO ())
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper sync"
+  syncCallback3
+    :: (JSVal -> JSVal -> JSVal -> IO ())
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper sync"
+  syncCallback'
+    :: IO JSVal
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper sync"
+  syncCallback1'
+    :: (JSVal -> IO JSVal)
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper sync"
+  syncCallback2'
+    :: (JSVal -> JSVal -> IO JSVal)
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript "wrapper sync"
+  syncCallback3'
+    :: (JSVal -> JSVal -> JSVal -> IO JSVal)
+    -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return Object.keys($1);
+  """
+  listProps_ffi :: JSVal -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1.apply($2, $3);
+  """
+  invokeFunction
+    :: JSVal
+    -- ^ Func
+    -> JSVal
+    -- ^ Obj
+    -> JSVal
+    -- ^ Args
+    -> IO JSVal
+    -- ^ Return value
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  "$3[$1]=$2"
+  setPropIndex_ffi
+    :: Int
+    -- ^ Index
+    -> JSVal
+    -- ^ Value
+    -> JSVal
+    -- ^ Object
+    -> IO ()
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  "$3[$1]=$2"
+  setProp_ffi
+    :: JSString
+    -- ^ Field
+    -> JSVal
+    -- ^ Value
+    -> JSVal
+    -- ^ Object
+    -> IO ()
+-----------------------------------------------------------------------------
+-- | Regular FFIs
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  "return new $1(...$2)"
+  new_ffi
+    :: JSVal
+    -- ^ Constructor
+    -> JSVal
+    -- ^ Args
+    -> IO JSVal
+    -- ^ Return
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return {}" create_ffi :: IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return $2[$1]"
+  getProp_ffi
+    :: JSString
+    -- ^ Key
+    -> JSVal
+    -- ^ Value
+    -> IO JSVal
+    -- ^ Return
+-----------------------------------------------------------------------------
+-- | Unsafe JS eval, use at your own risk! You have been warned
+foreign import javascript unsafe
+  """
+  return eval($1);
+  """ eval_ffi :: JSString -> IO JSVal
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1
+  """ fromJSValUnchecked_Int :: JSVal -> IO Int
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1
+  """ fromJSValUnchecked_Double :: JSVal -> IO Double
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1
+  """ fromJSValUnchecked_Bool :: JSVal -> IO Bool
+-----------------------------------------------------------------------------
+foreign import javascript unsafe "return $2[$1]"
+  getPropIndex_ffi
+    :: Int
+    -- ^ Key
+    -> JSVal
+    -- ^ Value
+    -> IO JSVal
+    -- ^ Return
+-----------------------------------------------------------------------------
+freeFunction_ffi :: JSVal -> IO ()
+freeFunction_ffi = freeJSVal
+{-# INLINE freeFunction_ffi #-}
+-----------------------------------------------------------------------------
+-- | Eagerly release a 'JSVal' handle. See 'Miso.DSL.freeJSVal'.
+freeJSVal_ffi :: JSVal -> IO ()
+freeJSVal_ffi = freeJSVal
+{-# INLINE freeJSVal_ffi #-}
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return requestAnimationFrame($1);
+  """ requestAnimationFrame :: JSVal -> IO Int
+-----------------------------------------------------------------------------
+-- | High-resolution timestamp where one exists, wall clock where it does not.
+foreign import javascript unsafe
+  """
+  return (typeof performance !== 'undefined' && performance && typeof performance.now === 'function')
+    ? performance.now()
+    : Date.now();
+  """ now_ffi :: IO Double
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return cancelAnimationFrame($1);
+  """ cancelAnimationFrame :: Int -> IO ()
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return Array.isArray($1);
+  """ isArray :: JSVal -> IO Bool
+-----------------------------------------------------------------------------
+foreign import javascript unsafe
+  """
+  return $1.length
+  """ length :: JSVal -> IO Int
+-----------------------------------------------------------------------------
+fromJSVal_Maybe :: JSVal -> IO (Maybe (Maybe JSVal))
+fromJSVal_Maybe jsval = do
+  if isNullOrUndefined jsval
+    then pure (Just Nothing)
+    else pure $ Just (Just jsval)
+{-# INLINE fromJSVal_Maybe #-}
+-----------------------------------------------------------------------------
+fromJSValUnchecked_Maybe :: JSVal -> IO (Maybe JSVal)
+fromJSValUnchecked_Maybe jsval = do
+  if isNullOrUndefined jsval
+    then pure Nothing
+    else pure (Just jsval)
+{-# INLINE fromJSValUnchecked_Maybe #-}
+-----------------------------------------------------------------------------
+#ifdef MISO_TEXT
+-- | Parses using 'Data.Text.Read' directly (no JS FFI round trip),
+-- matching JS's @parseInt@ semantics: leading\/trailing whitespace and
+-- trailing garbage are ignored, a leading @+\/-@ is allowed, and a
+-- @0x@\/@0X@ prefix is read as hexadecimal.
+parseInt :: Text -> Maybe Int
+parseInt input =
+  applySign <$>
+    case T.stripPrefix (T.pack "0x") unsigned `mplus` T.stripPrefix (T.pack "0X") unsigned of
+      Just hex -> hush (TR.hexadecimal hex)
+      Nothing  -> hush (TR.decimal unsigned)
+  where
+    stripped = T.strip input
+    (isNegative, unsigned) = case T.uncons stripped of
+      Just ('-', rest) -> (True, rest)
+      Just ('+', rest) -> (False, rest)
+      _                -> (False, stripped)
+    applySign = if isNegative then negate else id
+{-# INLINE parseInt #-}
+#else
+foreign import javascript unsafe
+  """
+  return parseInt($1);
+  """
+  parseInt_Unchecked :: JSString -> Double
+-----------------------------------------------------------------------------
+parseInt :: JSString -> Maybe Int
+parseInt string =
+  case parseInt_Unchecked string of
+    double | isNaN double -> Nothing
+           | otherwise -> Just (round double)
+{-# INLINE parseInt #-}
+#endif
+-----------------------------------------------------------------------------
+#ifdef MISO_TEXT
+parseWord :: Text -> Maybe Word
+#else
+parseWord :: JSString -> Maybe Word
+#endif
+parseWord string = fromIntegral <$> parseInt string
+{-# INLINE parseWord #-}
+-----------------------------------------------------------------------------
+#ifdef MISO_TEXT
+-- | Parses using 'Data.Text.Read' directly (no JS FFI round trip),
+-- matching JS's @parseFloat@ semantics: leading\/trailing whitespace and
+-- trailing garbage are ignored, and a leading @+\/-@ is allowed.
+parseDouble :: Text -> Maybe Double
+parseDouble = hush . TR.double . T.strip
+{-# INLINE parseDouble #-}
+-----------------------------------------------------------------------------
+hush :: Either String (a, Text) -> Maybe a
+hush = either (const Nothing) (Just . fst)
+{-# INLINE hush #-}
+#else
+foreign import javascript unsafe
+  """
+  return parseFloat($1);
+  """
+  parseDouble_Unchecked :: JSString -> Double
+-----------------------------------------------------------------------------
+parseDouble :: JSString -> Maybe Double
+parseDouble string =
+  case parseDouble_Unchecked string of
+    double | isNaN double -> Nothing
+           | otherwise -> Just double
+{-# INLINE parseDouble #-}
+#endif
+-----------------------------------------------------------------------------
+#ifdef MISO_TEXT
+parseFloat :: Text -> Maybe Float
+#else
+parseFloat :: JSString -> Maybe Float
+#endif
+parseFloat string = realToFrac <$> parseDouble string
+{-# INLINE parseFloat #-}
+-----------------------------------------------------------------------------
+#ifdef MISO_TEXT
+-- | 'show' agrees with JS's native number formatting for 'Int', so this
+-- avoids allocating a throwaway 'JSVal' via the FFI just to convert it
+-- straight back to 'Text'. Built via 'Data.Text.Lazy.Builder' rather than
+-- @pack . show@ to skip the intermediate 'String'.
+toString_Int :: Int -> Text
+toString_Int = TL.toStrict . TB.toLazyText . TBI.decimal
+{-# INLINE toString_Int #-}
+-----------------------------------------------------------------------------
+toString_Double :: Double -> Text
+toString_Double = TL.toStrict . TB.toLazyText . TBR.realFloat
+{-# INLINE toString_Double #-}
+-----------------------------------------------------------------------------
+toString_Float :: Float -> Text
+toString_Float = TL.toStrict . TB.toLazyText . TBR.realFloat
+{-# INLINE toString_Float #-}
+-----------------------------------------------------------------------------
+-- | See 'toString_Int': 'show' matches JS formatting for 'Word' too.
+toString_Word :: Word -> Text
+toString_Word = TL.toStrict . TB.toLazyText . TBI.decimal
+{-# INLINE toString_Word #-}
+#endif
+-----------------------------------------------------------------------------
diff --git a/ffi/wasm/Miso/DSL/TH.hs b/ffi/wasm/Miso/DSL/TH.hs
new file mode 100644
--- /dev/null
+++ b/ffi/wasm/Miso/DSL/TH.hs
@@ -0,0 +1,40 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE ImportQualifiedPost #-}
+{-# LANGUAGE TemplateHaskell     #-}
+{-# LANGUAGE LambdaCase          #-}
+-----------------------------------------------------------------------------
+module Miso.DSL.TH (evalTH) where
+-----------------------------------------------------------------------------
+import Control.Exception
+import Language.Haskell.TH qualified as TH
+import Language.Haskell.TH.Syntax qualified as TH
+-----------------------------------------------------------------------------
+-- | This is from @amesgen. It's a workaround until we can have proper
+-- support for js-sources. It constructs an FFI declaration to import @miso.js@.
+--
+evalTH :: String -> [TH.Q TH.Type] -> TH.Q TH.Exp
+evalTH jsChunk argTys = do
+  ffiImportName <- TH.newName . show =<< TH.newName "wasm_ffi_import_eval"
+  sig <- mkSig argTys
+  let ffiImport =
+        TH.ForeignD $
+          TH.ImportF
+            TH.JavaScript
+            TH.Unsafe
+            jsChunk
+            ffiImportName
+            sig
+  TH.addTopDecls [ffiImport]
+
+  argNames <- traverse (\_ -> TH.newName "x") argTys
+  let argPats = TH.varP <$> argNames
+      argExps = TH.varE <$> argNames
+  -- Safe FFI imports return a thunk that needs to be evaluated to make sure
+  -- that the FFI call actually completed ('unsafeInterleaveIO'-like). To avoid
+  -- surprises, use this unconditionally.
+  TH.lamE argPats [|evaluate =<< $(TH.appsE $ TH.varE ffiImportName : argExps)|]
+  where
+    mkSig = \case
+      [] -> [t|IO ()|]
+      t : ts -> [t|$t -> $(mkSig ts)|]
+-----------------------------------------------------------------------------
diff --git a/ffi/wasm/Miso/DSL/TH/File.hs b/ffi/wasm/Miso/DSL/TH/File.hs
new file mode 100644
--- /dev/null
+++ b/ffi/wasm/Miso/DSL/TH/File.hs
@@ -0,0 +1,20 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE ImportQualifiedPost #-}
+{-# LANGUAGE TemplateHaskell     #-}
+-----------------------------------------------------------------------------
+module Miso.DSL.TH.File (evalFile) where
+-----------------------------------------------------------------------------
+import Language.Haskell.TH qualified as TH
+-----------------------------------------------------------------------------
+import Miso.DSL.TH (evalTH)
+-----------------------------------------------------------------------------
+-- | Like 'eval', but read the JS code to evaluate from a file.
+evalFile
+  :: FilePath
+  -- ^ Path to JS file that will be converted into an FFI declaration.
+  -> TH.Q TH.Exp
+evalFile path = eval_ =<< TH.runIO (readFile path)
+  where
+    eval_ :: String -> TH.Q TH.Exp
+    eval_ chunk = [| $(Miso.DSL.TH.evalTH chunk []) :: IO () |]
+-----------------------------------------------------------------------------
diff --git a/ghc-src/Miso.hs b/ghc-src/Miso.hs
deleted file mode 100644
--- a/ghc-src/Miso.hs
+++ /dev/null
@@ -1,27 +0,0 @@
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE LambdaCase          #-}
-{-# LANGUAGE RecordWildCards     #-}
-{-# LANGUAGE DataKinds           #-}
-{-# LANGUAGE KindSignatures      #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso
-  ( module Miso.Event
-  , module Miso.Html
-  , module Miso.Router
-  , module Miso.TypeLevel
-  , module Miso.Util
-  ) where
-
-import           Miso.Event
-import           Miso.Html
-import           Miso.Router
-import           Miso.TypeLevel
-import           Miso.Util
diff --git a/ghc-src/Miso/Html/Internal.hs b/ghc-src/Miso/Html/Internal.hs
deleted file mode 100644
--- a/ghc-src/Miso/Html/Internal.hs
+++ /dev/null
@@ -1,248 +0,0 @@
-{-# LANGUAGE DeriveFunctor        #-}
-{-# LANGUAGE KindSignatures       #-}
-{-# LANGUAGE DataKinds            #-}
-{-# LANGUAGE FlexibleInstances    #-}
-{-# LANGUAGE TypeSynonymInstances #-}
-{-# LANGUAGE RankNTypes           #-}
-{-# LANGUAGE GADTs                #-}
-{-# LANGUAGE RecordWildCards      #-}
-{-# LANGUAGE ConstraintKinds      #-}
-{-# LANGUAGE TypeFamilies         #-}
-{-# LANGUAGE OverloadedStrings    #-}
-{-# LANGUAGE UndecidableInstances #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Html.Internal
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Html.Internal (
-  -- * Core types and interface
-    VTree  (..)
-  , View   (..)
-  , ToView (..)
-  , Attribute (..)
-  -- * Smart `View` constructors
-  , node
-  , text
-  -- * Key patch internals
-  , Key    (..)
-  , ToKey  (..)
-  -- * Namespace
-  , NS     (..)
-  -- * Setting properties on virtual DOM nodes
-  , prop
-  -- * Setting CSS
-  , style_
-  -- * Handling events
-  , on
-  , onWithOptions
-  -- * Life cycle events
-  , onCreated
-  , onDestroyed
-  ) where
-
-import           Data.Aeson (Value(..), ToJSON(..))
-import qualified Data.Map    as M
-import           Data.Monoid
-import           Data.Proxy
-import           Data.String (IsString(..))
-import qualified Data.Text   as T
-import qualified Data.Vector as V
-import qualified Lucid       as L
-import qualified Lucid.Base  as L
-import           Servant.API
-
-import           Miso.Event
-import           Miso.String hiding (map)
-
--- | Virtual DOM implemented as a Rose `Vector`.
---   Used for diffing, patching and event delegation.
---   Not meant to be constructed directly, see `View` instead.
-data VTree action where
-  VNode :: { vType :: Text -- ^ Element type (i.e. "div", "a", "p")
-           , vNs :: NS -- ^ HTML or SVG
-           , vProps :: Props -- ^ Fields present on DOM Node
-           , vKey :: Maybe Key -- ^ Key used for child swap patch
-           , vChildren :: V.Vector (VTree action) -- ^ Child nodes
-           } -> VTree action
-  VText :: { vText :: Text -- ^ TextNode content
-           } -> VTree action
-  deriving Functor
-
-instance Show (VTree action) where
-  show = show . L.toHtml
-
--- | Converting `VTree` to Lucid's `L.Html`
-instance L.ToHtml (VTree action) where
-  toHtmlRaw = L.toHtml
-  toHtml (VText x) | T.null x = L.toHtml (" " :: MisoString)
-                   | otherwise = L.toHtml x
-  toHtml VNode{..} =
-    let ele = L.makeElement (toTag vType) kids
-    in L.with ele as
-      where
-        Props xs = vProps
-        as = [ L.makeAttribute k (if k `elem` exceptions && v == Bool True then k else v')
-             | (k,v) <- M.toList xs
-             , let v' = toHtmlFromJSON v
-             , not (k `elem` exceptions && v == Bool False)
-             ]
-        exceptions = [ "checked"
-                     , "disabled"
-                     , "selected"
-                     , "hidden"
-                     , "readOnly"
-                     , "autoplay"
-                     , "required"
-                     , "default"
-                     , "autofocus"
-                     , "multiple"
-                     , "noValidate"
-                     , "autocomplete"
-                     ]
-        toTag = T.toLower
-        kids = foldMap L.toHtml vChildren
-
--- | Helper for turning JSON into Text
--- Object, Array and Null are kind of non-sensical here
-toHtmlFromJSON :: Value -> Text
-toHtmlFromJSON (String t) = t
-toHtmlFromJSON (Number t) = pack (show t)
-toHtmlFromJSON (Bool b) = if b then "true" else "false"
-toHtmlFromJSON Null = "null"
-toHtmlFromJSON (Object o) = pack (show o)
-toHtmlFromJSON (Array a) = pack (show a)
-
--- | Core type for constructing a `VTree`, use this instead of `VTree` directly.
-newtype View action = View { runView :: VTree action }
-  deriving Functor
-
--- | For constructing type-safe links
-instance HasLink (View a) where
-  type MkLink (View a) = MkLink (Get '[] ())
-  toLink _ = toLink (Proxy :: Proxy (Get '[] ()))
-
--- | Convenience class for using View
-class ToView v where toView :: v -> View action
-
--- | Show `View`
-instance Show (View action) where
-  show (View xs) = show xs
-
--- | Converting `View` to Lucid's `L.Html`
-instance L.ToHtml (View action) where
-  toHtmlRaw = L.toHtml
-  toHtml (View xs) = L.toHtml xs
-
--- | Namespace for element creation
-data NS
-  = HTML -- ^ HTML Namespace
-  | SVG  -- ^ SVG Namespace
-  deriving (Show, Eq)
-
--- | `VNode` creation
-node :: NS -> MisoString -> Maybe Key -> [Attribute action] -> [View action] -> View action
-node vNs vType vKey as xs =
-  let vProps  = Props  $ M.fromList [ (k,v) | P k v <- as ]
-      vChildren = V.fromList $ map runView xs
-  in View VNode {..}
-
--- | `VText` creation
-text :: MisoString -> View action
-text = View . VText
-
--- | `IsString` instance
-instance IsString (View a) where
-  fromString = text . fromString
-
--- | Key for specific children patch
-newtype Key = Key MisoString
-  deriving (Show, Eq, Ord)
-
--- | Convert type into Key, ensure `Key` is unique
-class ToKey key where toKey :: key -> Key
--- | Identity instance
-instance ToKey Key    where toKey = id
--- | Convert `Text` to `Key`
-instance ToKey MisoString where toKey = Key
--- | Convert `String` to `Key`
-instance ToKey String where toKey = Key . T.pack
--- | Convert `Int` to `Key`
-instance ToKey Int    where toKey = Key . T.pack . show
--- | Convert `Double` to `Key`
-instance ToKey Double where toKey = Key . T.pack . show
--- | Convert `Float` to `Key`
-instance ToKey Float  where toKey = Key . T.pack . show
--- | Convert `Word` to `Key`
-instance ToKey Word   where toKey = Key . T.pack . show
-
--- | Properties
-newtype Props = Props (M.Map MisoString Value)
-  deriving (Show, Eq)
-
--- | `View` Attributes to annotate DOM, converted into Events, Props, Attrs and CSS
-data Attribute action
-  = P MisoString Value
-  | E ()
-  deriving (Show, Eq)
-
--- | DMJ: this used to get set on preventDefault on Options... if options are dynamic now what
--- | Useful for `drop` events
-newtype AllowDrop = AllowDrop Bool
-  deriving (Show, Eq)
-
--- | Constructs a property on a `VNode`, used to set fields on a DOM Node
-prop :: ToJSON a => MisoString -> a -> Attribute action
-prop k v = P k (toJSON v)
-
--- | For defining delegated events
---
--- > let clickHandler = on "click" emptyDecoder $ \() -> Action
--- > in button_ [ clickHandler, class_ "add" ] [ text_ "+" ]
---
-on :: MisoString
-   -> Decoder r
-   -> (r -> action)
-   -> Attribute action
-on _ _ _ = E ()
-
--- | For defining delegated events with options
---
--- > let clickHandler = onWithOptions defaultOptions "click" emptyDecoder $ \() -> Action
--- > in button_ [ clickHandler, class_ "add" ] [ text_ "+" ]
---
-onWithOptions
-   :: Options
-   -> MisoString
-   -> Decoder r
-   -> (r -> action)
-   -> Attribute action
-onWithOptions _ _ _ _ = E ()
-
--- | @onCreated action@ is an event that gets called after the actual DOM
--- element is created.
-onCreated :: action -> Attribute action
-onCreated _ = E ()
-
--- | @onDestroyed action@ is an event that gets called after the DOM element
--- is removed from the DOM. The @action@ is given the DOM element that was
--- removed from the DOM tree.
-onDestroyed :: action -> Attribute action
-onDestroyed _ = E ()
-
--- | Constructs CSS for a DOM Element
---
--- > import qualified Data.Map as M
--- > div_ [ style_  $ M.singleton "background" "red" ] [ ]
---
--- <https://developer.mozilla.org/en-US/docs/Web/CSS>
---
-style_ :: M.Map MisoString MisoString -> Attribute action
-style_ map' = P "style" $ String (M.foldrWithKey go mempty map')
-  where
-    go :: MisoString -> MisoString -> MisoString -> MisoString
-    go k v xs = mconcat [ k, ":", v, ";" ] <> xs
diff --git a/ghc-src/Miso/String.hs b/ghc-src/Miso/String.hs
deleted file mode 100644
--- a/ghc-src/Miso/String.hs
+++ /dev/null
@@ -1,56 +0,0 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE TypeSynonymInstances #-}
-{-# LANGUAGE OverloadedStrings #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.String
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.String
-  ( ToMisoString (..)
-  , MisoString
-  , module Data.Monoid
-  , module Data.Text
-  , ms
-  ) where
-
-import qualified Data.ByteString         as B
-import qualified Data.ByteString.Lazy    as BL
-import           Data.Monoid
-import           Data.Text
-import qualified Data.Text               as T
-import qualified Data.Text.Encoding      as T
-import qualified Data.Text.Lazy          as LT
-import qualified Data.Text.Lazy.Encoding as LT
-
--- | String type swappable based on compiler
-type MisoString = Text
-
--- | Convenience class for creating `MisoString` from other string-like types
-class ToMisoString str where
-  toMisoString :: str -> MisoString
-  fromMisoString :: MisoString -> str
-
--- | Convenience function, shorthand for `toMisoString`
-ms :: ToMisoString str => str -> MisoString
-ms = toMisoString
-
-instance ToMisoString MisoString where
-  toMisoString = id
-  fromMisoString = id
-instance ToMisoString String where
-  toMisoString = T.pack
-  fromMisoString = T.unpack
-instance ToMisoString LT.Text where
-  toMisoString = LT.toStrict
-  fromMisoString = LT.fromStrict
-instance ToMisoString B.ByteString where
-  toMisoString = toMisoString . T.decodeUtf8
-  fromMisoString = T.encodeUtf8 . fromMisoString
-instance ToMisoString BL.ByteString where
-  toMisoString = toMisoString . LT.decodeUtf8
-  fromMisoString = LT.encodeUtf8 . fromMisoString
diff --git a/ghc-src/Miso/TypeLevel.hs b/ghc-src/Miso/TypeLevel.hs
deleted file mode 100644
--- a/ghc-src/Miso/TypeLevel.hs
+++ /dev/null
@@ -1,19 +0,0 @@
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE TypeOperators #-}
-module Miso.TypeLevel ( ToServerRoutes ) where
-
-import Miso.Html
-import Servant.API
-import Servant.HTML.Lucid
-
--- | Convert client route type to a server web handler type
-type family ToServerRoutes (layout :: k) (wrapper :: * -> *) (action :: *) :: k where
-  ToServerRoutes (a :<|> b) wrapper action =
-    ToServerRoutes a wrapper action :<|>
-      ToServerRoutes b wrapper action
-  ToServerRoutes (a :> b) wrapper action =
-    a :> ToServerRoutes b wrapper action
-  ToServerRoutes (View a) wrapper action =
-    Get '[HTML] (wrapper (View action))
diff --git a/ghcjs-src/Miso.hs b/ghcjs-src/Miso.hs
deleted file mode 100644
--- a/ghcjs-src/Miso.hs
+++ /dev/null
@@ -1,139 +0,0 @@
-{-# LANGUAGE BangPatterns        #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE LambdaCase          #-}
-{-# LANGUAGE RecordWildCards     #-}
-{-# LANGUAGE DataKinds           #-}
-{-# LANGUAGE KindSignatures      #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso
-  ( miso
-  , startApp
-  , module Miso.Effect
-  , module Miso.Event
-  , module Miso.Html
-  , module Miso.Subscription
-  , module Miso.Types
-  , module Miso.Router
-  , module Miso.Util
-  , module Miso.FFI
-  ) where
-
-import           Control.Concurrent
-import           Control.Monad
-import           Data.IORef
-import           Data.List
-import           Data.Sequence                 ((|>))
-import qualified Data.Sequence                 as S
-import           GHCJS.Types (JSVal)
-import qualified JavaScript.Object.Internal    as OI
-import           JavaScript.Web.AnimationFrame
-
-import           Miso.Concurrent
-import           Miso.Delegate
-import           Miso.Diff
-import           Miso.Effect
-import           Miso.Event
-import           Miso.Util
-import           Miso.Html
-import           Miso.Router
-import           Miso.Subscription
-import           Miso.Types
-import           Miso.FFI
-
--- | Helper function to abstract out common functionality between `startApp` and `miso`
-common
-  :: Eq model
-  => App model action
-  -> model
-  -> (Sink action -> IO (IORef VTree))
-  -> IO b
-common App {..} m getView = do
-  -- init Notifier
-  Notify {..} <- newNotify
-  -- init empty actions
-  actionsRef <- newIORef S.empty
-  let writeEvent a = void . forkIO $ do
-        atomicModifyIORef' actionsRef $ \as -> (as |> a, ())
-        notify
-  -- init Subs
-  forM_ subs $ \sub ->
-    sub writeEvent
-  -- Hack to get around `BlockedIndefinitelyOnMVar` exception
-  -- that occurs when no event handlers are present on a template
-  -- and `notify` is no longer in scope
-  void . forkIO . forever $ threadDelay (1000000 * 86400) >> notify
-  -- Retrieves reference view
-  viewRef <- getView writeEvent
-  -- know thy mountElement
-  mountEl <- mountElement mountPoint
-  -- Begin listening for events in the virtual dom
-  delegator mountEl viewRef events
-  -- Process initial action of application
-  writeEvent initialAction
-  -- Program loop, blocking on SkipChan
-
-  let loop !oldModel = wait >> do
-        -- Apply actions to model
-        actions <- atomicModifyIORef' actionsRef $ \actions -> (S.empty, actions)
-        let (Acc newModel effects) = foldl' (foldEffects writeEvent update)
-                                            (Acc oldModel (pure ())) actions
-        effects
-        when (oldModel /= newModel) $ do
-          newVTree <- runView (view newModel) writeEvent
-          oldVTree <- readIORef viewRef
-          void $ waitForAnimationFrame
-          (diff mountPoint) (Just oldVTree) (Just newVTree)
-          atomicWriteIORef viewRef newVTree
-        loop newModel
-  loop m
-
--- | Runs an isomorphic miso application
--- Assumes the pre-rendered DOM is already present
-miso :: Eq model => (URI -> App model action) -> IO ()
-miso f = do
-  app@App {..} <- f <$> getCurrentURI
-  common app model $ \writeEvent -> do
-    let initialView = view model
-    VTree (OI.Object iv) <- flip runView writeEvent initialView
-    -- Initial diff can be bypassed, just copy DOM into VTree
-    copyDOMIntoVTree iv
-    let initialVTree = VTree (OI.Object iv)
-    -- Create virtual dom, perform initial diff
-    newIORef initialVTree
-
--- | Runs a miso application
-startApp :: Eq model => App model action -> IO ()
-startApp app@App {..} =
-  common app model $ \writeEvent -> do
-    let initialView = view model
-    initialVTree <- flip runView writeEvent initialView
-    (diff mountPoint) Nothing (Just initialVTree)
-    newIORef initialVTree
-
--- | Helper
-foldEffects
-  :: Sink action
-  -> (action -> model -> Effect action model)
-  -> Acc model -> action -> Acc model
-foldEffects sink update = \(Acc model as) action ->
-  case update action model of
-    Effect newModel effs -> Acc newModel newAs
-      where
-        newAs = as >> do
-          forM_ effs $ \eff ->
-            void $ forkIO (eff sink)
-
-data Acc model = Acc !model !(IO ())
-
--- | Copies DOM pointers into virtual dom
--- entry point into isomorphic javascript
-foreign import javascript unsafe "copyDOMIntoVTree($1);"
-  copyDOMIntoVTree :: JSVal -> IO ()
diff --git a/ghcjs-src/Miso/Delegate.hs b/ghcjs-src/Miso/Delegate.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Delegate.hs
+++ /dev/null
@@ -1,41 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Delegate
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Delegate where
-
-import           Data.IORef
-import qualified Data.Map                 as M
-import           Miso.Html.Internal
-import           Miso.String
-import qualified JavaScript.Object.Internal as OI
-import           GHCJS.Foreign.Callback
-import           GHCJS.Marshal
-import           GHCJS.Types (JSVal)
-
--- | Entry point for event delegation
-delegator
-  :: JSVal
-  -> IORef VTree
-  -> M.Map MisoString Bool
-  -> IO ()
-delegator mountPointElement vtreeRef es = do
-  evts <- toJSVal (M.toList es)
-  getVTreeFromRef <- syncCallback' $ do
-    VTree (OI.Object val) <- readIORef vtreeRef
-    pure val
-  delegateEvent mountPointElement evts getVTreeFromRef
-
--- | Event delegation FFI, routes events received on body through the virtual dom
--- Invokes event handler when found
-foreign import javascript unsafe "delegate($1, $2, $3);"
-  delegateEvent
-     :: JSVal               -- ^ mountPoint element
-     -> JSVal               -- ^ Events
-     -> Callback (IO JSVal) -- ^ Virtual DOM callback
-     -> IO ()
diff --git a/ghcjs-src/Miso/Dev.hs b/ghcjs-src/Miso/Dev.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Dev.hs
+++ /dev/null
@@ -1,14 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Dev
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Dev
-  ( clearBody
-  ) where
-
-import Miso.FFI (clearBody)
diff --git a/ghcjs-src/Miso/Diff.hs b/ghcjs-src/Miso/Diff.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Diff.hs
+++ /dev/null
@@ -1,66 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Diff
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Diff ( diff
-                 , mountElement
-                 ) where
-
-import GHCJS.Foreign.Internal     hiding (Object)
-import GHCJS.Types
-import JavaScript.Object
-import JavaScript.Object.Internal
-import Miso.Html.Internal
-
--- | Entry point for diffing / patching algorithm
-diff :: Maybe JSString -> Maybe VTree -> Maybe VTree -> IO ()
-diff mayElem current new =
-  case mayElem of
-    Nothing -> do
-      body <- getBody
-      diffElement body current new
-    Just elemId -> do
-      e <- getElementById elemId
-      diffElement e current new
-
--- | diffing / patching a given element
-diffElement :: JSVal -> Maybe VTree -> Maybe VTree -> IO ()
-diffElement mountEl current new = do
-  doc <- getDoc
-  case (current, new) of
-    (Nothing, Nothing) -> pure ()
-    (Just (VTree current'), Just (VTree new')) -> do
-      diff' current' new' mountEl doc
-    (Nothing, Just (VTree new')) -> do
-      diff' (Object jsNull) new' mountEl doc
-    (Just (VTree current'), Nothing) -> do
-      diff' current' (Object jsNull) mountEl doc
-
--- | return the configured mountPoint element or the body
-mountElement :: Maybe JSString -> IO JSVal
-mountElement mayMp =
-  case mayMp of
-    Nothing -> getBody
-    Just eid -> getElementById eid
-
-foreign import javascript unsafe "$r = document.body;"
-  getBody :: IO JSVal
-
-foreign import javascript unsafe "$r = document;"
-  getDoc :: IO JSVal
-
-foreign import javascript unsafe "$r = document.getElementById($1);"
-  getElementById :: JSString -> IO JSVal
-
-foreign import javascript unsafe "diff($1, $2, $3, $4);"
-  diff'
-    :: Object -- ^ current object
-    -> Object -- ^ new object
-    -> JSVal  -- ^ parent node
-    -> JSVal  -- ^ document
-    -> IO ()
diff --git a/ghcjs-src/Miso/Effect.hs b/ghcjs-src/Miso/Effect.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Effect.hs
+++ /dev/null
@@ -1,80 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Effect
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Effect (
-  module Miso.Effect.Storage
-, module Miso.Effect.XHR
-, module Miso.Effect.DOM
-, Effect (..), Sub, Sink
-, noEff
-, (<#)
-, (#>)
-, effectSub
-) where
-
-import Data.Bifunctor
-
-import Miso.Effect.Storage
-import Miso.Effect.XHR
-import Miso.Effect.DOM
-
--- | An effect represents the results of an update action.
---
--- It consists of the updated model and a list of subscriptions. Each 'Sub' is
--- run in a new thread so there is no risk of accidentally blocking the
--- application.
-data Effect action model = Effect model [Sub action]
-
--- | Type synonym for constructing event subscriptions.
---
--- The 'Sink' callback is used to dispatch actions which are then fed
--- back to the 'update' function.
-type Sub action = Sink action -> IO ()
-
--- | Function to asynchronously dispatch actions to the 'update' function.
-type Sink action = action -> IO ()
-
-instance Functor (Effect action) where
-  fmap f (Effect m acts) = Effect (f m) acts
-
-instance Applicative (Effect action) where
-  pure m = Effect m []
-  Effect fModel fActs <*> Effect xModel xActs = Effect (fModel xModel) (fActs ++ xActs)
-
-instance Monad (Effect action) where
-  return = pure
-  Effect m acts >>= f =
-    case f m of
-      Effect m' acts' -> Effect m' (acts ++ acts')
-
-instance Bifunctor Effect where
-  bimap f g (Effect m acts) = Effect (g m) (map (\act -> \sink -> act (sink . f)) acts)
-
--- | Smart constructor for an 'Effect' with no actions.
-noEff :: model -> Effect action model
-noEff m = Effect m []
-
--- | Smart constructor for an 'Effect' with exactly one action.
-(<#) :: model -> IO action -> Effect action model
-(<#) m a = effectSub m $ \sink -> a >>= sink
-
--- | `Effect` smart constructor, flipped
-(#>) :: IO action -> model -> Effect action model
-(#>) = flip (<#)
-
--- | Like '<#' but schedules a subscription which is an IO computation which has
--- access to a 'Sink' which can be used to asynchronously dispatch actions to
--- the 'update' function.
---
--- A use-case is scheduling an IO computation which creates a 3rd-party JS
--- widget which has an associated callback. The callback can then call the sink
--- to turn events into actions. To do this without accessing a sink requires
--- going via a @'Sub'scription@ which introduces a leaky-abstraction.
-effectSub :: model -> Sub action -> Effect action model
-effectSub model sub = Effect model [sub]
diff --git a/ghcjs-src/Miso/Effect/DOM.hs b/ghcjs-src/Miso/Effect/DOM.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Effect/DOM.hs
+++ /dev/null
@@ -1,33 +0,0 @@
-{-# LANGUAGE ForeignFunctionInterface #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Effect.DOM
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Effect.DOM
-  ( focus
-  , blur
-  , alert
-  ) where
-
-import Miso.String
-
--- | Fails silently if the element is not found.
---
--- Analogous to @document.getElementById(id).focus()@.
-foreign import javascript unsafe "callFocus($1);"
-  focus :: MisoString -> IO ()
-
--- | Fails silently if the element is not found.
---
--- Analogous to @document.getElementById(id).blur()@
-foreign import javascript unsafe "callBlur($1);"
-  blur :: MisoString -> IO ()
-
--- | Calls the @alert()@ function.
-foreign import javascript unsafe "alert($1);"
-  alert :: MisoString -> IO ()
diff --git a/ghcjs-src/Miso/Effect/Storage.hs b/ghcjs-src/Miso/Effect/Storage.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Effect/Storage.hs
+++ /dev/null
@@ -1,116 +0,0 @@
-{-# LANGUAGE ScopedTypeVariables       #-}
-{-# LANGUAGE OverloadedStrings         #-}
-{-# LANGUAGE ForeignFunctionInterface  #-}
-{-# LANGUAGE LambdaCase                #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Effect.Storage
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
---
--- This module provides an interface to the
--- [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API).
-----------------------------------------------------------------------------
-module Miso.Effect.Storage
-  ( -- * Retrieve storage
-    getLocalStorage
-  , getSessionStorage
-    -- * Set items in storage
-  , setLocalStorage
-  , setSessionStorage
-    -- * Remove items from storage
-  , removeLocalStorage
-  , removeSessionStorage
-    -- * Clear storage
-  , clearLocalStorage
-  , clearSessionStorage
-    -- * Get number of items in storage
-  , localStorageLength
-  , sessionStorageLength
-  ) where
-
-import Data.Aeson     hiding (Object, String)
-import Data.JSString
-import GHCJS.Nullable
-import GHCJS.Types
-
-import Miso.FFI
-
--- | Helper for retrieving either local or session storage
-getStorageCommon
-  :: FromJSON b => (t -> IO (Maybe JSVal)) -> t -> IO (Either String b)
-getStorageCommon f key = do
-  result :: Maybe JSVal <- f key
-  case result of
-    Nothing -> pure $ Left "Not Found"
-    Just v -> do
-      r <- parse v
-      pure $ case fromJSON r of
-        Success x -> Right x
-        Error y -> Left y
-
--- | Retrieve session storage
-getSessionStorage :: FromJSON model => JSString -> IO (Either String model)
-getSessionStorage =
-  getStorageCommon $ \t -> do
-    r <- getItemSS t
-    pure (nullableToMaybe r)
-
--- | Retrieve local storage
-getLocalStorage :: FromJSON model => JSString -> IO (Either String model)
-getLocalStorage = getStorageCommon $ \t -> do
-    r <- getItemLS t
-    pure (nullableToMaybe r)
-
--- | Set the value of a key in local storage.
---
--- @setLocalStorage key value@ sets the value of @key@ to @value@.
-setLocalStorage :: ToJSON model => JSString -> model -> IO ()
-setLocalStorage key model =
-  setItemLS key =<< stringify model
-
--- | Set the value of a key in session storage.
---
--- @setSessionStorage key value@ sets the value of @key@ to @value@.
-setSessionStorage :: ToJSON model => JSString -> model -> IO ()
-setSessionStorage key model =
-  setItemSS key =<< stringify model
-
-foreign import javascript unsafe "$r = window.localStorage.getItem($1);"
-  getItemLS :: JSString -> IO (Nullable JSVal)
-
-foreign import javascript unsafe "$r = window.sessionStorage.getItem($1);"
-  getItemSS :: JSString -> IO (Nullable JSVal)
-
--- | Removes item from local storage by key name.
-foreign import javascript unsafe "window.localStorage.removeItem($1);"
-  removeLocalStorage :: JSString -> IO ()
-
--- | Removes item from session storage by key name.
-foreign import javascript unsafe "window.sessionStorage.removeItem($1);"
-  removeSessionStorage :: JSString -> IO ()
-
-foreign import javascript unsafe "window.localStorage.setItem($1, $2);"
-  setItemLS :: JSString -> JSString -> IO ()
-
-foreign import javascript unsafe "window.sessionStorage.setItem($1, $2);"
-  setItemSS :: JSString -> JSString -> IO ()
-
--- | Retrieves the number of items in local storage.
-foreign import javascript unsafe "$r = window.localStorage.length;"
-  localStorageLength :: IO Int
-
--- | Retrieves the number of items in session storage.
-foreign import javascript unsafe "$r = window.sessionStorage.length;"
-  sessionStorageLength :: IO Int
-
--- | Clears local storage.
-foreign import javascript unsafe "window.localStorage.clear();"
-  clearLocalStorage :: IO ()
-
--- | Clears session storage.
-foreign import javascript unsafe "window.sessionStorage.clear();"
-  clearSessionStorage :: IO ()
diff --git a/ghcjs-src/Miso/Effect/XHR.hs b/ghcjs-src/Miso/Effect/XHR.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Effect/XHR.hs
+++ /dev/null
@@ -1,321 +0,0 @@
-{-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE DataKinds            #-}
-{-# LANGUAGE TypeFamilies         #-}
-{-# LANGUAGE FlexibleInstances    #-}
-{-# LANGUAGE TypeOperators        #-}
-{-# LANGUAGE ScopedTypeVariables  #-}
-{-# LANGUAGE LambdaCase           #-}
-{-# LANGUAGE OverloadedStrings    #-}
-{-# LANGUAGE CPP                  #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Effect.XHR
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Effect.XHR where
-
-import Data.Proxy
-import GHC.TypeLits
-import JavaScript.Web.XMLHttpRequest
-import Miso.String
-import Servant.API
-
--- | Still a WIP, use ghcjs-base XHR for now, or other
-
--- | Intermediate type for accumulation
-data RouteInfo
-  = RouteInfo { riPath :: String
-              , riMethod :: Method
-              } deriving (Show, Eq)
-
--- | Class for `XHR`
-class HasXHR api where
-  type XHR api :: *
-  xhrWithRoute
-    :: Proxy api
-    -> RouteInfo
-    -> XHR api
-
--- | Result of using `XHR`
-type Result a = IO (Either MisoString a)
-
--- | Verb
-instance {-# OVERLAPPABLE #-}
-  ( MimeUnrender ct a
-  , ReflectMethod method
-  , cts' ~ (ct ': cts)
-  ) => HasXHR (Verb method status cts' a) where
-  type XHR (Verb method status cts' a) = Result a
-  xhrWithRoute Proxy _ = undefined
-    -- snd <$> performRequestCT (Proxy :: Proxy ct) method req
-    --   where method = reflectMethod (Proxy :: Proxy method)
-
--- | Verb NoContent
-instance {-# OVERLAPPING #-}
-  ReflectMethod method => HasXHR (Verb method status cts NoContent) where
-  type XHR (Verb method status cts NoContent) = Result NoContent
-  xhrWithRoute Proxy _ = undefined
-    -- performRequestNoBody method req >> return NoContent
-    --   where method = reflectMethod (Proxy :: Proxy method)
-
--- | Verb, with HEADERS
-instance {-# OVERLAPPING #-}
-  ( MimeUnrender ct a, BuildHeadersTo ls, ReflectMethod method, cts' ~ (ct ': cts)
-  ) => HasXHR (Verb method status cts' (Headers ls a)) where
-  type XHR (Verb method status cts' (Headers ls a)) = Result (Headers ls a)
-  xhrWithRoute Proxy _ = undefined
-    -- let method = reflectMethod (Proxy :: Proxy method)
-    -- (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) method req
-    -- return $ Headers { getResponse = resp
-    --                  , getHeadersHList = buildHeadersTo hdrs
-    --                  }
-
-
--- | `Headers`, with `NoContent`
-instance {-# OVERLAPPING #-}
-  ( BuildHeadersTo ls, ReflectMethod method
-  ) => HasXHR (Verb method status cts (Headers ls NoContent)) where
-  type XHR (Verb method status cts (Headers ls NoContent)) = Result (Headers ls NoContent)
-  xhrWithRoute Proxy _ = undefined
-    -- let method = reflectMethod (Proxy :: Proxy method)
-    -- hdrs <- performRequestNoBody method req
-    -- return $ Headers { getResponse = NoContent
-    --                  , getHeadersHList = buildHeadersTo hdrs
-    --                  }
-
--- | Capture
-instance (ToHttpApiData a, HasXHR api, KnownSymbol sym) => HasXHR (Capture sym a :> api) where
-  type XHR (Capture sym a :> api) = a -> XHR api
-  xhrWithRoute Proxy _ (_ :: a) = undefined
-
-#if MIN_VERSION_servant(0,8,1)
--- | CaptureAll
-instance (KnownSymbol capture, ToHttpApiData a, HasXHR sublayout)
-   => HasXHR (CaptureAll capture a :> sublayout) where
-  type XHR (CaptureAll capture a :> sublayout) = [a] -> XHR sublayout
-  xhrWithRoute Proxy _ _ = undefined
-    -- xhrWithRoute (Proxy :: Proxy sublayout)
-    --   (foldl' (flip appendToPath) req ps)
-#endif
-
--- | Path (done)
-instance (HasXHR api, KnownSymbol sym) => HasXHR (sym :> api) where
-  type XHR (sym :> api) = XHR api
-  xhrWithRoute Proxy req = xhrWithRoute (Proxy :: Proxy api) newReq
-    where
-      newReq = req {
-        riPath = riPath req ++ "/" ++ symbolVal (Proxy :: Proxy sym)
-      }
-
--- | Raw (not supported)
--- instance HasXHR Raw where
---   type XHR Raw = XHR (Response MisoString)
---   xhrWithRoute Proxy _ = putStrLn "Raw is not supported"
-
--- | Alternate
-instance (HasXHR left, HasXHR right) => HasXHR (left :<|> right) where
-  type XHR (left :<|> right) = XHR left :<|> XHR right
-  xhrWithRoute Proxy s =
-    xhrWithRoute (Proxy :: Proxy left) s :<|>
-      xhrWithRoute (Proxy :: Proxy right) s
-
--- | Header
-instance (ToHttpApiData a, HasXHR api, KnownSymbol sym) => HasXHR (Header sym a :> api) where
-  type XHR (Header sym a :> api) = Maybe a -> XHR api
-  xhrWithRoute Proxy _ = undefined
-
--- | HttpVersion
-instance HasXHR api => HasXHR (HttpVersion :> api) where
-  type XHR (HttpVersion :> api) = XHR api
-  xhrWithRoute Proxy = xhrWithRoute (Proxy :: Proxy api)
-
--- | Query param
-instance (KnownSymbol sym, ToHttpApiData a, HasXHR api) => HasXHR (QueryParam sym a :> api) where
-  type XHR (QueryParam sym a :> api) = Maybe a -> XHR api
-  xhrWithRoute Proxy _ _ = undefined
-
--- | Query param(s)
-instance (KnownSymbol sym, ToHttpApiData a, HasXHR api) => HasXHR (QueryParams sym a :> api) where
-  type XHR (QueryParams sym a :> api) = [a] -> XHR api
-  xhrWithRoute Proxy _ _ = undefined
-
--- | Query flag
-instance (KnownSymbol sym, HasXHR api) => HasXHR (QueryFlag sym :> api) where
-  type XHR (QueryFlag sym :> api) = Bool -> XHR api
-  xhrWithRoute Proxy _ _ = undefined
-
--- | Request Body
-instance (MimeRender ct a, HasXHR api) => HasXHR (ReqBody (ct ': cts) a :> api) where
-  type XHR (ReqBody (ct ': cts) a :> api) = a -> XHR api
-  xhrWithRoute Proxy _ _ = undefined
-
--- | Remote host (done)
-instance HasXHR api => HasXHR (RemoteHost :> api) where
-  type XHR (RemoteHost :> api) = XHR api
-  xhrWithRoute Proxy req =  xhrWithRoute (Proxy :: Proxy api) req
-
--- | IsSecure host (done)
-instance HasXHR api => HasXHR (IsSecure :> api) where
-  type XHR (IsSecure :> api) = XHR api
-  xhrWithRoute Proxy req =  xhrWithRoute (Proxy :: Proxy api) req
-
--- | WithNamedContext (done)
-instance HasXHR api => HasXHR (WithNamedContext :> api) where
-  type XHR (WithNamedContext :> api) = XHR api
-  xhrWithRoute Proxy req =  xhrWithRoute (Proxy :: Proxy api) req
-
--- | Vault (done)
-instance HasXHR api => HasXHR (Vault :> api) where
-  type XHR (Vault :> api) = XHR api
-  xhrWithRoute Proxy req = xhrWithRoute (Proxy :: Proxy api) req
-
--- | BasicAuth
-instance HasXHR api => HasXHR (BasicAuth realm usr :> api) where
-  type XHR (BasicAuth realm usr :> api) = BasicAuthData -> XHR api
-  xhrWithRoute Proxy _ _ = undefined
-
--- | Can't find AuthenticateReq
--- instance HasXHR api => HasXHR (AuthProtect tag :> api) where
---   type XHR (AuthProtect tag :> api) = AuthenticateReq (AuthProtect tag) -> XHR api
---   xhrWithRoute Proxy req (AuthenticateReq (val,func)) =
---     xhrWithRoute (Proxy :: Proxy api) (func val req)
-
-
-
-
-
--- xhrWithRoute (Proxy :: Proxy api)
---                     (let ctProxy = Proxy :: Proxy ct
---                      in setReqBodyLBS (mimeRender ctProxy body)
---                                   -- We use first contentType from the Accept list
---                                   (contentType ctProxy)
---                                   req
---                     )
-
-
--- xhrJSON :: FromJSON json => Request -> IO (Response json)
--- xhrJSON req = do
---   r <- xhr' req
---   case contents r of
---     Nothing -> pure r { contents = Just Null }
---     Just jsstring -> do
---       x <- parse (unsafeCoerce jsstring)
---       pure $ r { contents = Just x }
-
-
--- import Data.JSString
--- import GHCJS.Foreign.Callback
--- import GHCJS.Nullable
--- import GHCJS.Types
--- import Prelude                hiding (lines)
-
--- data ReadyState
---   = UNSENT
---   -- ^ XHR has been created. open() not called yet.
---   | OPENED
---   -- ^ open() has been called.
---   | HEADERS_RECEIVED
---   -- ^ send() has been called, and headers and status are available.
---   | LOADING
---   -- ^ Downloading; responseText holds partial data.
---   | DONE
---   -- ^ The operation is complete.
---   deriving (Show, Eq, Enum)
-
--- data ResponseType
---   = DOMStringType
---   | ArrayBufferType
---   | BlobType
---   | DocumentType
---   | JSONType
---   | UnknownXHRType
---   deriving (Show, Eq)
-
--- newtype Document = Document JSVal
--- newtype XHR = XHR JSVal
-
--- foreign import javascript unsafe "$r = new XMLHttpRequest();"
---   newXHR :: IO XHR
-
--- foreign import javascript unsafe "$1.abort();"
---   abort :: XHR -> IO ()
-
--- foreign import javascript unsafe "$r = $1.responseURL;"
---   responseURL :: XHR -> IO JSString
-
--- foreign import javascript unsafe "$r = $1.readyState;"
---   readyState' :: XHR -> IO Int
-
--- foreign import javascript unsafe "$r = $1.responseType;"
---   responseType' :: XHR -> IO JSString
-
--- responseType :: XHR -> IO ResponseType
--- {-# INLINE responseType #-}
--- responseType xhr =
---   responseType' xhr >>= \case
---     "" -> pure DOMStringType
---     "blob" -> pure BlobType
---     "document" -> pure DocumentType
---     "json" -> pure JSONType
---     "arraybuffer" -> pure ArrayBufferType
---     "text" -> pure DOMStringType
---     _ -> pure UnknownXHRType
-
--- readyState :: XHR -> IO ReadyState
--- {-# INLINE readyState #-}
--- readyState xhr = toEnum <$> readyState' xhr
-
--- -- request.open("GET", "foo.txt", true);
--- foreign import javascript unsafe "$1.open($2, $3, $4);"
---   open :: XHR -> JSString -> JSString -> Bool -> IO ()
-
--- foreign import javascript unsafe "$1.send();"
---   send :: XHR -> IO ()
-
--- foreign import javascript unsafe "$1.setRequestHeader($2,$3);"
---   setRequestHeader :: XHR -> JSString -> JSString -> IO ()
-
--- foreign import javascript unsafe "$1.onreadystatechanged = $2;"
---   onReadyStateChanged :: XHR -> Callback (JSVal -> IO ()) -> IO ()
-
--- foreign import javascript unsafe "$r = $1.getAllResponseHeaders();"
---   getAllResponseHeaders' :: XHR -> IO (Nullable JSString)
-
--- foreign import javascript unsafe "$r = $1.getResponseHeader($2);"
---   getResponseHeader' :: XHR -> JSString -> IO (Nullable JSString)
-
--- getResponseHeader :: XHR -> JSString -> IO (Maybe JSString)
--- {-# INLINE getResponseHeader #-}
--- getResponseHeader xhr key =
---   nullableToMaybe <$> getResponseHeader' xhr key
-
--- foreign import javascript unsafe "$r = $1.response;"
---   response' :: XHR -> IO (Nullable JSVal)
-
--- foreign import javascript unsafe "$r = $1.status;"
---   status' :: XHR -> IO (Nullable Int)
-
--- foreign import javascript unsafe "$r = $1.statusText;"
---   statusText' :: XHR -> IO (Nullable JSString)
-
--- foreign import javascript unsafe "$1.overrideMimeType($2);"
---   overrideMimeType :: XHR -> JSString -> IO ()
-
--- foreign import javascript unsafe "$r = $1.timeout;"
---   timeout :: XHR -> IO Int
-
--- foreign import javascript unsafe "$1.withCredentials = true;"
---   withCredentials :: XHR -> IO ()
-
--- foreign import javascript unsafe "$1.response ? true : false"
---   hasResponse :: XHR -> IO Bool
-
--- getAllResponseHeaders :: XHR -> IO (Maybe [JSString])
--- {-# INLINE getAllResponseHeaders #-}
--- getAllResponseHeaders = \xhr -> do
---   result <- getAllResponseHeaders' xhr
---   pure $ lines <$> nullableToMaybe result
diff --git a/ghcjs-src/Miso/FFI.hs b/ghcjs-src/Miso/FFI.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/FFI.hs
+++ /dev/null
@@ -1,127 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE ForeignFunctionInterface #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE LambdaCase #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.FFI
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.FFI
-   ( windowAddEventListener
-   , windowRemoveEventListener
-   , windowInnerHeight
-   , windowInnerWidth
-   , now
-   , consoleLog
-   , stringify
-   , parse
-   , item
-   , jsvalToValue
-   , clearBody
-   ) where
-
-import           Control.Monad
-import           Control.Monad.Trans.Maybe
-import qualified Data.Aeson                 as AE
-import           Data.Aeson                 hiding (Object)
-import qualified Data.HashMap.Strict        as H
-import           Data.JSString
-import qualified Data.JSString.Text         as JSS
-import           Data.Maybe
-import           Data.Scientific
-import qualified Data.Vector                as V
-import           GHCJS.Foreign.Callback
-import           GHCJS.Foreign.Internal
-import           GHCJS.Marshal
-import           GHCJS.Types
-import           JavaScript.Array.Internal
-import qualified JavaScript.Object.Internal as OI
-import           Unsafe.Coerce
-
--- | Convert JSVal to Maybe `Value`
-jsvalToValue :: JSVal -> IO (Maybe Value)
-jsvalToValue r = do
-  case jsonTypeOf r of
-    JSONNull -> return (Just Null)
-    JSONInteger -> liftM (AE.Number . flip scientific 0 . (toInteger :: Int -> Integer))
-         <$> fromJSVal r
-    JSONFloat -> liftM (AE.Number . (fromFloatDigits :: Double -> Scientific))
-         <$> fromJSVal r
-    JSONBool -> liftM AE.Bool <$> fromJSVal r
-    JSONString -> liftM AE.String <$> fromJSVal r
-    JSONArray -> do
-      xs :: [Value] <-
-        catMaybes <$>
-          forM (toList (unsafeCoerce r)) jsvalToValue
-      pure . pure $ Array . V.fromList $ xs
-    JSONObject -> do
-        Just (props :: [JSString]) <- fromJSVal =<< getKeys (OI.Object r)
-        runMaybeT $ do
-            propVals <- forM props $ \p -> do
-              v <- MaybeT (jsvalToValue =<< OI.getProp p (OI.Object r))
-              return (JSS.textFromJSString p, v)
-            return (AE.Object (H.fromList propVals))
-
--- | Retrieves keys
-foreign import javascript unsafe "$r = Object.keys($1);"
-  getKeys :: OI.Object -> IO JSVal
-
--- | Adds event listener to window
-foreign import javascript unsafe "window.addEventListener($1, $2);"
-  windowAddEventListener :: JSString -> Callback (JSVal -> IO ()) -> IO ()
-
--- | Removes event listener from window
-foreign import javascript unsafe "window.removeEventListener($1, $2);"
-  windowRemoveEventListener :: JSString -> Callback (JSVal -> IO ()) -> IO ()
-
--- | Retrieves inner height
-foreign import javascript unsafe "$r = window.innerHeight;"
-  windowInnerHeight :: IO Int
-
--- | Retrieves outer height
-foreign import javascript unsafe "$r = window.innerWidth;"
-  windowInnerWidth :: IO Int
-
--- | Retrieve high performance time stamp
-foreign import javascript unsafe "$r = performance.now();"
-  now :: IO Double
-
--- | Console-logging
-foreign import javascript unsafe "console.log($1);"
-  consoleLog :: JSVal -> IO ()
-
--- | Converts a JS object into a JSON string
-foreign import javascript unsafe "$r = JSON.stringify($1);"
-  stringify' :: JSVal -> IO JSString
-
-foreign import javascript unsafe "$r = JSON.parse($1);"
-  parse' :: JSVal -> IO JSVal
-
--- | Converts a JS object into a JSON string
-stringify :: ToJSON json => json -> IO JSString
-{-# INLINE stringify #-}
-stringify j = stringify' =<< toJSVal (toJSON j)
-
--- | Parses a JSString
-parse :: FromJSON json => JSVal -> IO json
-{-# INLINE parse #-}
-parse jval = do
-  k <- parse' jval
-  Just val <- jsvalToValue k
-  case fromJSON val of
-    Success x -> pure x
-    Error y -> error y
-
--- | Indexing into a JS object
-foreign import javascript unsafe "$r = $1[$2];"
-  item :: JSVal -> JSString -> IO JSVal
-
--- | Clear the document body. This is particularly useful to avoid
--- creating multiple copies of your app when running in GHCJSi.
-foreign import javascript unsafe "document.body.innerHTML = '';"
-  clearBody :: IO ()
diff --git a/ghcjs-src/Miso/Html/Internal.hs b/ghcjs-src/Miso/Html/Internal.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Html/Internal.hs
+++ /dev/null
@@ -1,294 +0,0 @@
-{-# LANGUAGE OverloadedStrings          #-}
-{-# LANGUAGE CPP                        #-}
-{-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE TypeOperators              #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE DataKinds                  #-}
-{-# LANGUAGE KindSignatures             #-}
-{-# LANGUAGE LambdaCase                 #-}
-{-# LANGUAGE ConstraintKinds            #-}
-{-# LANGUAGE FlexibleInstances          #-}
-{-# LANGUAGE MultiParamTypeClasses      #-}
-{-# LANGUAGE UndecidableInstances       #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-{-# LANGUAGE OverloadedStrings          #-}
-{-# LANGUAGE DeriveGeneric              #-}
-{-# LANGUAGE DeriveFunctor              #-}
-{-# LANGUAGE RecordWildCards            #-}
-{-# OPTIONS_GHC -fno-warn-orphans       #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Html.Internal
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Html.Internal (
-  -- * Core types and interface
-    VTree  (..)
-  , View   (..)
-  , ToView (..)
-  , Attribute (..)
-  -- * Smart `View` constructors
-  , node
-  , text
-  -- * Key patch internals
-  , Key    (..)
-  , ToKey  (..)
-  -- * Namespace
-  , NS     (..)
-  -- * Setting properties on virtual DOM nodes
-  , prop
-  -- * Setting css
-  , style_
-  -- * Handling events
-  , on
-  , onWithOptions
-  -- * Life cycle events
-  , onCreated
-  , onDestroyed
-  -- * Events
-  , defaultEvents
-  -- * Subscription type
-  , Sub
-  ) where
-
-import           Control.Monad
-import           Data.Aeson.Types           (parseEither)
-import           Data.JSString
-import qualified Data.Map                   as M
-import           Data.Monoid
-import           Data.Proxy
-import           Data.String                (IsString(..))
-import qualified Data.Text                  as T
-import           GHCJS.Foreign.Callback
-import           GHCJS.Marshal
-import           GHCJS.Types
-import           JavaScript.Object
-import           JavaScript.Object.Internal (Object (Object))
-import qualified JavaScript.Array as JSArray
-import           Servant.API
-
-import           Miso.Effect (Sub)
-import           Miso.Event.Decoder
-import           Miso.Event.Types
-import           Miso.String
-import           Miso.Effect (Sink)
-import           Miso.FFI
-
--- | Virtual DOM implemented as a JavaScript `Object`.
---   Used for diffing, patching and event delegation.
---   Not meant to be constructed directly, see `View` instead.
-newtype VTree = VTree { getTree :: Object }
-
--- | Core type for constructing a `VTree`, use this instead of `VTree` directly.
-newtype View action = View {
-  runView :: Sink action -> IO VTree
-} deriving Functor
-
--- | For constructing type-safe links
-instance HasLink (View a) where
-  type MkLink (View a) = MkLink (Get '[] ())
-  toLink _ = toLink (Proxy :: Proxy (Get '[] ()))
-
--- | Convenience class for using View
-class ToView v where toView :: v -> View m
-
-set :: ToJSVal v => JSString -> v -> Object -> IO ()
-set k v obj = toJSVal v >>= \x -> setProp k x obj
-
--- | `ToJSVal` instance for `Decoder`
-instance ToJSVal DecodeTarget where
-  toJSVal (DecodeTarget xs) = toJSVal xs
-  toJSVal (DecodeTargets xs) = toJSVal xs
-
--- | Create a new @VNode@.
---
--- @node ns tag key attrs children@ creates a new node with tag @tag@
--- and 'Key' @key@ in the namespace @ns@. All @attrs@ are called when
--- the node is created and its children are initialized to @children@.
-node :: NS
-     -> MisoString
-     -> Maybe Key
-     -> [Attribute m]
-     -> [View m]
-     -> View m
-node ns tag key attrs kids = View $ \sink -> do
-  vnode <- create
-  cssObj <- jsval <$> create
-  propsObj <- jsval <$> create
-  eventObj <- jsval <$> create
-  set "css" cssObj vnode
-  set "props" propsObj vnode
-  set "events" eventObj vnode
-  set "type" ("vnode" :: JSString) vnode
-  set "ns" ns vnode
-  set "tag" tag vnode
-  set "key" key vnode
-  setAttrs vnode sink
-  flip (set "children") vnode =<< setKids sink
-  pure $ VTree vnode
-    where
-      setAttrs vnode sink =
-        forM_ attrs $ \(Attribute attr) ->
-          attr sink vnode
-
-      setKids sink =
-        jsval . JSArray.fromList <$>
-          fmap (jsval . getTree) <$>
-            traverse (flip runView sink) kids
-
-instance ToJSVal Options
-instance ToJSVal Key where toJSVal (Key x) = toJSVal x
-
-instance ToJSVal NS where
-  toJSVal SVG  = toJSVal ("svg" :: JSString)
-  toJSVal HTML = toJSVal ("html" :: JSString)
-
--- | Namespace of DOM elements.
-data NS
-  = HTML -- ^ HTML Namespace
-  | SVG  -- ^ SVG Namespace
-  deriving (Show, Eq)
-
--- | Create a new @VText@ with the given content.
-text :: MisoString -> View m
-text t = View . const $ do
-  vtree <- create
-  set "type" ("vtext" :: JSString) vtree
-  set "text" t vtree
-  pure $ VTree vtree
-
--- | `IsString` instance
-instance IsString (View a) where
-  fromString = text . fromString
-
--- | A unique key for a dom node.
---
--- This key is only used to speed up diffing the children of a DOM
--- node, the actual content is not important. The keys of the children
--- of a given DOM node must be unique. Failure to satisfy this
--- invariant gives undefined behavior at runtime.
-newtype Key = Key MisoString
-
--- | Convert custom key types to `Key`.
---
--- Instances of this class do not have to guarantee uniqueness of the
--- generated keys, it is up to the user to do so. `toKey` must be an
--- injective function.
-class ToKey key where toKey :: key -> Key
--- | Identity instance
-instance ToKey Key where toKey = id
--- | Convert `MisoString` to `Key`
-instance ToKey MisoString where toKey = Key
--- | Convert `Text` to `Key`
-instance ToKey T.Text where toKey = Key . toMisoString
--- | Convert `String` to `Key`
-instance ToKey String where toKey = Key . toMisoString
--- | Convert `Int` to `Key`
-instance ToKey Int where toKey = Key . toMisoString
--- | Convert `Double` to `Key`
-instance ToKey Double where toKey = Key . toMisoString
--- | Convert `Float` to `Key`
-instance ToKey Float where toKey = Key . toMisoString
--- | Convert `Word` to `Key`
-instance ToKey Word where toKey = Key . toMisoString
-
--- | Attribute of a vnode in a `View`.
---
--- The 'Sink' callback can be used to dispatch actions which are fed back to
--- the @update@ function. This is especially useful for event handlers
--- like the @onclick@ attribute. The second argument represents the
--- vnode the attribute is attached to.
-newtype Attribute action = Attribute (Sink action -> Object -> IO ())
-
--- | @prop k v@ is an attribute that will set the attribute @k@ of the DOM node associated with the vnode
--- to @v@.
-prop :: ToJSVal a => MisoString -> a -> Attribute action
-prop k v = Attribute . const $ \n -> do
-  val <- toJSVal v
-  o <- getProp ("props" :: MisoString) n
-  set k val (Object o)
-
--- | Convenience wrapper for @onWithOptions defaultOptions@.
---
--- > let clickHandler = on "click" emptyDecoder $ \() -> Action
--- > in button_ [ clickHandler, class_ "add" ] [ text_ "+" ]
---
-on :: MisoString
-   -> Decoder r
-   -> (r -> action)
-   -> Attribute action
-on = onWithOptions defaultOptions
-
-foreign import javascript unsafe "$r = objectToJSON($1,$2);"
-  objectToJSON
-    :: JSVal -- ^ decodeAt :: [JSString]
-    -> JSVal -- ^ object with impure references to the DOM
-    -> IO JSVal
-
--- | @onWithOptions opts eventName decoder toAction@ is an attribute
--- that will set the event handler of the associated DOM node to a function that
--- decodes its argument using @decoder@, converts it to an action
--- using @toAction@ and then feeds that action back to the @update@ function.
---
--- @opts@ can be used to disable further event propagation.
---
--- > let clickHandler = onWithOptions defaultOptions "click" emptyDecoder $ \() -> Action
--- > in button_ [ clickHandler, class_ "add" ] [ text_ "+" ]
---
-onWithOptions
-  :: Options
-  -> MisoString
-  -> Decoder r
-  -> (r -> action)
-  -> Attribute action
-onWithOptions options eventName Decoder{..} toAction =
-  Attribute $ \sink n -> do
-   eventObj <- getProp "events" n
-   eventHandlerObject@(Object eo) <- create
-   jsOptions <- toJSVal options
-   decodeAtVal <- toJSVal decodeAt
-   cb <- jsval <$> (asyncCallback1 $ \e -> do
-       Just v <- jsvalToValue =<< objectToJSON decodeAtVal e
-       case parseEither decoder v of
-         Left s -> error $ "Parse error on " <> unpack eventName <> ": " <> s
-         Right r -> sink (toAction r))
-   setProp "runEvent" cb eventHandlerObject
-   setProp "options" jsOptions eventHandlerObject
-   setProp eventName eo (Object eventObj)
-
--- | @onCreated action@ is an event that gets called after the actual DOM
--- element is created.
-onCreated :: action -> Attribute action
-onCreated action =
-  Attribute $ \sink n -> do
-    cb <- jsval <$> asyncCallback (sink action)
-    setProp "onCreated" cb n
-
--- | @onDestroyed action@ is an event that gets called after the DOM element
--- is removed from the DOM. The @action@ is given the DOM element that was
--- removed from the DOM tree.
-onDestroyed :: action -> Attribute action
-onDestroyed action =
-  Attribute $ \sink n -> do
-    cb <- jsval <$> asyncCallback (sink action)
-    setProp "onDestroyed" cb n
-
--- | @style_ attrs@ is an attribute that will set the @style@
--- attribute of the associated DOM node to @attrs@.
---
--- @style@ attributes not contained in @attrs@ will be deleted.
---
--- > import qualified Data.Map as M
--- > div_ [ style_  $ M.singleton "background" "red" ] [ ]
---
--- <https://developer.mozilla.org/en-US/docs/Web/CSS>
---
-style_ :: M.Map MisoString MisoString -> Attribute action
-style_ m = Attribute . const $ \n -> do
-   cssObj <- getProp "css" n
-   forM_ (M.toList m) $ \(k,v) ->
-     setProp k (jsval v) (Object cssObj)
diff --git a/ghcjs-src/Miso/String.hs b/ghcjs-src/Miso/String.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/String.hs
+++ /dev/null
@@ -1,93 +0,0 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE ExistentialQuantification #-}
-{-# LANGUAGE TypeSynonymInstances #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# OPTIONS_GHC -fno-warn-orphans       #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.String
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.String (
-    ToMisoString (..)
-  , MisoString
-  , module Data.JSString
-  , module Data.Monoid
-  , ms
-  ) where
-
-import           Data.Aeson
-import qualified Data.ByteString         as B
-import qualified Data.ByteString.Lazy    as BL
-import           Data.JSString
-import           Data.JSString.Int
-import           Data.JSString.RealFloat
-import           Data.JSString.Text
-import           Data.Monoid
-import qualified Data.Text               as T
-import qualified Data.Text.Encoding      as T
-import qualified Data.Text.Lazy          as LT
-import qualified Data.Text.Lazy.Encoding as LT
-import           GHCJS.Marshal.Pure
-import           GHCJS.Types
-
--- | String type swappable based on compiler
-type MisoString = JSString
-
--- | `ToJSON` for `MisoString`
-instance ToJSON MisoString where
-  toJSON = String . textFromJSString
-
--- | `FromJSON` for `MisoString`
-instance FromJSON MisoString where
-  parseJSON =
-    withText "Not a valid string" $ \x ->
-      pure (toMisoString x)
-
--- | Convenience class for creating `MisoString` from other string-like types
-class ToMisoString str where
-  toMisoString :: str -> MisoString
-  fromMisoString :: MisoString -> str
-
--- | Convenience function, shorthand for `toMisoString`
-ms :: ToMisoString str => str -> MisoString
-ms = toMisoString
-
-instance ToMisoString MisoString where
-  toMisoString = id
-  fromMisoString = id
-instance ToMisoString String where
-  toMisoString = pack
-  fromMisoString = unpack
-instance ToMisoString T.Text where
-  toMisoString = textToJSString
-  fromMisoString = textFromJSString
-instance ToMisoString LT.Text where
-  toMisoString = lazyTextToJSString
-  fromMisoString = lazyTextFromJSString
-instance ToMisoString B.ByteString where
-  toMisoString = toMisoString . T.decodeUtf8
-  fromMisoString = T.encodeUtf8 . fromMisoString
-instance ToMisoString BL.ByteString where
-  toMisoString = toMisoString . LT.decodeUtf8
-  fromMisoString = LT.encodeUtf8 . fromMisoString
-instance ToMisoString Float where
-  toMisoString = realFloat
-  fromMisoString = pFromJSVal . toJSNumber
-instance ToMisoString Double where
-  toMisoString = realFloat
-  fromMisoString = pFromJSVal . toJSNumber
-instance ToMisoString Int where
-  toMisoString = decimal
-  fromMisoString = pFromJSVal . toJSNumber
-instance ToMisoString Word where
-  toMisoString = decimal
-  fromMisoString = pFromJSVal . toJSNumber
-
-foreign import javascript unsafe "$r = Number($1);"
-  toJSNumber :: JSString -> JSVal
diff --git a/ghcjs-src/Miso/Subscription.hs b/ghcjs-src/Miso/Subscription.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Subscription.hs
+++ /dev/null
@@ -1,24 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Subscription
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Subscription
-  ( module Miso.Subscription.Mouse
-  , module Miso.Subscription.Keyboard
-  , module Miso.Subscription.History
-  , module Miso.Subscription.WebSocket
-  , module Miso.Subscription.Window
-  , module Miso.Subscription.SSE
-  ) where
-
-import Miso.Subscription.Mouse
-import Miso.Subscription.Keyboard
-import Miso.Subscription.History
-import Miso.Subscription.WebSocket
-import Miso.Subscription.Window
-import Miso.Subscription.SSE
diff --git a/ghcjs-src/Miso/Subscription/History.hs b/ghcjs-src/Miso/Subscription/History.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Subscription/History.hs
+++ /dev/null
@@ -1,125 +0,0 @@
-{-# LANGUAGE DataKinds         #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards   #-}
-{-# LANGUAGE TypeFamilies      #-}
-{-# LANGUAGE TypeOperators     #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Subscription.History
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Subscription.History
-  ( getCurrentURI
-  , pushURI
-  , replaceURI
-  , back
-  , forward
-  , go
-  , uriSub
-  , URI (..)
-  ) where
-
-import           Control.Concurrent
-import           Control.Monad
-import           GHCJS.Foreign.Callback
-import           Miso.Concurrent
-import           Miso.Html.Internal     (Sub)
-import           Miso.String
-import           Network.URI            hiding (path)
-import           System.IO.Unsafe
-
--- | Retrieves current URI of page
-getCurrentURI :: IO URI
-{-# INLINE getCurrentURI #-}
-getCurrentURI = getURI
-
--- | Retrieves current URI of page
-getURI :: IO URI
-{-# INLINE getURI #-}
-getURI = do
-  href <- fromMisoString <$> getWindowLocationHref
-  case parseURI href of
-    Nothing  -> fail $ "Could not parse URI from window.location: " ++ href
-    Just uri -> return uri
-
--- | Pushes a new URI onto the History stack
-pushURI :: URI -> IO ()
-{-# INLINE pushURI #-}
-pushURI uri = pushStateNoModel uri { uriPath = path }
-  where
-    path | uriPath uri == mempty = "/"
-         | otherwise = uriPath uri
-
--- | Replaces current URI on stack
-replaceURI :: URI -> IO ()
-{-# INLINE replaceURI #-}
-replaceURI uri = replaceTo' uri { uriPath = path }
-  where
-    path | uriPath uri == mempty = "/"
-         | otherwise = uriPath uri
-
--- | Navigates backwards
-back :: IO ()
-{-# INLINE back #-}
-back = back'
-
--- | Navigates forwards
-forward :: IO ()
-{-# INLINE forward #-}
-forward = forward'
-
--- | Jumps to a specific position in history
-go :: Int -> IO ()
-{-# INLINE go #-}
-go n = go' n
-
-chan :: Notify
-{-# NOINLINE chan #-}
-chan = unsafePerformIO newNotify
-
--- | Subscription for `popState` events, from the History API
-uriSub :: (URI -> action) -> Sub action
-uriSub = \f sink -> do
-  void.forkIO.forever $ do
-    wait chan >> do
-      sink =<< f <$> getURI
-  onPopState =<< do
-     asyncCallback $ do
-      sink =<< f <$> getURI
-
-foreign import javascript safe "$r = window.location.href || '';"
-  getWindowLocationHref :: IO MisoString
-
-foreign import javascript unsafe "window.history.go($1);"
-  go' :: Int -> IO ()
-
-foreign import javascript unsafe "window.history.back();"
-  back' :: IO ()
-
-foreign import javascript unsafe "window.history.forward();"
-  forward' :: IO ()
-
-foreign import javascript unsafe "window.addEventListener('popstate', $1);"
-  onPopState :: Callback (IO ()) -> IO ()
-
-foreign import javascript unsafe "window.history.pushState(null, null, $1);"
-  pushStateNoModel' :: JSString -> IO ()
-
-foreign import javascript unsafe "window.history.replaceState(null, null, $1);"
-  replaceState' :: JSString -> IO ()
-
-pushStateNoModel :: URI -> IO ()
-{-# INLINE pushStateNoModel #-}
-pushStateNoModel u = do
-  pushStateNoModel' . pack . show $ u
-  notify chan
-
-replaceTo' :: URI -> IO ()
-{-# INLINE replaceTo' #-}
-replaceTo' u = do
-  replaceState' . pack . show $ u
-  notify chan
diff --git a/ghcjs-src/Miso/Subscription/Keyboard.hs b/ghcjs-src/Miso/Subscription/Keyboard.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Subscription/Keyboard.hs
+++ /dev/null
@@ -1,99 +0,0 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE RecordWildCards     #-}
-{-# LANGUAGE OverloadedStrings   #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Subscription.Keyboard
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Subscription.Keyboard
-  ( -- * Types
-    Arrows (..)
-    -- * Subscriptions
-  , arrowsSub
-  , directionSub
-  , keyboardSub
-  , wasdSub
-  ) where
-
-import           Data.IORef
-import           Data.Set
-import qualified Data.Set as S
-import           GHCJS.Foreign.Callback
-import           GHCJS.Marshal
-import           JavaScript.Object
-import           JavaScript.Object.Internal
-
-import           Miso.FFI
-import           Miso.Html.Internal ( Sub )
-
--- | type for arrow keys currently pressed
---  37 left arrow  ( x = -1 )
---  38 up arrow    ( y =  1 )
---  39 right arrow ( x =  1 )
---  40 down arrow  ( y = -1 )
-data Arrows = Arrows {
-   arrowX :: !Int
- , arrowY :: !Int
- } deriving (Show, Eq)
-
--- | Helper function to convert keys currently pressed to `Arrow`, given a
--- mapping for keys representing up, down, left and right respectively.
-toArrows :: ([Int], [Int], [Int], [Int]) -> Set Int -> Arrows
-toArrows (up, down, left, right) set =
-  Arrows {
-    arrowX =
-      case (check left, check right) of
-        (True, False) -> -1
-        (False, True) -> 1
-        (_,_) -> 0
-  , arrowY =
-      case (check down, check up) of
-        (True, False) -> -1
-        (False, True) -> 1
-        (_,_) -> 0
-  }
-  where
-    check = any (`S.member` set)
-
--- | Maps `Arrows` onto a Keyboard subscription
-arrowsSub :: (Arrows -> action) -> Sub action
-arrowsSub = directionSub ([38], [40], [37], [39])
-
--- | Maps `WASD` onto a Keyboard subscription for directions
-wasdSub :: (Arrows -> action) -> Sub action
-wasdSub = directionSub ([87], [83], [65], [68])
-
--- | Maps a specified list of keys to directions (up, down, left, right)
-directionSub :: ([Int], [Int], [Int], [Int])
-             -> (Arrows -> action)
-             -> Sub action
-directionSub dirs = keyboardSub . (. toArrows dirs)
-
--- | Returns subscription for Keyboard
-keyboardSub :: (Set Int -> action) -> Sub action
-keyboardSub f sink = do
-  keySetRef <- newIORef mempty
-  windowAddEventListener "keyup" =<< keyUpCallback keySetRef
-  windowAddEventListener "keydown" =<< keyDownCallback keySetRef
-    where
-      keyDownCallback keySetRef = do
-        asyncCallback1 $ \keyDownEvent -> do
-          Just key <- fromJSVal =<< getProp "keyCode" (Object keyDownEvent)
-          newKeys <- atomicModifyIORef' keySetRef $ \keys ->
-             let !new = S.insert key keys
-             in (new, new)
-          sink (f newKeys)
-
-      keyUpCallback keySetRef = do
-        asyncCallback1 $ \keyUpEvent -> do
-          Just key <- fromJSVal =<< getProp "keyCode" (Object keyUpEvent)
-          newKeys <- atomicModifyIORef' keySetRef $ \keys ->
-             let !new = S.delete key keys
-             in (new, new)
-          sink (f newKeys)
diff --git a/ghcjs-src/Miso/Subscription/Mouse.hs b/ghcjs-src/Miso/Subscription/Mouse.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Subscription/Mouse.hs
+++ /dev/null
@@ -1,30 +0,0 @@
-{-# LANGUAGE RecordWildCards   #-}
-{-# LANGUAGE OverloadedStrings #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Subscription.Mouse
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Subscription.Mouse (mouseSub) where
-
-import GHCJS.Foreign.Callback
-import GHCJS.Marshal
-import JavaScript.Object
-import JavaScript.Object.Internal
-
-import Miso.FFI
-import Miso.Html.Internal ( Sub )
-
--- | Captures mouse coordinates as they occur and writes them to
--- an event sink
-mouseSub :: ((Int,Int) -> action) -> Sub action
-mouseSub f = \sink -> do
-  windowAddEventListener "mousemove" =<< do
-    asyncCallback1 $ \mouseEvent -> do
-      Just x <- fromJSVal =<< getProp "clientX" (Object mouseEvent)
-      Just y <- fromJSVal =<< getProp "clientY" (Object mouseEvent)
-      sink $ f (x,y)
diff --git a/ghcjs-src/Miso/Subscription/SSE.hs b/ghcjs-src/Miso/Subscription/SSE.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Subscription/SSE.hs
+++ /dev/null
@@ -1,68 +0,0 @@
-{-# LANGUAGE RecordWildCards   #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE LambdaCase #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Subscription.SSE
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Subscription.SSE
- ( -- * Subscription
-   sseSub
-   -- * Types
- , SSE (..)
- ) where
-
-import Data.Aeson
-import GHCJS.Foreign.Callback
-import GHCJS.Types
-import Miso.FFI
-import Miso.Html.Internal     ( Sub )
-import Miso.String
-
--- | Server-sent events Subscription
-sseSub :: FromJSON msg => MisoString -> (SSE msg -> action) -> Sub action
-sseSub url f = \sink -> do
-  es <- newEventSource url
-  onMessage es =<< do
-    asyncCallback1 $ \val -> do
-      getData val >>= parse >>= \x -> do
-        sink $ f (SSEMessage x)
-  onError es =<< do
-    asyncCallback $
-      sink (f SSEError)
-  onClose es =<< do
-    asyncCallback $
-      sink (f SSEClose)
-
--- | Server-sent events data
-data SSE message
-  = SSEMessage message
-  | SSEClose
-  | SSEError
-  deriving (Show, Eq)
-
-foreign import javascript unsafe "$r = $1.data;"
-  getData :: JSVal -> IO JSVal
-
-newtype EventSource = EventSource JSVal
-
-foreign import javascript unsafe "$r = new EventSource($1);"
-  newEventSource :: JSString -> IO EventSource
-
-foreign import javascript unsafe "$1.onmessage = $2;"
-  onMessage :: EventSource -> Callback (JSVal -> IO ()) -> IO ()
-
-foreign import javascript unsafe "$1.onerror = $2;"
-  onError :: EventSource -> Callback (IO ()) -> IO ()
-
-foreign import javascript unsafe "$1.onclose = $2;"
-  onClose :: EventSource -> Callback (IO ()) -> IO ()
-
--- | Test URL
--- http://sapid.sourceforge.net/ssetest/webkit.events.php
--- var source = new EventSource("demo_sse.php");
diff --git a/ghcjs-src/Miso/Subscription/WebSocket.hs b/ghcjs-src/Miso/Subscription/WebSocket.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Subscription/WebSocket.hs
+++ /dev/null
@@ -1,252 +0,0 @@
-{-# LANGUAGE DeriveGeneric              #-}
-{-# LANGUAGE TemplateHaskell            #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-{-# LANGUAGE OverloadedStrings          #-}
-{-# LANGUAGE RankNTypes                 #-}
-{-# LANGUAGE LambdaCase                 #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Subscription.WebSocket
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Subscription.WebSocket
-  ( -- * Types
-    WebSocket   (..)
-  , URL         (..)
-  , Protocols   (..)
-  , SocketState (..)
-  , CloseCode   (..)
-  , WasClean    (..)
-  , Reason      (..)
-    -- * Subscription
-  , websocketSub
-  , send
-  , connect
-  , getSocketState
-  ) where
-
-import Control.Concurrent
-import Control.Monad
-import Data.Aeson
-import Data.IORef
-import Data.Maybe
-import GHC.Generics
-import GHCJS.Foreign.Callback
-import GHCJS.Marshal
-import GHCJS.Types
-import Prelude                hiding (map)
-import System.IO.Unsafe
-
-import Miso.FFI
-import Miso.Html.Internal     ( Sub )
-import Miso.String
-
--- | WebSocket connection messages
-data WebSocket action
-  = WebSocketMessage action
-  | WebSocketClose CloseCode WasClean Reason
-  | WebSocketOpen
-  | WebSocketError MisoString
-
-websocket :: IORef (Maybe Socket)
-{-# NOINLINE websocket #-}
-websocket = unsafePerformIO (newIORef Nothing)
-
-closedCode :: IORef (Maybe CloseCode)
-{-# NOINLINE closedCode #-}
-closedCode = unsafePerformIO (newIORef Nothing)
-
-secs :: Int -> Int
-secs = (*1000000)
-
--- | WebSocket subscription
-websocketSub
-  :: FromJSON m
-  => URL
-  -> Protocols
-  -> (WebSocket m -> action)
-  -> Sub action
-websocketSub (URL u) (Protocols ps) f sink = do
-  socket <- createWebSocket u ps
-  writeIORef websocket (Just socket)
-  void . forkIO $ handleReconnect
-  onOpen socket =<< do
-    writeIORef closedCode Nothing
-    asyncCallback $ sink (f WebSocketOpen)
-  onMessage socket =<< do
-    asyncCallback1 $ \v -> do
-      d <- parse =<< getData v
-      sink $ f (WebSocketMessage d)
-  onClose socket =<< do
-    asyncCallback1 $ \e -> do
-      code <- codeToCloseCode <$> getCode e
-      writeIORef closedCode (Just code)
-      reason <- getReason e
-      clean <- wasClean e
-      sink $ f (WebSocketClose code clean reason)
-  onError socket =<< do
-    asyncCallback1 $ \v -> do
-      writeIORef closedCode Nothing
-      d <- parse =<< getData v
-      sink $ f (WebSocketError d)
-  where
-    handleReconnect = do
-      threadDelay (secs 3)
-      Just s <- readIORef websocket
-      status <- getSocketState' s
-      code <- readIORef closedCode
-      if status == 3
-        then do
-          unless (code == Just CLOSE_NORMAL) $
-            websocketSub (URL u) (Protocols ps) f sink
-        else handleReconnect
-
--- | Sends message to a websocket server
-send :: ToJSON a => a -> IO ()
-{-# INLINE send #-}
-send x = do
-  Just socket <- readIORef websocket
-  sendJson' socket x
-
--- | Connects to a websocket server
-connect :: URL -> Protocols -> IO ()
-{-# INLINE connect #-}
-connect (URL url') (Protocols ps) = do
-  Just ws <- readIORef websocket
-  s <- getSocketState' ws
-  when (s == 3) $ do
-    socket <- createWebSocket url' ps
-    atomicWriteIORef websocket (Just socket)
-
--- | URL of Websocket server
-newtype URL = URL MisoString
-  deriving (Show, Eq)
-
--- | Protocols for Websocket connection
-newtype Protocols = Protocols [MisoString]
-  deriving (Show, Eq)
-
--- | Wether or not the connection closed was done so cleanly
-newtype WasClean = WasClean Bool deriving (Show, Eq)
-
--- | Reason for closed connection
-newtype Reason = Reason MisoString deriving (Show, Eq)
-
-foreign import javascript unsafe "$r = new WebSocket($1, $2);"
-  createWebSocket' :: JSString -> JSVal -> IO Socket
-
-foreign import javascript unsafe "$r = $1.readyState;"
-  getSocketState' :: Socket -> IO Int
-
--- | `SocketState` corresponding to current WebSocket connection
-data SocketState
-  = CONNECTING -- ^ 0
-  | OPEN       -- ^ 1
-  | CLOSING    -- ^ 2
-  | CLOSED     -- ^ 3
-  deriving (Show, Eq, Ord, Enum)
-
--- | Retrieves current status of `WebSocket`
-getSocketState :: IO SocketState
-getSocketState = do
-  Just ws <- readIORef websocket
-  toEnum <$> getSocketState' ws
-
-foreign import javascript unsafe "$1.send($2);"
-  send' :: Socket -> JSString -> IO ()
-
-sendJson' :: ToJSON json => Socket -> json -> IO ()
-sendJson' socket m = send' socket =<< stringify m
-
-createWebSocket :: JSString -> [JSString] -> IO Socket
-{-# INLINE createWebSocket #-}
-createWebSocket url' protocols =
-  createWebSocket' url' =<< toJSVal protocols
-
-foreign import javascript unsafe "$1.onopen = $2"
-  onOpen :: Socket -> Callback (IO ()) -> IO ()
-
-foreign import javascript unsafe "$1.onclose = $2"
-  onClose :: Socket -> Callback (JSVal -> IO ()) -> IO ()
-
-foreign import javascript unsafe "$1.onmessage = $2"
-  onMessage :: Socket -> Callback (JSVal -> IO ()) -> IO ()
-
-foreign import javascript unsafe "$1.onerror = $2"
-  onError :: Socket -> Callback (JSVal -> IO ()) -> IO ()
-
-foreign import javascript unsafe "$r = $1.data"
-  getData :: JSVal -> IO JSVal
-
-foreign import javascript unsafe "$r = $1.wasClean"
-  wasClean :: JSVal -> IO WasClean
-
-foreign import javascript unsafe "$r = $1.code"
-  getCode :: JSVal -> IO Int
-
-foreign import javascript unsafe "$r = $1.reason"
-  getReason :: JSVal -> IO Reason
-
-newtype Socket = Socket JSVal
-
--- | Code corresponding to a closed connection
--- https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
-data CloseCode
-  = CLOSE_NORMAL
-   -- ^ 1000, Normal closure; the connection successfully completed whatever purpose for which it was created.
-  | CLOSE_GOING_AWAY
-   -- ^ 1001, The endpoint is going away, either because of a server failure or because the browser is navigating away from the page that opened the connection.
-  | CLOSE_PROTOCOL_ERROR
-   -- ^ 1002, The endpoint is terminating the connection due to a protocol error.
-  | CLOSE_UNSUPPORTED
-   -- ^ 1003, The connection is being terminated because the endpoint received data of a type it cannot accept (for example, a textonly endpoint received binary data).
-  | CLOSE_NO_STATUS
-   -- ^ 1005, Reserved.  Indicates that no status code was provided even though one was expected.
-  | CLOSE_ABNORMAL
-   -- ^ 1006, Reserved. Used to indicate that a connection was closed abnormally (that is, with no close frame being sent) when a status code is expected.
-  | Unsupported_Data
-   -- ^ 1007, The endpoint is terminating the connection because a message was received that contained inconsistent data (e.g., nonUTF8 data within a text message).
-  | Policy_Violation
-   -- ^ 1008, The endpoint is terminating the connection because it received a message that violates its policy. This is a generic status code, used when codes 1003 and 1009 are not suitable.
-  | CLOSE_TOO_LARGE
-   -- ^ 1009, The endpoint is terminating the connection because a data frame was received that is too large.
-  | Missing_Extension
-   -- ^ 1010, The client is terminating the connection because it expected the server to negotiate one or more extension, but the server didn't.
-  | Internal_Error
-   -- ^ 1011, The server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.
-  | Service_Restart
-   -- ^ 1012, The server is terminating the connection because it is restarting.
-  | Try_Again_Later
-   -- ^ 1013, The server is terminating the connection due to a temporary condition, e.g. it is overloaded and is casting off some of its clients.
-  | TLS_Handshake
-   -- ^ 1015, Reserved. Indicates that the connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).
-  | OtherCode Int
-   -- ^ OtherCode that is reserved and not in the range 0999
-  deriving (Show, Eq, Generic)
-
-instance ToJSVal CloseCode
-instance FromJSVal CloseCode
-
-codeToCloseCode :: Int -> CloseCode
-codeToCloseCode = go
-  where
-    go 1000 = CLOSE_NORMAL
-    go 1001 = CLOSE_GOING_AWAY
-    go 1002 = CLOSE_PROTOCOL_ERROR
-    go 1003 = CLOSE_UNSUPPORTED
-    go 1005 = CLOSE_NO_STATUS
-    go 1006 = CLOSE_ABNORMAL
-    go 1007 = Unsupported_Data
-    go 1008 = Policy_Violation
-    go 1009 = CLOSE_TOO_LARGE
-    go 1010 = Missing_Extension
-    go 1011 = Internal_Error
-    go 1012 = Service_Restart
-    go 1013 = Try_Again_Later
-    go 1015 = TLS_Handshake
-    go n    = OtherCode n
diff --git a/ghcjs-src/Miso/Subscription/Window.hs b/ghcjs-src/Miso/Subscription/Window.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Subscription/Window.hs
+++ /dev/null
@@ -1,32 +0,0 @@
-{-# LANGUAGE RecordWildCards   #-}
-{-# LANGUAGE OverloadedStrings #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Subscription.Window
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Subscription.Window where
-
-import GHCJS.Foreign.Callback
-import GHCJS.Marshal
-
-import JavaScript.Object
-import JavaScript.Object.Internal
-import Miso.FFI
-import Miso.Html.Internal ( Sub )
-
--- | Captures window coordinates changes as they occur and writes them to
--- an event sink
-windowSub :: ((Int, Int) -> action) -> Sub action
-windowSub f = \sink -> do
-  sink . f =<< (,) <$> windowInnerHeight <*> windowInnerWidth
-  windowAddEventListener "resize" =<< do
-    asyncCallback1 $ \windowEvent -> do
-      target <- getProp "target" (Object windowEvent)
-      Just w <- fromJSVal =<< getProp "innerWidth" (Object target)
-      Just h <- fromJSVal =<< getProp "innerHeight" (Object target)
-      sink $ f (h, w)
diff --git a/ghcjs-src/Miso/Types.hs b/ghcjs-src/Miso/Types.hs
deleted file mode 100644
--- a/ghcjs-src/Miso/Types.hs
+++ /dev/null
@@ -1,109 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Types
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Types
-  ( App (..)
-
-    -- * The Transition Monad
-  , Transition
-  , fromTransition
-  , toTransition
-  , scheduleIO
-  , scheduleSub
-  ) where
-
-import           Control.Monad.Trans.Class (lift)
-import           Control.Monad.Trans.State.Strict (StateT(StateT), execStateT)
-import           Control.Monad.Trans.Writer.Strict (WriterT(WriterT), Writer, runWriter, tell)
-import qualified Data.Map           as M
-import           Miso.Effect
-import           Miso.Html.Internal
-import           Miso.String
-
--- | Application entry point
-data App model action = App
-  { model :: model
-  -- ^ initial model
-  , update :: action -> model -> Effect action model
-  -- ^ Function to update model, optionally provide effects.
-  --   See the 'Transition' monad for succinctly expressing model transitions.
-  , view :: model -> View action
-  -- ^ Function to draw `View`
-  , subs :: [ Sub action ]
-  -- ^ List of subscriptions to run during application lifetime
-  , events :: M.Map MisoString Bool
-  -- ^ List of delegated events that the body element will listen for
-  , initialAction :: action
-  -- ^ Initial action that is run after the application has loaded
-  , mountPoint :: Maybe MisoString
-  -- ^ root element for DOM diff
-  }
-
--- | A monad for succinctly expressing model transitions in the 'update' function.
---
--- @Transition@ is a state monad so it abstracts over manually passing the model
--- around. It's also a writer monad where the accumulator is a list of scheduled
--- IO actions. Multiple actions can be scheduled using
--- @Control.Monad.Writer.Class.tell@ from the @mtl@ library and a single action
--- can be scheduled using 'scheduleIO'.
---
--- Tip: use the @Transition@ monad in combination with the stateful
--- <http://hackage.haskell.org/package/lens-4.15.4/docs/Control-Lens-Operators.html lens>
--- operators (all operators ending in "@=@"). The following example assumes
--- the lenses @field1@, @counter@ and @field2@ are in scope and that the
--- @LambdaCase@ language extension is enabled:
---
--- @
--- myApp = App
---   { update = 'fromTransition' . \\case
---       MyAction1 -> do
---         field1 .= value1
---         counter += 1
---       MyAction2 -> do
---         field2 %= f
---         scheduleIO $ do
---           putStrLn \"Hello\"
---           putStrLn \"World!\"
---   , ...
---   }
--- @
-type Transition action model = StateT model (Writer [Sub action])
-
--- | Convert a @Transition@ computation to a function that can be given to 'update'.
-fromTransition
-    :: Transition action model ()
-    -> (model -> Effect action model) -- ^ model 'update' function.
-fromTransition act = uncurry Effect . runWriter . execStateT act
-
--- | Convert an 'update' function to a @Transition@ computation.
-toTransition
-    :: (model -> Effect action model) -- ^ model 'update' function
-    -> Transition action model ()
-toTransition f = StateT $ \s ->
-                   let Effect s' ios = f s
-                   in WriterT $ pure (((), s'), ios)
-
--- | Schedule a single IO action for later execution.
---
--- Note that multiple IO action can be scheduled using
--- @Control.Monad.Writer.Class.tell@ from the @mtl@ library.
-scheduleIO :: IO action -> Transition action model ()
-scheduleIO ioAction = scheduleSub $ \sink -> ioAction >>= sink
-
--- | Like 'scheduleIO' but schedules a subscription which is an IO
--- computation that has access to a 'Sink' which can be used to
--- asynchronously dispatch actions to the 'update' function.
---
--- A use-case is scheduling an IO computation which creates a
--- 3rd-party JS widget which has an associated callback. The callback
--- can then call the sink to turn events into actions. To do this
--- without accessing a sink requires going via a @'Sub'scription@
--- which introduces a leaky-abstraction.
-scheduleSub :: Sub action -> Transition action model ()
-scheduleSub sub = lift $ tell [ sub ]
diff --git a/js/miso-native.js b/js/miso-native.js
new file mode 100644
--- /dev/null
+++ b/js/miso-native.js
@@ -0,0 +1,3 @@
+var __create=Object.create;var __getProtoOf=Object.getPrototypeOf;var __defProp=Object.defineProperty;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;function __accessProp(key){return this[key]}var __toESMCache_node;var __toESMCache_esm;var __toESM=(mod,isNodeMode,target)=>{var canCache=mod!=null&&typeof mod==="object";if(canCache){var cache=isNodeMode?__toESMCache_node??=new WeakMap:__toESMCache_esm??=new WeakMap;var cached=cache.get(mod);if(cached)return cached}target=mod!=null?__create(__getProtoOf(mod)):{};const to=isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:true}):target;for(let key of __getOwnPropNames(mod))if(!__hasOwnProp.call(to,key))__defProp(to,key,{get:__accessProp.bind(mod,key),enumerable:true});if(canCache)cache.set(mod,to);return to};var __commonJS=(cb,mod)=>()=>(mod||cb((mod={exports:{}}).exports,mod),mod.exports);var require_encoding_indexes=__commonJS((exports,module)=>{(function(global){if(typeof module!=="undefined"&&module.exports){module.exports=global}global["encoding-indexes"]={big5:[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,17392,19506,17923,17830,17784,160359,19831,17843,162993,19682,163013,15253,18230,18244,19527,19520,148159,144919,160594,159371,159954,19543,172881,18255,17882,19589,162924,19719,19108,18081,158499,29221,154196,137827,146950,147297,26189,22267,null,32149,22813,166841,15860,38708,162799,23515,138590,23204,13861,171696,23249,23479,23804,26478,34195,170309,29793,29853,14453,138579,145054,155681,16108,153822,15093,31484,40855,147809,166157,143850,133770,143966,17162,33924,40854,37935,18736,34323,22678,38730,37400,31184,31282,26208,27177,34973,29772,31685,26498,31276,21071,36934,13542,29636,155065,29894,40903,22451,18735,21580,16689,145038,22552,31346,162661,35727,18094,159368,16769,155033,31662,140476,40904,140481,140489,140492,40905,34052,144827,16564,40906,17633,175615,25281,28782,40907,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,12736,12737,12738,12739,12740,131340,12741,131281,131277,12742,12743,131275,139240,12744,131274,12745,12746,12747,12748,131342,12749,12750,256,193,461,192,274,201,282,200,332,211,465,210,null,7870,null,7872,202,257,225,462,224,593,275,233,283,232,299,237,464,236,333,243,466,242,363,250,468,249,470,472,474,476,252,null,7871,null,7873,234,609,9178,9179,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,172969,135493,null,25866,null,null,20029,28381,40270,37343,null,null,161589,25745,20250,20264,20392,20822,20852,20892,20964,21153,21160,21307,21326,21457,21464,22242,22768,22788,22791,22834,22836,23398,23454,23455,23706,24198,24635,25993,26622,26628,26725,27982,28860,30005,32420,32428,32442,32455,32463,32479,32518,32567,33402,33487,33647,35270,35774,35810,36710,36711,36718,29713,31996,32205,26950,31433,21031,null,null,null,null,37260,30904,37214,32956,null,36107,33014,133607,null,null,32927,40647,19661,40393,40460,19518,171510,159758,40458,172339,13761,null,28314,33342,29977,null,18705,39532,39567,40857,31111,164972,138698,132560,142054,20004,20097,20096,20103,20159,20203,20279,13388,20413,15944,20483,20616,13437,13459,13477,20870,22789,20955,20988,20997,20105,21113,21136,21287,13767,21417,13649,21424,13651,21442,21539,13677,13682,13953,21651,21667,21684,21689,21712,21743,21784,21795,21800,13720,21823,13733,13759,21975,13765,163204,21797,null,134210,134421,151851,21904,142534,14828,131905,36422,150968,169189,16467,164030,30586,142392,14900,18389,164189,158194,151018,25821,134524,135092,134357,135412,25741,36478,134806,134155,135012,142505,164438,148691,null,134470,170573,164073,18420,151207,142530,39602,14951,169460,16365,13574,152263,169940,161992,142660,40302,38933,null,17369,155813,25780,21731,142668,142282,135287,14843,135279,157402,157462,162208,25834,151634,134211,36456,139681,166732,132913,null,18443,131497,16378,22643,142733,null,148936,132348,155799,134988,134550,21881,16571,17338,null,19124,141926,135325,33194,39157,134556,25465,14846,141173,36288,22177,25724,15939,null,173569,134665,142031,142537,null,135368,145858,14738,14854,164507,13688,155209,139463,22098,134961,142514,169760,13500,27709,151099,null,null,161140,142987,139784,173659,167117,134778,134196,157724,32659,135375,141315,141625,13819,152035,134796,135053,134826,16275,134960,134471,135503,134732,null,134827,134057,134472,135360,135485,16377,140950,25650,135085,144372,161337,142286,134526,134527,142417,142421,14872,134808,135367,134958,173618,158544,167122,167321,167114,38314,21708,33476,21945,null,171715,39974,39606,161630,142830,28992,33133,33004,23580,157042,33076,14231,21343,164029,37302,134906,134671,134775,134907,13789,151019,13833,134358,22191,141237,135369,134672,134776,135288,135496,164359,136277,134777,151120,142756,23124,135197,135198,135413,135414,22428,134673,161428,164557,135093,134779,151934,14083,135094,135552,152280,172733,149978,137274,147831,164476,22681,21096,13850,153405,31666,23400,18432,19244,40743,18919,39967,39821,154484,143677,22011,13810,22153,20008,22786,138177,194680,38737,131206,20059,20155,13630,23587,24401,24516,14586,25164,25909,27514,27701,27706,28780,29227,20012,29357,149737,32594,31035,31993,32595,156266,13505,null,156491,32770,32896,157202,158033,21341,34916,35265,161970,35744,36125,38021,38264,38271,38376,167439,38886,39029,39118,39134,39267,170000,40060,40479,40644,27503,63751,20023,131207,38429,25143,38050,null,20539,28158,171123,40870,15817,34959,147790,28791,23797,19232,152013,13657,154928,24866,166450,36775,37366,29073,26393,29626,144001,172295,15499,137600,19216,30948,29698,20910,165647,16393,27235,172730,16931,34319,133743,31274,170311,166634,38741,28749,21284,139390,37876,30425,166371,40871,30685,20131,20464,20668,20015,20247,40872,21556,32139,22674,22736,138678,24210,24217,24514,141074,25995,144377,26905,27203,146531,27903,null,29184,148741,29580,16091,150035,23317,29881,35715,154788,153237,31379,31724,31939,32364,33528,34199,40873,34960,40874,36537,40875,36815,34143,39392,37409,40876,167353,136255,16497,17058,23066,null,null,null,39016,26475,17014,22333,null,34262,149883,33471,160013,19585,159092,23931,158485,159678,40877,40878,23446,40879,26343,32347,28247,31178,15752,17603,143958,141206,17306,17718,null,23765,146202,35577,23672,15634,144721,23928,40882,29015,17752,147692,138787,19575,14712,13386,131492,158785,35532,20404,131641,22975,33132,38998,170234,24379,134047,null,139713,166253,16642,18107,168057,16135,40883,172469,16632,14294,18167,158790,16764,165554,160767,17773,14548,152730,17761,17691,19849,19579,19830,17898,16328,150287,13921,17630,17597,16877,23870,23880,23894,15868,14351,23972,23993,14368,14392,24130,24253,24357,24451,14600,14612,14655,14669,24791,24893,23781,14729,25015,25017,25039,14776,25132,25232,25317,25368,14840,22193,14851,25570,25595,25607,25690,14923,25792,23829,22049,40863,14999,25990,15037,26111,26195,15090,26258,15138,26390,15170,26532,26624,15192,26698,26756,15218,15217,15227,26889,26947,29276,26980,27039,27013,15292,27094,15325,27237,27252,27249,27266,15340,27289,15346,27307,27317,27348,27382,27521,27585,27626,27765,27818,15563,27906,27910,27942,28033,15599,28068,28081,28181,28184,28201,28294,166336,28347,28386,28378,40831,28392,28393,28452,28468,15686,147265,28545,28606,15722,15733,29111,23705,15754,28716,15761,28752,28756,28783,28799,28809,131877,17345,13809,134872,147159,22462,159443,28990,153568,13902,27042,166889,23412,31305,153825,169177,31333,31357,154028,31419,31408,31426,31427,29137,156813,16842,31450,31453,31466,16879,21682,154625,31499,31573,31529,152334,154878,31650,31599,33692,154548,158847,31696,33825,31634,31672,154912,15789,154725,33938,31738,31750,31797,154817,31812,31875,149634,31910,26237,148856,31945,31943,31974,31860,31987,31989,31950,32359,17693,159300,32093,159446,29837,32137,32171,28981,32179,32210,147543,155689,32228,15635,32245,137209,32229,164717,32285,155937,155994,32366,32402,17195,37996,32295,32576,32577,32583,31030,156368,39393,32663,156497,32675,136801,131176,17756,145254,17667,164666,32762,156809,32773,32776,32797,32808,32815,172167,158915,32827,32828,32865,141076,18825,157222,146915,157416,26405,32935,166472,33031,33050,22704,141046,27775,156824,151480,25831,136330,33304,137310,27219,150117,150165,17530,33321,133901,158290,146814,20473,136445,34018,33634,158474,149927,144688,137075,146936,33450,26907,194964,16859,34123,33488,33562,134678,137140,14017,143741,144730,33403,33506,33560,147083,159139,158469,158615,144846,15807,33565,21996,33669,17675,159141,33708,33729,33747,13438,159444,27223,34138,13462,159298,143087,33880,154596,33905,15827,17636,27303,33866,146613,31064,33960,158614,159351,159299,34014,33807,33681,17568,33939,34020,154769,16960,154816,17731,34100,23282,159385,17703,34163,17686,26559,34326,165413,165435,34241,159880,34306,136578,159949,194994,17770,34344,13896,137378,21495,160666,34430,34673,172280,34798,142375,34737,34778,34831,22113,34412,26710,17935,34885,34886,161248,146873,161252,34910,34972,18011,34996,34997,25537,35013,30583,161551,35207,35210,35238,35241,35239,35260,166437,35303,162084,162493,35484,30611,37374,35472,162393,31465,162618,147343,18195,162616,29052,35596,35615,152624,152933,35647,35660,35661,35497,150138,35728,35739,35503,136927,17941,34895,35995,163156,163215,195028,14117,163155,36054,163224,163261,36114,36099,137488,36059,28764,36113,150729,16080,36215,36265,163842,135188,149898,15228,164284,160012,31463,36525,36534,36547,37588,36633,36653,164709,164882,36773,37635,172703,133712,36787,18730,166366,165181,146875,24312,143970,36857,172052,165564,165121,140069,14720,159447,36919,165180,162494,36961,165228,165387,37032,165651,37060,165606,37038,37117,37223,15088,37289,37316,31916,166195,138889,37390,27807,37441,37474,153017,37561,166598,146587,166668,153051,134449,37676,37739,166625,166891,28815,23235,166626,166629,18789,37444,166892,166969,166911,37747,37979,36540,38277,38310,37926,38304,28662,17081,140922,165592,135804,146990,18911,27676,38523,38550,16748,38563,159445,25050,38582,30965,166624,38589,21452,18849,158904,131700,156688,168111,168165,150225,137493,144138,38705,34370,38710,18959,17725,17797,150249,28789,23361,38683,38748,168405,38743,23370,168427,38751,37925,20688,143543,143548,38793,38815,38833,38846,38848,38866,38880,152684,38894,29724,169011,38911,38901,168989,162170,19153,38964,38963,38987,39014,15118,160117,15697,132656,147804,153350,39114,39095,39112,39111,19199,159015,136915,21936,39137,39142,39148,37752,39225,150057,19314,170071,170245,39413,39436,39483,39440,39512,153381,14020,168113,170965,39648,39650,170757,39668,19470,39700,39725,165376,20532,39732,158120,14531,143485,39760,39744,171326,23109,137315,39822,148043,39938,39935,39948,171624,40404,171959,172434,172459,172257,172323,172511,40318,40323,172340,40462,26760,40388,139611,172435,172576,137531,172595,40249,172217,172724,40592,40597,40606,40610,19764,40618,40623,148324,40641,15200,14821,15645,20274,14270,166955,40706,40712,19350,37924,159138,40727,40726,40761,22175,22154,40773,39352,168075,38898,33919,40802,40809,31452,40846,29206,19390,149877,149947,29047,150008,148296,150097,29598,166874,137466,31135,166270,167478,37737,37875,166468,37612,37761,37835,166252,148665,29207,16107,30578,31299,28880,148595,148472,29054,137199,28835,137406,144793,16071,137349,152623,137208,14114,136955,137273,14049,137076,137425,155467,14115,136896,22363,150053,136190,135848,136134,136374,34051,145062,34051,33877,149908,160101,146993,152924,147195,159826,17652,145134,170397,159526,26617,14131,15381,15847,22636,137506,26640,16471,145215,147681,147595,147727,158753,21707,22174,157361,22162,135135,134056,134669,37830,166675,37788,20216,20779,14361,148534,20156,132197,131967,20299,20362,153169,23144,131499,132043,14745,131850,132116,13365,20265,131776,167603,131701,35546,131596,20120,20685,20749,20386,20227,150030,147082,20290,20526,20588,20609,20428,20453,20568,20732,20825,20827,20829,20830,28278,144789,147001,147135,28018,137348,147081,20904,20931,132576,17629,132259,132242,132241,36218,166556,132878,21081,21156,133235,21217,37742,18042,29068,148364,134176,149932,135396,27089,134685,29817,16094,29849,29716,29782,29592,19342,150204,147597,21456,13700,29199,147657,21940,131909,21709,134086,22301,37469,38644,37734,22493,22413,22399,13886,22731,23193,166470,136954,137071,136976,23084,22968,37519,23166,23247,23058,153926,137715,137313,148117,14069,27909,29763,23073,155267,23169,166871,132115,37856,29836,135939,28933,18802,37896,166395,37821,14240,23582,23710,24158,24136,137622,137596,146158,24269,23375,137475,137476,14081,137376,14045,136958,14035,33066,166471,138682,144498,166312,24332,24334,137511,137131,23147,137019,23364,34324,161277,34912,24702,141408,140843,24539,16056,140719,140734,168072,159603,25024,131134,131142,140827,24985,24984,24693,142491,142599,149204,168269,25713,149093,142186,14889,142114,144464,170218,142968,25399,173147,25782,25393,25553,149987,142695,25252,142497,25659,25963,26994,15348,143502,144045,149897,144043,21773,144096,137433,169023,26318,144009,143795,15072,16784,152964,166690,152975,136956,152923,152613,30958,143619,137258,143924,13412,143887,143746,148169,26254,159012,26219,19347,26160,161904,138731,26211,144082,144097,26142,153714,14545,145466,145340,15257,145314,144382,29904,15254,26511,149034,26806,26654,15300,27326,14435,145365,148615,27187,27218,27337,27397,137490,25873,26776,27212,15319,27258,27479,147392,146586,37792,37618,166890,166603,37513,163870,166364,37991,28069,28427,149996,28007,147327,15759,28164,147516,23101,28170,22599,27940,30786,28987,148250,148086,28913,29264,29319,29332,149391,149285,20857,150180,132587,29818,147192,144991,150090,149783,155617,16134,16049,150239,166947,147253,24743,16115,29900,29756,37767,29751,17567,159210,17745,30083,16227,150745,150790,16216,30037,30323,173510,15129,29800,166604,149931,149902,15099,15821,150094,16127,149957,149747,37370,22322,37698,166627,137316,20703,152097,152039,30584,143922,30478,30479,30587,149143,145281,14942,149744,29752,29851,16063,150202,150215,16584,150166,156078,37639,152961,30750,30861,30856,30930,29648,31065,161601,153315,16654,31131,33942,31141,27181,147194,31290,31220,16750,136934,16690,37429,31217,134476,149900,131737,146874,137070,13719,21867,13680,13994,131540,134157,31458,23129,141045,154287,154268,23053,131675,30960,23082,154566,31486,16889,31837,31853,16913,154547,155324,155302,31949,150009,137136,31886,31868,31918,27314,32220,32263,32211,32590,156257,155996,162632,32151,155266,17002,158581,133398,26582,131150,144847,22468,156690,156664,149858,32733,31527,133164,154345,154947,31500,155150,39398,34373,39523,27164,144447,14818,150007,157101,39455,157088,33920,160039,158929,17642,33079,17410,32966,33033,33090,157620,39107,158274,33378,33381,158289,33875,159143,34320,160283,23174,16767,137280,23339,137377,23268,137432,34464,195004,146831,34861,160802,23042,34926,20293,34951,35007,35046,35173,35149,153219,35156,161669,161668,166901,166873,166812,166393,16045,33955,18165,18127,14322,35389,35356,169032,24397,37419,148100,26068,28969,28868,137285,40301,35999,36073,163292,22938,30659,23024,17262,14036,36394,36519,150537,36656,36682,17140,27736,28603,140065,18587,28537,28299,137178,39913,14005,149807,37051,37015,21873,18694,37307,37892,166475,16482,166652,37927,166941,166971,34021,35371,38297,38311,38295,38294,167220,29765,16066,149759,150082,148458,16103,143909,38543,167655,167526,167525,16076,149997,150136,147438,29714,29803,16124,38721,168112,26695,18973,168083,153567,38749,37736,166281,166950,166703,156606,37562,23313,35689,18748,29689,147995,38811,38769,39224,134950,24001,166853,150194,38943,169178,37622,169431,37349,17600,166736,150119,166756,39132,166469,16128,37418,18725,33812,39227,39245,162566,15869,39323,19311,39338,39516,166757,153800,27279,39457,23294,39471,170225,19344,170312,39356,19389,19351,37757,22642,135938,22562,149944,136424,30788,141087,146872,26821,15741,37976,14631,24912,141185,141675,24839,40015,40019,40059,39989,39952,39807,39887,171565,39839,172533,172286,40225,19630,147716,40472,19632,40204,172468,172269,172275,170287,40357,33981,159250,159711,158594,34300,17715,159140,159364,159216,33824,34286,159232,145367,155748,31202,144796,144960,18733,149982,15714,37851,37566,37704,131775,30905,37495,37965,20452,13376,36964,152925,30781,30804,30902,30795,137047,143817,149825,13978,20338,28634,28633,28702,28702,21524,147893,22459,22771,22410,40214,22487,28980,13487,147884,29163,158784,151447,23336,137141,166473,24844,23246,23051,17084,148616,14124,19323,166396,37819,37816,137430,134941,33906,158912,136211,148218,142374,148417,22932,146871,157505,32168,155995,155812,149945,149899,166394,37605,29666,16105,29876,166755,137375,16097,150195,27352,29683,29691,16086,150078,150164,137177,150118,132007,136228,149989,29768,149782,28837,149878,37508,29670,37727,132350,37681,166606,166422,37766,166887,153045,18741,166530,29035,149827,134399,22180,132634,134123,134328,21762,31172,137210,32254,136898,150096,137298,17710,37889,14090,166592,149933,22960,137407,137347,160900,23201,14050,146779,14000,37471,23161,166529,137314,37748,15565,133812,19094,14730,20724,15721,15692,136092,29045,17147,164376,28175,168164,17643,27991,163407,28775,27823,15574,147437,146989,28162,28428,15727,132085,30033,14012,13512,18048,16090,18545,22980,37486,18750,36673,166940,158656,22546,22472,14038,136274,28926,148322,150129,143331,135856,140221,26809,26983,136088,144613,162804,145119,166531,145366,144378,150687,27162,145069,158903,33854,17631,17614,159014,159057,158850,159710,28439,160009,33597,137018,33773,158848,159827,137179,22921,23170,137139,23137,23153,137477,147964,14125,23023,137020,14023,29070,37776,26266,148133,23150,23083,148115,27179,147193,161590,148571,148170,28957,148057,166369,20400,159016,23746,148686,163405,148413,27148,148054,135940,28838,28979,148457,15781,27871,194597,150095,32357,23019,23855,15859,24412,150109,137183,32164,33830,21637,146170,144128,131604,22398,133333,132633,16357,139166,172726,28675,168283,23920,29583,31955,166489,168992,20424,32743,29389,29456,162548,29496,29497,153334,29505,29512,16041,162584,36972,29173,149746,29665,33270,16074,30476,16081,27810,22269,29721,29726,29727,16098,16112,16116,16122,29907,16142,16211,30018,30061,30066,30093,16252,30152,30172,16320,30285,16343,30324,16348,30330,151388,29064,22051,35200,22633,16413,30531,16441,26465,16453,13787,30616,16490,16495,23646,30654,30667,22770,30744,28857,30748,16552,30777,30791,30801,30822,33864,152885,31027,26627,31026,16643,16649,31121,31129,36795,31238,36796,16743,31377,16818,31420,33401,16836,31439,31451,16847,20001,31586,31596,31611,31762,31771,16992,17018,31867,31900,17036,31928,17044,31981,36755,28864,134351,32207,32212,32208,32253,32686,32692,29343,17303,32800,32805,31545,32814,32817,32852,15820,22452,28832,32951,33001,17389,33036,29482,33038,33042,30048,33044,17409,15161,33110,33113,33114,17427,22586,33148,33156,17445,33171,17453,33189,22511,33217,33252,33364,17551,33446,33398,33482,33496,33535,17584,33623,38505,27018,33797,28917,33892,24803,33928,17668,33982,34017,34040,34064,34104,34130,17723,34159,34160,34272,17783,34418,34450,34482,34543,38469,34699,17926,17943,34990,35071,35108,35143,35217,162151,35369,35384,35476,35508,35921,36052,36082,36124,18328,22623,36291,18413,20206,36410,21976,22356,36465,22005,36528,18487,36558,36578,36580,36589,36594,36791,36801,36810,36812,36915,39364,18605,39136,37395,18718,37416,37464,37483,37553,37550,37567,37603,37611,37619,37620,37629,37699,37764,37805,18757,18769,40639,37911,21249,37917,37933,37950,18794,37972,38009,38189,38306,18855,38388,38451,18917,26528,18980,38720,18997,38834,38850,22100,19172,24808,39097,19225,39153,22596,39182,39193,20916,39196,39223,39234,39261,39266,19312,39365,19357,39484,39695,31363,39785,39809,39901,39921,39924,19565,39968,14191,138178,40265,39994,40702,22096,40339,40381,40384,40444,38134,36790,40571,40620,40625,40637,40646,38108,40674,40689,40696,31432,40772,131220,131767,132000,26906,38083,22956,132311,22592,38081,14265,132565,132629,132726,136890,22359,29043,133826,133837,134079,21610,194619,134091,21662,134139,134203,134227,134245,134268,24807,134285,22138,134325,134365,134381,134511,134578,134600,26965,39983,34725,134660,134670,134871,135056,134957,134771,23584,135100,24075,135260,135247,135286,26398,135291,135304,135318,13895,135359,135379,135471,135483,21348,33965,135907,136053,135990,35713,136567,136729,137155,137159,20088,28859,137261,137578,137773,137797,138282,138352,138412,138952,25283,138965,139029,29080,26709,139333,27113,14024,139900,140247,140282,141098,141425,141647,33533,141671,141715,142037,35237,142056,36768,142094,38840,142143,38983,39613,142412,null,142472,142519,154600,142600,142610,142775,142741,142914,143220,143308,143411,143462,144159,144350,24497,26184,26303,162425,144743,144883,29185,149946,30679,144922,145174,32391,131910,22709,26382,26904,146087,161367,155618,146961,147129,161278,139418,18640,19128,147737,166554,148206,148237,147515,148276,148374,150085,132554,20946,132625,22943,138920,15294,146687,148484,148694,22408,149108,14747,149295,165352,170441,14178,139715,35678,166734,39382,149522,149755,150037,29193,150208,134264,22885,151205,151430,132985,36570,151596,21135,22335,29041,152217,152601,147274,150183,21948,152646,152686,158546,37332,13427,152895,161330,152926,18200,152930,152934,153543,149823,153693,20582,13563,144332,24798,153859,18300,166216,154286,154505,154630,138640,22433,29009,28598,155906,162834,36950,156082,151450,35682,156674,156746,23899,158711,36662,156804,137500,35562,150006,156808,147439,156946,19392,157119,157365,141083,37989,153569,24981,23079,194765,20411,22201,148769,157436,20074,149812,38486,28047,158909,13848,35191,157593,157806,156689,157790,29151,157895,31554,168128,133649,157990,37124,158009,31301,40432,158202,39462,158253,13919,156777,131105,31107,158260,158555,23852,144665,33743,158621,18128,158884,30011,34917,159150,22710,14108,140685,159819,160205,15444,160384,160389,37505,139642,160395,37680,160486,149968,27705,38047,160848,134904,34855,35061,141606,164979,137137,28344,150058,137248,14756,14009,23568,31203,17727,26294,171181,170148,35139,161740,161880,22230,16607,136714,14753,145199,164072,136133,29101,33638,162269,168360,23143,19639,159919,166315,162301,162314,162571,163174,147834,31555,31102,163849,28597,172767,27139,164632,21410,159239,37823,26678,38749,164207,163875,158133,136173,143919,163912,23941,166960,163971,22293,38947,166217,23979,149896,26046,27093,21458,150181,147329,15377,26422,163984,164084,164142,139169,164175,164233,164271,164378,164614,164655,164746,13770,164968,165546,18682,25574,166230,30728,37461,166328,17394,166375,17375,166376,166726,166868,23032,166921,36619,167877,168172,31569,168208,168252,15863,168286,150218,36816,29327,22155,169191,169449,169392,169400,169778,170193,170313,170346,170435,170536,170766,171354,171419,32415,171768,171811,19620,38215,172691,29090,172799,19857,36882,173515,19868,134300,36798,21953,36794,140464,36793,150163,17673,32383,28502,27313,20202,13540,166700,161949,14138,36480,137205,163876,166764,166809,162366,157359,15851,161365,146615,153141,153942,20122,155265,156248,22207,134765,36366,23405,147080,150686,25566,25296,137206,137339,25904,22061,154698,21530,152337,15814,171416,19581,22050,22046,32585,155352,22901,146752,34672,19996,135146,134473,145082,33047,40286,36120,30267,40005,30286,30649,37701,21554,33096,33527,22053,33074,33816,32957,21994,31074,22083,21526,134813,13774,22021,22001,26353,164578,13869,30004,22000,21946,21655,21874,134209,134294,24272,151880,134774,142434,134818,40619,32090,21982,135285,25245,38765,21652,36045,29174,37238,25596,25529,25598,21865,142147,40050,143027,20890,13535,134567,20903,21581,21790,21779,30310,36397,157834,30129,32950,34820,34694,35015,33206,33820,135361,17644,29444,149254,23440,33547,157843,22139,141044,163119,147875,163187,159440,160438,37232,135641,37384,146684,173737,134828,134905,29286,138402,18254,151490,163833,135147,16634,40029,25887,142752,18675,149472,171388,135148,134666,24674,161187,135149,null,155720,135559,29091,32398,40272,19994,19972,13687,23309,27826,21351,13996,14812,21373,13989,149016,22682,150382,33325,21579,22442,154261,133497,null,14930,140389,29556,171692,19721,39917,146686,171824,19547,151465,169374,171998,33884,146870,160434,157619,145184,25390,32037,147191,146988,14890,36872,21196,15988,13946,17897,132238,30272,23280,134838,30842,163630,22695,16575,22140,39819,23924,30292,173108,40581,19681,30201,14331,24857,143578,148466,null,22109,135849,22439,149859,171526,21044,159918,13741,27722,40316,31830,39737,22494,137068,23635,25811,169168,156469,160100,34477,134440,159010,150242,134513,null,20990,139023,23950,38659,138705,40577,36940,31519,39682,23761,31651,25192,25397,39679,31695,39722,31870,39726,31810,31878,39957,31740,39689,40727,39963,149822,40794,21875,23491,20477,40600,20466,21088,15878,21201,22375,20566,22967,24082,38856,40363,36700,21609,38836,39232,38842,21292,24880,26924,21466,39946,40194,19515,38465,27008,20646,30022,137069,39386,21107,null,37209,38529,37212,null,37201,167575,25471,159011,27338,22033,37262,30074,25221,132092,29519,31856,154657,146685,null,149785,30422,39837,20010,134356,33726,34882,null,23626,27072,20717,22394,21023,24053,20174,27697,131570,20281,21660,21722,21146,36226,13822,24332,13811,null,27474,37244,40869,39831,38958,39092,39610,40616,40580,29050,31508,null,27642,34840,32632,null,22048,173642,36471,40787,null,36308,36431,40476,36353,25218,164733,36392,36469,31443,150135,31294,30936,27882,35431,30215,166490,40742,27854,34774,30147,172722,30803,194624,36108,29410,29553,35629,29442,29937,36075,150203,34351,24506,34976,17591,null,137275,159237,null,35454,140571,null,24829,30311,39639,40260,37742,39823,34805,null,34831,36087,29484,38689,39856,13782,29362,19463,31825,39242,155993,24921,19460,40598,24957,null,22367,24943,25254,25145,25294,14940,25058,21418,144373,25444,26626,13778,23895,166850,36826,167481,null,20697,138566,30982,21298,38456,134971,16485,null,30718,null,31938,155418,31962,31277,32870,32867,32077,29957,29938,35220,33306,26380,32866,160902,32859,29936,33027,30500,35209,157644,30035,159441,34729,34766,33224,34700,35401,36013,35651,30507,29944,34010,13877,27058,36262,null,35241,29800,28089,34753,147473,29927,15835,29046,24740,24988,15569,29026,24695,null,32625,166701,29264,24809,19326,21024,15384,146631,155351,161366,152881,137540,135934,170243,159196,159917,23745,156077,166415,145015,131310,157766,151310,17762,23327,156492,40784,40614,156267,12288,65292,12289,12290,65294,8231,65307,65306,65311,65281,65072,8230,8229,65104,65105,65106,183,65108,65109,65110,65111,65372,8211,65073,8212,65075,9588,65076,65103,65288,65289,65077,65078,65371,65373,65079,65080,12308,12309,65081,65082,12304,12305,65083,65084,12298,12299,65085,65086,12296,12297,65087,65088,12300,12301,65089,65090,12302,12303,65091,65092,65113,65114,65115,65116,65117,65118,8216,8217,8220,8221,12317,12318,8245,8242,65283,65286,65290,8251,167,12291,9675,9679,9651,9650,9678,9734,9733,9671,9670,9633,9632,9661,9660,12963,8453,175,65507,65343,717,65097,65098,65101,65102,65099,65100,65119,65120,65121,65291,65293,215,247,177,8730,65308,65310,65309,8806,8807,8800,8734,8786,8801,65122,65123,65124,65125,65126,65374,8745,8746,8869,8736,8735,8895,13266,13265,8747,8750,8757,8756,9792,9794,8853,8857,8593,8595,8592,8594,8598,8599,8601,8600,8741,8739,65295,65340,8725,65128,65284,65509,12306,65504,65505,65285,65312,8451,8457,65129,65130,65131,13269,13212,13213,13214,13262,13217,13198,13199,13252,176,20825,20827,20830,20829,20833,20835,21991,29929,31950,9601,9602,9603,9604,9605,9606,9607,9608,9615,9614,9613,9612,9611,9610,9609,9532,9524,9516,9508,9500,9620,9472,9474,9621,9484,9488,9492,9496,9581,9582,9584,9583,9552,9566,9578,9569,9698,9699,9701,9700,9585,9586,9587,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,12321,12322,12323,12324,12325,12326,12327,12328,12329,21313,21316,21317,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,729,713,714,711,715,9216,9217,9218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9246,9247,9249,8364,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,19968,20057,19969,19971,20035,20061,20102,20108,20154,20799,20837,20843,20960,20992,20993,21147,21269,21313,21340,21448,19977,19979,19976,19978,20011,20024,20961,20037,20040,20063,20062,20110,20129,20800,20995,21242,21315,21449,21475,22303,22763,22805,22823,22899,23376,23377,23379,23544,23567,23586,23608,23665,24029,24037,24049,24050,24051,24062,24178,24318,24331,24339,25165,19985,19984,19981,20013,20016,20025,20043,23609,20104,20113,20117,20114,20116,20130,20161,20160,20163,20166,20167,20173,20170,20171,20164,20803,20801,20839,20845,20846,20844,20887,20982,20998,20999,21000,21243,21246,21247,21270,21305,21320,21319,21317,21342,21380,21451,21450,21453,22764,22825,22827,22826,22829,23380,23569,23588,23610,23663,24052,24187,24319,24340,24341,24515,25096,25142,25163,25166,25903,25991,26007,26020,26041,26085,26352,26376,26408,27424,27490,27513,27595,27604,27611,27663,27700,28779,29226,29238,29243,29255,29273,29275,29356,29579,19993,19990,19989,19988,19992,20027,20045,20047,20046,20197,20184,20180,20181,20182,20183,20195,20196,20185,20190,20805,20804,20873,20874,20908,20985,20986,20984,21002,21152,21151,21253,21254,21271,21277,20191,21322,21321,21345,21344,21359,21358,21435,21487,21476,21491,21484,21486,21481,21480,21500,21496,21493,21483,21478,21482,21490,21489,21488,21477,21485,21499,22235,22234,22806,22830,22833,22900,22902,23381,23427,23612,24040,24039,24038,24066,24067,24179,24188,24321,24344,24343,24517,25098,25171,25172,25170,25169,26021,26086,26414,26412,26410,26411,26413,27491,27597,27665,27664,27704,27713,27712,27710,29359,29572,29577,29916,29926,29976,29983,29992,29993,30000,30001,30002,30003,30091,30333,30382,30399,30446,30683,30690,30707,31034,31166,31348,31435,19998,19999,20050,20051,20073,20121,20132,20134,20133,20223,20233,20249,20234,20245,20237,20240,20241,20239,20210,20214,20219,20208,20211,20221,20225,20235,20809,20807,20806,20808,20840,20849,20877,20912,21015,21009,21010,21006,21014,21155,21256,21281,21280,21360,21361,21513,21519,21516,21514,21520,21505,21515,21508,21521,21517,21512,21507,21518,21510,21522,22240,22238,22237,22323,22320,22312,22317,22316,22319,22313,22809,22810,22839,22840,22916,22904,22915,22909,22905,22914,22913,23383,23384,23431,23432,23429,23433,23546,23574,23673,24030,24070,24182,24180,24335,24347,24537,24534,25102,25100,25101,25104,25187,25179,25176,25910,26089,26088,26092,26093,26354,26355,26377,26429,26420,26417,26421,27425,27492,27515,27670,27741,27735,27737,27743,27744,27728,27733,27745,27739,27725,27726,28784,29279,29277,30334,31481,31859,31992,32566,32650,32701,32769,32771,32780,32786,32819,32895,32905,32907,32908,33251,33258,33267,33276,33292,33307,33311,33390,33394,33406,34411,34880,34892,34915,35199,38433,20018,20136,20301,20303,20295,20311,20318,20276,20315,20309,20272,20304,20305,20285,20282,20280,20291,20308,20284,20294,20323,20316,20320,20271,20302,20278,20313,20317,20296,20314,20812,20811,20813,20853,20918,20919,21029,21028,21033,21034,21032,21163,21161,21162,21164,21283,21363,21365,21533,21549,21534,21566,21542,21582,21543,21574,21571,21555,21576,21570,21531,21545,21578,21561,21563,21560,21550,21557,21558,21536,21564,21568,21553,21547,21535,21548,22250,22256,22244,22251,22346,22353,22336,22349,22343,22350,22334,22352,22351,22331,22767,22846,22941,22930,22952,22942,22947,22937,22934,22925,22948,22931,22922,22949,23389,23388,23386,23387,23436,23435,23439,23596,23616,23617,23615,23614,23696,23697,23700,23692,24043,24076,24207,24199,24202,24311,24324,24351,24420,24418,24439,24441,24536,24524,24535,24525,24561,24555,24568,24554,25106,25105,25220,25239,25238,25216,25206,25225,25197,25226,25212,25214,25209,25203,25234,25199,25240,25198,25237,25235,25233,25222,25913,25915,25912,26097,26356,26463,26446,26447,26448,26449,26460,26454,26462,26441,26438,26464,26451,26455,27493,27599,27714,27742,27801,27777,27784,27785,27781,27803,27754,27770,27792,27760,27788,27752,27798,27794,27773,27779,27762,27774,27764,27782,27766,27789,27796,27800,27778,28790,28796,28797,28792,29282,29281,29280,29380,29378,29590,29996,29995,30007,30008,30338,30447,30691,31169,31168,31167,31350,31995,32597,32918,32915,32925,32920,32923,32922,32946,33391,33426,33419,33421,35211,35282,35328,35895,35910,35925,35997,36196,36208,36275,36523,36554,36763,36784,36802,36806,36805,36804,24033,37009,37026,37034,37030,37027,37193,37318,37324,38450,38446,38449,38442,38444,20006,20054,20083,20107,20123,20126,20139,20140,20335,20381,20365,20339,20351,20332,20379,20363,20358,20355,20336,20341,20360,20329,20347,20374,20350,20367,20369,20346,20820,20818,20821,20841,20855,20854,20856,20925,20989,21051,21048,21047,21050,21040,21038,21046,21057,21182,21179,21330,21332,21331,21329,21350,21367,21368,21369,21462,21460,21463,21619,21621,21654,21624,21653,21632,21627,21623,21636,21650,21638,21628,21648,21617,21622,21644,21658,21602,21608,21643,21629,21646,22266,22403,22391,22378,22377,22369,22374,22372,22396,22812,22857,22855,22856,22852,22868,22974,22971,22996,22969,22958,22993,22982,22992,22989,22987,22995,22986,22959,22963,22994,22981,23391,23396,23395,23447,23450,23448,23452,23449,23451,23578,23624,23621,23622,23735,23713,23736,23721,23723,23729,23731,24088,24090,24086,24085,24091,24081,24184,24218,24215,24220,24213,24214,24310,24358,24359,24361,24448,24449,24447,24444,24541,24544,24573,24565,24575,24591,24596,24623,24629,24598,24618,24597,24609,24615,24617,24619,24603,25110,25109,25151,25150,25152,25215,25289,25292,25284,25279,25282,25273,25298,25307,25259,25299,25300,25291,25288,25256,25277,25276,25296,25305,25287,25293,25269,25306,25265,25304,25302,25303,25286,25260,25294,25918,26023,26044,26106,26132,26131,26124,26118,26114,26126,26112,26127,26133,26122,26119,26381,26379,26477,26507,26517,26481,26524,26483,26487,26503,26525,26519,26479,26480,26495,26505,26494,26512,26485,26522,26515,26492,26474,26482,27427,27494,27495,27519,27667,27675,27875,27880,27891,27825,27852,27877,27827,27837,27838,27836,27874,27819,27861,27859,27832,27844,27833,27841,27822,27863,27845,27889,27839,27835,27873,27867,27850,27820,27887,27868,27862,27872,28821,28814,28818,28810,28825,29228,29229,29240,29256,29287,29289,29376,29390,29401,29399,29392,29609,29608,29599,29611,29605,30013,30109,30105,30106,30340,30402,30450,30452,30693,30717,31038,31040,31041,31177,31176,31354,31353,31482,31998,32596,32652,32651,32773,32954,32933,32930,32945,32929,32939,32937,32948,32938,32943,33253,33278,33293,33459,33437,33433,33453,33469,33439,33465,33457,33452,33445,33455,33464,33443,33456,33470,33463,34382,34417,21021,34920,36555,36814,36820,36817,37045,37048,37041,37046,37319,37329,38263,38272,38428,38464,38463,38459,38468,38466,38585,38632,38738,38750,20127,20141,20142,20449,20405,20399,20415,20448,20433,20431,20445,20419,20406,20440,20447,20426,20439,20398,20432,20420,20418,20442,20430,20446,20407,20823,20882,20881,20896,21070,21059,21066,21069,21068,21067,21063,21191,21193,21187,21185,21261,21335,21371,21402,21467,21676,21696,21672,21710,21705,21688,21670,21683,21703,21698,21693,21674,21697,21700,21704,21679,21675,21681,21691,21673,21671,21695,22271,22402,22411,22432,22435,22434,22478,22446,22419,22869,22865,22863,22862,22864,23004,23000,23039,23011,23016,23043,23013,23018,23002,23014,23041,23035,23401,23459,23462,23460,23458,23461,23553,23630,23631,23629,23627,23769,23762,24055,24093,24101,24095,24189,24224,24230,24314,24328,24365,24421,24456,24453,24458,24459,24455,24460,24457,24594,24605,24608,24613,24590,24616,24653,24688,24680,24674,24646,24643,24684,24683,24682,24676,25153,25308,25366,25353,25340,25325,25345,25326,25341,25351,25329,25335,25327,25324,25342,25332,25361,25346,25919,25925,26027,26045,26082,26149,26157,26144,26151,26159,26143,26152,26161,26148,26359,26623,26579,26609,26580,26576,26604,26550,26543,26613,26601,26607,26564,26577,26548,26586,26597,26552,26575,26590,26611,26544,26585,26594,26589,26578,27498,27523,27526,27573,27602,27607,27679,27849,27915,27954,27946,27969,27941,27916,27953,27934,27927,27963,27965,27966,27958,27931,27893,27961,27943,27960,27945,27950,27957,27918,27947,28843,28858,28851,28844,28847,28845,28856,28846,28836,29232,29298,29295,29300,29417,29408,29409,29623,29642,29627,29618,29645,29632,29619,29978,29997,30031,30028,30030,30027,30123,30116,30117,30114,30115,30328,30342,30343,30344,30408,30406,30403,30405,30465,30457,30456,30473,30475,30462,30460,30471,30684,30722,30740,30732,30733,31046,31049,31048,31047,31161,31162,31185,31186,31179,31359,31361,31487,31485,31869,32002,32005,32000,32009,32007,32004,32006,32568,32654,32703,32772,32784,32781,32785,32822,32982,32997,32986,32963,32964,32972,32993,32987,32974,32990,32996,32989,33268,33314,33511,33539,33541,33507,33499,33510,33540,33509,33538,33545,33490,33495,33521,33537,33500,33492,33489,33502,33491,33503,33519,33542,34384,34425,34427,34426,34893,34923,35201,35284,35336,35330,35331,35998,36000,36212,36211,36276,36557,36556,36848,36838,36834,36842,36837,36845,36843,36836,36840,37066,37070,37057,37059,37195,37194,37325,38274,38480,38475,38476,38477,38754,38761,38859,38893,38899,38913,39080,39131,39135,39318,39321,20056,20147,20492,20493,20515,20463,20518,20517,20472,20521,20502,20486,20540,20511,20506,20498,20497,20474,20480,20500,20520,20465,20513,20491,20505,20504,20467,20462,20525,20522,20478,20523,20489,20860,20900,20901,20898,20941,20940,20934,20939,21078,21084,21076,21083,21085,21290,21375,21407,21405,21471,21736,21776,21761,21815,21756,21733,21746,21766,21754,21780,21737,21741,21729,21769,21742,21738,21734,21799,21767,21757,21775,22275,22276,22466,22484,22475,22467,22537,22799,22871,22872,22874,23057,23064,23068,23071,23067,23059,23020,23072,23075,23081,23077,23052,23049,23403,23640,23472,23475,23478,23476,23470,23477,23481,23480,23556,23633,23637,23632,23789,23805,23803,23786,23784,23792,23798,23809,23796,24046,24109,24107,24235,24237,24231,24369,24466,24465,24464,24665,24675,24677,24656,24661,24685,24681,24687,24708,24735,24730,24717,24724,24716,24709,24726,25159,25331,25352,25343,25422,25406,25391,25429,25410,25414,25423,25417,25402,25424,25405,25386,25387,25384,25421,25420,25928,25929,26009,26049,26053,26178,26185,26191,26179,26194,26188,26181,26177,26360,26388,26389,26391,26657,26680,26696,26694,26707,26681,26690,26708,26665,26803,26647,26700,26705,26685,26612,26704,26688,26684,26691,26666,26693,26643,26648,26689,27530,27529,27575,27683,27687,27688,27686,27684,27888,28010,28053,28040,28039,28006,28024,28023,27993,28051,28012,28041,28014,27994,28020,28009,28044,28042,28025,28037,28005,28052,28874,28888,28900,28889,28872,28879,29241,29305,29436,29433,29437,29432,29431,29574,29677,29705,29678,29664,29674,29662,30036,30045,30044,30042,30041,30142,30149,30151,30130,30131,30141,30140,30137,30146,30136,30347,30384,30410,30413,30414,30505,30495,30496,30504,30697,30768,30759,30776,30749,30772,30775,30757,30765,30752,30751,30770,31061,31056,31072,31071,31062,31070,31069,31063,31066,31204,31203,31207,31199,31206,31209,31192,31364,31368,31449,31494,31505,31881,32033,32023,32011,32010,32032,32034,32020,32016,32021,32026,32028,32013,32025,32027,32570,32607,32660,32709,32705,32774,32792,32789,32793,32791,32829,32831,33009,33026,33008,33029,33005,33012,33030,33016,33011,33032,33021,33034,33020,33007,33261,33260,33280,33296,33322,33323,33320,33324,33467,33579,33618,33620,33610,33592,33616,33609,33589,33588,33615,33586,33593,33590,33559,33600,33585,33576,33603,34388,34442,34474,34451,34468,34473,34444,34467,34460,34928,34935,34945,34946,34941,34937,35352,35344,35342,35340,35349,35338,35351,35347,35350,35343,35345,35912,35962,35961,36001,36002,36215,36524,36562,36564,36559,36785,36865,36870,36855,36864,36858,36852,36867,36861,36869,36856,37013,37089,37085,37090,37202,37197,37196,37336,37341,37335,37340,37337,38275,38498,38499,38497,38491,38493,38500,38488,38494,38587,39138,39340,39592,39640,39717,39730,39740,20094,20602,20605,20572,20551,20547,20556,20570,20553,20581,20598,20558,20565,20597,20596,20599,20559,20495,20591,20589,20828,20885,20976,21098,21103,21202,21209,21208,21205,21264,21263,21273,21311,21312,21310,21443,26364,21830,21866,21862,21828,21854,21857,21827,21834,21809,21846,21839,21845,21807,21860,21816,21806,21852,21804,21859,21811,21825,21847,22280,22283,22281,22495,22533,22538,22534,22496,22500,22522,22530,22581,22519,22521,22816,22882,23094,23105,23113,23142,23146,23104,23100,23138,23130,23110,23114,23408,23495,23493,23492,23490,23487,23494,23561,23560,23559,23648,23644,23645,23815,23814,23822,23835,23830,23842,23825,23849,23828,23833,23844,23847,23831,24034,24120,24118,24115,24119,24247,24248,24246,24245,24254,24373,24375,24407,24428,24425,24427,24471,24473,24478,24472,24481,24480,24476,24703,24739,24713,24736,24744,24779,24756,24806,24765,24773,24763,24757,24796,24764,24792,24789,24774,24799,24760,24794,24775,25114,25115,25160,25504,25511,25458,25494,25506,25509,25463,25447,25496,25514,25457,25513,25481,25475,25499,25451,25512,25476,25480,25497,25505,25516,25490,25487,25472,25467,25449,25448,25466,25949,25942,25937,25945,25943,21855,25935,25944,25941,25940,26012,26011,26028,26063,26059,26060,26062,26205,26202,26212,26216,26214,26206,26361,21207,26395,26753,26799,26786,26771,26805,26751,26742,26801,26791,26775,26800,26755,26820,26797,26758,26757,26772,26781,26792,26783,26785,26754,27442,27578,27627,27628,27691,28046,28092,28147,28121,28082,28129,28108,28132,28155,28154,28165,28103,28107,28079,28113,28078,28126,28153,28088,28151,28149,28101,28114,28186,28085,28122,28139,28120,28138,28145,28142,28136,28102,28100,28074,28140,28095,28134,28921,28937,28938,28925,28911,29245,29309,29313,29468,29467,29462,29459,29465,29575,29701,29706,29699,29702,29694,29709,29920,29942,29943,29980,29986,30053,30054,30050,30064,30095,30164,30165,30133,30154,30157,30350,30420,30418,30427,30519,30526,30524,30518,30520,30522,30827,30787,30798,31077,31080,31085,31227,31378,31381,31520,31528,31515,31532,31526,31513,31518,31534,31890,31895,31893,32070,32067,32113,32046,32057,32060,32064,32048,32051,32068,32047,32066,32050,32049,32573,32670,32666,32716,32718,32722,32796,32842,32838,33071,33046,33059,33067,33065,33072,33060,33282,33333,33335,33334,33337,33678,33694,33688,33656,33698,33686,33725,33707,33682,33674,33683,33673,33696,33655,33659,33660,33670,33703,34389,24426,34503,34496,34486,34500,34485,34502,34507,34481,34479,34505,34899,34974,34952,34987,34962,34966,34957,34955,35219,35215,35370,35357,35363,35365,35377,35373,35359,35355,35362,35913,35930,36009,36012,36011,36008,36010,36007,36199,36198,36286,36282,36571,36575,36889,36877,36890,36887,36899,36895,36893,36880,36885,36894,36896,36879,36898,36886,36891,36884,37096,37101,37117,37207,37326,37365,37350,37347,37351,37357,37353,38281,38506,38517,38515,38520,38512,38516,38518,38519,38508,38592,38634,38633,31456,31455,38914,38915,39770,40165,40565,40575,40613,40635,20642,20621,20613,20633,20625,20608,20630,20632,20634,26368,20977,21106,21108,21109,21097,21214,21213,21211,21338,21413,21883,21888,21927,21884,21898,21917,21912,21890,21916,21930,21908,21895,21899,21891,21939,21934,21919,21822,21938,21914,21947,21932,21937,21886,21897,21931,21913,22285,22575,22570,22580,22564,22576,22577,22561,22557,22560,22777,22778,22880,23159,23194,23167,23186,23195,23207,23411,23409,23506,23500,23507,23504,23562,23563,23601,23884,23888,23860,23879,24061,24133,24125,24128,24131,24190,24266,24257,24258,24260,24380,24429,24489,24490,24488,24785,24801,24754,24758,24800,24860,24867,24826,24853,24816,24827,24820,24936,24817,24846,24822,24841,24832,24850,25119,25161,25507,25484,25551,25536,25577,25545,25542,25549,25554,25571,25552,25569,25558,25581,25582,25462,25588,25578,25563,25682,25562,25593,25950,25958,25954,25955,26001,26000,26031,26222,26224,26228,26230,26223,26257,26234,26238,26231,26366,26367,26399,26397,26874,26837,26848,26840,26839,26885,26847,26869,26862,26855,26873,26834,26866,26851,26827,26829,26893,26898,26894,26825,26842,26990,26875,27454,27450,27453,27544,27542,27580,27631,27694,27695,27692,28207,28216,28244,28193,28210,28263,28234,28192,28197,28195,28187,28251,28248,28196,28246,28270,28205,28198,28271,28212,28237,28218,28204,28227,28189,28222,28363,28297,28185,28238,28259,28228,28274,28265,28255,28953,28954,28966,28976,28961,28982,29038,28956,29260,29316,29312,29494,29477,29492,29481,29754,29738,29747,29730,29733,29749,29750,29748,29743,29723,29734,29736,29989,29990,30059,30058,30178,30171,30179,30169,30168,30174,30176,30331,30332,30358,30355,30388,30428,30543,30701,30813,30828,30831,31245,31240,31243,31237,31232,31384,31383,31382,31461,31459,31561,31574,31558,31568,31570,31572,31565,31563,31567,31569,31903,31909,32094,32080,32104,32085,32043,32110,32114,32097,32102,32098,32112,32115,21892,32724,32725,32779,32850,32901,33109,33108,33099,33105,33102,33081,33094,33086,33100,33107,33140,33298,33308,33769,33795,33784,33805,33760,33733,33803,33729,33775,33777,33780,33879,33802,33776,33804,33740,33789,33778,33738,33848,33806,33796,33756,33799,33748,33759,34395,34527,34521,34541,34516,34523,34532,34512,34526,34903,35009,35010,34993,35203,35222,35387,35424,35413,35422,35388,35393,35412,35419,35408,35398,35380,35386,35382,35414,35937,35970,36015,36028,36019,36029,36033,36027,36032,36020,36023,36022,36031,36024,36234,36229,36225,36302,36317,36299,36314,36305,36300,36315,36294,36603,36600,36604,36764,36910,36917,36913,36920,36914,36918,37122,37109,37129,37118,37219,37221,37327,37396,37397,37411,37385,37406,37389,37392,37383,37393,38292,38287,38283,38289,38291,38290,38286,38538,38542,38539,38525,38533,38534,38541,38514,38532,38593,38597,38596,38598,38599,38639,38642,38860,38917,38918,38920,39143,39146,39151,39145,39154,39149,39342,39341,40643,40653,40657,20098,20653,20661,20658,20659,20677,20670,20652,20663,20667,20655,20679,21119,21111,21117,21215,21222,21220,21218,21219,21295,21983,21992,21971,21990,21966,21980,21959,21969,21987,21988,21999,21978,21985,21957,21958,21989,21961,22290,22291,22622,22609,22616,22615,22618,22612,22635,22604,22637,22602,22626,22610,22603,22887,23233,23241,23244,23230,23229,23228,23219,23234,23218,23913,23919,24140,24185,24265,24264,24338,24409,24492,24494,24858,24847,24904,24863,24819,24859,24825,24833,24840,24910,24908,24900,24909,24894,24884,24871,24845,24838,24887,25121,25122,25619,25662,25630,25642,25645,25661,25644,25615,25628,25620,25613,25654,25622,25623,25606,25964,26015,26032,26263,26249,26247,26248,26262,26244,26264,26253,26371,27028,26989,26970,26999,26976,26964,26997,26928,27010,26954,26984,26987,26974,26963,27001,27014,26973,26979,26971,27463,27506,27584,27583,27603,27645,28322,28335,28371,28342,28354,28304,28317,28359,28357,28325,28312,28348,28346,28331,28369,28310,28316,28356,28372,28330,28327,28340,29006,29017,29033,29028,29001,29031,29020,29036,29030,29004,29029,29022,28998,29032,29014,29242,29266,29495,29509,29503,29502,29807,29786,29781,29791,29790,29761,29759,29785,29787,29788,30070,30072,30208,30192,30209,30194,30193,30202,30207,30196,30195,30430,30431,30555,30571,30566,30558,30563,30585,30570,30572,30556,30565,30568,30562,30702,30862,30896,30871,30872,30860,30857,30844,30865,30867,30847,31098,31103,31105,33836,31165,31260,31258,31264,31252,31263,31262,31391,31392,31607,31680,31584,31598,31591,31921,31923,31925,32147,32121,32145,32129,32143,32091,32622,32617,32618,32626,32681,32680,32676,32854,32856,32902,32900,33137,33136,33144,33125,33134,33139,33131,33145,33146,33126,33285,33351,33922,33911,33853,33841,33909,33894,33899,33865,33900,33883,33852,33845,33889,33891,33897,33901,33862,34398,34396,34399,34553,34579,34568,34567,34560,34558,34555,34562,34563,34566,34570,34905,35039,35028,35033,35036,35032,35037,35041,35018,35029,35026,35228,35299,35435,35442,35443,35430,35433,35440,35463,35452,35427,35488,35441,35461,35437,35426,35438,35436,35449,35451,35390,35432,35938,35978,35977,36042,36039,36040,36036,36018,36035,36034,36037,36321,36319,36328,36335,36339,36346,36330,36324,36326,36530,36611,36617,36606,36618,36767,36786,36939,36938,36947,36930,36948,36924,36949,36944,36935,36943,36942,36941,36945,36926,36929,37138,37143,37228,37226,37225,37321,37431,37463,37432,37437,37440,37438,37467,37451,37476,37457,37428,37449,37453,37445,37433,37439,37466,38296,38552,38548,38549,38605,38603,38601,38602,38647,38651,38649,38646,38742,38772,38774,38928,38929,38931,38922,38930,38924,39164,39156,39165,39166,39347,39345,39348,39649,40169,40578,40718,40723,40736,20711,20718,20709,20694,20717,20698,20693,20687,20689,20721,20686,20713,20834,20979,21123,21122,21297,21421,22014,22016,22043,22039,22013,22036,22022,22025,22029,22030,22007,22038,22047,22024,22032,22006,22296,22294,22645,22654,22659,22675,22666,22649,22661,22653,22781,22821,22818,22820,22890,22889,23265,23270,23273,23255,23254,23256,23267,23413,23518,23527,23521,23525,23526,23528,23522,23524,23519,23565,23650,23940,23943,24155,24163,24149,24151,24148,24275,24278,24330,24390,24432,24505,24903,24895,24907,24951,24930,24931,24927,24922,24920,24949,25130,25735,25688,25684,25764,25720,25695,25722,25681,25703,25652,25709,25723,25970,26017,26071,26070,26274,26280,26269,27036,27048,27029,27073,27054,27091,27083,27035,27063,27067,27051,27060,27088,27085,27053,27084,27046,27075,27043,27465,27468,27699,28467,28436,28414,28435,28404,28457,28478,28448,28460,28431,28418,28450,28415,28399,28422,28465,28472,28466,28451,28437,28459,28463,28552,28458,28396,28417,28402,28364,28407,29076,29081,29053,29066,29060,29074,29246,29330,29334,29508,29520,29796,29795,29802,29808,29805,29956,30097,30247,30221,30219,30217,30227,30433,30435,30596,30589,30591,30561,30913,30879,30887,30899,30889,30883,31118,31119,31117,31278,31281,31402,31401,31469,31471,31649,31637,31627,31605,31639,31645,31636,31631,31672,31623,31620,31929,31933,31934,32187,32176,32156,32189,32190,32160,32202,32180,32178,32177,32186,32162,32191,32181,32184,32173,32210,32199,32172,32624,32736,32737,32735,32862,32858,32903,33104,33152,33167,33160,33162,33151,33154,33255,33274,33287,33300,33310,33355,33993,33983,33990,33988,33945,33950,33970,33948,33995,33976,33984,34003,33936,33980,34001,33994,34623,34588,34619,34594,34597,34612,34584,34645,34615,34601,35059,35074,35060,35065,35064,35069,35048,35098,35055,35494,35468,35486,35491,35469,35489,35475,35492,35498,35493,35496,35480,35473,35482,35495,35946,35981,35980,36051,36049,36050,36203,36249,36245,36348,36628,36626,36629,36627,36771,36960,36952,36956,36963,36953,36958,36962,36957,36955,37145,37144,37150,37237,37240,37239,37236,37496,37504,37509,37528,37526,37499,37523,37532,37544,37500,37521,38305,38312,38313,38307,38309,38308,38553,38556,38555,38604,38610,38656,38780,38789,38902,38935,38936,39087,39089,39171,39173,39180,39177,39361,39599,39600,39654,39745,39746,40180,40182,40179,40636,40763,40778,20740,20736,20731,20725,20729,20738,20744,20745,20741,20956,21127,21128,21129,21133,21130,21232,21426,22062,22075,22073,22066,22079,22068,22057,22099,22094,22103,22132,22070,22063,22064,22656,22687,22686,22707,22684,22702,22697,22694,22893,23305,23291,23307,23285,23308,23304,23534,23532,23529,23531,23652,23653,23965,23956,24162,24159,24161,24290,24282,24287,24285,24291,24288,24392,24433,24503,24501,24950,24935,24942,24925,24917,24962,24956,24944,24939,24958,24999,24976,25003,24974,25004,24986,24996,24980,25006,25134,25705,25711,25721,25758,25778,25736,25744,25776,25765,25747,25749,25769,25746,25774,25773,25771,25754,25772,25753,25762,25779,25973,25975,25976,26286,26283,26292,26289,27171,27167,27112,27137,27166,27161,27133,27169,27155,27146,27123,27138,27141,27117,27153,27472,27470,27556,27589,27590,28479,28540,28548,28497,28518,28500,28550,28525,28507,28536,28526,28558,28538,28528,28516,28567,28504,28373,28527,28512,28511,29087,29100,29105,29096,29270,29339,29518,29527,29801,29835,29827,29822,29824,30079,30240,30249,30239,30244,30246,30241,30242,30362,30394,30436,30606,30599,30604,30609,30603,30923,30917,30906,30922,30910,30933,30908,30928,31295,31292,31296,31293,31287,31291,31407,31406,31661,31665,31684,31668,31686,31687,31681,31648,31692,31946,32224,32244,32239,32251,32216,32236,32221,32232,32227,32218,32222,32233,32158,32217,32242,32249,32629,32631,32687,32745,32806,33179,33180,33181,33184,33178,33176,34071,34109,34074,34030,34092,34093,34067,34065,34083,34081,34068,34028,34085,34047,34054,34690,34676,34678,34656,34662,34680,34664,34649,34647,34636,34643,34907,34909,35088,35079,35090,35091,35093,35082,35516,35538,35527,35524,35477,35531,35576,35506,35529,35522,35519,35504,35542,35533,35510,35513,35547,35916,35918,35948,36064,36062,36070,36068,36076,36077,36066,36067,36060,36074,36065,36205,36255,36259,36395,36368,36381,36386,36367,36393,36383,36385,36382,36538,36637,36635,36639,36649,36646,36650,36636,36638,36645,36969,36974,36968,36973,36983,37168,37165,37159,37169,37255,37257,37259,37251,37573,37563,37559,37610,37548,37604,37569,37555,37564,37586,37575,37616,37554,38317,38321,38660,38662,38663,38665,38752,38797,38795,38799,38945,38955,38940,39091,39178,39187,39186,39192,39389,39376,39391,39387,39377,39381,39378,39385,39607,39662,39663,39719,39749,39748,39799,39791,40198,40201,40195,40617,40638,40654,22696,40786,20754,20760,20756,20752,20757,20864,20906,20957,21137,21139,21235,22105,22123,22137,22121,22116,22136,22122,22120,22117,22129,22127,22124,22114,22134,22721,22718,22727,22725,22894,23325,23348,23416,23536,23566,24394,25010,24977,25001,24970,25037,25014,25022,25034,25032,25136,25797,25793,25803,25787,25788,25818,25796,25799,25794,25805,25791,25810,25812,25790,25972,26310,26313,26297,26308,26311,26296,27197,27192,27194,27225,27243,27224,27193,27204,27234,27233,27211,27207,27189,27231,27208,27481,27511,27653,28610,28593,28577,28611,28580,28609,28583,28595,28608,28601,28598,28582,28576,28596,29118,29129,29136,29138,29128,29141,29113,29134,29145,29148,29123,29124,29544,29852,29859,29848,29855,29854,29922,29964,29965,30260,30264,30266,30439,30437,30624,30622,30623,30629,30952,30938,30956,30951,31142,31309,31310,31302,31308,31307,31418,31705,31761,31689,31716,31707,31713,31721,31718,31957,31958,32266,32273,32264,32283,32291,32286,32285,32265,32272,32633,32690,32752,32753,32750,32808,33203,33193,33192,33275,33288,33368,33369,34122,34137,34120,34152,34153,34115,34121,34157,34154,34142,34691,34719,34718,34722,34701,34913,35114,35122,35109,35115,35105,35242,35238,35558,35578,35563,35569,35584,35548,35559,35566,35582,35585,35586,35575,35565,35571,35574,35580,35947,35949,35987,36084,36420,36401,36404,36418,36409,36405,36667,36655,36664,36659,36776,36774,36981,36980,36984,36978,36988,36986,37172,37266,37664,37686,37624,37683,37679,37666,37628,37675,37636,37658,37648,37670,37665,37653,37678,37657,38331,38567,38568,38570,38613,38670,38673,38678,38669,38675,38671,38747,38748,38758,38808,38960,38968,38971,38967,38957,38969,38948,39184,39208,39198,39195,39201,39194,39405,39394,39409,39608,39612,39675,39661,39720,39825,40213,40227,40230,40232,40210,40219,40664,40660,40845,40860,20778,20767,20769,20786,21237,22158,22144,22160,22149,22151,22159,22741,22739,22737,22734,23344,23338,23332,23418,23607,23656,23996,23994,23997,23992,24171,24396,24509,25033,25026,25031,25062,25035,25138,25140,25806,25802,25816,25824,25840,25830,25836,25841,25826,25837,25986,25987,26329,26326,27264,27284,27268,27298,27292,27355,27299,27262,27287,27280,27296,27484,27566,27610,27656,28632,28657,28639,28640,28635,28644,28651,28655,28544,28652,28641,28649,28629,28654,28656,29159,29151,29166,29158,29157,29165,29164,29172,29152,29237,29254,29552,29554,29865,29872,29862,29864,30278,30274,30284,30442,30643,30634,30640,30636,30631,30637,30703,30967,30970,30964,30959,30977,31143,31146,31319,31423,31751,31757,31742,31735,31756,31712,31968,31964,31966,31970,31967,31961,31965,32302,32318,32326,32311,32306,32323,32299,32317,32305,32325,32321,32308,32313,32328,32309,32319,32303,32580,32755,32764,32881,32882,32880,32879,32883,33222,33219,33210,33218,33216,33215,33213,33225,33214,33256,33289,33393,34218,34180,34174,34204,34193,34196,34223,34203,34183,34216,34186,34407,34752,34769,34739,34770,34758,34731,34747,34746,34760,34763,35131,35126,35140,35128,35133,35244,35598,35607,35609,35611,35594,35616,35613,35588,35600,35905,35903,35955,36090,36093,36092,36088,36091,36264,36425,36427,36424,36426,36676,36670,36674,36677,36671,36991,36989,36996,36993,36994,36992,37177,37283,37278,37276,37709,37762,37672,37749,37706,37733,37707,37656,37758,37740,37723,37744,37722,37716,38346,38347,38348,38344,38342,38577,38584,38614,38684,38686,38816,38867,38982,39094,39221,39425,39423,39854,39851,39850,39853,40251,40255,40587,40655,40670,40668,40669,40667,40766,40779,21474,22165,22190,22745,22744,23352,24413,25059,25139,25844,25842,25854,25862,25850,25851,25847,26039,26332,26406,27315,27308,27331,27323,27320,27330,27310,27311,27487,27512,27567,28681,28683,28670,28678,28666,28689,28687,29179,29180,29182,29176,29559,29557,29863,29887,29973,30294,30296,30290,30653,30655,30651,30652,30990,31150,31329,31330,31328,31428,31429,31787,31783,31786,31774,31779,31777,31975,32340,32341,32350,32346,32353,32338,32345,32584,32761,32763,32887,32886,33229,33231,33290,34255,34217,34253,34256,34249,34224,34234,34233,34214,34799,34796,34802,34784,35206,35250,35316,35624,35641,35628,35627,35920,36101,36441,36451,36454,36452,36447,36437,36544,36681,36685,36999,36995,37000,37291,37292,37328,37780,37770,37782,37794,37811,37806,37804,37808,37784,37786,37783,38356,38358,38352,38357,38626,38620,38617,38619,38622,38692,38819,38822,38829,38905,38989,38991,38988,38990,38995,39098,39230,39231,39229,39214,39333,39438,39617,39683,39686,39759,39758,39757,39882,39881,39933,39880,39872,40273,40285,40288,40672,40725,40748,20787,22181,22750,22751,22754,23541,40848,24300,25074,25079,25078,25077,25856,25871,26336,26333,27365,27357,27354,27347,28699,28703,28712,28698,28701,28693,28696,29190,29197,29272,29346,29560,29562,29885,29898,29923,30087,30086,30303,30305,30663,31001,31153,31339,31337,31806,31807,31800,31805,31799,31808,32363,32365,32377,32361,32362,32645,32371,32694,32697,32696,33240,34281,34269,34282,34261,34276,34277,34295,34811,34821,34829,34809,34814,35168,35167,35158,35166,35649,35676,35672,35657,35674,35662,35663,35654,35673,36104,36106,36476,36466,36487,36470,36460,36474,36468,36692,36686,36781,37002,37003,37297,37294,37857,37841,37855,37827,37832,37852,37853,37846,37858,37837,37848,37860,37847,37864,38364,38580,38627,38698,38695,38753,38876,38907,39006,39000,39003,39100,39237,39241,39446,39449,39693,39912,39911,39894,39899,40329,40289,40306,40298,40300,40594,40599,40595,40628,21240,22184,22199,22198,22196,22204,22756,23360,23363,23421,23542,24009,25080,25082,25880,25876,25881,26342,26407,27372,28734,28720,28722,29200,29563,29903,30306,30309,31014,31018,31020,31019,31431,31478,31820,31811,31821,31983,31984,36782,32381,32380,32386,32588,32768,33242,33382,34299,34297,34321,34298,34310,34315,34311,34314,34836,34837,35172,35258,35320,35696,35692,35686,35695,35679,35691,36111,36109,36489,36481,36485,36482,37300,37323,37912,37891,37885,38369,38704,39108,39250,39249,39336,39467,39472,39479,39477,39955,39949,40569,40629,40680,40751,40799,40803,40801,20791,20792,22209,22208,22210,22804,23660,24013,25084,25086,25885,25884,26005,26345,27387,27396,27386,27570,28748,29211,29351,29910,29908,30313,30675,31824,32399,32396,32700,34327,34349,34330,34851,34850,34849,34847,35178,35180,35261,35700,35703,35709,36115,36490,36493,36491,36703,36783,37306,37934,37939,37941,37946,37944,37938,37931,38370,38712,38713,38706,38911,39015,39013,39255,39493,39491,39488,39486,39631,39764,39761,39981,39973,40367,40372,40386,40376,40605,40687,40729,40796,40806,40807,20796,20795,22216,22218,22217,23423,24020,24018,24398,25087,25892,27402,27489,28753,28760,29568,29924,30090,30318,30316,31155,31840,31839,32894,32893,33247,35186,35183,35324,35712,36118,36119,36497,36499,36705,37192,37956,37969,37970,38717,38718,38851,38849,39019,39253,39509,39501,39634,39706,40009,39985,39998,39995,40403,40407,40756,40812,40810,40852,22220,24022,25088,25891,25899,25898,26348,27408,29914,31434,31844,31843,31845,32403,32406,32404,33250,34360,34367,34865,35722,37008,37007,37987,37984,37988,38760,39023,39260,39514,39515,39511,39635,39636,39633,40020,40023,40022,40421,40607,40692,22225,22761,25900,28766,30321,30322,30679,32592,32648,34870,34873,34914,35731,35730,35734,33399,36123,37312,37994,38722,38728,38724,38854,39024,39519,39714,39768,40031,40441,40442,40572,40573,40711,40823,40818,24307,27414,28771,31852,31854,34875,35264,36513,37313,38002,38000,39025,39262,39638,39715,40652,28772,30682,35738,38007,38857,39522,39525,32412,35740,36522,37317,38013,38014,38012,40055,40056,40695,35924,38015,40474,29224,39530,39729,40475,40478,31858,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,20022,20031,20101,20128,20866,20886,20907,21241,21304,21353,21430,22794,23424,24027,12083,24191,24308,24400,24417,25908,26080,30098,30326,36789,38582,168,710,12541,12542,12445,12446,12291,20189,12293,12294,12295,12540,65339,65341,10045,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,8679,8632,8633,12751,131276,20058,131210,20994,17553,40880,20872,40881,161287,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,65506,65508,65287,65282,12849,8470,8481,12443,12444,11904,11908,11910,11911,11912,11914,11916,11917,11925,11932,11933,11941,11943,11946,11948,11950,11958,11964,11966,11974,11978,11980,11981,11983,11990,11991,11998,12003,null,null,null,643,592,603,596,629,339,248,331,650,618,20034,20060,20981,21274,21378,19975,19980,20039,20109,22231,64012,23662,24435,19983,20871,19982,20014,20115,20162,20169,20168,20888,21244,21356,21433,22304,22787,22828,23568,24063,26081,27571,27596,27668,29247,20017,20028,20200,20188,20201,20193,20189,20186,21004,21276,21324,22306,22307,22807,22831,23425,23428,23570,23611,23668,23667,24068,24192,24194,24521,25097,25168,27669,27702,27715,27711,27707,29358,29360,29578,31160,32906,38430,20238,20248,20268,20213,20244,20209,20224,20215,20232,20253,20226,20229,20258,20243,20228,20212,20242,20913,21011,21001,21008,21158,21282,21279,21325,21386,21511,22241,22239,22318,22314,22324,22844,22912,22908,22917,22907,22910,22903,22911,23382,23573,23589,23676,23674,23675,23678,24031,24181,24196,24322,24346,24436,24533,24532,24527,25180,25182,25188,25185,25190,25186,25177,25184,25178,25189,26095,26094,26430,26425,26424,26427,26426,26431,26428,26419,27672,27718,27730,27740,27727,27722,27732,27723,27724,28785,29278,29364,29365,29582,29994,30335,31349,32593,33400,33404,33408,33405,33407,34381,35198,37017,37015,37016,37019,37012,38434,38436,38432,38435,20310,20283,20322,20297,20307,20324,20286,20327,20306,20319,20289,20312,20269,20275,20287,20321,20879,20921,21020,21022,21025,21165,21166,21257,21347,21362,21390,21391,21552,21559,21546,21588,21573,21529,21532,21541,21528,21565,21583,21569,21544,21540,21575,22254,22247,22245,22337,22341,22348,22345,22347,22354,22790,22848,22950,22936,22944,22935,22926,22946,22928,22927,22951,22945,23438,23442,23592,23594,23693,23695,23688,23691,23689,23698,23690,23686,23699,23701,24032,24074,24078,24203,24201,24204,24200,24205,24325,24349,24440,24438,24530,24529,24528,24557,24552,24558,24563,24545,24548,24547,24570,24559,24567,24571,24576,24564,25146,25219,25228,25230,25231,25236,25223,25201,25211,25210,25200,25217,25224,25207,25213,25202,25204,25911,26096,26100,26099,26098,26101,26437,26439,26457,26453,26444,26440,26461,26445,26458,26443,27600,27673,27674,27768,27751,27755,27780,27787,27791,27761,27759,27753,27802,27757,27783,27797,27804,27750,27763,27749,27771,27790,28788,28794,29283,29375,29373,29379,29382,29377,29370,29381,29589,29591,29587,29588,29586,30010,30009,30100,30101,30337,31037,32820,32917,32921,32912,32914,32924,33424,33423,33413,33422,33425,33427,33418,33411,33412,35960,36809,36799,37023,37025,37029,37022,37031,37024,38448,38440,38447,38445,20019,20376,20348,20357,20349,20352,20359,20342,20340,20361,20356,20343,20300,20375,20330,20378,20345,20353,20344,20368,20380,20372,20382,20370,20354,20373,20331,20334,20894,20924,20926,21045,21042,21043,21062,21041,21180,21258,21259,21308,21394,21396,21639,21631,21633,21649,21634,21640,21611,21626,21630,21605,21612,21620,21606,21645,21615,21601,21600,21656,21603,21607,21604,22263,22265,22383,22386,22381,22379,22385,22384,22390,22400,22389,22395,22387,22388,22370,22376,22397,22796,22853,22965,22970,22991,22990,22962,22988,22977,22966,22972,22979,22998,22961,22973,22976,22984,22964,22983,23394,23397,23443,23445,23620,23623,23726,23716,23712,23733,23727,23720,23724,23711,23715,23725,23714,23722,23719,23709,23717,23734,23728,23718,24087,24084,24089,24360,24354,24355,24356,24404,24450,24446,24445,24542,24549,24621,24614,24601,24626,24587,24628,24586,24599,24627,24602,24606,24620,24610,24589,24592,24622,24595,24593,24588,24585,24604,25108,25149,25261,25268,25297,25278,25258,25270,25290,25262,25267,25263,25275,25257,25264,25272,25917,26024,26043,26121,26108,26116,26130,26120,26107,26115,26123,26125,26117,26109,26129,26128,26358,26378,26501,26476,26510,26514,26486,26491,26520,26502,26500,26484,26509,26508,26490,26527,26513,26521,26499,26493,26497,26488,26489,26516,27429,27520,27518,27614,27677,27795,27884,27883,27886,27865,27830,27860,27821,27879,27831,27856,27842,27834,27843,27846,27885,27890,27858,27869,27828,27786,27805,27776,27870,27840,27952,27853,27847,27824,27897,27855,27881,27857,28820,28824,28805,28819,28806,28804,28817,28822,28802,28826,28803,29290,29398,29387,29400,29385,29404,29394,29396,29402,29388,29393,29604,29601,29613,29606,29602,29600,29612,29597,29917,29928,30015,30016,30014,30092,30104,30383,30451,30449,30448,30453,30712,30716,30713,30715,30714,30711,31042,31039,31173,31352,31355,31483,31861,31997,32821,32911,32942,32931,32952,32949,32941,33312,33440,33472,33451,33434,33432,33435,33461,33447,33454,33468,33438,33466,33460,33448,33441,33449,33474,33444,33475,33462,33442,34416,34415,34413,34414,35926,36818,36811,36819,36813,36822,36821,36823,37042,37044,37039,37043,37040,38457,38461,38460,38458,38467,20429,20421,20435,20402,20425,20427,20417,20436,20444,20441,20411,20403,20443,20423,20438,20410,20416,20409,20460,21060,21065,21184,21186,21309,21372,21399,21398,21401,21400,21690,21665,21677,21669,21711,21699,33549,21687,21678,21718,21686,21701,21702,21664,21616,21692,21666,21694,21618,21726,21680,22453,22430,22431,22436,22412,22423,22429,22427,22420,22424,22415,22425,22437,22426,22421,22772,22797,22867,23009,23006,23022,23040,23025,23005,23034,23037,23036,23030,23012,23026,23031,23003,23017,23027,23029,23008,23038,23028,23021,23464,23628,23760,23768,23756,23767,23755,23771,23774,23770,23753,23751,23754,23766,23763,23764,23759,23752,23750,23758,23775,23800,24057,24097,24098,24099,24096,24100,24240,24228,24226,24219,24227,24229,24327,24366,24406,24454,24631,24633,24660,24690,24670,24645,24659,24647,24649,24667,24652,24640,24642,24671,24612,24644,24664,24678,24686,25154,25155,25295,25357,25355,25333,25358,25347,25323,25337,25359,25356,25336,25334,25344,25363,25364,25338,25365,25339,25328,25921,25923,26026,26047,26166,26145,26162,26165,26140,26150,26146,26163,26155,26170,26141,26164,26169,26158,26383,26384,26561,26610,26568,26554,26588,26555,26616,26584,26560,26551,26565,26603,26596,26591,26549,26573,26547,26615,26614,26606,26595,26562,26553,26574,26599,26608,26546,26620,26566,26605,26572,26542,26598,26587,26618,26569,26570,26563,26602,26571,27432,27522,27524,27574,27606,27608,27616,27680,27681,27944,27956,27949,27935,27964,27967,27922,27914,27866,27955,27908,27929,27962,27930,27921,27904,27933,27970,27905,27928,27959,27907,27919,27968,27911,27936,27948,27912,27938,27913,27920,28855,28831,28862,28849,28848,28833,28852,28853,28841,29249,29257,29258,29292,29296,29299,29294,29386,29412,29416,29419,29407,29418,29414,29411,29573,29644,29634,29640,29637,29625,29622,29621,29620,29675,29631,29639,29630,29635,29638,29624,29643,29932,29934,29998,30023,30024,30119,30122,30329,30404,30472,30467,30468,30469,30474,30455,30459,30458,30695,30696,30726,30737,30738,30725,30736,30735,30734,30729,30723,30739,31050,31052,31051,31045,31044,31189,31181,31183,31190,31182,31360,31358,31441,31488,31489,31866,31864,31865,31871,31872,31873,32003,32008,32001,32600,32657,32653,32702,32775,32782,32783,32788,32823,32984,32967,32992,32977,32968,32962,32976,32965,32995,32985,32988,32970,32981,32969,32975,32983,32998,32973,33279,33313,33428,33497,33534,33529,33543,33512,33536,33493,33594,33515,33494,33524,33516,33505,33522,33525,33548,33531,33526,33520,33514,33508,33504,33530,33523,33517,34423,34420,34428,34419,34881,34894,34919,34922,34921,35283,35332,35335,36210,36835,36833,36846,36832,37105,37053,37055,37077,37061,37054,37063,37067,37064,37332,37331,38484,38479,38481,38483,38474,38478,20510,20485,20487,20499,20514,20528,20507,20469,20468,20531,20535,20524,20470,20471,20503,20508,20512,20519,20533,20527,20529,20494,20826,20884,20883,20938,20932,20933,20936,20942,21089,21082,21074,21086,21087,21077,21090,21197,21262,21406,21798,21730,21783,21778,21735,21747,21732,21786,21759,21764,21768,21739,21777,21765,21745,21770,21755,21751,21752,21728,21774,21763,21771,22273,22274,22476,22578,22485,22482,22458,22470,22461,22460,22456,22454,22463,22471,22480,22457,22465,22798,22858,23065,23062,23085,23086,23061,23055,23063,23050,23070,23091,23404,23463,23469,23468,23555,23638,23636,23788,23807,23790,23793,23799,23808,23801,24105,24104,24232,24238,24234,24236,24371,24368,24423,24669,24666,24679,24641,24738,24712,24704,24722,24705,24733,24707,24725,24731,24727,24711,24732,24718,25113,25158,25330,25360,25430,25388,25412,25413,25398,25411,25572,25401,25419,25418,25404,25385,25409,25396,25432,25428,25433,25389,25415,25395,25434,25425,25400,25431,25408,25416,25930,25926,26054,26051,26052,26050,26186,26207,26183,26193,26386,26387,26655,26650,26697,26674,26675,26683,26699,26703,26646,26673,26652,26677,26667,26669,26671,26702,26692,26676,26653,26642,26644,26662,26664,26670,26701,26682,26661,26656,27436,27439,27437,27441,27444,27501,32898,27528,27622,27620,27624,27619,27618,27623,27685,28026,28003,28004,28022,27917,28001,28050,27992,28002,28013,28015,28049,28045,28143,28031,28038,27998,28007,28000,28055,28016,28028,27999,28034,28056,27951,28008,28043,28030,28032,28036,27926,28035,28027,28029,28021,28048,28892,28883,28881,28893,28875,32569,28898,28887,28882,28894,28896,28884,28877,28869,28870,28871,28890,28878,28897,29250,29304,29303,29302,29440,29434,29428,29438,29430,29427,29435,29441,29651,29657,29669,29654,29628,29671,29667,29673,29660,29650,29659,29652,29661,29658,29655,29656,29672,29918,29919,29940,29941,29985,30043,30047,30128,30145,30139,30148,30144,30143,30134,30138,30346,30409,30493,30491,30480,30483,30482,30499,30481,30485,30489,30490,30498,30503,30755,30764,30754,30773,30767,30760,30766,30763,30753,30761,30771,30762,30769,31060,31067,31055,31068,31059,31058,31057,31211,31212,31200,31214,31213,31210,31196,31198,31197,31366,31369,31365,31371,31372,31370,31367,31448,31504,31492,31507,31493,31503,31496,31498,31502,31497,31506,31876,31889,31882,31884,31880,31885,31877,32030,32029,32017,32014,32024,32022,32019,32031,32018,32015,32012,32604,32609,32606,32608,32605,32603,32662,32658,32707,32706,32704,32790,32830,32825,33018,33010,33017,33013,33025,33019,33024,33281,33327,33317,33587,33581,33604,33561,33617,33573,33622,33599,33601,33574,33564,33570,33602,33614,33563,33578,33544,33596,33613,33558,33572,33568,33591,33583,33577,33607,33605,33612,33619,33566,33580,33611,33575,33608,34387,34386,34466,34472,34454,34445,34449,34462,34439,34455,34438,34443,34458,34437,34469,34457,34465,34471,34453,34456,34446,34461,34448,34452,34883,34884,34925,34933,34934,34930,34944,34929,34943,34927,34947,34942,34932,34940,35346,35911,35927,35963,36004,36003,36214,36216,36277,36279,36278,36561,36563,36862,36853,36866,36863,36859,36868,36860,36854,37078,37088,37081,37082,37091,37087,37093,37080,37083,37079,37084,37092,37200,37198,37199,37333,37346,37338,38492,38495,38588,39139,39647,39727,20095,20592,20586,20577,20574,20576,20563,20555,20573,20594,20552,20557,20545,20571,20554,20578,20501,20549,20575,20585,20587,20579,20580,20550,20544,20590,20595,20567,20561,20944,21099,21101,21100,21102,21206,21203,21293,21404,21877,21878,21820,21837,21840,21812,21802,21841,21858,21814,21813,21808,21842,21829,21772,21810,21861,21838,21817,21832,21805,21819,21824,21835,22282,22279,22523,22548,22498,22518,22492,22516,22528,22509,22525,22536,22520,22539,22515,22479,22535,22510,22499,22514,22501,22508,22497,22542,22524,22544,22503,22529,22540,22513,22505,22512,22541,22532,22876,23136,23128,23125,23143,23134,23096,23093,23149,23120,23135,23141,23148,23123,23140,23127,23107,23133,23122,23108,23131,23112,23182,23102,23117,23097,23116,23152,23145,23111,23121,23126,23106,23132,23410,23406,23489,23488,23641,23838,23819,23837,23834,23840,23820,23848,23821,23846,23845,23823,23856,23826,23843,23839,23854,24126,24116,24241,24244,24249,24242,24243,24374,24376,24475,24470,24479,24714,24720,24710,24766,24752,24762,24787,24788,24783,24804,24793,24797,24776,24753,24795,24759,24778,24767,24771,24781,24768,25394,25445,25482,25474,25469,25533,25502,25517,25501,25495,25515,25486,25455,25479,25488,25454,25519,25461,25500,25453,25518,25468,25508,25403,25503,25464,25477,25473,25489,25485,25456,25939,26061,26213,26209,26203,26201,26204,26210,26392,26745,26759,26768,26780,26733,26734,26798,26795,26966,26735,26787,26796,26793,26741,26740,26802,26767,26743,26770,26748,26731,26738,26794,26752,26737,26750,26779,26774,26763,26784,26761,26788,26744,26747,26769,26764,26762,26749,27446,27443,27447,27448,27537,27535,27533,27534,27532,27690,28096,28075,28084,28083,28276,28076,28137,28130,28087,28150,28116,28160,28104,28128,28127,28118,28094,28133,28124,28125,28123,28148,28106,28093,28141,28144,28090,28117,28098,28111,28105,28112,28146,28115,28157,28119,28109,28131,28091,28922,28941,28919,28951,28916,28940,28912,28932,28915,28944,28924,28927,28934,28947,28928,28920,28918,28939,28930,28942,29310,29307,29308,29311,29469,29463,29447,29457,29464,29450,29448,29439,29455,29470,29576,29686,29688,29685,29700,29697,29693,29703,29696,29690,29692,29695,29708,29707,29684,29704,30052,30051,30158,30162,30159,30155,30156,30161,30160,30351,30345,30419,30521,30511,30509,30513,30514,30516,30515,30525,30501,30523,30517,30792,30802,30793,30797,30794,30796,30758,30789,30800,31076,31079,31081,31082,31075,31083,31073,31163,31226,31224,31222,31223,31375,31380,31376,31541,31559,31540,31525,31536,31522,31524,31539,31512,31530,31517,31537,31531,31533,31535,31538,31544,31514,31523,31892,31896,31894,31907,32053,32061,32056,32054,32058,32069,32044,32041,32065,32071,32062,32063,32074,32059,32040,32611,32661,32668,32669,32667,32714,32715,32717,32720,32721,32711,32719,32713,32799,32798,32795,32839,32835,32840,33048,33061,33049,33051,33069,33055,33068,33054,33057,33045,33063,33053,33058,33297,33336,33331,33338,33332,33330,33396,33680,33699,33704,33677,33658,33651,33700,33652,33679,33665,33685,33689,33653,33684,33705,33661,33667,33676,33693,33691,33706,33675,33662,33701,33711,33672,33687,33712,33663,33702,33671,33710,33654,33690,34393,34390,34495,34487,34498,34497,34501,34490,34480,34504,34489,34483,34488,34508,34484,34491,34492,34499,34493,34494,34898,34953,34965,34984,34978,34986,34970,34961,34977,34975,34968,34983,34969,34971,34967,34980,34988,34956,34963,34958,35202,35286,35289,35285,35376,35367,35372,35358,35897,35899,35932,35933,35965,36005,36221,36219,36217,36284,36290,36281,36287,36289,36568,36574,36573,36572,36567,36576,36577,36900,36875,36881,36892,36876,36897,37103,37098,37104,37108,37106,37107,37076,37099,37100,37097,37206,37208,37210,37203,37205,37356,37364,37361,37363,37368,37348,37369,37354,37355,37367,37352,37358,38266,38278,38280,38524,38509,38507,38513,38511,38591,38762,38916,39141,39319,20635,20629,20628,20638,20619,20643,20611,20620,20622,20637,20584,20636,20626,20610,20615,20831,20948,21266,21265,21412,21415,21905,21928,21925,21933,21879,22085,21922,21907,21896,21903,21941,21889,21923,21906,21924,21885,21900,21926,21887,21909,21921,21902,22284,22569,22583,22553,22558,22567,22563,22568,22517,22600,22565,22556,22555,22579,22591,22582,22574,22585,22584,22573,22572,22587,22881,23215,23188,23199,23162,23202,23198,23160,23206,23164,23205,23212,23189,23214,23095,23172,23178,23191,23171,23179,23209,23163,23165,23180,23196,23183,23187,23197,23530,23501,23499,23508,23505,23498,23502,23564,23600,23863,23875,23915,23873,23883,23871,23861,23889,23886,23893,23859,23866,23890,23869,23857,23897,23874,23865,23881,23864,23868,23858,23862,23872,23877,24132,24129,24408,24486,24485,24491,24777,24761,24780,24802,24782,24772,24852,24818,24842,24854,24837,24821,24851,24824,24828,24830,24769,24835,24856,24861,24848,24831,24836,24843,25162,25492,25521,25520,25550,25573,25576,25583,25539,25757,25587,25546,25568,25590,25557,25586,25589,25697,25567,25534,25565,25564,25540,25560,25555,25538,25543,25548,25547,25544,25584,25559,25561,25906,25959,25962,25956,25948,25960,25957,25996,26013,26014,26030,26064,26066,26236,26220,26235,26240,26225,26233,26218,26226,26369,26892,26835,26884,26844,26922,26860,26858,26865,26895,26838,26871,26859,26852,26870,26899,26896,26867,26849,26887,26828,26888,26992,26804,26897,26863,26822,26900,26872,26832,26877,26876,26856,26891,26890,26903,26830,26824,26845,26846,26854,26868,26833,26886,26836,26857,26901,26917,26823,27449,27451,27455,27452,27540,27543,27545,27541,27581,27632,27634,27635,27696,28156,28230,28231,28191,28233,28296,28220,28221,28229,28258,28203,28223,28225,28253,28275,28188,28211,28235,28224,28241,28219,28163,28206,28254,28264,28252,28257,28209,28200,28256,28273,28267,28217,28194,28208,28243,28261,28199,28280,28260,28279,28245,28281,28242,28262,28213,28214,28250,28960,28958,28975,28923,28974,28977,28963,28965,28962,28978,28959,28968,28986,28955,29259,29274,29320,29321,29318,29317,29323,29458,29451,29488,29474,29489,29491,29479,29490,29485,29478,29475,29493,29452,29742,29740,29744,29739,29718,29722,29729,29741,29745,29732,29731,29725,29737,29728,29746,29947,29999,30063,30060,30183,30170,30177,30182,30173,30175,30180,30167,30357,30354,30426,30534,30535,30532,30541,30533,30538,30542,30539,30540,30686,30700,30816,30820,30821,30812,30829,30833,30826,30830,30832,30825,30824,30814,30818,31092,31091,31090,31088,31234,31242,31235,31244,31236,31385,31462,31460,31562,31547,31556,31560,31564,31566,31552,31576,31557,31906,31902,31912,31905,32088,32111,32099,32083,32086,32103,32106,32079,32109,32092,32107,32082,32084,32105,32081,32095,32078,32574,32575,32613,32614,32674,32672,32673,32727,32849,32847,32848,33022,32980,33091,33098,33106,33103,33095,33085,33101,33082,33254,33262,33271,33272,33273,33284,33340,33341,33343,33397,33595,33743,33785,33827,33728,33768,33810,33767,33764,33788,33782,33808,33734,33736,33771,33763,33727,33793,33757,33765,33752,33791,33761,33739,33742,33750,33781,33737,33801,33807,33758,33809,33798,33730,33779,33749,33786,33735,33745,33770,33811,33731,33772,33774,33732,33787,33751,33762,33819,33755,33790,34520,34530,34534,34515,34531,34522,34538,34525,34539,34524,34540,34537,34519,34536,34513,34888,34902,34901,35002,35031,35001,35000,35008,35006,34998,35004,34999,35005,34994,35073,35017,35221,35224,35223,35293,35290,35291,35406,35405,35385,35417,35392,35415,35416,35396,35397,35410,35400,35409,35402,35404,35407,35935,35969,35968,36026,36030,36016,36025,36021,36228,36224,36233,36312,36307,36301,36295,36310,36316,36303,36309,36313,36296,36311,36293,36591,36599,36602,36601,36582,36590,36581,36597,36583,36584,36598,36587,36593,36588,36596,36585,36909,36916,36911,37126,37164,37124,37119,37116,37128,37113,37115,37121,37120,37127,37125,37123,37217,37220,37215,37218,37216,37377,37386,37413,37379,37402,37414,37391,37388,37376,37394,37375,37373,37382,37380,37415,37378,37404,37412,37401,37399,37381,37398,38267,38285,38284,38288,38535,38526,38536,38537,38531,38528,38594,38600,38595,38641,38640,38764,38768,38766,38919,39081,39147,40166,40697,20099,20100,20150,20669,20671,20678,20654,20676,20682,20660,20680,20674,20656,20673,20666,20657,20683,20681,20662,20664,20951,21114,21112,21115,21116,21955,21979,21964,21968,21963,21962,21981,21952,21972,21956,21993,21951,21970,21901,21967,21973,21986,21974,21960,22002,21965,21977,21954,22292,22611,22632,22628,22607,22605,22601,22639,22613,22606,22621,22617,22629,22619,22589,22627,22641,22780,23239,23236,23243,23226,23224,23217,23221,23216,23231,23240,23227,23238,23223,23232,23242,23220,23222,23245,23225,23184,23510,23512,23513,23583,23603,23921,23907,23882,23909,23922,23916,23902,23912,23911,23906,24048,24143,24142,24138,24141,24139,24261,24268,24262,24267,24263,24384,24495,24493,24823,24905,24906,24875,24901,24886,24882,24878,24902,24879,24911,24873,24896,25120,37224,25123,25125,25124,25541,25585,25579,25616,25618,25609,25632,25636,25651,25667,25631,25621,25624,25657,25655,25634,25635,25612,25638,25648,25640,25665,25653,25647,25610,25626,25664,25637,25639,25611,25575,25627,25646,25633,25614,25967,26002,26067,26246,26252,26261,26256,26251,26250,26265,26260,26232,26400,26982,26975,26936,26958,26978,26993,26943,26949,26986,26937,26946,26967,26969,27002,26952,26953,26933,26988,26931,26941,26981,26864,27000,26932,26985,26944,26991,26948,26998,26968,26945,26996,26956,26939,26955,26935,26972,26959,26961,26930,26962,26927,27003,26940,27462,27461,27459,27458,27464,27457,27547,64013,27643,27644,27641,27639,27640,28315,28374,28360,28303,28352,28319,28307,28308,28320,28337,28345,28358,28370,28349,28353,28318,28361,28343,28336,28365,28326,28367,28338,28350,28355,28380,28376,28313,28306,28302,28301,28324,28321,28351,28339,28368,28362,28311,28334,28323,28999,29012,29010,29027,29024,28993,29021,29026,29042,29048,29034,29025,28994,29016,28995,29003,29040,29023,29008,29011,28996,29005,29018,29263,29325,29324,29329,29328,29326,29500,29506,29499,29498,29504,29514,29513,29764,29770,29771,29778,29777,29783,29760,29775,29776,29774,29762,29766,29773,29780,29921,29951,29950,29949,29981,30073,30071,27011,30191,30223,30211,30199,30206,30204,30201,30200,30224,30203,30198,30189,30197,30205,30361,30389,30429,30549,30559,30560,30546,30550,30554,30569,30567,30548,30553,30573,30688,30855,30874,30868,30863,30852,30869,30853,30854,30881,30851,30841,30873,30848,30870,30843,31100,31106,31101,31097,31249,31256,31257,31250,31255,31253,31266,31251,31259,31248,31395,31394,31390,31467,31590,31588,31597,31604,31593,31602,31589,31603,31601,31600,31585,31608,31606,31587,31922,31924,31919,32136,32134,32128,32141,32127,32133,32122,32142,32123,32131,32124,32140,32148,32132,32125,32146,32621,32619,32615,32616,32620,32678,32677,32679,32731,32732,32801,33124,33120,33143,33116,33129,33115,33122,33138,26401,33118,33142,33127,33135,33092,33121,33309,33353,33348,33344,33346,33349,34033,33855,33878,33910,33913,33935,33933,33893,33873,33856,33926,33895,33840,33869,33917,33882,33881,33908,33907,33885,34055,33886,33847,33850,33844,33914,33859,33912,33842,33861,33833,33753,33867,33839,33858,33837,33887,33904,33849,33870,33868,33874,33903,33989,33934,33851,33863,33846,33843,33896,33918,33860,33835,33888,33876,33902,33872,34571,34564,34551,34572,34554,34518,34549,34637,34552,34574,34569,34561,34550,34573,34565,35030,35019,35021,35022,35038,35035,35034,35020,35024,35205,35227,35295,35301,35300,35297,35296,35298,35292,35302,35446,35462,35455,35425,35391,35447,35458,35460,35445,35459,35457,35444,35450,35900,35915,35914,35941,35940,35942,35974,35972,35973,36044,36200,36201,36241,36236,36238,36239,36237,36243,36244,36240,36242,36336,36320,36332,36337,36334,36304,36329,36323,36322,36327,36338,36331,36340,36614,36607,36609,36608,36613,36615,36616,36610,36619,36946,36927,36932,36937,36925,37136,37133,37135,37137,37142,37140,37131,37134,37230,37231,37448,37458,37424,37434,37478,37427,37477,37470,37507,37422,37450,37446,37485,37484,37455,37472,37479,37487,37430,37473,37488,37425,37460,37475,37456,37490,37454,37459,37452,37462,37426,38303,38300,38302,38299,38546,38547,38545,38551,38606,38650,38653,38648,38645,38771,38775,38776,38770,38927,38925,38926,39084,39158,39161,39343,39346,39344,39349,39597,39595,39771,40170,40173,40167,40576,40701,20710,20692,20695,20712,20723,20699,20714,20701,20708,20691,20716,20720,20719,20707,20704,20952,21120,21121,21225,21227,21296,21420,22055,22037,22028,22034,22012,22031,22044,22017,22035,22018,22010,22045,22020,22015,22009,22665,22652,22672,22680,22662,22657,22655,22644,22667,22650,22663,22673,22670,22646,22658,22664,22651,22676,22671,22782,22891,23260,23278,23269,23253,23274,23258,23277,23275,23283,23266,23264,23259,23276,23262,23261,23257,23272,23263,23415,23520,23523,23651,23938,23936,23933,23942,23930,23937,23927,23946,23945,23944,23934,23932,23949,23929,23935,24152,24153,24147,24280,24273,24279,24270,24284,24277,24281,24274,24276,24388,24387,24431,24502,24876,24872,24897,24926,24945,24947,24914,24915,24946,24940,24960,24948,24916,24954,24923,24933,24891,24938,24929,24918,25129,25127,25131,25643,25677,25691,25693,25716,25718,25714,25715,25725,25717,25702,25766,25678,25730,25694,25692,25675,25683,25696,25680,25727,25663,25708,25707,25689,25701,25719,25971,26016,26273,26272,26271,26373,26372,26402,27057,27062,27081,27040,27086,27030,27056,27052,27068,27025,27033,27022,27047,27021,27049,27070,27055,27071,27076,27069,27044,27092,27065,27082,27034,27087,27059,27027,27050,27041,27038,27097,27031,27024,27074,27061,27045,27078,27466,27469,27467,27550,27551,27552,27587,27588,27646,28366,28405,28401,28419,28453,28408,28471,28411,28462,28425,28494,28441,28442,28455,28440,28475,28434,28397,28426,28470,28531,28409,28398,28461,28480,28464,28476,28469,28395,28423,28430,28483,28421,28413,28406,28473,28444,28412,28474,28447,28429,28446,28424,28449,29063,29072,29065,29056,29061,29058,29071,29051,29062,29057,29079,29252,29267,29335,29333,29331,29507,29517,29521,29516,29794,29811,29809,29813,29810,29799,29806,29952,29954,29955,30077,30096,30230,30216,30220,30229,30225,30218,30228,30392,30593,30588,30597,30594,30574,30592,30575,30590,30595,30898,30890,30900,30893,30888,30846,30891,30878,30885,30880,30892,30882,30884,31128,31114,31115,31126,31125,31124,31123,31127,31112,31122,31120,31275,31306,31280,31279,31272,31270,31400,31403,31404,31470,31624,31644,31626,31633,31632,31638,31629,31628,31643,31630,31621,31640,21124,31641,31652,31618,31931,31935,31932,31930,32167,32183,32194,32163,32170,32193,32192,32197,32157,32206,32196,32198,32203,32204,32175,32185,32150,32188,32159,32166,32174,32169,32161,32201,32627,32738,32739,32741,32734,32804,32861,32860,33161,33158,33155,33159,33165,33164,33163,33301,33943,33956,33953,33951,33978,33998,33986,33964,33966,33963,33977,33972,33985,33997,33962,33946,33969,34000,33949,33959,33979,33954,33940,33991,33996,33947,33961,33967,33960,34006,33944,33974,33999,33952,34007,34004,34002,34011,33968,33937,34401,34611,34595,34600,34667,34624,34606,34590,34593,34585,34587,34627,34604,34625,34622,34630,34592,34610,34602,34605,34620,34578,34618,34609,34613,34626,34598,34599,34616,34596,34586,34608,34577,35063,35047,35057,35058,35066,35070,35054,35068,35062,35067,35056,35052,35051,35229,35233,35231,35230,35305,35307,35304,35499,35481,35467,35474,35471,35478,35901,35944,35945,36053,36047,36055,36246,36361,36354,36351,36365,36349,36362,36355,36359,36358,36357,36350,36352,36356,36624,36625,36622,36621,37155,37148,37152,37154,37151,37149,37146,37156,37153,37147,37242,37234,37241,37235,37541,37540,37494,37531,37498,37536,37524,37546,37517,37542,37530,37547,37497,37527,37503,37539,37614,37518,37506,37525,37538,37501,37512,37537,37514,37510,37516,37529,37543,37502,37511,37545,37533,37515,37421,38558,38561,38655,38744,38781,38778,38782,38787,38784,38786,38779,38788,38785,38783,38862,38861,38934,39085,39086,39170,39168,39175,39325,39324,39363,39353,39355,39354,39362,39357,39367,39601,39651,39655,39742,39743,39776,39777,39775,40177,40178,40181,40615,20735,20739,20784,20728,20742,20743,20726,20734,20747,20748,20733,20746,21131,21132,21233,21231,22088,22082,22092,22069,22081,22090,22089,22086,22104,22106,22080,22067,22077,22060,22078,22072,22058,22074,22298,22699,22685,22705,22688,22691,22703,22700,22693,22689,22783,23295,23284,23293,23287,23286,23299,23288,23298,23289,23297,23303,23301,23311,23655,23961,23959,23967,23954,23970,23955,23957,23968,23964,23969,23962,23966,24169,24157,24160,24156,32243,24283,24286,24289,24393,24498,24971,24963,24953,25009,25008,24994,24969,24987,24979,25007,25005,24991,24978,25002,24993,24973,24934,25011,25133,25710,25712,25750,25760,25733,25751,25756,25743,25739,25738,25740,25763,25759,25704,25777,25752,25974,25978,25977,25979,26034,26035,26293,26288,26281,26290,26295,26282,26287,27136,27142,27159,27109,27128,27157,27121,27108,27168,27135,27116,27106,27163,27165,27134,27175,27122,27118,27156,27127,27111,27200,27144,27110,27131,27149,27132,27115,27145,27140,27160,27173,27151,27126,27174,27143,27124,27158,27473,27557,27555,27554,27558,27649,27648,27647,27650,28481,28454,28542,28551,28614,28562,28557,28553,28556,28514,28495,28549,28506,28566,28534,28524,28546,28501,28530,28498,28496,28503,28564,28563,28509,28416,28513,28523,28541,28519,28560,28499,28555,28521,28543,28565,28515,28535,28522,28539,29106,29103,29083,29104,29088,29082,29097,29109,29085,29093,29086,29092,29089,29098,29084,29095,29107,29336,29338,29528,29522,29534,29535,29536,29533,29531,29537,29530,29529,29538,29831,29833,29834,29830,29825,29821,29829,29832,29820,29817,29960,29959,30078,30245,30238,30233,30237,30236,30243,30234,30248,30235,30364,30365,30366,30363,30605,30607,30601,30600,30925,30907,30927,30924,30929,30926,30932,30920,30915,30916,30921,31130,31137,31136,31132,31138,31131,27510,31289,31410,31412,31411,31671,31691,31678,31660,31694,31663,31673,31690,31669,31941,31944,31948,31947,32247,32219,32234,32231,32215,32225,32259,32250,32230,32246,32241,32240,32238,32223,32630,32684,32688,32685,32749,32747,32746,32748,32742,32744,32868,32871,33187,33183,33182,33173,33186,33177,33175,33302,33359,33363,33362,33360,33358,33361,34084,34107,34063,34048,34089,34062,34057,34061,34079,34058,34087,34076,34043,34091,34042,34056,34060,34036,34090,34034,34069,34039,34027,34035,34044,34066,34026,34025,34070,34046,34088,34077,34094,34050,34045,34078,34038,34097,34086,34023,34024,34032,34031,34041,34072,34080,34096,34059,34073,34095,34402,34646,34659,34660,34679,34785,34675,34648,34644,34651,34642,34657,34650,34641,34654,34669,34666,34640,34638,34655,34653,34671,34668,34682,34670,34652,34661,34639,34683,34677,34658,34663,34665,34906,35077,35084,35092,35083,35095,35096,35097,35078,35094,35089,35086,35081,35234,35236,35235,35309,35312,35308,35535,35526,35512,35539,35537,35540,35541,35515,35543,35518,35520,35525,35544,35523,35514,35517,35545,35902,35917,35983,36069,36063,36057,36072,36058,36061,36071,36256,36252,36257,36251,36384,36387,36389,36388,36398,36373,36379,36374,36369,36377,36390,36391,36372,36370,36376,36371,36380,36375,36378,36652,36644,36632,36634,36640,36643,36630,36631,36979,36976,36975,36967,36971,37167,37163,37161,37162,37170,37158,37166,37253,37254,37258,37249,37250,37252,37248,37584,37571,37572,37568,37593,37558,37583,37617,37599,37592,37609,37591,37597,37580,37615,37570,37608,37578,37576,37582,37606,37581,37589,37577,37600,37598,37607,37585,37587,37557,37601,37574,37556,38268,38316,38315,38318,38320,38564,38562,38611,38661,38664,38658,38746,38794,38798,38792,38864,38863,38942,38941,38950,38953,38952,38944,38939,38951,39090,39176,39162,39185,39188,39190,39191,39189,39388,39373,39375,39379,39380,39374,39369,39382,39384,39371,39383,39372,39603,39660,39659,39667,39666,39665,39750,39747,39783,39796,39793,39782,39798,39797,39792,39784,39780,39788,40188,40186,40189,40191,40183,40199,40192,40185,40187,40200,40197,40196,40579,40659,40719,40720,20764,20755,20759,20762,20753,20958,21300,21473,22128,22112,22126,22131,22118,22115,22125,22130,22110,22135,22300,22299,22728,22717,22729,22719,22714,22722,22716,22726,23319,23321,23323,23329,23316,23315,23312,23318,23336,23322,23328,23326,23535,23980,23985,23977,23975,23989,23984,23982,23978,23976,23986,23981,23983,23988,24167,24168,24166,24175,24297,24295,24294,24296,24293,24395,24508,24989,25000,24982,25029,25012,25030,25025,25036,25018,25023,25016,24972,25815,25814,25808,25807,25801,25789,25737,25795,25819,25843,25817,25907,25983,25980,26018,26312,26302,26304,26314,26315,26319,26301,26299,26298,26316,26403,27188,27238,27209,27239,27186,27240,27198,27229,27245,27254,27227,27217,27176,27226,27195,27199,27201,27242,27236,27216,27215,27220,27247,27241,27232,27196,27230,27222,27221,27213,27214,27206,27477,27476,27478,27559,27562,27563,27592,27591,27652,27651,27654,28589,28619,28579,28615,28604,28622,28616,28510,28612,28605,28574,28618,28584,28676,28581,28590,28602,28588,28586,28623,28607,28600,28578,28617,28587,28621,28591,28594,28592,29125,29122,29119,29112,29142,29120,29121,29131,29140,29130,29127,29135,29117,29144,29116,29126,29146,29147,29341,29342,29545,29542,29543,29548,29541,29547,29546,29823,29850,29856,29844,29842,29845,29857,29963,30080,30255,30253,30257,30269,30259,30268,30261,30258,30256,30395,30438,30618,30621,30625,30620,30619,30626,30627,30613,30617,30615,30941,30953,30949,30954,30942,30947,30939,30945,30946,30957,30943,30944,31140,31300,31304,31303,31414,31416,31413,31409,31415,31710,31715,31719,31709,31701,31717,31706,31720,31737,31700,31722,31714,31708,31723,31704,31711,31954,31956,31959,31952,31953,32274,32289,32279,32268,32287,32288,32275,32270,32284,32277,32282,32290,32267,32271,32278,32269,32276,32293,32292,32579,32635,32636,32634,32689,32751,32810,32809,32876,33201,33190,33198,33209,33205,33195,33200,33196,33204,33202,33207,33191,33266,33365,33366,33367,34134,34117,34155,34125,34131,34145,34136,34112,34118,34148,34113,34146,34116,34129,34119,34147,34110,34139,34161,34126,34158,34165,34133,34151,34144,34188,34150,34141,34132,34149,34156,34403,34405,34404,34715,34703,34711,34707,34706,34696,34689,34710,34712,34681,34695,34723,34693,34704,34705,34717,34692,34708,34716,34714,34697,35102,35110,35120,35117,35118,35111,35121,35106,35113,35107,35119,35116,35103,35313,35552,35554,35570,35572,35573,35549,35604,35556,35551,35568,35528,35550,35553,35560,35583,35567,35579,35985,35986,35984,36085,36078,36081,36080,36083,36204,36206,36261,36263,36403,36414,36408,36416,36421,36406,36412,36413,36417,36400,36415,36541,36662,36654,36661,36658,36665,36663,36660,36982,36985,36987,36998,37114,37171,37173,37174,37267,37264,37265,37261,37263,37671,37662,37640,37663,37638,37647,37754,37688,37692,37659,37667,37650,37633,37702,37677,37646,37645,37579,37661,37626,37669,37651,37625,37623,37684,37634,37668,37631,37673,37689,37685,37674,37652,37644,37643,37630,37641,37632,37627,37654,38332,38349,38334,38329,38330,38326,38335,38325,38333,38569,38612,38667,38674,38672,38809,38807,38804,38896,38904,38965,38959,38962,39204,39199,39207,39209,39326,39406,39404,39397,39396,39408,39395,39402,39401,39399,39609,39615,39604,39611,39670,39674,39673,39671,39731,39808,39813,39815,39804,39806,39803,39810,39827,39826,39824,39802,39829,39805,39816,40229,40215,40224,40222,40212,40233,40221,40216,40226,40208,40217,40223,40584,40582,40583,40622,40621,40661,40662,40698,40722,40765,20774,20773,20770,20772,20768,20777,21236,22163,22156,22157,22150,22148,22147,22142,22146,22143,22145,22742,22740,22735,22738,23341,23333,23346,23331,23340,23335,23334,23343,23342,23419,23537,23538,23991,24172,24170,24510,24507,25027,25013,25020,25063,25056,25061,25060,25064,25054,25839,25833,25827,25835,25828,25832,25985,25984,26038,26074,26322,27277,27286,27265,27301,27273,27295,27291,27297,27294,27271,27283,27278,27285,27267,27304,27300,27281,27263,27302,27290,27269,27276,27282,27483,27565,27657,28620,28585,28660,28628,28643,28636,28653,28647,28646,28638,28658,28637,28642,28648,29153,29169,29160,29170,29156,29168,29154,29555,29550,29551,29847,29874,29867,29840,29866,29869,29873,29861,29871,29968,29969,29970,29967,30084,30275,30280,30281,30279,30372,30441,30645,30635,30642,30647,30646,30644,30641,30632,30704,30963,30973,30978,30971,30972,30962,30981,30969,30974,30980,31147,31144,31324,31323,31318,31320,31316,31322,31422,31424,31425,31749,31759,31730,31744,31743,31739,31758,31732,31755,31731,31746,31753,31747,31745,31736,31741,31750,31728,31729,31760,31754,31976,32301,32316,32322,32307,38984,32312,32298,32329,32320,32327,32297,32332,32304,32315,32310,32324,32314,32581,32639,32638,32637,32756,32754,32812,33211,33220,33228,33226,33221,33223,33212,33257,33371,33370,33372,34179,34176,34191,34215,34197,34208,34187,34211,34171,34212,34202,34206,34167,34172,34185,34209,34170,34168,34135,34190,34198,34182,34189,34201,34205,34177,34210,34178,34184,34181,34169,34166,34200,34192,34207,34408,34750,34730,34733,34757,34736,34732,34745,34741,34748,34734,34761,34755,34754,34764,34743,34735,34756,34762,34740,34742,34751,34744,34749,34782,34738,35125,35123,35132,35134,35137,35154,35127,35138,35245,35247,35246,35314,35315,35614,35608,35606,35601,35589,35595,35618,35599,35602,35605,35591,35597,35592,35590,35612,35603,35610,35919,35952,35954,35953,35951,35989,35988,36089,36207,36430,36429,36435,36432,36428,36423,36675,36672,36997,36990,37176,37274,37282,37275,37273,37279,37281,37277,37280,37793,37763,37807,37732,37718,37703,37756,37720,37724,37750,37705,37712,37713,37728,37741,37775,37708,37738,37753,37719,37717,37714,37711,37745,37751,37755,37729,37726,37731,37735,37760,37710,37721,38343,38336,38345,38339,38341,38327,38574,38576,38572,38688,38687,38680,38685,38681,38810,38817,38812,38814,38813,38869,38868,38897,38977,38980,38986,38985,38981,38979,39205,39211,39212,39210,39219,39218,39215,39213,39217,39216,39320,39331,39329,39426,39418,39412,39415,39417,39416,39414,39419,39421,39422,39420,39427,39614,39678,39677,39681,39676,39752,39834,39848,39838,39835,39846,39841,39845,39844,39814,39842,39840,39855,40243,40257,40295,40246,40238,40239,40241,40248,40240,40261,40258,40259,40254,40247,40256,40253,32757,40237,40586,40585,40589,40624,40648,40666,40699,40703,40740,40739,40738,40788,40864,20785,20781,20782,22168,22172,22167,22170,22173,22169,22896,23356,23657,23658,24000,24173,24174,25048,25055,25069,25070,25073,25066,25072,25067,25046,25065,25855,25860,25853,25848,25857,25859,25852,26004,26075,26330,26331,26328,27333,27321,27325,27361,27334,27322,27318,27319,27335,27316,27309,27486,27593,27659,28679,28684,28685,28673,28677,28692,28686,28671,28672,28667,28710,28668,28663,28682,29185,29183,29177,29187,29181,29558,29880,29888,29877,29889,29886,29878,29883,29890,29972,29971,30300,30308,30297,30288,30291,30295,30298,30374,30397,30444,30658,30650,30975,30988,30995,30996,30985,30992,30994,30993,31149,31148,31327,31772,31785,31769,31776,31775,31789,31773,31782,31784,31778,31781,31792,32348,32336,32342,32355,32344,32354,32351,32337,32352,32343,32339,32693,32691,32759,32760,32885,33233,33234,33232,33375,33374,34228,34246,34240,34243,34242,34227,34229,34237,34247,34244,34239,34251,34254,34248,34245,34225,34230,34258,34340,34232,34231,34238,34409,34791,34790,34786,34779,34795,34794,34789,34783,34803,34788,34772,34780,34771,34797,34776,34787,34724,34775,34777,34817,34804,34792,34781,35155,35147,35151,35148,35142,35152,35153,35145,35626,35623,35619,35635,35632,35637,35655,35631,35644,35646,35633,35621,35639,35622,35638,35630,35620,35643,35645,35642,35906,35957,35993,35992,35991,36094,36100,36098,36096,36444,36450,36448,36439,36438,36446,36453,36455,36443,36442,36449,36445,36457,36436,36678,36679,36680,36683,37160,37178,37179,37182,37288,37285,37287,37295,37290,37813,37772,37778,37815,37787,37789,37769,37799,37774,37802,37790,37798,37781,37768,37785,37791,37773,37809,37777,37810,37796,37800,37812,37795,37797,38354,38355,38353,38579,38615,38618,24002,38623,38616,38621,38691,38690,38693,38828,38830,38824,38827,38820,38826,38818,38821,38871,38873,38870,38872,38906,38992,38993,38994,39096,39233,39228,39226,39439,39435,39433,39437,39428,39441,39434,39429,39431,39430,39616,39644,39688,39684,39685,39721,39733,39754,39756,39755,39879,39878,39875,39871,39873,39861,39864,39891,39862,39876,39865,39869,40284,40275,40271,40266,40283,40267,40281,40278,40268,40279,40274,40276,40287,40280,40282,40590,40588,40671,40705,40704,40726,40741,40747,40746,40745,40744,40780,40789,20788,20789,21142,21239,21428,22187,22189,22182,22183,22186,22188,22746,22749,22747,22802,23357,23358,23359,24003,24176,24511,25083,25863,25872,25869,25865,25868,25870,25988,26078,26077,26334,27367,27360,27340,27345,27353,27339,27359,27356,27344,27371,27343,27341,27358,27488,27568,27660,28697,28711,28704,28694,28715,28705,28706,28707,28713,28695,28708,28700,28714,29196,29194,29191,29186,29189,29349,29350,29348,29347,29345,29899,29893,29879,29891,29974,30304,30665,30666,30660,30705,31005,31003,31009,31004,30999,31006,31152,31335,31336,31795,31804,31801,31788,31803,31980,31978,32374,32373,32376,32368,32375,32367,32378,32370,32372,32360,32587,32586,32643,32646,32695,32765,32766,32888,33239,33237,33380,33377,33379,34283,34289,34285,34265,34273,34280,34266,34263,34284,34290,34296,34264,34271,34275,34268,34257,34288,34278,34287,34270,34274,34816,34810,34819,34806,34807,34825,34828,34827,34822,34812,34824,34815,34826,34818,35170,35162,35163,35159,35169,35164,35160,35165,35161,35208,35255,35254,35318,35664,35656,35658,35648,35667,35670,35668,35659,35669,35665,35650,35666,35671,35907,35959,35958,35994,36102,36103,36105,36268,36266,36269,36267,36461,36472,36467,36458,36463,36475,36546,36690,36689,36687,36688,36691,36788,37184,37183,37296,37293,37854,37831,37839,37826,37850,37840,37881,37868,37836,37849,37801,37862,37834,37844,37870,37859,37845,37828,37838,37824,37842,37863,38269,38362,38363,38625,38697,38699,38700,38696,38694,38835,38839,38838,38877,38878,38879,39004,39001,39005,38999,39103,39101,39099,39102,39240,39239,39235,39334,39335,39450,39445,39461,39453,39460,39451,39458,39456,39463,39459,39454,39452,39444,39618,39691,39690,39694,39692,39735,39914,39915,39904,39902,39908,39910,39906,39920,39892,39895,39916,39900,39897,39909,39893,39905,39898,40311,40321,40330,40324,40328,40305,40320,40312,40326,40331,40332,40317,40299,40308,40309,40304,40297,40325,40307,40315,40322,40303,40313,40319,40327,40296,40596,40593,40640,40700,40749,40768,40769,40781,40790,40791,40792,21303,22194,22197,22195,22755,23365,24006,24007,24302,24303,24512,24513,25081,25879,25878,25877,25875,26079,26344,26339,26340,27379,27376,27370,27368,27385,27377,27374,27375,28732,28725,28719,28727,28724,28721,28738,28728,28735,28730,28729,28736,28731,28723,28737,29203,29204,29352,29565,29564,29882,30379,30378,30398,30445,30668,30670,30671,30669,30706,31013,31011,31015,31016,31012,31017,31154,31342,31340,31341,31479,31817,31816,31818,31815,31813,31982,32379,32382,32385,32384,32698,32767,32889,33243,33241,33291,33384,33385,34338,34303,34305,34302,34331,34304,34294,34308,34313,34309,34316,34301,34841,34832,34833,34839,34835,34838,35171,35174,35257,35319,35680,35690,35677,35688,35683,35685,35687,35693,36270,36486,36488,36484,36697,36694,36695,36693,36696,36698,37005,37187,37185,37303,37301,37298,37299,37899,37907,37883,37920,37903,37908,37886,37909,37904,37928,37913,37901,37877,37888,37879,37895,37902,37910,37906,37882,37897,37880,37898,37887,37884,37900,37878,37905,37894,38366,38368,38367,38702,38703,38841,38843,38909,38910,39008,39010,39011,39007,39105,39106,39248,39246,39257,39244,39243,39251,39474,39476,39473,39468,39466,39478,39465,39470,39480,39469,39623,39626,39622,39696,39698,39697,39947,39944,39927,39941,39954,39928,40000,39943,39950,39942,39959,39956,39945,40351,40345,40356,40349,40338,40344,40336,40347,40352,40340,40348,40362,40343,40353,40346,40354,40360,40350,40355,40383,40361,40342,40358,40359,40601,40603,40602,40677,40676,40679,40678,40752,40750,40795,40800,40798,40797,40793,40849,20794,20793,21144,21143,22211,22205,22206,23368,23367,24011,24015,24305,25085,25883,27394,27388,27395,27384,27392,28739,28740,28746,28744,28745,28741,28742,29213,29210,29209,29566,29975,30314,30672,31021,31025,31023,31828,31827,31986,32394,32391,32392,32395,32390,32397,32589,32699,32816,33245,34328,34346,34342,34335,34339,34332,34329,34343,34350,34337,34336,34345,34334,34341,34857,34845,34843,34848,34852,34844,34859,34890,35181,35177,35182,35179,35322,35705,35704,35653,35706,35707,36112,36116,36271,36494,36492,36702,36699,36701,37190,37188,37189,37305,37951,37947,37942,37929,37949,37948,37936,37945,37930,37943,37932,37952,37937,38373,38372,38371,38709,38714,38847,38881,39012,39113,39110,39104,39256,39254,39481,39485,39494,39492,39490,39489,39482,39487,39629,39701,39703,39704,39702,39738,39762,39979,39965,39964,39980,39971,39976,39977,39972,39969,40375,40374,40380,40385,40391,40394,40399,40382,40389,40387,40379,40373,40398,40377,40378,40364,40392,40369,40365,40396,40371,40397,40370,40570,40604,40683,40686,40685,40731,40728,40730,40753,40782,40805,40804,40850,20153,22214,22213,22219,22897,23371,23372,24021,24017,24306,25889,25888,25894,25890,27403,27400,27401,27661,28757,28758,28759,28754,29214,29215,29353,29567,29912,29909,29913,29911,30317,30381,31029,31156,31344,31345,31831,31836,31833,31835,31834,31988,31985,32401,32591,32647,33246,33387,34356,34357,34355,34348,34354,34358,34860,34856,34854,34858,34853,35185,35263,35262,35323,35710,35716,35714,35718,35717,35711,36117,36501,36500,36506,36498,36496,36502,36503,36704,36706,37191,37964,37968,37962,37963,37967,37959,37957,37960,37961,37958,38719,38883,39018,39017,39115,39252,39259,39502,39507,39508,39500,39503,39496,39498,39497,39506,39504,39632,39705,39723,39739,39766,39765,40006,40008,39999,40004,39993,39987,40001,39996,39991,39988,39986,39997,39990,40411,40402,40414,40410,40395,40400,40412,40401,40415,40425,40409,40408,40406,40437,40405,40413,40630,40688,40757,40755,40754,40770,40811,40853,40866,20797,21145,22760,22759,22898,23373,24024,34863,24399,25089,25091,25092,25897,25893,26006,26347,27409,27410,27407,27594,28763,28762,29218,29570,29569,29571,30320,30676,31847,31846,32405,33388,34362,34368,34361,34364,34353,34363,34366,34864,34866,34862,34867,35190,35188,35187,35326,35724,35726,35723,35720,35909,36121,36504,36708,36707,37308,37986,37973,37981,37975,37982,38852,38853,38912,39510,39513,39710,39711,39712,40018,40024,40016,40010,40013,40011,40021,40025,40012,40014,40443,40439,40431,40419,40427,40440,40420,40438,40417,40430,40422,40434,40432,40418,40428,40436,40435,40424,40429,40642,40656,40690,40691,40710,40732,40760,40759,40758,40771,40783,40817,40816,40814,40815,22227,22221,23374,23661,25901,26349,26350,27411,28767,28769,28765,28768,29219,29915,29925,30677,31032,31159,31158,31850,32407,32649,33389,34371,34872,34871,34869,34891,35732,35733,36510,36511,36512,36509,37310,37309,37314,37995,37992,37993,38629,38726,38723,38727,38855,38885,39518,39637,39769,40035,40039,40038,40034,40030,40032,40450,40446,40455,40451,40454,40453,40448,40449,40457,40447,40445,40452,40608,40734,40774,40820,40821,40822,22228,25902,26040,27416,27417,27415,27418,28770,29222,29354,30680,30681,31033,31849,31851,31990,32410,32408,32411,32409,33248,33249,34374,34375,34376,35193,35194,35196,35195,35327,35736,35737,36517,36516,36515,37998,37997,37999,38001,38003,38729,39026,39263,40040,40046,40045,40459,40461,40464,40463,40466,40465,40609,40693,40713,40775,40824,40827,40826,40825,22302,28774,31855,34876,36274,36518,37315,38004,38008,38006,38005,39520,40052,40051,40049,40053,40468,40467,40694,40714,40868,28776,28773,31991,34410,34878,34877,34879,35742,35996,36521,36553,38731,39027,39028,39116,39265,39339,39524,39526,39527,39716,40469,40471,40776,25095,27422,29223,34380,36520,38018,38016,38017,39529,39528,39726,40473,29225,34379,35743,38019,40057,40631,30325,39531,40058,40477,28777,28778,40612,40830,40777,40856,30849,37561,35023,22715,24658,31911,23290,9556,9574,9559,9568,9580,9571,9562,9577,9565,9554,9572,9557,9566,9578,9569,9560,9575,9563,9555,9573,9558,9567,9579,9570,9561,9576,9564,9553,9552,9581,9582,9584,9583,65517,132423,37595,132575,147397,34124,17077,29679,20917,13897,149826,166372,37700,137691,33518,146632,30780,26436,25311,149811,166314,131744,158643,135941,20395,140525,20488,159017,162436,144896,150193,140563,20521,131966,24484,131968,131911,28379,132127,20605,20737,13434,20750,39020,14147,33814,149924,132231,20832,144308,20842,134143,139516,131813,140592,132494,143923,137603,23426,34685,132531,146585,20914,20920,40244,20937,20943,20945,15580,20947,150182,20915,20962,21314,20973,33741,26942,145197,24443,21003,21030,21052,21173,21079,21140,21177,21189,31765,34114,21216,34317,158483,21253,166622,21833,28377,147328,133460,147436,21299,21316,134114,27851,136998,26651,29653,24650,16042,14540,136936,29149,17570,21357,21364,165547,21374,21375,136598,136723,30694,21395,166555,21408,21419,21422,29607,153458,16217,29596,21441,21445,27721,20041,22526,21465,15019,134031,21472,147435,142755,21494,134263,21523,28793,21803,26199,27995,21613,158547,134516,21853,21647,21668,18342,136973,134877,15796,134477,166332,140952,21831,19693,21551,29719,21894,21929,22021,137431,147514,17746,148533,26291,135348,22071,26317,144010,26276,26285,22093,22095,30961,22257,38791,21502,22272,22255,22253,166758,13859,135759,22342,147877,27758,28811,22338,14001,158846,22502,136214,22531,136276,148323,22566,150517,22620,22698,13665,22752,22748,135740,22779,23551,22339,172368,148088,37843,13729,22815,26790,14019,28249,136766,23076,21843,136850,34053,22985,134478,158849,159018,137180,23001,137211,137138,159142,28017,137256,136917,23033,159301,23211,23139,14054,149929,23159,14088,23190,29797,23251,159649,140628,15749,137489,14130,136888,24195,21200,23414,25992,23420,162318,16388,18525,131588,23509,24928,137780,154060,132517,23539,23453,19728,23557,138052,23571,29646,23572,138405,158504,23625,18653,23685,23785,23791,23947,138745,138807,23824,23832,23878,138916,23738,24023,33532,14381,149761,139337,139635,33415,14390,15298,24110,27274,24181,24186,148668,134355,21414,20151,24272,21416,137073,24073,24308,164994,24313,24315,14496,24316,26686,37915,24333,131521,194708,15070,18606,135994,24378,157832,140240,24408,140401,24419,38845,159342,24434,37696,166454,24487,23990,15711,152144,139114,159992,140904,37334,131742,166441,24625,26245,137335,14691,15815,13881,22416,141236,31089,15936,24734,24740,24755,149890,149903,162387,29860,20705,23200,24932,33828,24898,194726,159442,24961,20980,132694,24967,23466,147383,141407,25043,166813,170333,25040,14642,141696,141505,24611,24924,25886,25483,131352,25285,137072,25301,142861,25452,149983,14871,25656,25592,136078,137212,25744,28554,142902,38932,147596,153373,25825,25829,38011,14950,25658,14935,25933,28438,150056,150051,25989,25965,25951,143486,26037,149824,19255,26065,16600,137257,26080,26083,24543,144384,26136,143863,143864,26180,143780,143781,26187,134773,26215,152038,26227,26228,138813,143921,165364,143816,152339,30661,141559,39332,26370,148380,150049,15147,27130,145346,26462,26471,26466,147917,168173,26583,17641,26658,28240,37436,26625,144358,159136,26717,144495,27105,27147,166623,26995,26819,144845,26881,26880,15666,14849,144956,15232,26540,26977,166474,17148,26934,27032,15265,132041,33635,20624,27129,144985,139562,27205,145155,27293,15347,26545,27336,168348,15373,27421,133411,24798,27445,27508,141261,28341,146139,132021,137560,14144,21537,146266,27617,147196,27612,27703,140427,149745,158545,27738,33318,27769,146876,17605,146877,147876,149772,149760,146633,14053,15595,134450,39811,143865,140433,32655,26679,159013,159137,159211,28054,27996,28284,28420,149887,147589,159346,34099,159604,20935,27804,28189,33838,166689,28207,146991,29779,147330,31180,28239,23185,143435,28664,14093,28573,146992,28410,136343,147517,17749,37872,28484,28508,15694,28532,168304,15675,28575,147780,28627,147601,147797,147513,147440,147380,147775,20959,147798,147799,147776,156125,28747,28798,28839,28801,28876,28885,28886,28895,16644,15848,29108,29078,148087,28971,28997,23176,29002,29038,23708,148325,29007,37730,148161,28972,148570,150055,150050,29114,166888,28861,29198,37954,29205,22801,37955,29220,37697,153093,29230,29248,149876,26813,29269,29271,15957,143428,26637,28477,29314,29482,29483,149539,165931,18669,165892,29480,29486,29647,29610,134202,158254,29641,29769,147938,136935,150052,26147,14021,149943,149901,150011,29687,29717,26883,150054,29753,132547,16087,29788,141485,29792,167602,29767,29668,29814,33721,29804,14128,29812,37873,27180,29826,18771,150156,147807,150137,166799,23366,166915,137374,29896,137608,29966,29929,29982,167641,137803,23511,167596,37765,30029,30026,30055,30062,151426,16132,150803,30094,29789,30110,30132,30210,30252,30289,30287,30319,30326,156661,30352,33263,14328,157969,157966,30369,30373,30391,30412,159647,33890,151709,151933,138780,30494,30502,30528,25775,152096,30552,144044,30639,166244,166248,136897,30708,30729,136054,150034,26826,30895,30919,30931,38565,31022,153056,30935,31028,30897,161292,36792,34948,166699,155779,140828,31110,35072,26882,31104,153687,31133,162617,31036,31145,28202,160038,16040,31174,168205,31188],"euc-kr":[44034,44035,44037,44038,44043,44044,44045,44046,44047,44056,44062,44063,44065,44066,44067,44069,44070,44071,44072,44073,44074,44075,44078,44082,44083,44084,null,null,null,null,null,null,44085,44086,44087,44090,44091,44093,44094,44095,44097,44098,44099,44100,44101,44102,44103,44104,44105,44106,44108,44110,44111,44112,44113,44114,44115,44117,null,null,null,null,null,null,44118,44119,44121,44122,44123,44125,44126,44127,44128,44129,44130,44131,44132,44133,44134,44135,44136,44137,44138,44139,44140,44141,44142,44143,44146,44147,44149,44150,44153,44155,44156,44157,44158,44159,44162,44167,44168,44173,44174,44175,44177,44178,44179,44181,44182,44183,44184,44185,44186,44187,44190,44194,44195,44196,44197,44198,44199,44203,44205,44206,44209,44210,44211,44212,44213,44214,44215,44218,44222,44223,44224,44226,44227,44229,44230,44231,44233,44234,44235,44237,44238,44239,44240,44241,44242,44243,44244,44246,44248,44249,44250,44251,44252,44253,44254,44255,44258,44259,44261,44262,44265,44267,44269,44270,44274,44276,44279,44280,44281,44282,44283,44286,44287,44289,44290,44291,44293,44295,44296,44297,44298,44299,44302,44304,44306,44307,44308,44309,44310,44311,44313,44314,44315,44317,44318,44319,44321,44322,44323,44324,44325,44326,44327,44328,44330,44331,44334,44335,44336,44337,44338,44339,null,null,null,null,null,null,44342,44343,44345,44346,44347,44349,44350,44351,44352,44353,44354,44355,44358,44360,44362,44363,44364,44365,44366,44367,44369,44370,44371,44373,44374,44375,null,null,null,null,null,null,44377,44378,44379,44380,44381,44382,44383,44384,44386,44388,44389,44390,44391,44392,44393,44394,44395,44398,44399,44401,44402,44407,44408,44409,44410,44414,44416,44419,44420,44421,44422,44423,44426,44427,44429,44430,44431,44433,44434,44435,44436,44437,44438,44439,44440,44441,44442,44443,44446,44447,44448,44449,44450,44451,44453,44454,44455,44456,44457,44458,44459,44460,44461,44462,44463,44464,44465,44466,44467,44468,44469,44470,44472,44473,44474,44475,44476,44477,44478,44479,44482,44483,44485,44486,44487,44489,44490,44491,44492,44493,44494,44495,44498,44500,44501,44502,44503,44504,44505,44506,44507,44509,44510,44511,44513,44514,44515,44517,44518,44519,44520,44521,44522,44523,44524,44525,44526,44527,44528,44529,44530,44531,44532,44533,44534,44535,44538,44539,44541,44542,44546,44547,44548,44549,44550,44551,44554,44556,44558,44559,44560,44561,44562,44563,44565,44566,44567,44568,44569,44570,44571,44572,null,null,null,null,null,null,44573,44574,44575,44576,44577,44578,44579,44580,44581,44582,44583,44584,44585,44586,44587,44588,44589,44590,44591,44594,44595,44597,44598,44601,44603,44604,null,null,null,null,null,null,44605,44606,44607,44610,44612,44615,44616,44617,44619,44623,44625,44626,44627,44629,44631,44632,44633,44634,44635,44638,44642,44643,44644,44646,44647,44650,44651,44653,44654,44655,44657,44658,44659,44660,44661,44662,44663,44666,44670,44671,44672,44673,44674,44675,44678,44679,44680,44681,44682,44683,44685,44686,44687,44688,44689,44690,44691,44692,44693,44694,44695,44696,44697,44698,44699,44700,44701,44702,44703,44704,44705,44706,44707,44708,44709,44710,44711,44712,44713,44714,44715,44716,44717,44718,44719,44720,44721,44722,44723,44724,44725,44726,44727,44728,44729,44730,44731,44735,44737,44738,44739,44741,44742,44743,44744,44745,44746,44747,44750,44754,44755,44756,44757,44758,44759,44762,44763,44765,44766,44767,44768,44769,44770,44771,44772,44773,44774,44775,44777,44778,44780,44782,44783,44784,44785,44786,44787,44789,44790,44791,44793,44794,44795,44797,44798,44799,44800,44801,44802,44803,44804,44805,null,null,null,null,null,null,44806,44809,44810,44811,44812,44814,44815,44817,44818,44819,44820,44821,44822,44823,44824,44825,44826,44827,44828,44829,44830,44831,44832,44833,44834,44835,null,null,null,null,null,null,44836,44837,44838,44839,44840,44841,44842,44843,44846,44847,44849,44851,44853,44854,44855,44856,44857,44858,44859,44862,44864,44868,44869,44870,44871,44874,44875,44876,44877,44878,44879,44881,44882,44883,44884,44885,44886,44887,44888,44889,44890,44891,44894,44895,44896,44897,44898,44899,44902,44903,44904,44905,44906,44907,44908,44909,44910,44911,44912,44913,44914,44915,44916,44917,44918,44919,44920,44922,44923,44924,44925,44926,44927,44929,44930,44931,44933,44934,44935,44937,44938,44939,44940,44941,44942,44943,44946,44947,44948,44950,44951,44952,44953,44954,44955,44957,44958,44959,44960,44961,44962,44963,44964,44965,44966,44967,44968,44969,44970,44971,44972,44973,44974,44975,44976,44977,44978,44979,44980,44981,44982,44983,44986,44987,44989,44990,44991,44993,44994,44995,44996,44997,44998,45002,45004,45007,45008,45009,45010,45011,45013,45014,45015,45016,45017,45018,45019,45021,45022,45023,45024,45025,null,null,null,null,null,null,45026,45027,45028,45029,45030,45031,45034,45035,45036,45037,45038,45039,45042,45043,45045,45046,45047,45049,45050,45051,45052,45053,45054,45055,45058,45059,null,null,null,null,null,null,45061,45062,45063,45064,45065,45066,45067,45069,45070,45071,45073,45074,45075,45077,45078,45079,45080,45081,45082,45083,45086,45087,45088,45089,45090,45091,45092,45093,45094,45095,45097,45098,45099,45100,45101,45102,45103,45104,45105,45106,45107,45108,45109,45110,45111,45112,45113,45114,45115,45116,45117,45118,45119,45120,45121,45122,45123,45126,45127,45129,45131,45133,45135,45136,45137,45138,45142,45144,45146,45147,45148,45150,45151,45152,45153,45154,45155,45156,45157,45158,45159,45160,45161,45162,45163,45164,45165,45166,45167,45168,45169,45170,45171,45172,45173,45174,45175,45176,45177,45178,45179,45182,45183,45185,45186,45187,45189,45190,45191,45192,45193,45194,45195,45198,45200,45202,45203,45204,45205,45206,45207,45211,45213,45214,45219,45220,45221,45222,45223,45226,45232,45234,45238,45239,45241,45242,45243,45245,45246,45247,45248,45249,45250,45251,45254,45258,45259,45260,45261,45262,45263,45266,null,null,null,null,null,null,45267,45269,45270,45271,45273,45274,45275,45276,45277,45278,45279,45281,45282,45283,45284,45286,45287,45288,45289,45290,45291,45292,45293,45294,45295,45296,null,null,null,null,null,null,45297,45298,45299,45300,45301,45302,45303,45304,45305,45306,45307,45308,45309,45310,45311,45312,45313,45314,45315,45316,45317,45318,45319,45322,45325,45326,45327,45329,45332,45333,45334,45335,45338,45342,45343,45344,45345,45346,45350,45351,45353,45354,45355,45357,45358,45359,45360,45361,45362,45363,45366,45370,45371,45372,45373,45374,45375,45378,45379,45381,45382,45383,45385,45386,45387,45388,45389,45390,45391,45394,45395,45398,45399,45401,45402,45403,45405,45406,45407,45409,45410,45411,45412,45413,45414,45415,45416,45417,45418,45419,45420,45421,45422,45423,45424,45425,45426,45427,45428,45429,45430,45431,45434,45435,45437,45438,45439,45441,45443,45444,45445,45446,45447,45450,45452,45454,45455,45456,45457,45461,45462,45463,45465,45466,45467,45469,45470,45471,45472,45473,45474,45475,45476,45477,45478,45479,45481,45482,45483,45484,45485,45486,45487,45488,45489,45490,45491,45492,45493,45494,45495,45496,null,null,null,null,null,null,45497,45498,45499,45500,45501,45502,45503,45504,45505,45506,45507,45508,45509,45510,45511,45512,45513,45514,45515,45517,45518,45519,45521,45522,45523,45525,null,null,null,null,null,null,45526,45527,45528,45529,45530,45531,45534,45536,45537,45538,45539,45540,45541,45542,45543,45546,45547,45549,45550,45551,45553,45554,45555,45556,45557,45558,45559,45560,45562,45564,45566,45567,45568,45569,45570,45571,45574,45575,45577,45578,45581,45582,45583,45584,45585,45586,45587,45590,45592,45594,45595,45596,45597,45598,45599,45601,45602,45603,45604,45605,45606,45607,45608,45609,45610,45611,45612,45613,45614,45615,45616,45617,45618,45619,45621,45622,45623,45624,45625,45626,45627,45629,45630,45631,45632,45633,45634,45635,45636,45637,45638,45639,45640,45641,45642,45643,45644,45645,45646,45647,45648,45649,45650,45651,45652,45653,45654,45655,45657,45658,45659,45661,45662,45663,45665,45666,45667,45668,45669,45670,45671,45674,45675,45676,45677,45678,45679,45680,45681,45682,45683,45686,45687,45688,45689,45690,45691,45693,45694,45695,45696,45697,45698,45699,45702,45703,45704,45706,45707,45708,45709,45710,null,null,null,null,null,null,45711,45714,45715,45717,45718,45719,45723,45724,45725,45726,45727,45730,45732,45735,45736,45737,45739,45741,45742,45743,45745,45746,45747,45749,45750,45751,null,null,null,null,null,null,45752,45753,45754,45755,45756,45757,45758,45759,45760,45761,45762,45763,45764,45765,45766,45767,45770,45771,45773,45774,45775,45777,45779,45780,45781,45782,45783,45786,45788,45790,45791,45792,45793,45795,45799,45801,45802,45808,45809,45810,45814,45820,45821,45822,45826,45827,45829,45830,45831,45833,45834,45835,45836,45837,45838,45839,45842,45846,45847,45848,45849,45850,45851,45853,45854,45855,45856,45857,45858,45859,45860,45861,45862,45863,45864,45865,45866,45867,45868,45869,45870,45871,45872,45873,45874,45875,45876,45877,45878,45879,45880,45881,45882,45883,45884,45885,45886,45887,45888,45889,45890,45891,45892,45893,45894,45895,45896,45897,45898,45899,45900,45901,45902,45903,45904,45905,45906,45907,45911,45913,45914,45917,45920,45921,45922,45923,45926,45928,45930,45932,45933,45935,45938,45939,45941,45942,45943,45945,45946,45947,45948,45949,45950,45951,45954,45958,45959,45960,45961,45962,45963,45965,null,null,null,null,null,null,45966,45967,45969,45970,45971,45973,45974,45975,45976,45977,45978,45979,45980,45981,45982,45983,45986,45987,45988,45989,45990,45991,45993,45994,45995,45997,null,null,null,null,null,null,45998,45999,46000,46001,46002,46003,46004,46005,46006,46007,46008,46009,46010,46011,46012,46013,46014,46015,46016,46017,46018,46019,46022,46023,46025,46026,46029,46031,46033,46034,46035,46038,46040,46042,46044,46046,46047,46049,46050,46051,46053,46054,46055,46057,46058,46059,46060,46061,46062,46063,46064,46065,46066,46067,46068,46069,46070,46071,46072,46073,46074,46075,46077,46078,46079,46080,46081,46082,46083,46084,46085,46086,46087,46088,46089,46090,46091,46092,46093,46094,46095,46097,46098,46099,46100,46101,46102,46103,46105,46106,46107,46109,46110,46111,46113,46114,46115,46116,46117,46118,46119,46122,46124,46125,46126,46127,46128,46129,46130,46131,46133,46134,46135,46136,46137,46138,46139,46140,46141,46142,46143,46144,46145,46146,46147,46148,46149,46150,46151,46152,46153,46154,46155,46156,46157,46158,46159,46162,46163,46165,46166,46167,46169,46170,46171,46172,46173,46174,46175,46178,46180,46182,null,null,null,null,null,null,46183,46184,46185,46186,46187,46189,46190,46191,46192,46193,46194,46195,46196,46197,46198,46199,46200,46201,46202,46203,46204,46205,46206,46207,46209,46210,null,null,null,null,null,null,46211,46212,46213,46214,46215,46217,46218,46219,46220,46221,46222,46223,46224,46225,46226,46227,46228,46229,46230,46231,46232,46233,46234,46235,46236,46238,46239,46240,46241,46242,46243,46245,46246,46247,46249,46250,46251,46253,46254,46255,46256,46257,46258,46259,46260,46262,46264,46266,46267,46268,46269,46270,46271,46273,46274,46275,46277,46278,46279,46281,46282,46283,46284,46285,46286,46287,46289,46290,46291,46292,46294,46295,46296,46297,46298,46299,46302,46303,46305,46306,46309,46311,46312,46313,46314,46315,46318,46320,46322,46323,46324,46325,46326,46327,46329,46330,46331,46332,46333,46334,46335,46336,46337,46338,46339,46340,46341,46342,46343,46344,46345,46346,46347,46348,46349,46350,46351,46352,46353,46354,46355,46358,46359,46361,46362,46365,46366,46367,46368,46369,46370,46371,46374,46379,46380,46381,46382,46383,46386,46387,46389,46390,46391,46393,46394,46395,46396,46397,46398,46399,46402,46406,null,null,null,null,null,null,46407,46408,46409,46410,46414,46415,46417,46418,46419,46421,46422,46423,46424,46425,46426,46427,46430,46434,46435,46436,46437,46438,46439,46440,46441,46442,null,null,null,null,null,null,46443,46444,46445,46446,46447,46448,46449,46450,46451,46452,46453,46454,46455,46456,46457,46458,46459,46460,46461,46462,46463,46464,46465,46466,46467,46468,46469,46470,46471,46472,46473,46474,46475,46476,46477,46478,46479,46480,46481,46482,46483,46484,46485,46486,46487,46488,46489,46490,46491,46492,46493,46494,46495,46498,46499,46501,46502,46503,46505,46508,46509,46510,46511,46514,46518,46519,46520,46521,46522,46526,46527,46529,46530,46531,46533,46534,46535,46536,46537,46538,46539,46542,46546,46547,46548,46549,46550,46551,46553,46554,46555,46556,46557,46558,46559,46560,46561,46562,46563,46564,46565,46566,46567,46568,46569,46570,46571,46573,46574,46575,46576,46577,46578,46579,46580,46581,46582,46583,46584,46585,46586,46587,46588,46589,46590,46591,46592,46593,46594,46595,46596,46597,46598,46599,46600,46601,46602,46603,46604,46605,46606,46607,46610,46611,46613,46614,46615,46617,46618,46619,46620,46621,null,null,null,null,null,null,46622,46623,46624,46625,46626,46627,46628,46630,46631,46632,46633,46634,46635,46637,46638,46639,46640,46641,46642,46643,46645,46646,46647,46648,46649,46650,null,null,null,null,null,null,46651,46652,46653,46654,46655,46656,46657,46658,46659,46660,46661,46662,46663,46665,46666,46667,46668,46669,46670,46671,46672,46673,46674,46675,46676,46677,46678,46679,46680,46681,46682,46683,46684,46685,46686,46687,46688,46689,46690,46691,46693,46694,46695,46697,46698,46699,46700,46701,46702,46703,46704,46705,46706,46707,46708,46709,46710,46711,46712,46713,46714,46715,46716,46717,46718,46719,46720,46721,46722,46723,46724,46725,46726,46727,46728,46729,46730,46731,46732,46733,46734,46735,46736,46737,46738,46739,46740,46741,46742,46743,46744,46745,46746,46747,46750,46751,46753,46754,46755,46757,46758,46759,46760,46761,46762,46765,46766,46767,46768,46770,46771,46772,46773,46774,46775,46776,46777,46778,46779,46780,46781,46782,46783,46784,46785,46786,46787,46788,46789,46790,46791,46792,46793,46794,46795,46796,46797,46798,46799,46800,46801,46802,46803,46805,46806,46807,46808,46809,46810,46811,46812,46813,null,null,null,null,null,null,46814,46815,46816,46817,46818,46819,46820,46821,46822,46823,46824,46825,46826,46827,46828,46829,46830,46831,46833,46834,46835,46837,46838,46839,46841,46842,null,null,null,null,null,null,46843,46844,46845,46846,46847,46850,46851,46852,46854,46855,46856,46857,46858,46859,46860,46861,46862,46863,46864,46865,46866,46867,46868,46869,46870,46871,46872,46873,46874,46875,46876,46877,46878,46879,46880,46881,46882,46883,46884,46885,46886,46887,46890,46891,46893,46894,46897,46898,46899,46900,46901,46902,46903,46906,46908,46909,46910,46911,46912,46913,46914,46915,46917,46918,46919,46921,46922,46923,46925,46926,46927,46928,46929,46930,46931,46934,46935,46936,46937,46938,46939,46940,46941,46942,46943,46945,46946,46947,46949,46950,46951,46953,46954,46955,46956,46957,46958,46959,46962,46964,46966,46967,46968,46969,46970,46971,46974,46975,46977,46978,46979,46981,46982,46983,46984,46985,46986,46987,46990,46995,46996,46997,47002,47003,47005,47006,47007,47009,47010,47011,47012,47013,47014,47015,47018,47022,47023,47024,47025,47026,47027,47030,47031,47033,47034,47035,47036,47037,47038,47039,47040,47041,null,null,null,null,null,null,47042,47043,47044,47045,47046,47048,47050,47051,47052,47053,47054,47055,47056,47057,47058,47059,47060,47061,47062,47063,47064,47065,47066,47067,47068,47069,null,null,null,null,null,null,47070,47071,47072,47073,47074,47075,47076,47077,47078,47079,47080,47081,47082,47083,47086,47087,47089,47090,47091,47093,47094,47095,47096,47097,47098,47099,47102,47106,47107,47108,47109,47110,47114,47115,47117,47118,47119,47121,47122,47123,47124,47125,47126,47127,47130,47132,47134,47135,47136,47137,47138,47139,47142,47143,47145,47146,47147,47149,47150,47151,47152,47153,47154,47155,47158,47162,47163,47164,47165,47166,47167,47169,47170,47171,47173,47174,47175,47176,47177,47178,47179,47180,47181,47182,47183,47184,47186,47188,47189,47190,47191,47192,47193,47194,47195,47198,47199,47201,47202,47203,47205,47206,47207,47208,47209,47210,47211,47214,47216,47218,47219,47220,47221,47222,47223,47225,47226,47227,47229,47230,47231,47232,47233,47234,47235,47236,47237,47238,47239,47240,47241,47242,47243,47244,47246,47247,47248,47249,47250,47251,47252,47253,47254,47255,47256,47257,47258,47259,47260,47261,47262,47263,null,null,null,null,null,null,47264,47265,47266,47267,47268,47269,47270,47271,47273,47274,47275,47276,47277,47278,47279,47281,47282,47283,47285,47286,47287,47289,47290,47291,47292,47293,null,null,null,null,null,null,47294,47295,47298,47300,47302,47303,47304,47305,47306,47307,47309,47310,47311,47313,47314,47315,47317,47318,47319,47320,47321,47322,47323,47324,47326,47328,47330,47331,47332,47333,47334,47335,47338,47339,47341,47342,47343,47345,47346,47347,47348,47349,47350,47351,47354,47356,47358,47359,47360,47361,47362,47363,47365,47366,47367,47368,47369,47370,47371,47372,47373,47374,47375,47376,47377,47378,47379,47380,47381,47382,47383,47385,47386,47387,47388,47389,47390,47391,47393,47394,47395,47396,47397,47398,47399,47400,47401,47402,47403,47404,47405,47406,47407,47408,47409,47410,47411,47412,47413,47414,47415,47416,47417,47418,47419,47422,47423,47425,47426,47427,47429,47430,47431,47432,47433,47434,47435,47437,47438,47440,47442,47443,47444,47445,47446,47447,47450,47451,47453,47454,47455,47457,47458,47459,47460,47461,47462,47463,47466,47468,47470,47471,47472,47473,47474,47475,47478,47479,47481,47482,47483,47485,null,null,null,null,null,null,47486,47487,47488,47489,47490,47491,47494,47496,47499,47500,47503,47504,47505,47506,47507,47508,47509,47510,47511,47512,47513,47514,47515,47516,47517,47518,null,null,null,null,null,null,47519,47520,47521,47522,47523,47524,47525,47526,47527,47528,47529,47530,47531,47534,47535,47537,47538,47539,47541,47542,47543,47544,47545,47546,47547,47550,47552,47554,47555,47556,47557,47558,47559,47562,47563,47565,47571,47572,47573,47574,47575,47578,47580,47583,47584,47586,47590,47591,47593,47594,47595,47597,47598,47599,47600,47601,47602,47603,47606,47611,47612,47613,47614,47615,47618,47619,47620,47621,47622,47623,47625,47626,47627,47628,47629,47630,47631,47632,47633,47634,47635,47636,47638,47639,47640,47641,47642,47643,47644,47645,47646,47647,47648,47649,47650,47651,47652,47653,47654,47655,47656,47657,47658,47659,47660,47661,47662,47663,47664,47665,47666,47667,47668,47669,47670,47671,47674,47675,47677,47678,47679,47681,47683,47684,47685,47686,47687,47690,47692,47695,47696,47697,47698,47702,47703,47705,47706,47707,47709,47710,47711,47712,47713,47714,47715,47718,47722,47723,47724,47725,47726,47727,null,null,null,null,null,null,47730,47731,47733,47734,47735,47737,47738,47739,47740,47741,47742,47743,47744,47745,47746,47750,47752,47753,47754,47755,47757,47758,47759,47760,47761,47762,null,null,null,null,null,null,47763,47764,47765,47766,47767,47768,47769,47770,47771,47772,47773,47774,47775,47776,47777,47778,47779,47780,47781,47782,47783,47786,47789,47790,47791,47793,47795,47796,47797,47798,47799,47802,47804,47806,47807,47808,47809,47810,47811,47813,47814,47815,47817,47818,47819,47820,47821,47822,47823,47824,47825,47826,47827,47828,47829,47830,47831,47834,47835,47836,47837,47838,47839,47840,47841,47842,47843,47844,47845,47846,47847,47848,47849,47850,47851,47852,47853,47854,47855,47856,47857,47858,47859,47860,47861,47862,47863,47864,47865,47866,47867,47869,47870,47871,47873,47874,47875,47877,47878,47879,47880,47881,47882,47883,47884,47886,47888,47890,47891,47892,47893,47894,47895,47897,47898,47899,47901,47902,47903,47905,47906,47907,47908,47909,47910,47911,47912,47914,47916,47917,47918,47919,47920,47921,47922,47923,47927,47929,47930,47935,47936,47937,47938,47939,47942,47944,47946,47947,47948,47950,47953,47954,null,null,null,null,null,null,47955,47957,47958,47959,47961,47962,47963,47964,47965,47966,47967,47968,47970,47972,47973,47974,47975,47976,47977,47978,47979,47981,47982,47983,47984,47985,null,null,null,null,null,null,47986,47987,47988,47989,47990,47991,47992,47993,47994,47995,47996,47997,47998,47999,48000,48001,48002,48003,48004,48005,48006,48007,48009,48010,48011,48013,48014,48015,48017,48018,48019,48020,48021,48022,48023,48024,48025,48026,48027,48028,48029,48030,48031,48032,48033,48034,48035,48037,48038,48039,48041,48042,48043,48045,48046,48047,48048,48049,48050,48051,48053,48054,48056,48057,48058,48059,48060,48061,48062,48063,48065,48066,48067,48069,48070,48071,48073,48074,48075,48076,48077,48078,48079,48081,48082,48084,48085,48086,48087,48088,48089,48090,48091,48092,48093,48094,48095,48096,48097,48098,48099,48100,48101,48102,48103,48104,48105,48106,48107,48108,48109,48110,48111,48112,48113,48114,48115,48116,48117,48118,48119,48122,48123,48125,48126,48129,48131,48132,48133,48134,48135,48138,48142,48144,48146,48147,48153,48154,48160,48161,48162,48163,48166,48168,48170,48171,48172,48174,48175,48178,48179,48181,null,null,null,null,null,null,48182,48183,48185,48186,48187,48188,48189,48190,48191,48194,48198,48199,48200,48202,48203,48206,48207,48209,48210,48211,48212,48213,48214,48215,48216,48217,null,null,null,null,null,null,48218,48219,48220,48222,48223,48224,48225,48226,48227,48228,48229,48230,48231,48232,48233,48234,48235,48236,48237,48238,48239,48240,48241,48242,48243,48244,48245,48246,48247,48248,48249,48250,48251,48252,48253,48254,48255,48256,48257,48258,48259,48262,48263,48265,48266,48269,48271,48272,48273,48274,48275,48278,48280,48283,48284,48285,48286,48287,48290,48291,48293,48294,48297,48298,48299,48300,48301,48302,48303,48306,48310,48311,48312,48313,48314,48315,48318,48319,48321,48322,48323,48325,48326,48327,48328,48329,48330,48331,48332,48334,48338,48339,48340,48342,48343,48345,48346,48347,48349,48350,48351,48352,48353,48354,48355,48356,48357,48358,48359,48360,48361,48362,48363,48364,48365,48366,48367,48368,48369,48370,48371,48375,48377,48378,48379,48381,48382,48383,48384,48385,48386,48387,48390,48392,48394,48395,48396,48397,48398,48399,48401,48402,48403,48405,48406,48407,48408,48409,48410,48411,48412,48413,null,null,null,null,null,null,48414,48415,48416,48417,48418,48419,48421,48422,48423,48424,48425,48426,48427,48429,48430,48431,48432,48433,48434,48435,48436,48437,48438,48439,48440,48441,null,null,null,null,null,null,48442,48443,48444,48445,48446,48447,48449,48450,48451,48452,48453,48454,48455,48458,48459,48461,48462,48463,48465,48466,48467,48468,48469,48470,48471,48474,48475,48476,48477,48478,48479,48480,48481,48482,48483,48485,48486,48487,48489,48490,48491,48492,48493,48494,48495,48496,48497,48498,48499,48500,48501,48502,48503,48504,48505,48506,48507,48508,48509,48510,48511,48514,48515,48517,48518,48523,48524,48525,48526,48527,48530,48532,48534,48535,48536,48539,48541,48542,48543,48544,48545,48546,48547,48549,48550,48551,48552,48553,48554,48555,48556,48557,48558,48559,48561,48562,48563,48564,48565,48566,48567,48569,48570,48571,48572,48573,48574,48575,48576,48577,48578,48579,48580,48581,48582,48583,48584,48585,48586,48587,48588,48589,48590,48591,48592,48593,48594,48595,48598,48599,48601,48602,48603,48605,48606,48607,48608,48609,48610,48611,48612,48613,48614,48615,48616,48618,48619,48620,48621,48622,48623,48625,null,null,null,null,null,null,48626,48627,48629,48630,48631,48633,48634,48635,48636,48637,48638,48639,48641,48642,48644,48646,48647,48648,48649,48650,48651,48654,48655,48657,48658,48659,null,null,null,null,null,null,48661,48662,48663,48664,48665,48666,48667,48670,48672,48673,48674,48675,48676,48677,48678,48679,48680,48681,48682,48683,48684,48685,48686,48687,48688,48689,48690,48691,48692,48693,48694,48695,48696,48697,48698,48699,48700,48701,48702,48703,48704,48705,48706,48707,48710,48711,48713,48714,48715,48717,48719,48720,48721,48722,48723,48726,48728,48732,48733,48734,48735,48738,48739,48741,48742,48743,48745,48747,48748,48749,48750,48751,48754,48758,48759,48760,48761,48762,48766,48767,48769,48770,48771,48773,48774,48775,48776,48777,48778,48779,48782,48786,48787,48788,48789,48790,48791,48794,48795,48796,48797,48798,48799,48800,48801,48802,48803,48804,48805,48806,48807,48809,48810,48811,48812,48813,48814,48815,48816,48817,48818,48819,48820,48821,48822,48823,48824,48825,48826,48827,48828,48829,48830,48831,48832,48833,48834,48835,48836,48837,48838,48839,48840,48841,48842,48843,48844,48845,48846,48847,48850,48851,null,null,null,null,null,null,48853,48854,48857,48858,48859,48860,48861,48862,48863,48865,48866,48870,48871,48872,48873,48874,48875,48877,48878,48879,48880,48881,48882,48883,48884,48885,null,null,null,null,null,null,48886,48887,48888,48889,48890,48891,48892,48893,48894,48895,48896,48898,48899,48900,48901,48902,48903,48906,48907,48908,48909,48910,48911,48912,48913,48914,48915,48916,48917,48918,48919,48922,48926,48927,48928,48929,48930,48931,48932,48933,48934,48935,48936,48937,48938,48939,48940,48941,48942,48943,48944,48945,48946,48947,48948,48949,48950,48951,48952,48953,48954,48955,48956,48957,48958,48959,48962,48963,48965,48966,48967,48969,48970,48971,48972,48973,48974,48975,48978,48979,48980,48982,48983,48984,48985,48986,48987,48988,48989,48990,48991,48992,48993,48994,48995,48996,48997,48998,48999,49000,49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,49012,49013,49014,49015,49016,49017,49018,49019,49020,49021,49022,49023,49024,49025,49026,49027,49028,49029,49030,49031,49032,49033,49034,49035,49036,49037,49038,49039,49040,49041,49042,49043,49045,49046,49047,49048,49049,49050,49051,49052,49053,null,null,null,null,null,null,49054,49055,49056,49057,49058,49059,49060,49061,49062,49063,49064,49065,49066,49067,49068,49069,49070,49071,49073,49074,49075,49076,49077,49078,49079,49080,null,null,null,null,null,null,49081,49082,49083,49084,49085,49086,49087,49088,49089,49090,49091,49092,49094,49095,49096,49097,49098,49099,49102,49103,49105,49106,49107,49109,49110,49111,49112,49113,49114,49115,49117,49118,49120,49122,49123,49124,49125,49126,49127,49128,49129,49130,49131,49132,49133,49134,49135,49136,49137,49138,49139,49140,49141,49142,49143,49144,49145,49146,49147,49148,49149,49150,49151,49152,49153,49154,49155,49156,49157,49158,49159,49160,49161,49162,49163,49164,49165,49166,49167,49168,49169,49170,49171,49172,49173,49174,49175,49176,49177,49178,49179,49180,49181,49182,49183,49184,49185,49186,49187,49188,49189,49190,49191,49192,49193,49194,49195,49196,49197,49198,49199,49200,49201,49202,49203,49204,49205,49206,49207,49208,49209,49210,49211,49213,49214,49215,49216,49217,49218,49219,49220,49221,49222,49223,49224,49225,49226,49227,49228,49229,49230,49231,49232,49234,49235,49236,49237,49238,49239,49241,49242,49243,null,null,null,null,null,null,49245,49246,49247,49249,49250,49251,49252,49253,49254,49255,49258,49259,49260,49261,49262,49263,49264,49265,49266,49267,49268,49269,49270,49271,49272,49273,null,null,null,null,null,null,49274,49275,49276,49277,49278,49279,49280,49281,49282,49283,49284,49285,49286,49287,49288,49289,49290,49291,49292,49293,49294,49295,49298,49299,49301,49302,49303,49305,49306,49307,49308,49309,49310,49311,49314,49316,49318,49319,49320,49321,49322,49323,49326,49329,49330,49335,49336,49337,49338,49339,49342,49346,49347,49348,49350,49351,49354,49355,49357,49358,49359,49361,49362,49363,49364,49365,49366,49367,49370,49374,49375,49376,49377,49378,49379,49382,49383,49385,49386,49387,49389,49390,49391,49392,49393,49394,49395,49398,49400,49402,49403,49404,49405,49406,49407,49409,49410,49411,49413,49414,49415,49417,49418,49419,49420,49421,49422,49423,49425,49426,49427,49428,49430,49431,49432,49433,49434,49435,49441,49442,49445,49448,49449,49450,49451,49454,49458,49459,49460,49461,49463,49466,49467,49469,49470,49471,49473,49474,49475,49476,49477,49478,49479,49482,49486,49487,49488,49489,49490,49491,49494,49495,null,null,null,null,null,null,49497,49498,49499,49501,49502,49503,49504,49505,49506,49507,49510,49514,49515,49516,49517,49518,49519,49521,49522,49523,49525,49526,49527,49529,49530,49531,null,null,null,null,null,null,49532,49533,49534,49535,49536,49537,49538,49539,49540,49542,49543,49544,49545,49546,49547,49551,49553,49554,49555,49557,49559,49560,49561,49562,49563,49566,49568,49570,49571,49572,49574,49575,49578,49579,49581,49582,49583,49585,49586,49587,49588,49589,49590,49591,49592,49593,49594,49595,49596,49598,49599,49600,49601,49602,49603,49605,49606,49607,49609,49610,49611,49613,49614,49615,49616,49617,49618,49619,49621,49622,49625,49626,49627,49628,49629,49630,49631,49633,49634,49635,49637,49638,49639,49641,49642,49643,49644,49645,49646,49647,49650,49652,49653,49654,49655,49656,49657,49658,49659,49662,49663,49665,49666,49667,49669,49670,49671,49672,49673,49674,49675,49678,49680,49682,49683,49684,49685,49686,49687,49690,49691,49693,49694,49697,49698,49699,49700,49701,49702,49703,49706,49708,49710,49712,49715,49717,49718,49719,49720,49721,49722,49723,49724,49725,49726,49727,49728,49729,49730,49731,49732,49733,null,null,null,null,null,null,49734,49735,49737,49738,49739,49740,49741,49742,49743,49746,49747,49749,49750,49751,49753,49754,49755,49756,49757,49758,49759,49761,49762,49763,49764,49766,null,null,null,null,null,null,49767,49768,49769,49770,49771,49774,49775,49777,49778,49779,49781,49782,49783,49784,49785,49786,49787,49790,49792,49794,49795,49796,49797,49798,49799,49802,49803,49804,49805,49806,49807,49809,49810,49811,49812,49813,49814,49815,49817,49818,49820,49822,49823,49824,49825,49826,49827,49830,49831,49833,49834,49835,49838,49839,49840,49841,49842,49843,49846,49848,49850,49851,49852,49853,49854,49855,49856,49857,49858,49859,49860,49861,49862,49863,49864,49865,49866,49867,49868,49869,49870,49871,49872,49873,49874,49875,49876,49877,49878,49879,49880,49881,49882,49883,49886,49887,49889,49890,49893,49894,49895,49896,49897,49898,49902,49904,49906,49907,49908,49909,49911,49914,49917,49918,49919,49921,49922,49923,49924,49925,49926,49927,49930,49931,49934,49935,49936,49937,49938,49942,49943,49945,49946,49947,49949,49950,49951,49952,49953,49954,49955,49958,49959,49962,49963,49964,49965,49966,49967,49968,49969,49970,null,null,null,null,null,null,49971,49972,49973,49974,49975,49976,49977,49978,49979,49980,49981,49982,49983,49984,49985,49986,49987,49988,49990,49991,49992,49993,49994,49995,49996,49997,null,null,null,null,null,null,49998,49999,50000,50001,50002,50003,50004,50005,50006,50007,50008,50009,50010,50011,50012,50013,50014,50015,50016,50017,50018,50019,50020,50021,50022,50023,50026,50027,50029,50030,50031,50033,50035,50036,50037,50038,50039,50042,50043,50046,50047,50048,50049,50050,50051,50053,50054,50055,50057,50058,50059,50061,50062,50063,50064,50065,50066,50067,50068,50069,50070,50071,50072,50073,50074,50075,50076,50077,50078,50079,50080,50081,50082,50083,50084,50085,50086,50087,50088,50089,50090,50091,50092,50093,50094,50095,50096,50097,50098,50099,50100,50101,50102,50103,50104,50105,50106,50107,50108,50109,50110,50111,50113,50114,50115,50116,50117,50118,50119,50120,50121,50122,50123,50124,50125,50126,50127,50128,50129,50130,50131,50132,50133,50134,50135,50138,50139,50141,50142,50145,50147,50148,50149,50150,50151,50154,50155,50156,50158,50159,50160,50161,50162,50163,50166,50167,50169,50170,50171,50172,50173,50174,null,null,null,null,null,null,50175,50176,50177,50178,50179,50180,50181,50182,50183,50185,50186,50187,50188,50189,50190,50191,50193,50194,50195,50196,50197,50198,50199,50200,50201,50202,null,null,null,null,null,null,50203,50204,50205,50206,50207,50208,50209,50210,50211,50213,50214,50215,50216,50217,50218,50219,50221,50222,50223,50225,50226,50227,50229,50230,50231,50232,50233,50234,50235,50238,50239,50240,50241,50242,50243,50244,50245,50246,50247,50249,50250,50251,50252,50253,50254,50255,50256,50257,50258,50259,50260,50261,50262,50263,50264,50265,50266,50267,50268,50269,50270,50271,50272,50273,50274,50275,50278,50279,50281,50282,50283,50285,50286,50287,50288,50289,50290,50291,50294,50295,50296,50298,50299,50300,50301,50302,50303,50305,50306,50307,50308,50309,50310,50311,50312,50313,50314,50315,50316,50317,50318,50319,50320,50321,50322,50323,50325,50326,50327,50328,50329,50330,50331,50333,50334,50335,50336,50337,50338,50339,50340,50341,50342,50343,50344,50345,50346,50347,50348,50349,50350,50351,50352,50353,50354,50355,50356,50357,50358,50359,50361,50362,50363,50365,50366,50367,50368,50369,50370,50371,50372,50373,null,null,null,null,null,null,50374,50375,50376,50377,50378,50379,50380,50381,50382,50383,50384,50385,50386,50387,50388,50389,50390,50391,50392,50393,50394,50395,50396,50397,50398,50399,null,null,null,null,null,null,50400,50401,50402,50403,50404,50405,50406,50407,50408,50410,50411,50412,50413,50414,50415,50418,50419,50421,50422,50423,50425,50427,50428,50429,50430,50434,50435,50436,50437,50438,50439,50440,50441,50442,50443,50445,50446,50447,50449,50450,50451,50453,50454,50455,50456,50457,50458,50459,50461,50462,50463,50464,50465,50466,50467,50468,50469,50470,50471,50474,50475,50477,50478,50479,50481,50482,50483,50484,50485,50486,50487,50490,50492,50494,50495,50496,50497,50498,50499,50502,50503,50507,50511,50512,50513,50514,50518,50522,50523,50524,50527,50530,50531,50533,50534,50535,50537,50538,50539,50540,50541,50542,50543,50546,50550,50551,50552,50553,50554,50555,50558,50559,50561,50562,50563,50565,50566,50568,50569,50570,50571,50574,50576,50578,50579,50580,50582,50585,50586,50587,50589,50590,50591,50593,50594,50595,50596,50597,50598,50599,50600,50602,50603,50604,50605,50606,50607,50608,50609,50610,50611,50614,null,null,null,null,null,null,50615,50618,50623,50624,50625,50626,50627,50635,50637,50639,50642,50643,50645,50646,50647,50649,50650,50651,50652,50653,50654,50655,50658,50660,50662,50663,null,null,null,null,null,null,50664,50665,50666,50667,50671,50673,50674,50675,50677,50680,50681,50682,50683,50690,50691,50692,50697,50698,50699,50701,50702,50703,50705,50706,50707,50708,50709,50710,50711,50714,50717,50718,50719,50720,50721,50722,50723,50726,50727,50729,50730,50731,50735,50737,50738,50742,50744,50746,50748,50749,50750,50751,50754,50755,50757,50758,50759,50761,50762,50763,50764,50765,50766,50767,50770,50774,50775,50776,50777,50778,50779,50782,50783,50785,50786,50787,50788,50789,50790,50791,50792,50793,50794,50795,50797,50798,50800,50802,50803,50804,50805,50806,50807,50810,50811,50813,50814,50815,50817,50818,50819,50820,50821,50822,50823,50826,50828,50830,50831,50832,50833,50834,50835,50838,50839,50841,50842,50843,50845,50846,50847,50848,50849,50850,50851,50854,50856,50858,50859,50860,50861,50862,50863,50866,50867,50869,50870,50871,50875,50876,50877,50878,50879,50882,50884,50886,50887,50888,50889,50890,50891,50894,null,null,null,null,null,null,50895,50897,50898,50899,50901,50902,50903,50904,50905,50906,50907,50910,50911,50914,50915,50916,50917,50918,50919,50922,50923,50925,50926,50927,50929,50930,null,null,null,null,null,null,50931,50932,50933,50934,50935,50938,50939,50940,50942,50943,50944,50945,50946,50947,50950,50951,50953,50954,50955,50957,50958,50959,50960,50961,50962,50963,50966,50968,50970,50971,50972,50973,50974,50975,50978,50979,50981,50982,50983,50985,50986,50987,50988,50989,50990,50991,50994,50996,50998,51000,51001,51002,51003,51006,51007,51009,51010,51011,51013,51014,51015,51016,51017,51019,51022,51024,51033,51034,51035,51037,51038,51039,51041,51042,51043,51044,51045,51046,51047,51049,51050,51052,51053,51054,51055,51056,51057,51058,51059,51062,51063,51065,51066,51067,51071,51072,51073,51074,51078,51083,51084,51085,51087,51090,51091,51093,51097,51099,51100,51101,51102,51103,51106,51111,51112,51113,51114,51115,51118,51119,51121,51122,51123,51125,51126,51127,51128,51129,51130,51131,51134,51138,51139,51140,51141,51142,51143,51146,51147,51149,51151,51153,51154,51155,51156,51157,51158,51159,51161,51162,51163,51164,null,null,null,null,null,null,51166,51167,51168,51169,51170,51171,51173,51174,51175,51177,51178,51179,51181,51182,51183,51184,51185,51186,51187,51188,51189,51190,51191,51192,51193,51194,null,null,null,null,null,null,51195,51196,51197,51198,51199,51202,51203,51205,51206,51207,51209,51211,51212,51213,51214,51215,51218,51220,51223,51224,51225,51226,51227,51230,51231,51233,51234,51235,51237,51238,51239,51240,51241,51242,51243,51246,51248,51250,51251,51252,51253,51254,51255,51257,51258,51259,51261,51262,51263,51265,51266,51267,51268,51269,51270,51271,51274,51275,51278,51279,51280,51281,51282,51283,51285,51286,51287,51288,51289,51290,51291,51292,51293,51294,51295,51296,51297,51298,51299,51300,51301,51302,51303,51304,51305,51306,51307,51308,51309,51310,51311,51314,51315,51317,51318,51319,51321,51323,51324,51325,51326,51327,51330,51332,51336,51337,51338,51342,51343,51344,51345,51346,51347,51349,51350,51351,51352,51353,51354,51355,51356,51358,51360,51362,51363,51364,51365,51366,51367,51369,51370,51371,51372,51373,51374,51375,51376,51377,51378,51379,51380,51381,51382,51383,51384,51385,51386,51387,51390,51391,51392,51393,null,null,null,null,null,null,51394,51395,51397,51398,51399,51401,51402,51403,51405,51406,51407,51408,51409,51410,51411,51414,51416,51418,51419,51420,51421,51422,51423,51426,51427,51429,null,null,null,null,null,null,51430,51431,51432,51433,51434,51435,51436,51437,51438,51439,51440,51441,51442,51443,51444,51446,51447,51448,51449,51450,51451,51454,51455,51457,51458,51459,51463,51464,51465,51466,51467,51470,12288,12289,12290,183,8229,8230,168,12291,173,8213,8741,65340,8764,8216,8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,177,215,247,8800,8804,8805,8734,8756,176,8242,8243,8451,8491,65504,65505,65509,9794,9792,8736,8869,8978,8706,8711,8801,8786,167,8251,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8594,8592,8593,8595,8596,12307,8810,8811,8730,8765,8733,8757,8747,8748,8712,8715,8838,8839,8834,8835,8746,8745,8743,8744,65506,51472,51474,51475,51476,51477,51478,51479,51481,51482,51483,51484,51485,51486,51487,51488,51489,51490,51491,51492,51493,51494,51495,51496,51497,51498,51499,null,null,null,null,null,null,51501,51502,51503,51504,51505,51506,51507,51509,51510,51511,51512,51513,51514,51515,51516,51517,51518,51519,51520,51521,51522,51523,51524,51525,51526,51527,null,null,null,null,null,null,51528,51529,51530,51531,51532,51533,51534,51535,51538,51539,51541,51542,51543,51545,51546,51547,51548,51549,51550,51551,51554,51556,51557,51558,51559,51560,51561,51562,51563,51565,51566,51567,8658,8660,8704,8707,180,65374,711,728,733,730,729,184,731,161,191,720,8750,8721,8719,164,8457,8240,9665,9664,9655,9654,9828,9824,9825,9829,9831,9827,8857,9672,9635,9680,9681,9618,9636,9637,9640,9639,9638,9641,9832,9743,9742,9756,9758,182,8224,8225,8597,8599,8601,8598,8600,9837,9833,9834,9836,12927,12828,8470,13255,8482,13250,13272,8481,8364,174,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,51569,51570,51571,51573,51574,51575,51576,51577,51578,51579,51581,51582,51583,51584,51585,51586,51587,51588,51589,51590,51591,51594,51595,51597,51598,51599,null,null,null,null,null,null,51601,51602,51603,51604,51605,51606,51607,51610,51612,51614,51615,51616,51617,51618,51619,51620,51621,51622,51623,51624,51625,51626,51627,51628,51629,51630,null,null,null,null,null,null,51631,51632,51633,51634,51635,51636,51637,51638,51639,51640,51641,51642,51643,51644,51645,51646,51647,51650,51651,51653,51654,51657,51659,51660,51661,51662,51663,51666,51668,51671,51672,51675,65281,65282,65283,65284,65285,65286,65287,65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339,65510,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,65373,65507,51678,51679,51681,51683,51685,51686,51688,51689,51690,51691,51694,51698,51699,51700,51701,51702,51703,51706,51707,51709,51710,51711,51713,51714,51715,51716,null,null,null,null,null,null,51717,51718,51719,51722,51726,51727,51728,51729,51730,51731,51733,51734,51735,51737,51738,51739,51740,51741,51742,51743,51744,51745,51746,51747,51748,51749,null,null,null,null,null,null,51750,51751,51752,51754,51755,51756,51757,51758,51759,51760,51761,51762,51763,51764,51765,51766,51767,51768,51769,51770,51771,51772,51773,51774,51775,51776,51777,51778,51779,51780,51781,51782,12593,12594,12595,12596,12597,12598,12599,12600,12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615,12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631,12632,12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679,12680,12681,12682,12683,12684,12685,12686,51783,51784,51785,51786,51787,51790,51791,51793,51794,51795,51797,51798,51799,51800,51801,51802,51803,51806,51810,51811,51812,51813,51814,51815,51817,51818,null,null,null,null,null,null,51819,51820,51821,51822,51823,51824,51825,51826,51827,51828,51829,51830,51831,51832,51833,51834,51835,51836,51838,51839,51840,51841,51842,51843,51845,51846,null,null,null,null,null,null,51847,51848,51849,51850,51851,51852,51853,51854,51855,51856,51857,51858,51859,51860,51861,51862,51863,51865,51866,51867,51868,51869,51870,51871,51872,51873,51874,51875,51876,51877,51878,51879,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,null,null,null,null,null,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,null,null,null,null,null,null,null,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,null,null,null,null,null,null,null,null,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,null,null,null,null,null,null,51880,51881,51882,51883,51884,51885,51886,51887,51888,51889,51890,51891,51892,51893,51894,51895,51896,51897,51898,51899,51902,51903,51905,51906,51907,51909,null,null,null,null,null,null,51910,51911,51912,51913,51914,51915,51918,51920,51922,51924,51925,51926,51927,51930,51931,51932,51933,51934,51935,51937,51938,51939,51940,51941,51942,51943,null,null,null,null,null,null,51944,51945,51946,51947,51949,51950,51951,51952,51953,51954,51955,51957,51958,51959,51960,51961,51962,51963,51964,51965,51966,51967,51968,51969,51970,51971,51972,51973,51974,51975,51977,51978,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,9490,9489,9498,9497,9494,9493,9486,9485,9502,9503,9505,9506,9510,9511,9513,9514,9517,9518,9521,9522,9525,9526,9529,9530,9533,9534,9536,9537,9539,9540,9541,9542,9543,9544,9545,9546,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,51979,51980,51981,51982,51983,51985,51986,51987,51989,51990,51991,51993,51994,51995,51996,51997,51998,51999,52002,52003,52004,52005,52006,52007,52008,52009,null,null,null,null,null,null,52010,52011,52012,52013,52014,52015,52016,52017,52018,52019,52020,52021,52022,52023,52024,52025,52026,52027,52028,52029,52030,52031,52032,52034,52035,52036,null,null,null,null,null,null,52037,52038,52039,52042,52043,52045,52046,52047,52049,52050,52051,52052,52053,52054,52055,52058,52059,52060,52062,52063,52064,52065,52066,52067,52069,52070,52071,52072,52073,52074,52075,52076,13205,13206,13207,8467,13208,13252,13219,13220,13221,13222,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13258,13197,13198,13199,13263,13192,13193,13256,13223,13224,13232,13233,13234,13235,13236,13237,13238,13239,13240,13241,13184,13185,13186,13187,13188,13242,13243,13244,13245,13246,13247,13200,13201,13202,13203,13204,8486,13248,13249,13194,13195,13196,13270,13253,13229,13230,13231,13275,13225,13226,13227,13228,13277,13264,13267,13251,13257,13276,13254,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52077,52078,52079,52080,52081,52082,52083,52084,52085,52086,52087,52090,52091,52092,52093,52094,52095,52096,52097,52098,52099,52100,52101,52102,52103,52104,null,null,null,null,null,null,52105,52106,52107,52108,52109,52110,52111,52112,52113,52114,52115,52116,52117,52118,52119,52120,52121,52122,52123,52125,52126,52127,52128,52129,52130,52131,null,null,null,null,null,null,52132,52133,52134,52135,52136,52137,52138,52139,52140,52141,52142,52143,52144,52145,52146,52147,52148,52149,52150,52151,52153,52154,52155,52156,52157,52158,52159,52160,52161,52162,52163,52164,198,208,170,294,null,306,null,319,321,216,338,186,222,358,330,null,12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,9424,9425,9426,9427,9428,9429,9430,9431,9432,9433,9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446,9447,9448,9449,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,189,8531,8532,188,190,8539,8540,8541,8542,52165,52166,52167,52168,52169,52170,52171,52172,52173,52174,52175,52176,52177,52178,52179,52181,52182,52183,52184,52185,52186,52187,52188,52189,52190,52191,null,null,null,null,null,null,52192,52193,52194,52195,52197,52198,52200,52202,52203,52204,52205,52206,52207,52208,52209,52210,52211,52212,52213,52214,52215,52216,52217,52218,52219,52220,null,null,null,null,null,null,52221,52222,52223,52224,52225,52226,52227,52228,52229,52230,52231,52232,52233,52234,52235,52238,52239,52241,52242,52243,52245,52246,52247,52248,52249,52250,52251,52254,52255,52256,52259,52260,230,273,240,295,305,307,312,320,322,248,339,223,254,359,331,329,12800,12801,12802,12803,12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,12818,12819,12820,12821,12822,12823,12824,12825,12826,12827,9372,9373,9374,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,9396,9397,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,185,178,179,8308,8319,8321,8322,8323,8324,52261,52262,52266,52267,52269,52271,52273,52274,52275,52276,52277,52278,52279,52282,52287,52288,52289,52290,52291,52294,52295,52297,52298,52299,52301,52302,null,null,null,null,null,null,52303,52304,52305,52306,52307,52310,52314,52315,52316,52317,52318,52319,52321,52322,52323,52325,52327,52329,52330,52331,52332,52333,52334,52335,52337,52338,null,null,null,null,null,null,52339,52340,52342,52343,52344,52345,52346,52347,52348,52349,52350,52351,52352,52353,52354,52355,52356,52357,52358,52359,52360,52361,52362,52363,52364,52365,52366,52367,52368,52369,52370,52371,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,null,null,null,null,null,null,null,null,null,null,null,52372,52373,52374,52375,52378,52379,52381,52382,52383,52385,52386,52387,52388,52389,52390,52391,52394,52398,52399,52400,52401,52402,52403,52406,52407,52409,null,null,null,null,null,null,52410,52411,52413,52414,52415,52416,52417,52418,52419,52422,52424,52426,52427,52428,52429,52430,52431,52433,52434,52435,52437,52438,52439,52440,52441,52442,null,null,null,null,null,null,52443,52444,52445,52446,52447,52448,52449,52450,52451,52453,52454,52455,52456,52457,52458,52459,52461,52462,52463,52465,52466,52467,52468,52469,52470,52471,52472,52473,52474,52475,52476,52477,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,null,null,null,null,null,null,null,null,52478,52479,52480,52482,52483,52484,52485,52486,52487,52490,52491,52493,52494,52495,52497,52498,52499,52500,52501,52502,52503,52506,52508,52510,52511,52512,null,null,null,null,null,null,52513,52514,52515,52517,52518,52519,52521,52522,52523,52525,52526,52527,52528,52529,52530,52531,52532,52533,52534,52535,52536,52538,52539,52540,52541,52542,null,null,null,null,null,null,52543,52544,52545,52546,52547,52548,52549,52550,52551,52552,52553,52554,52555,52556,52557,52558,52559,52560,52561,52562,52563,52564,52565,52566,52567,52568,52569,52570,52571,52573,52574,52575,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,null,null,null,null,null,null,null,null,null,null,null,null,null,52577,52578,52579,52581,52582,52583,52584,52585,52586,52587,52590,52592,52594,52595,52596,52597,52598,52599,52601,52602,52603,52604,52605,52606,52607,52608,null,null,null,null,null,null,52609,52610,52611,52612,52613,52614,52615,52617,52618,52619,52620,52621,52622,52623,52624,52625,52626,52627,52630,52631,52633,52634,52635,52637,52638,52639,null,null,null,null,null,null,52640,52641,52642,52643,52646,52648,52650,52651,52652,52653,52654,52655,52657,52658,52659,52660,52661,52662,52663,52664,52665,52666,52667,52668,52669,52670,52671,52672,52673,52674,52675,52677,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52678,52679,52680,52681,52682,52683,52685,52686,52687,52689,52690,52691,52692,52693,52694,52695,52696,52697,52698,52699,52700,52701,52702,52703,52704,52705,null,null,null,null,null,null,52706,52707,52708,52709,52710,52711,52713,52714,52715,52717,52718,52719,52721,52722,52723,52724,52725,52726,52727,52730,52732,52734,52735,52736,52737,52738,null,null,null,null,null,null,52739,52741,52742,52743,52745,52746,52747,52749,52750,52751,52752,52753,52754,52755,52757,52758,52759,52760,52762,52763,52764,52765,52766,52767,52770,52771,52773,52774,52775,52777,52778,52779,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52780,52781,52782,52783,52786,52788,52790,52791,52792,52793,52794,52795,52796,52797,52798,52799,52800,52801,52802,52803,52804,52805,52806,52807,52808,52809,null,null,null,null,null,null,52810,52811,52812,52813,52814,52815,52816,52817,52818,52819,52820,52821,52822,52823,52826,52827,52829,52830,52834,52835,52836,52837,52838,52839,52842,52844,null,null,null,null,null,null,52846,52847,52848,52849,52850,52851,52854,52855,52857,52858,52859,52861,52862,52863,52864,52865,52866,52867,52870,52872,52874,52875,52876,52877,52878,52879,52882,52883,52885,52886,52887,52889,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52890,52891,52892,52893,52894,52895,52898,52902,52903,52904,52905,52906,52907,52910,52911,52912,52913,52914,52915,52916,52917,52918,52919,52920,52921,52922,null,null,null,null,null,null,52923,52924,52925,52926,52927,52928,52930,52931,52932,52933,52934,52935,52936,52937,52938,52939,52940,52941,52942,52943,52944,52945,52946,52947,52948,52949,null,null,null,null,null,null,52950,52951,52952,52953,52954,52955,52956,52957,52958,52959,52960,52961,52962,52963,52966,52967,52969,52970,52973,52974,52975,52976,52977,52978,52979,52982,52986,52987,52988,52989,52990,52991,44032,44033,44036,44039,44040,44041,44042,44048,44049,44050,44051,44052,44053,44054,44055,44057,44058,44059,44060,44061,44064,44068,44076,44077,44079,44080,44081,44088,44089,44092,44096,44107,44109,44116,44120,44124,44144,44145,44148,44151,44152,44154,44160,44161,44163,44164,44165,44166,44169,44170,44171,44172,44176,44180,44188,44189,44191,44192,44193,44200,44201,44202,44204,44207,44208,44216,44217,44219,44220,44221,44225,44228,44232,44236,44245,44247,44256,44257,44260,44263,44264,44266,44268,44271,44272,44273,44275,44277,44278,44284,44285,44288,44292,44294,52994,52995,52997,52998,52999,53001,53002,53003,53004,53005,53006,53007,53010,53012,53014,53015,53016,53017,53018,53019,53021,53022,53023,53025,53026,53027,null,null,null,null,null,null,53029,53030,53031,53032,53033,53034,53035,53038,53042,53043,53044,53045,53046,53047,53049,53050,53051,53052,53053,53054,53055,53056,53057,53058,53059,53060,null,null,null,null,null,null,53061,53062,53063,53064,53065,53066,53067,53068,53069,53070,53071,53072,53073,53074,53075,53078,53079,53081,53082,53083,53085,53086,53087,53088,53089,53090,53091,53094,53096,53098,53099,53100,44300,44301,44303,44305,44312,44316,44320,44329,44332,44333,44340,44341,44344,44348,44356,44357,44359,44361,44368,44372,44376,44385,44387,44396,44397,44400,44403,44404,44405,44406,44411,44412,44413,44415,44417,44418,44424,44425,44428,44432,44444,44445,44452,44471,44480,44481,44484,44488,44496,44497,44499,44508,44512,44516,44536,44537,44540,44543,44544,44545,44552,44553,44555,44557,44564,44592,44593,44596,44599,44600,44602,44608,44609,44611,44613,44614,44618,44620,44621,44622,44624,44628,44630,44636,44637,44639,44640,44641,44645,44648,44649,44652,44656,44664,53101,53102,53103,53106,53107,53109,53110,53111,53113,53114,53115,53116,53117,53118,53119,53121,53122,53123,53124,53126,53127,53128,53129,53130,53131,53133,null,null,null,null,null,null,53134,53135,53136,53137,53138,53139,53140,53141,53142,53143,53144,53145,53146,53147,53148,53149,53150,53151,53152,53154,53155,53156,53157,53158,53159,53161,null,null,null,null,null,null,53162,53163,53164,53165,53166,53167,53169,53170,53171,53172,53173,53174,53175,53176,53177,53178,53179,53180,53181,53182,53183,53184,53185,53186,53187,53189,53190,53191,53192,53193,53194,53195,44665,44667,44668,44669,44676,44677,44684,44732,44733,44734,44736,44740,44748,44749,44751,44752,44753,44760,44761,44764,44776,44779,44781,44788,44792,44796,44807,44808,44813,44816,44844,44845,44848,44850,44852,44860,44861,44863,44865,44866,44867,44872,44873,44880,44892,44893,44900,44901,44921,44928,44932,44936,44944,44945,44949,44956,44984,44985,44988,44992,44999,45000,45001,45003,45005,45006,45012,45020,45032,45033,45040,45041,45044,45048,45056,45057,45060,45068,45072,45076,45084,45085,45096,45124,45125,45128,45130,45132,45134,45139,45140,45141,45143,45145,53196,53197,53198,53199,53200,53201,53202,53203,53204,53205,53206,53207,53208,53209,53210,53211,53212,53213,53214,53215,53218,53219,53221,53222,53223,53225,null,null,null,null,null,null,53226,53227,53228,53229,53230,53231,53234,53236,53238,53239,53240,53241,53242,53243,53245,53246,53247,53249,53250,53251,53253,53254,53255,53256,53257,53258,null,null,null,null,null,null,53259,53260,53261,53262,53263,53264,53266,53267,53268,53269,53270,53271,53273,53274,53275,53276,53277,53278,53279,53280,53281,53282,53283,53284,53285,53286,53287,53288,53289,53290,53291,53292,45149,45180,45181,45184,45188,45196,45197,45199,45201,45208,45209,45210,45212,45215,45216,45217,45218,45224,45225,45227,45228,45229,45230,45231,45233,45235,45236,45237,45240,45244,45252,45253,45255,45256,45257,45264,45265,45268,45272,45280,45285,45320,45321,45323,45324,45328,45330,45331,45336,45337,45339,45340,45341,45347,45348,45349,45352,45356,45364,45365,45367,45368,45369,45376,45377,45380,45384,45392,45393,45396,45397,45400,45404,45408,45432,45433,45436,45440,45442,45448,45449,45451,45453,45458,45459,45460,45464,45468,45480,45516,45520,45524,45532,45533,53294,53295,53296,53297,53298,53299,53302,53303,53305,53306,53307,53309,53310,53311,53312,53313,53314,53315,53318,53320,53322,53323,53324,53325,53326,53327,null,null,null,null,null,null,53329,53330,53331,53333,53334,53335,53337,53338,53339,53340,53341,53342,53343,53345,53346,53347,53348,53349,53350,53351,53352,53353,53354,53355,53358,53359,null,null,null,null,null,null,53361,53362,53363,53365,53366,53367,53368,53369,53370,53371,53374,53375,53376,53378,53379,53380,53381,53382,53383,53384,53385,53386,53387,53388,53389,53390,53391,53392,53393,53394,53395,53396,45535,45544,45545,45548,45552,45561,45563,45565,45572,45573,45576,45579,45580,45588,45589,45591,45593,45600,45620,45628,45656,45660,45664,45672,45673,45684,45685,45692,45700,45701,45705,45712,45713,45716,45720,45721,45722,45728,45729,45731,45733,45734,45738,45740,45744,45748,45768,45769,45772,45776,45778,45784,45785,45787,45789,45794,45796,45797,45798,45800,45803,45804,45805,45806,45807,45811,45812,45813,45815,45816,45817,45818,45819,45823,45824,45825,45828,45832,45840,45841,45843,45844,45845,45852,45908,45909,45910,45912,45915,45916,45918,45919,45924,45925,53397,53398,53399,53400,53401,53402,53403,53404,53405,53406,53407,53408,53409,53410,53411,53414,53415,53417,53418,53419,53421,53422,53423,53424,53425,53426,null,null,null,null,null,null,53427,53430,53432,53434,53435,53436,53437,53438,53439,53442,53443,53445,53446,53447,53450,53451,53452,53453,53454,53455,53458,53462,53463,53464,53465,53466,null,null,null,null,null,null,53467,53470,53471,53473,53474,53475,53477,53478,53479,53480,53481,53482,53483,53486,53490,53491,53492,53493,53494,53495,53497,53498,53499,53500,53501,53502,53503,53504,53505,53506,53507,53508,45927,45929,45931,45934,45936,45937,45940,45944,45952,45953,45955,45956,45957,45964,45968,45972,45984,45985,45992,45996,46020,46021,46024,46027,46028,46030,46032,46036,46037,46039,46041,46043,46045,46048,46052,46056,46076,46096,46104,46108,46112,46120,46121,46123,46132,46160,46161,46164,46168,46176,46177,46179,46181,46188,46208,46216,46237,46244,46248,46252,46261,46263,46265,46272,46276,46280,46288,46293,46300,46301,46304,46307,46308,46310,46316,46317,46319,46321,46328,46356,46357,46360,46363,46364,46372,46373,46375,46376,46377,46378,46384,46385,46388,46392,53509,53510,53511,53512,53513,53514,53515,53516,53518,53519,53520,53521,53522,53523,53524,53525,53526,53527,53528,53529,53530,53531,53532,53533,53534,53535,null,null,null,null,null,null,53536,53537,53538,53539,53540,53541,53542,53543,53544,53545,53546,53547,53548,53549,53550,53551,53554,53555,53557,53558,53559,53561,53563,53564,53565,53566,null,null,null,null,null,null,53567,53570,53574,53575,53576,53577,53578,53579,53582,53583,53585,53586,53587,53589,53590,53591,53592,53593,53594,53595,53598,53600,53602,53603,53604,53605,53606,53607,53609,53610,53611,53613,46400,46401,46403,46404,46405,46411,46412,46413,46416,46420,46428,46429,46431,46432,46433,46496,46497,46500,46504,46506,46507,46512,46513,46515,46516,46517,46523,46524,46525,46528,46532,46540,46541,46543,46544,46545,46552,46572,46608,46609,46612,46616,46629,46636,46644,46664,46692,46696,46748,46749,46752,46756,46763,46764,46769,46804,46832,46836,46840,46848,46849,46853,46888,46889,46892,46895,46896,46904,46905,46907,46916,46920,46924,46932,46933,46944,46948,46952,46960,46961,46963,46965,46972,46973,46976,46980,46988,46989,46991,46992,46993,46994,46998,46999,53614,53615,53616,53617,53618,53619,53620,53621,53622,53623,53624,53625,53626,53627,53629,53630,53631,53632,53633,53634,53635,53637,53638,53639,53641,53642,null,null,null,null,null,null,53643,53644,53645,53646,53647,53648,53649,53650,53651,53652,53653,53654,53655,53656,53657,53658,53659,53660,53661,53662,53663,53666,53667,53669,53670,53671,null,null,null,null,null,null,53673,53674,53675,53676,53677,53678,53679,53682,53684,53686,53687,53688,53689,53691,53693,53694,53695,53697,53698,53699,53700,53701,53702,53703,53704,53705,53706,53707,53708,53709,53710,53711,47000,47001,47004,47008,47016,47017,47019,47020,47021,47028,47029,47032,47047,47049,47084,47085,47088,47092,47100,47101,47103,47104,47105,47111,47112,47113,47116,47120,47128,47129,47131,47133,47140,47141,47144,47148,47156,47157,47159,47160,47161,47168,47172,47185,47187,47196,47197,47200,47204,47212,47213,47215,47217,47224,47228,47245,47272,47280,47284,47288,47296,47297,47299,47301,47308,47312,47316,47325,47327,47329,47336,47337,47340,47344,47352,47353,47355,47357,47364,47384,47392,47420,47421,47424,47428,47436,47439,47441,47448,47449,47452,47456,47464,47465,53712,53713,53714,53715,53716,53717,53718,53719,53721,53722,53723,53724,53725,53726,53727,53728,53729,53730,53731,53732,53733,53734,53735,53736,53737,53738,null,null,null,null,null,null,53739,53740,53741,53742,53743,53744,53745,53746,53747,53749,53750,53751,53753,53754,53755,53756,53757,53758,53759,53760,53761,53762,53763,53764,53765,53766,null,null,null,null,null,null,53768,53770,53771,53772,53773,53774,53775,53777,53778,53779,53780,53781,53782,53783,53784,53785,53786,53787,53788,53789,53790,53791,53792,53793,53794,53795,53796,53797,53798,53799,53800,53801,47467,47469,47476,47477,47480,47484,47492,47493,47495,47497,47498,47501,47502,47532,47533,47536,47540,47548,47549,47551,47553,47560,47561,47564,47566,47567,47568,47569,47570,47576,47577,47579,47581,47582,47585,47587,47588,47589,47592,47596,47604,47605,47607,47608,47609,47610,47616,47617,47624,47637,47672,47673,47676,47680,47682,47688,47689,47691,47693,47694,47699,47700,47701,47704,47708,47716,47717,47719,47720,47721,47728,47729,47732,47736,47747,47748,47749,47751,47756,47784,47785,47787,47788,47792,47794,47800,47801,47803,47805,47812,47816,47832,47833,47868,53802,53803,53806,53807,53809,53810,53811,53813,53814,53815,53816,53817,53818,53819,53822,53824,53826,53827,53828,53829,53830,53831,53833,53834,53835,53836,null,null,null,null,null,null,53837,53838,53839,53840,53841,53842,53843,53844,53845,53846,53847,53848,53849,53850,53851,53853,53854,53855,53856,53857,53858,53859,53861,53862,53863,53864,null,null,null,null,null,null,53865,53866,53867,53868,53869,53870,53871,53872,53873,53874,53875,53876,53877,53878,53879,53880,53881,53882,53883,53884,53885,53886,53887,53890,53891,53893,53894,53895,53897,53898,53899,53900,47872,47876,47885,47887,47889,47896,47900,47904,47913,47915,47924,47925,47926,47928,47931,47932,47933,47934,47940,47941,47943,47945,47949,47951,47952,47956,47960,47969,47971,47980,48008,48012,48016,48036,48040,48044,48052,48055,48064,48068,48072,48080,48083,48120,48121,48124,48127,48128,48130,48136,48137,48139,48140,48141,48143,48145,48148,48149,48150,48151,48152,48155,48156,48157,48158,48159,48164,48165,48167,48169,48173,48176,48177,48180,48184,48192,48193,48195,48196,48197,48201,48204,48205,48208,48221,48260,48261,48264,48267,48268,48270,48276,48277,48279,53901,53902,53903,53906,53907,53908,53910,53911,53912,53913,53914,53915,53917,53918,53919,53921,53922,53923,53925,53926,53927,53928,53929,53930,53931,53933,null,null,null,null,null,null,53934,53935,53936,53938,53939,53940,53941,53942,53943,53946,53947,53949,53950,53953,53955,53956,53957,53958,53959,53962,53964,53965,53966,53967,53968,53969,null,null,null,null,null,null,53970,53971,53973,53974,53975,53977,53978,53979,53981,53982,53983,53984,53985,53986,53987,53990,53991,53992,53993,53994,53995,53996,53997,53998,53999,54002,54003,54005,54006,54007,54009,54010,48281,48282,48288,48289,48292,48295,48296,48304,48305,48307,48308,48309,48316,48317,48320,48324,48333,48335,48336,48337,48341,48344,48348,48372,48373,48374,48376,48380,48388,48389,48391,48393,48400,48404,48420,48428,48448,48456,48457,48460,48464,48472,48473,48484,48488,48512,48513,48516,48519,48520,48521,48522,48528,48529,48531,48533,48537,48538,48540,48548,48560,48568,48596,48597,48600,48604,48617,48624,48628,48632,48640,48643,48645,48652,48653,48656,48660,48668,48669,48671,48708,48709,48712,48716,48718,48724,48725,48727,48729,48730,48731,48736,48737,48740,54011,54012,54013,54014,54015,54018,54020,54022,54023,54024,54025,54026,54027,54031,54033,54034,54035,54037,54039,54040,54041,54042,54043,54046,54050,54051,null,null,null,null,null,null,54052,54054,54055,54058,54059,54061,54062,54063,54065,54066,54067,54068,54069,54070,54071,54074,54078,54079,54080,54081,54082,54083,54086,54087,54088,54089,null,null,null,null,null,null,54090,54091,54092,54093,54094,54095,54096,54097,54098,54099,54100,54101,54102,54103,54104,54105,54106,54107,54108,54109,54110,54111,54112,54113,54114,54115,54116,54117,54118,54119,54120,54121,48744,48746,48752,48753,48755,48756,48757,48763,48764,48765,48768,48772,48780,48781,48783,48784,48785,48792,48793,48808,48848,48849,48852,48855,48856,48864,48867,48868,48869,48876,48897,48904,48905,48920,48921,48923,48924,48925,48960,48961,48964,48968,48976,48977,48981,49044,49072,49093,49100,49101,49104,49108,49116,49119,49121,49212,49233,49240,49244,49248,49256,49257,49296,49297,49300,49304,49312,49313,49315,49317,49324,49325,49327,49328,49331,49332,49333,49334,49340,49341,49343,49344,49345,49349,49352,49353,49356,49360,49368,49369,49371,49372,49373,49380,54122,54123,54124,54125,54126,54127,54128,54129,54130,54131,54132,54133,54134,54135,54136,54137,54138,54139,54142,54143,54145,54146,54147,54149,54150,54151,null,null,null,null,null,null,54152,54153,54154,54155,54158,54162,54163,54164,54165,54166,54167,54170,54171,54173,54174,54175,54177,54178,54179,54180,54181,54182,54183,54186,54188,54190,null,null,null,null,null,null,54191,54192,54193,54194,54195,54197,54198,54199,54201,54202,54203,54205,54206,54207,54208,54209,54210,54211,54214,54215,54218,54219,54220,54221,54222,54223,54225,54226,54227,54228,54229,54230,49381,49384,49388,49396,49397,49399,49401,49408,49412,49416,49424,49429,49436,49437,49438,49439,49440,49443,49444,49446,49447,49452,49453,49455,49456,49457,49462,49464,49465,49468,49472,49480,49481,49483,49484,49485,49492,49493,49496,49500,49508,49509,49511,49512,49513,49520,49524,49528,49541,49548,49549,49550,49552,49556,49558,49564,49565,49567,49569,49573,49576,49577,49580,49584,49597,49604,49608,49612,49620,49623,49624,49632,49636,49640,49648,49649,49651,49660,49661,49664,49668,49676,49677,49679,49681,49688,49689,49692,49695,49696,49704,49705,49707,49709,54231,54233,54234,54235,54236,54237,54238,54239,54240,54242,54244,54245,54246,54247,54248,54249,54250,54251,54254,54255,54257,54258,54259,54261,54262,54263,null,null,null,null,null,null,54264,54265,54266,54267,54270,54272,54274,54275,54276,54277,54278,54279,54281,54282,54283,54284,54285,54286,54287,54288,54289,54290,54291,54292,54293,54294,null,null,null,null,null,null,54295,54296,54297,54298,54299,54300,54302,54303,54304,54305,54306,54307,54308,54309,54310,54311,54312,54313,54314,54315,54316,54317,54318,54319,54320,54321,54322,54323,54324,54325,54326,54327,49711,49713,49714,49716,49736,49744,49745,49748,49752,49760,49765,49772,49773,49776,49780,49788,49789,49791,49793,49800,49801,49808,49816,49819,49821,49828,49829,49832,49836,49837,49844,49845,49847,49849,49884,49885,49888,49891,49892,49899,49900,49901,49903,49905,49910,49912,49913,49915,49916,49920,49928,49929,49932,49933,49939,49940,49941,49944,49948,49956,49957,49960,49961,49989,50024,50025,50028,50032,50034,50040,50041,50044,50045,50052,50056,50060,50112,50136,50137,50140,50143,50144,50146,50152,50153,50157,50164,50165,50168,50184,50192,50212,50220,50224,54328,54329,54330,54331,54332,54333,54334,54335,54337,54338,54339,54341,54342,54343,54344,54345,54346,54347,54348,54349,54350,54351,54352,54353,54354,54355,null,null,null,null,null,null,54356,54357,54358,54359,54360,54361,54362,54363,54365,54366,54367,54369,54370,54371,54373,54374,54375,54376,54377,54378,54379,54380,54382,54384,54385,54386,null,null,null,null,null,null,54387,54388,54389,54390,54391,54394,54395,54397,54398,54401,54403,54404,54405,54406,54407,54410,54412,54414,54415,54416,54417,54418,54419,54421,54422,54423,54424,54425,54426,54427,54428,54429,50228,50236,50237,50248,50276,50277,50280,50284,50292,50293,50297,50304,50324,50332,50360,50364,50409,50416,50417,50420,50424,50426,50431,50432,50433,50444,50448,50452,50460,50472,50473,50476,50480,50488,50489,50491,50493,50500,50501,50504,50505,50506,50508,50509,50510,50515,50516,50517,50519,50520,50521,50525,50526,50528,50529,50532,50536,50544,50545,50547,50548,50549,50556,50557,50560,50564,50567,50572,50573,50575,50577,50581,50583,50584,50588,50592,50601,50612,50613,50616,50617,50619,50620,50621,50622,50628,50629,50630,50631,50632,50633,50634,50636,50638,54430,54431,54432,54433,54434,54435,54436,54437,54438,54439,54440,54442,54443,54444,54445,54446,54447,54448,54449,54450,54451,54452,54453,54454,54455,54456,null,null,null,null,null,null,54457,54458,54459,54460,54461,54462,54463,54464,54465,54466,54467,54468,54469,54470,54471,54472,54473,54474,54475,54477,54478,54479,54481,54482,54483,54485,null,null,null,null,null,null,54486,54487,54488,54489,54490,54491,54493,54494,54496,54497,54498,54499,54500,54501,54502,54503,54505,54506,54507,54509,54510,54511,54513,54514,54515,54516,54517,54518,54519,54521,54522,54524,50640,50641,50644,50648,50656,50657,50659,50661,50668,50669,50670,50672,50676,50678,50679,50684,50685,50686,50687,50688,50689,50693,50694,50695,50696,50700,50704,50712,50713,50715,50716,50724,50725,50728,50732,50733,50734,50736,50739,50740,50741,50743,50745,50747,50752,50753,50756,50760,50768,50769,50771,50772,50773,50780,50781,50784,50796,50799,50801,50808,50809,50812,50816,50824,50825,50827,50829,50836,50837,50840,50844,50852,50853,50855,50857,50864,50865,50868,50872,50873,50874,50880,50881,50883,50885,50892,50893,50896,50900,50908,50909,50912,50913,50920,54526,54527,54528,54529,54530,54531,54533,54534,54535,54537,54538,54539,54541,54542,54543,54544,54545,54546,54547,54550,54552,54553,54554,54555,54556,54557,null,null,null,null,null,null,54558,54559,54560,54561,54562,54563,54564,54565,54566,54567,54568,54569,54570,54571,54572,54573,54574,54575,54576,54577,54578,54579,54580,54581,54582,54583,null,null,null,null,null,null,54584,54585,54586,54587,54590,54591,54593,54594,54595,54597,54598,54599,54600,54601,54602,54603,54606,54608,54610,54611,54612,54613,54614,54615,54618,54619,54621,54622,54623,54625,54626,54627,50921,50924,50928,50936,50937,50941,50948,50949,50952,50956,50964,50965,50967,50969,50976,50977,50980,50984,50992,50993,50995,50997,50999,51004,51005,51008,51012,51018,51020,51021,51023,51025,51026,51027,51028,51029,51030,51031,51032,51036,51040,51048,51051,51060,51061,51064,51068,51069,51070,51075,51076,51077,51079,51080,51081,51082,51086,51088,51089,51092,51094,51095,51096,51098,51104,51105,51107,51108,51109,51110,51116,51117,51120,51124,51132,51133,51135,51136,51137,51144,51145,51148,51150,51152,51160,51165,51172,51176,51180,51200,51201,51204,51208,51210,54628,54630,54631,54634,54636,54638,54639,54640,54641,54642,54643,54646,54647,54649,54650,54651,54653,54654,54655,54656,54657,54658,54659,54662,54666,54667,null,null,null,null,null,null,54668,54669,54670,54671,54673,54674,54675,54676,54677,54678,54679,54680,54681,54682,54683,54684,54685,54686,54687,54688,54689,54690,54691,54692,54694,54695,null,null,null,null,null,null,54696,54697,54698,54699,54700,54701,54702,54703,54704,54705,54706,54707,54708,54709,54710,54711,54712,54713,54714,54715,54716,54717,54718,54719,54720,54721,54722,54723,54724,54725,54726,54727,51216,51217,51219,51221,51222,51228,51229,51232,51236,51244,51245,51247,51249,51256,51260,51264,51272,51273,51276,51277,51284,51312,51313,51316,51320,51322,51328,51329,51331,51333,51334,51335,51339,51340,51341,51348,51357,51359,51361,51368,51388,51389,51396,51400,51404,51412,51413,51415,51417,51424,51425,51428,51445,51452,51453,51456,51460,51461,51462,51468,51469,51471,51473,51480,51500,51508,51536,51537,51540,51544,51552,51553,51555,51564,51568,51572,51580,51592,51593,51596,51600,51608,51609,51611,51613,51648,51649,51652,51655,51656,51658,51664,51665,51667,54730,54731,54733,54734,54735,54737,54739,54740,54741,54742,54743,54746,54748,54750,54751,54752,54753,54754,54755,54758,54759,54761,54762,54763,54765,54766,null,null,null,null,null,null,54767,54768,54769,54770,54771,54774,54776,54778,54779,54780,54781,54782,54783,54786,54787,54789,54790,54791,54793,54794,54795,54796,54797,54798,54799,54802,null,null,null,null,null,null,54806,54807,54808,54809,54810,54811,54813,54814,54815,54817,54818,54819,54821,54822,54823,54824,54825,54826,54827,54828,54830,54831,54832,54833,54834,54835,54836,54837,54838,54839,54842,54843,51669,51670,51673,51674,51676,51677,51680,51682,51684,51687,51692,51693,51695,51696,51697,51704,51705,51708,51712,51720,51721,51723,51724,51725,51732,51736,51753,51788,51789,51792,51796,51804,51805,51807,51808,51809,51816,51837,51844,51864,51900,51901,51904,51908,51916,51917,51919,51921,51923,51928,51929,51936,51948,51956,51976,51984,51988,51992,52000,52001,52033,52040,52041,52044,52048,52056,52057,52061,52068,52088,52089,52124,52152,52180,52196,52199,52201,52236,52237,52240,52244,52252,52253,52257,52258,52263,52264,52265,52268,52270,52272,52280,52281,52283,54845,54846,54847,54849,54850,54851,54852,54854,54855,54858,54860,54862,54863,54864,54866,54867,54870,54871,54873,54874,54875,54877,54878,54879,54880,54881,null,null,null,null,null,null,54882,54883,54884,54885,54886,54888,54890,54891,54892,54893,54894,54895,54898,54899,54901,54902,54903,54904,54905,54906,54907,54908,54909,54910,54911,54912,null,null,null,null,null,null,54913,54914,54916,54918,54919,54920,54921,54922,54923,54926,54927,54929,54930,54931,54933,54934,54935,54936,54937,54938,54939,54940,54942,54944,54946,54947,54948,54949,54950,54951,54953,54954,52284,52285,52286,52292,52293,52296,52300,52308,52309,52311,52312,52313,52320,52324,52326,52328,52336,52341,52376,52377,52380,52384,52392,52393,52395,52396,52397,52404,52405,52408,52412,52420,52421,52423,52425,52432,52436,52452,52460,52464,52481,52488,52489,52492,52496,52504,52505,52507,52509,52516,52520,52524,52537,52572,52576,52580,52588,52589,52591,52593,52600,52616,52628,52629,52632,52636,52644,52645,52647,52649,52656,52676,52684,52688,52712,52716,52720,52728,52729,52731,52733,52740,52744,52748,52756,52761,52768,52769,52772,52776,52784,52785,52787,52789,54955,54957,54958,54959,54961,54962,54963,54964,54965,54966,54967,54968,54970,54972,54973,54974,54975,54976,54977,54978,54979,54982,54983,54985,54986,54987,null,null,null,null,null,null,54989,54990,54991,54992,54994,54995,54997,54998,55000,55002,55003,55004,55005,55006,55007,55009,55010,55011,55013,55014,55015,55017,55018,55019,55020,55021,null,null,null,null,null,null,55022,55023,55025,55026,55027,55028,55030,55031,55032,55033,55034,55035,55038,55039,55041,55042,55043,55045,55046,55047,55048,55049,55050,55051,55052,55053,55054,55055,55056,55058,55059,55060,52824,52825,52828,52831,52832,52833,52840,52841,52843,52845,52852,52853,52856,52860,52868,52869,52871,52873,52880,52881,52884,52888,52896,52897,52899,52900,52901,52908,52909,52929,52964,52965,52968,52971,52972,52980,52981,52983,52984,52985,52992,52993,52996,53000,53008,53009,53011,53013,53020,53024,53028,53036,53037,53039,53040,53041,53048,53076,53077,53080,53084,53092,53093,53095,53097,53104,53105,53108,53112,53120,53125,53132,53153,53160,53168,53188,53216,53217,53220,53224,53232,53233,53235,53237,53244,53248,53252,53265,53272,53293,53300,53301,53304,53308,55061,55062,55063,55066,55067,55069,55070,55071,55073,55074,55075,55076,55077,55078,55079,55082,55084,55086,55087,55088,55089,55090,55091,55094,55095,55097,null,null,null,null,null,null,55098,55099,55101,55102,55103,55104,55105,55106,55107,55109,55110,55112,55114,55115,55116,55117,55118,55119,55122,55123,55125,55130,55131,55132,55133,55134,null,null,null,null,null,null,55135,55138,55140,55142,55143,55144,55146,55147,55149,55150,55151,55153,55154,55155,55157,55158,55159,55160,55161,55162,55163,55166,55167,55168,55170,55171,55172,55173,55174,55175,55178,55179,53316,53317,53319,53321,53328,53332,53336,53344,53356,53357,53360,53364,53372,53373,53377,53412,53413,53416,53420,53428,53429,53431,53433,53440,53441,53444,53448,53449,53456,53457,53459,53460,53461,53468,53469,53472,53476,53484,53485,53487,53488,53489,53496,53517,53552,53553,53556,53560,53562,53568,53569,53571,53572,53573,53580,53581,53584,53588,53596,53597,53599,53601,53608,53612,53628,53636,53640,53664,53665,53668,53672,53680,53681,53683,53685,53690,53692,53696,53720,53748,53752,53767,53769,53776,53804,53805,53808,53812,53820,53821,53823,53825,53832,53852,55181,55182,55183,55185,55186,55187,55188,55189,55190,55191,55194,55196,55198,55199,55200,55201,55202,55203,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,53860,53888,53889,53892,53896,53904,53905,53909,53916,53920,53924,53932,53937,53944,53945,53948,53951,53952,53954,53960,53961,53963,53972,53976,53980,53988,53989,54000,54001,54004,54008,54016,54017,54019,54021,54028,54029,54030,54032,54036,54038,54044,54045,54047,54048,54049,54053,54056,54057,54060,54064,54072,54073,54075,54076,54077,54084,54085,54140,54141,54144,54148,54156,54157,54159,54160,54161,54168,54169,54172,54176,54184,54185,54187,54189,54196,54200,54204,54212,54213,54216,54217,54224,54232,54241,54243,54252,54253,54256,54260,54268,54269,54271,54273,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,54280,54301,54336,54340,54364,54368,54372,54381,54383,54392,54393,54396,54399,54400,54402,54408,54409,54411,54413,54420,54441,54476,54480,54484,54492,54495,54504,54508,54512,54520,54523,54525,54532,54536,54540,54548,54549,54551,54588,54589,54592,54596,54604,54605,54607,54609,54616,54617,54620,54624,54629,54632,54633,54635,54637,54644,54645,54648,54652,54660,54661,54663,54664,54665,54672,54693,54728,54729,54732,54736,54738,54744,54745,54747,54749,54756,54757,54760,54764,54772,54773,54775,54777,54784,54785,54788,54792,54800,54801,54803,54804,54805,54812,54816,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,54820,54829,54840,54841,54844,54848,54853,54856,54857,54859,54861,54865,54868,54869,54872,54876,54887,54889,54896,54897,54900,54915,54917,54924,54925,54928,54932,54941,54943,54945,54952,54956,54960,54969,54971,54980,54981,54984,54988,54993,54996,54999,55001,55008,55012,55016,55024,55029,55036,55037,55040,55044,55057,55064,55065,55068,55072,55080,55081,55083,55085,55092,55093,55096,55100,55108,55111,55113,55120,55121,55124,55126,55127,55128,55129,55136,55137,55139,55141,55145,55148,55152,55156,55164,55165,55169,55176,55177,55180,55184,55192,55193,55195,55197,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20285,20339,20551,20729,21152,21487,21621,21733,22025,23233,23478,26247,26550,26551,26607,27468,29634,30146,31292,33499,33540,34903,34952,35382,36040,36303,36603,36838,39381,21051,21364,21508,24682,24932,27580,29647,33050,35258,35282,38307,20355,21002,22718,22904,23014,24178,24185,25031,25536,26438,26604,26751,28567,30286,30475,30965,31240,31487,31777,32925,33390,33393,35563,38291,20075,21917,26359,28212,30883,31469,33883,35088,34638,38824,21208,22350,22570,23884,24863,25022,25121,25954,26577,27204,28187,29976,30131,30435,30640,32058,37039,37969,37970,40853,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21283,23724,30002,32987,37440,38296,21083,22536,23004,23713,23831,24247,24378,24394,24951,27743,30074,30086,31968,32115,32177,32652,33108,33313,34193,35137,35611,37628,38477,40007,20171,20215,20491,20977,22607,24887,24894,24936,25913,27114,28433,30117,30342,30422,31623,33445,33995,63744,37799,38283,21888,23458,22353,63745,31923,32697,37301,20520,21435,23621,24040,25298,25454,25818,25831,28192,28844,31067,36317,36382,63746,36989,37445,37624,20094,20214,20581,24062,24314,24838,26967,33137,34388,36423,37749,39467,20062,20625,26480,26688,20745,21133,21138,27298,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30652,37392,40660,21163,24623,36850,20552,25001,25581,25802,26684,27268,28608,33160,35233,38548,22533,29309,29356,29956,32121,32365,32937,35211,35700,36963,40273,25225,27770,28500,32080,32570,35363,20860,24906,31645,35609,37463,37772,20140,20435,20510,20670,20742,21185,21197,21375,22384,22659,24218,24465,24950,25004,25806,25964,26223,26299,26356,26775,28039,28805,28913,29855,29861,29898,30169,30828,30956,31455,31478,32069,32147,32789,32831,33051,33686,35686,36629,36885,37857,38915,38968,39514,39912,20418,21843,22586,22865,23395,23622,24760,25106,26690,26800,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26856,28330,30028,30328,30926,31293,31995,32363,32380,35336,35489,35903,38542,40388,21476,21481,21578,21617,22266,22993,23396,23611,24235,25335,25911,25925,25970,26272,26543,27073,27837,30204,30352,30590,31295,32660,32771,32929,33167,33510,33533,33776,34241,34865,34996,35493,63747,36764,37678,38599,39015,39640,40723,21741,26011,26354,26767,31296,35895,40288,22256,22372,23825,26118,26801,26829,28414,29736,34974,39908,27752,63748,39592,20379,20844,20849,21151,23380,24037,24656,24685,25329,25511,25915,29657,31354,34467,36002,38799,20018,23521,25096,26524,29916,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31185,33747,35463,35506,36328,36942,37707,38982,24275,27112,34303,37101,63749,20896,23448,23532,24931,26874,27454,28748,29743,29912,31649,32592,33733,35264,36011,38364,39208,21038,24669,25324,36866,20362,20809,21281,22745,24291,26336,27960,28826,29378,29654,31568,33009,37979,21350,25499,32619,20054,20608,22602,22750,24618,24871,25296,27088,39745,23439,32024,32945,36703,20132,20689,21676,21932,23308,23968,24039,25898,25934,26657,27211,29409,30350,30703,32094,32761,33184,34126,34527,36611,36686,37066,39171,39509,39851,19992,20037,20061,20167,20465,20855,21246,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21312,21475,21477,21646,22036,22389,22434,23495,23943,24272,25084,25304,25937,26552,26601,27083,27472,27590,27628,27714,28317,28792,29399,29590,29699,30655,30697,31350,32127,32777,33276,33285,33290,33503,34914,35635,36092,36544,36881,37041,37476,37558,39378,39493,40169,40407,40860,22283,23616,33738,38816,38827,40628,21531,31384,32676,35033,36557,37089,22528,23624,25496,31391,23470,24339,31353,31406,33422,36524,20518,21048,21240,21367,22280,25331,25458,27402,28099,30519,21413,29527,34152,36470,38357,26426,27331,28528,35437,36556,39243,63750,26231,27512,36020,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,39740,63751,21483,22317,22862,25542,27131,29674,30789,31418,31429,31998,33909,35215,36211,36917,38312,21243,22343,30023,31584,33740,37406,63752,27224,20811,21067,21127,25119,26840,26997,38553,20677,21156,21220,25027,26020,26681,27135,29822,31563,33465,33771,35250,35641,36817,39241,63753,20170,22935,25810,26129,27278,29748,31105,31165,33449,34942,34943,35167,63754,37670,20235,21450,24613,25201,27762,32026,32102,20120,20834,30684,32943,20225,20238,20854,20864,21980,22120,22331,22522,22524,22804,22855,22931,23492,23696,23822,24049,24190,24524,25216,26071,26083,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26398,26399,26462,26827,26820,27231,27450,27683,27773,27778,28103,29592,29734,29738,29826,29859,30072,30079,30849,30959,31041,31047,31048,31098,31637,32000,32186,32648,32774,32813,32908,35352,35663,35912,36215,37665,37668,39138,39249,39438,39439,39525,40594,32202,20342,21513,25326,26708,37329,21931,20794,63755,63756,23068,25062,63757,25295,25343,63758,63759,63760,63761,63762,63763,37027,63764,63765,63766,63767,63768,35582,63769,63770,63771,63772,26262,63773,29014,63774,63775,38627,63776,25423,25466,21335,63777,26511,26976,28275,63778,30007,63779,63780,63781,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32013,63782,63783,34930,22218,23064,63784,63785,63786,63787,63788,20035,63789,20839,22856,26608,32784,63790,22899,24180,25754,31178,24565,24684,25288,25467,23527,23511,21162,63791,22900,24361,24594,63792,63793,63794,29785,63795,63796,63797,63798,63799,63800,39377,63801,63802,63803,63804,63805,63806,63807,63808,63809,63810,63811,28611,63812,63813,33215,36786,24817,63814,63815,33126,63816,63817,23615,63818,63819,63820,63821,63822,63823,63824,63825,23273,35365,26491,32016,63826,63827,63828,63829,63830,63831,33021,63832,63833,23612,27877,21311,28346,22810,33590,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20025,20150,20294,21934,22296,22727,24406,26039,26086,27264,27573,28237,30701,31471,31774,32222,34507,34962,37170,37723,25787,28606,29562,30136,36948,21846,22349,25018,25812,26311,28129,28251,28525,28601,30192,32835,33213,34113,35203,35527,35674,37663,27795,30035,31572,36367,36957,21776,22530,22616,24162,25095,25758,26848,30070,31958,34739,40680,20195,22408,22382,22823,23565,23729,24118,24453,25140,25825,29619,33274,34955,36024,38538,40667,23429,24503,24755,20498,20992,21040,22294,22581,22615,23566,23648,23798,23947,24230,24466,24764,25361,25481,25623,26691,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26873,27330,28120,28193,28372,28644,29182,30428,30585,31153,31291,33796,35241,36077,36339,36424,36867,36884,36947,37117,37709,38518,38876,27602,28678,29272,29346,29544,30563,31167,31716,32411,35712,22697,24775,25958,26109,26302,27788,28958,29129,35930,38931,20077,31361,20189,20908,20941,21205,21516,24999,26481,26704,26847,27934,28540,30140,30643,31461,33012,33891,37509,20828,26007,26460,26515,30168,31431,33651,63834,35910,36887,38957,23663,33216,33434,36929,36975,37389,24471,23965,27225,29128,30331,31561,34276,35588,37159,39472,21895,25078,63835,30313,32645,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,34367,34746,35064,37007,63836,27931,28889,29662,32097,33853,63837,37226,39409,63838,20098,21365,27396,27410,28734,29211,34349,40478,21068,36771,23888,25829,25900,27414,28651,31811,32412,34253,35172,35261,25289,33240,34847,24266,26391,28010,29436,29701,29807,34690,37086,20358,23821,24480,33802,20919,25504,30053,20142,20486,20841,20937,26753,27153,31918,31921,31975,33391,35538,36635,37327,20406,20791,21237,21570,24300,24942,25150,26053,27354,28670,31018,34268,34851,38317,39522,39530,40599,40654,21147,26310,27511,28701,31019,36706,38722,24976,25088,25891,28451,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29001,29833,32244,32879,34030,36646,36899,37706,20925,21015,21155,27916,28872,35010,24265,25986,27566,28610,31806,29557,20196,20278,22265,63839,23738,23994,24604,29618,31533,32666,32718,32838,36894,37428,38646,38728,38936,40801,20363,28583,31150,37300,38583,21214,63840,25736,25796,27347,28510,28696,29200,30439,32769,34310,34396,36335,36613,38706,39791,40442,40565,30860,31103,32160,33737,37636,40575,40595,35542,22751,24324,26407,28711,29903,31840,32894,20769,28712,29282,30922,36034,36058,36084,38647,20102,20698,23534,24278,26009,29134,30274,30637,32842,34044,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36988,39719,40845,22744,23105,23650,27155,28122,28431,30267,32047,32311,34078,35128,37860,38475,21129,26066,26611,27060,27969,28316,28687,29705,29792,30041,30244,30827,35628,39006,20845,25134,38520,20374,20523,23833,28138,32184,36650,24459,24900,26647,63841,38534,21202,32907,20956,20940,26974,31260,32190,33777,38517,20442,21033,21400,21519,21774,23653,24743,26446,26792,28012,29313,29432,29702,29827,63842,30178,31852,32633,32696,33673,35023,35041,37324,37328,38626,39881,21533,28542,29136,29848,34298,36522,38563,40023,40607,26519,28107,29747,33256,38678,30764,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31435,31520,31890,25705,29802,30194,30908,30952,39340,39764,40635,23518,24149,28448,33180,33707,37000,19975,21325,23081,24018,24398,24930,25405,26217,26364,28415,28459,28771,30622,33836,34067,34875,36627,39237,39995,21788,25273,26411,27819,33545,35178,38778,20129,22916,24536,24537,26395,32178,32596,33426,33579,33725,36638,37017,22475,22969,23186,23504,26151,26522,26757,27599,29028,32629,36023,36067,36993,39749,33032,35978,38476,39488,40613,23391,27667,29467,30450,30431,33804,20906,35219,20813,20885,21193,26825,27796,30468,30496,32191,32236,38754,40629,28357,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,34065,20901,21517,21629,26126,26269,26919,28319,30399,30609,33559,33986,34719,37225,37528,40180,34946,20398,20882,21215,22982,24125,24917,25720,25721,26286,26576,27169,27597,27611,29279,29281,29761,30520,30683,32791,33468,33541,35584,35624,35980,26408,27792,29287,30446,30566,31302,40361,27519,27794,22818,26406,33945,21359,22675,22937,24287,25551,26164,26483,28218,29483,31447,33495,37672,21209,24043,25006,25035,25098,25287,25771,26080,26969,27494,27595,28961,29687,30045,32326,33310,33538,34154,35491,36031,38695,40289,22696,40664,20497,21006,21563,21839,25991,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,27766,32010,32011,32862,34442,38272,38639,21247,27797,29289,21619,23194,23614,23883,24396,24494,26410,26806,26979,28220,28228,30473,31859,32654,34183,35598,36855,38753,40692,23735,24758,24845,25003,25935,26107,26108,27665,27887,29599,29641,32225,38292,23494,34588,35600,21085,21338,25293,25615,25778,26420,27192,27850,29632,29854,31636,31893,32283,33162,33334,34180,36843,38649,39361,20276,21322,21453,21467,25292,25644,25856,26001,27075,27886,28504,29677,30036,30242,30436,30460,30928,30971,31020,32070,33324,34784,36820,38930,39151,21187,25300,25765,28196,28497,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30332,36299,37297,37474,39662,39747,20515,20621,22346,22952,23592,24135,24439,25151,25918,26041,26049,26121,26507,27036,28354,30917,32033,32938,33152,33323,33459,33953,34444,35370,35607,37030,38450,40848,20493,20467,63843,22521,24472,25308,25490,26479,28227,28953,30403,32972,32986,35060,35061,35097,36064,36649,37197,38506,20271,20336,24091,26575,26658,30333,30334,39748,24161,27146,29033,29140,30058,63844,32321,34115,34281,39132,20240,31567,32624,38309,20961,24070,26805,27710,27726,27867,29359,31684,33539,27861,29754,20731,21128,22721,25816,27287,29863,30294,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30887,34327,38370,38713,63845,21342,24321,35722,36776,36783,37002,21029,30629,40009,40712,19993,20482,20853,23643,24183,26142,26170,26564,26821,28851,29953,30149,31177,31453,36647,39200,39432,20445,22561,22577,23542,26222,27493,27921,28282,28541,29668,29995,33769,35036,35091,35676,36628,20239,20693,21264,21340,23443,24489,26381,31119,33145,33583,34068,35079,35206,36665,36667,39333,39954,26412,20086,20472,22857,23553,23791,23792,25447,26834,28925,29090,29739,32299,34028,34562,36898,37586,40179,19981,20184,20463,20613,21078,21103,21542,21648,22496,22827,23142,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,23386,23413,23500,24220,63846,25206,25975,26023,28014,28325,29238,31526,31807,32566,33104,33105,33178,33344,33433,33705,35331,36000,36070,36091,36212,36282,37096,37340,38428,38468,39385,40167,21271,20998,21545,22132,22707,22868,22894,24575,24996,25198,26128,27774,28954,30406,31881,31966,32027,33452,36033,38640,63847,20315,24343,24447,25282,23849,26379,26842,30844,32323,40300,19989,20633,21269,21290,21329,22915,23138,24199,24754,24970,25161,25209,26000,26503,27047,27604,27606,27607,27608,27832,63848,29749,30202,30738,30865,31189,31192,31875,32203,32737,32933,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,33086,33218,33778,34586,35048,35513,35692,36027,37145,38750,39131,40763,22188,23338,24428,25996,27315,27567,27996,28657,28693,29277,29613,36007,36051,38971,24977,27703,32856,39425,20045,20107,20123,20181,20282,20284,20351,20447,20735,21490,21496,21766,21987,22235,22763,22882,23057,23531,23546,23556,24051,24107,24473,24605,25448,26012,26031,26614,26619,26797,27515,27801,27863,28195,28681,29509,30722,31038,31040,31072,31169,31721,32023,32114,32902,33293,33678,34001,34503,35039,35408,35422,35613,36060,36198,36781,37034,39164,39391,40605,21066,63849,26388,63850,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20632,21034,23665,25955,27733,29642,29987,30109,31639,33948,37240,38704,20087,25746,27578,29022,34217,19977,63851,26441,26862,28183,33439,34072,34923,25591,28545,37394,39087,19978,20663,20687,20767,21830,21930,22039,23360,23577,23776,24120,24202,24224,24258,24819,26705,27233,28248,29245,29248,29376,30456,31077,31665,32724,35059,35316,35443,35937,36062,38684,22622,29885,36093,21959,63852,31329,32034,33394,29298,29983,29989,63853,31513,22661,22779,23996,24207,24246,24464,24661,25234,25471,25933,26257,26329,26360,26646,26866,29312,29790,31598,32110,32214,32626,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32997,33298,34223,35199,35475,36893,37604,40653,40736,22805,22893,24109,24796,26132,26227,26512,27728,28101,28511,30707,30889,33990,37323,37675,20185,20682,20808,21892,23307,23459,25159,25982,26059,28210,29053,29697,29764,29831,29887,30316,31146,32218,32341,32680,33146,33203,33337,34330,34796,35445,36323,36984,37521,37925,39245,39854,21352,23633,26964,27844,27945,28203,33292,34203,35131,35373,35498,38634,40807,21089,26297,27570,32406,34814,36109,38275,38493,25885,28041,29166,63854,22478,22995,23468,24615,24826,25104,26143,26207,29481,29689,30427,30465,31596,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32854,32882,33125,35488,37266,19990,21218,27506,27927,31237,31545,32048,63855,36016,21484,22063,22609,23477,23567,23569,24034,25152,25475,25620,26157,26803,27836,28040,28335,28703,28836,29138,29990,30095,30094,30233,31505,31712,31787,32032,32057,34092,34157,34311,35380,36877,36961,37045,37559,38902,39479,20439,23660,26463,28049,31903,32396,35606,36118,36895,23403,24061,25613,33984,36956,39137,29575,23435,24730,26494,28126,35359,35494,36865,38924,21047,63856,28753,30862,37782,34928,37335,20462,21463,22013,22234,22402,22781,23234,23432,23723,23744,24101,24833,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,25101,25163,25480,25628,25910,25976,27193,27530,27700,27929,28465,29159,29417,29560,29703,29874,30246,30561,31168,31319,31466,31929,32143,32172,32353,32670,33065,33585,33936,34010,34282,34966,35504,35728,36664,36930,36995,37228,37526,37561,38539,38567,38568,38614,38656,38920,39318,39635,39706,21460,22654,22809,23408,23487,28113,28506,29087,29729,29881,32901,33789,24033,24455,24490,24642,26092,26642,26991,27219,27529,27957,28147,29667,30462,30636,31565,32020,33059,33308,33600,34036,34147,35426,35524,37255,37662,38918,39348,25100,34899,36848,37477,23815,23847,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,23913,29791,33181,34664,28629,25342,32722,35126,35186,19998,20056,20711,21213,21319,25215,26119,32361,34821,38494,20365,21273,22070,22987,23204,23608,23630,23629,24066,24337,24643,26045,26159,26178,26558,26612,29468,30690,31034,32709,33940,33997,35222,35430,35433,35553,35925,35962,22516,23508,24335,24687,25325,26893,27542,28252,29060,31698,34645,35672,36606,39135,39166,20280,20353,20449,21627,23072,23480,24892,26032,26216,29180,30003,31070,32051,33102,33251,33688,34218,34254,34563,35338,36523,36763,63857,36805,22833,23460,23526,24713,23529,23563,24515,27777,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63858,28145,28683,29978,33455,35574,20160,21313,63859,38617,27663,20126,20420,20818,21854,23077,23784,25105,29273,33469,33706,34558,34905,35357,38463,38597,39187,40201,40285,22538,23731,23997,24132,24801,24853,25569,27138,28197,37122,37716,38990,39952,40823,23433,23736,25353,26191,26696,30524,38593,38797,38996,39839,26017,35585,36555,38332,21813,23721,24022,24245,26263,30284,33780,38343,22739,25276,29390,40232,20208,22830,24591,26171,27523,31207,40230,21395,21696,22467,23830,24859,26326,28079,30861,33406,38552,38724,21380,25212,25494,28082,32266,33099,38989,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,27387,32588,40367,40474,20063,20539,20918,22812,24825,25590,26928,29242,32822,63860,37326,24369,63861,63862,32004,33509,33903,33979,34277,36493,63863,20335,63864,63865,22756,23363,24665,25562,25880,25965,26264,63866,26954,27171,27915,28673,29036,30162,30221,31155,31344,63867,32650,63868,35140,63869,35731,37312,38525,63870,39178,22276,24481,26044,28417,30208,31142,35486,39341,39770,40812,20740,25014,25233,27277,33222,20547,22576,24422,28937,35328,35578,23420,34326,20474,20796,22196,22852,25513,28153,23978,26989,20870,20104,20313,63871,63872,63873,22914,63874,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63875,27487,27741,63876,29877,30998,63877,33287,33349,33593,36671,36701,63878,39192,63879,63880,63881,20134,63882,22495,24441,26131,63883,63884,30123,32377,35695,63885,36870,39515,22181,22567,23032,23071,23476,63886,24310,63887,63888,25424,25403,63889,26941,27783,27839,28046,28051,28149,28436,63890,28895,28982,29017,63891,29123,29141,63892,30799,30831,63893,31605,32227,63894,32303,63895,34893,36575,63896,63897,63898,37467,63899,40182,63900,63901,63902,24709,28037,63903,29105,63904,63905,38321,21421,63906,63907,63908,26579,63909,28814,28976,29744,33398,33490,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63910,38331,39653,40573,26308,63911,29121,33865,63912,63913,22603,63914,63915,23992,24433,63916,26144,26254,27001,27054,27704,27891,28214,28481,28634,28699,28719,29008,29151,29552,63917,29787,63918,29908,30408,31310,32403,63919,63920,33521,35424,36814,63921,37704,63922,38681,63923,63924,20034,20522,63925,21000,21473,26355,27757,28618,29450,30591,31330,33454,34269,34306,63926,35028,35427,35709,35947,63927,37555,63928,38675,38928,20116,20237,20425,20658,21320,21566,21555,21978,22626,22714,22887,23067,23524,24735,63929,25034,25942,26111,26212,26791,27738,28595,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,28879,29100,29522,31613,34568,35492,39986,40711,23627,27779,29508,29577,37434,28331,29797,30239,31337,32277,34314,20800,22725,25793,29934,29973,30320,32705,37013,38605,39252,28198,29926,31401,31402,33253,34521,34680,35355,23113,23436,23451,26785,26880,28003,29609,29715,29740,30871,32233,32747,33048,33109,33694,35916,38446,38929,26352,24448,26106,26505,27754,29579,20525,23043,27498,30702,22806,23916,24013,29477,30031,63930,63931,20709,20985,22575,22829,22934,23002,23525,63932,63933,23970,25303,25622,25747,25854,63934,26332,63935,27208,63936,29183,29796,63937,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31368,31407,32327,32350,32768,33136,63938,34799,35201,35616,36953,63939,36992,39250,24958,27442,28020,32287,35109,36785,20433,20653,20887,21191,22471,22665,23481,24248,24898,27029,28044,28263,28342,29076,29794,29992,29996,32883,33592,33993,36362,37780,37854,63940,20110,20305,20598,20778,21448,21451,21491,23431,23507,23588,24858,24962,26100,29275,29591,29760,30402,31056,31121,31161,32006,32701,33419,34261,34398,36802,36935,37109,37354,38533,38632,38633,21206,24423,26093,26161,26671,29020,31286,37057,38922,20113,63941,27218,27550,28560,29065,32792,33464,34131,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36939,38549,38642,38907,34074,39729,20112,29066,38596,20803,21407,21729,22291,22290,22435,23195,23236,23491,24616,24895,25588,27781,27961,28274,28304,29232,29503,29783,33489,34945,36677,36960,63942,38498,39000,40219,26376,36234,37470,20301,20553,20702,21361,22285,22996,23041,23561,24944,26256,28205,29234,29771,32239,32963,33806,33894,34111,34655,34907,35096,35586,36949,38859,39759,20083,20369,20754,20842,63943,21807,21929,23418,23461,24188,24189,24254,24736,24799,24840,24841,25540,25912,26377,63944,26580,26586,63945,26977,26978,27833,27943,63946,28216,63947,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,28641,29494,29495,63948,29788,30001,63949,30290,63950,63951,32173,33278,33848,35029,35480,35547,35565,36400,36418,36938,36926,36986,37193,37321,37742,63952,63953,22537,63954,27603,32905,32946,63955,63956,20801,22891,23609,63957,63958,28516,29607,32996,36103,63959,37399,38287,63960,63961,63962,63963,32895,25102,28700,32104,34701,63964,22432,24681,24903,27575,35518,37504,38577,20057,21535,28139,34093,38512,38899,39150,25558,27875,37009,20957,25033,33210,40441,20381,20506,20736,23452,24847,25087,25836,26885,27589,30097,30691,32681,33380,34191,34811,34915,35516,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,35696,37291,20108,20197,20234,63965,63966,22839,23016,63967,24050,24347,24411,24609,63968,63969,63970,63971,29246,29669,63972,30064,30157,63973,31227,63974,32780,32819,32900,33505,33617,63975,63976,36029,36019,36999,63977,63978,39156,39180,63979,63980,28727,30410,32714,32716,32764,35610,20154,20161,20995,21360,63981,21693,22240,23035,23493,24341,24525,28270,63982,63983,32106,33589,63984,34451,35469,63985,38765,38775,63986,63987,19968,20314,20350,22777,26085,28322,36920,37808,39353,20219,22764,22922,23001,24641,63988,63989,31252,63990,33615,36035,20837,21316,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63991,63992,63993,20173,21097,23381,33471,20180,21050,21672,22985,23039,23376,23383,23388,24675,24904,28363,28825,29038,29574,29943,30133,30913,32043,32773,33258,33576,34071,34249,35566,36039,38604,20316,21242,22204,26027,26152,28796,28856,29237,32189,33421,37196,38592,40306,23409,26855,27544,28538,30430,23697,26283,28507,31668,31786,34870,38620,19976,20183,21280,22580,22715,22767,22892,23559,24115,24196,24373,25484,26290,26454,27167,27299,27404,28479,29254,63994,29520,29835,31456,31911,33144,33247,33255,33674,33900,34083,34196,34255,35037,36115,37292,38263,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38556,20877,21705,22312,23472,25165,26448,26685,26771,28221,28371,28797,32289,35009,36001,36617,40779,40782,29229,31631,35533,37658,20295,20302,20786,21632,22992,24213,25269,26485,26990,27159,27822,28186,29401,29482,30141,31672,32053,33511,33785,33879,34295,35419,36015,36487,36889,37048,38606,40799,21219,21514,23265,23490,25688,25973,28404,29380,63995,30340,31309,31515,31821,32318,32735,33659,35627,36042,36196,36321,36447,36842,36857,36969,37841,20291,20346,20659,20840,20856,21069,21098,22625,22652,22880,23560,23637,24283,24731,25136,26643,27583,27656,28593,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29006,29728,30000,30008,30033,30322,31564,31627,31661,31686,32399,35438,36670,36681,37439,37523,37666,37931,38651,39002,39019,39198,20999,25130,25240,27993,30308,31434,31680,32118,21344,23742,24215,28472,28857,31896,38673,39822,40670,25509,25722,34678,19969,20117,20141,20572,20597,21576,22979,23450,24128,24237,24311,24449,24773,25402,25919,25972,26060,26230,26232,26622,26984,27273,27491,27712,28096,28136,28191,28254,28702,28833,29582,29693,30010,30555,30855,31118,31243,31357,31934,32142,33351,35330,35562,35998,37165,37194,37336,37478,37580,37664,38662,38742,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38748,38914,40718,21046,21137,21884,22564,24093,24351,24716,25552,26799,28639,31085,31532,33229,34234,35069,35576,36420,37261,38500,38555,38717,38988,40778,20430,20806,20939,21161,22066,24340,24427,25514,25805,26089,26177,26362,26361,26397,26781,26839,27133,28437,28526,29031,29157,29226,29866,30522,31062,31066,31199,31264,31381,31895,31967,32068,32368,32903,34299,34468,35412,35519,36249,36481,36896,36973,37347,38459,38613,40165,26063,31751,36275,37827,23384,23562,21330,25305,29469,20519,23447,24478,24752,24939,26837,28121,29742,31278,32066,32156,32305,33131,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36394,36405,37758,37912,20304,22352,24038,24231,25387,32618,20027,20303,20367,20570,23005,32964,21610,21608,22014,22863,23449,24030,24282,26205,26417,26609,26666,27880,27954,28234,28557,28855,29664,30087,31820,32002,32044,32162,33311,34523,35387,35461,36208,36490,36659,36913,37198,37202,37956,39376,31481,31909,20426,20737,20934,22472,23535,23803,26201,27197,27994,28310,28652,28940,30063,31459,34850,36897,36981,38603,39423,33537,20013,20210,34886,37325,21373,27355,26987,27713,33914,22686,24974,26366,25327,28893,29969,30151,32338,33976,35657,36104,20043,21482,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21675,22320,22336,24535,25345,25351,25711,25903,26088,26234,26525,26547,27490,27744,27802,28460,30693,30757,31049,31063,32025,32930,33026,33267,33437,33463,34584,35468,63996,36100,36286,36978,30452,31257,31287,32340,32887,21767,21972,22645,25391,25634,26185,26187,26733,27035,27524,27941,28337,29645,29800,29857,30043,30137,30433,30494,30603,31206,32265,32285,33275,34095,34967,35386,36049,36587,36784,36914,37805,38499,38515,38663,20356,21489,23018,23241,24089,26702,29894,30142,31209,31378,33187,34541,36074,36300,36845,26015,26389,63997,22519,28503,32221,36655,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,37878,38598,24501,25074,28548,19988,20376,20511,21449,21983,23919,24046,27425,27492,30923,31642,63998,36425,36554,36974,25417,25662,30528,31364,37679,38015,40810,25776,28591,29158,29864,29914,31428,31762,32386,31922,32408,35738,36106,38013,39184,39244,21049,23519,25830,26413,32046,20717,21443,22649,24920,24921,25082,26028,31449,35730,35734,20489,20513,21109,21809,23100,24288,24432,24884,25950,26124,26166,26274,27085,28356,28466,29462,30241,31379,33081,33369,33750,33980,20661,22512,23488,23528,24425,25505,30758,32181,33756,34081,37319,37365,20874,26613,31574,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36012,20932,22971,24765,34389,20508,63999,21076,23610,24957,25114,25299,25842,26021,28364,30240,33034,36448,38495,38587,20191,21315,21912,22825,24029,25797,27849,28154,29588,31359,33307,34214,36068,36368,36983,37351,38369,38433,38854,20984,21746,21894,24505,25764,28552,32180,36639,36685,37941,20681,23574,27838,28155,29979,30651,31805,31844,35449,35522,22558,22974,24086,25463,29266,30090,30571,35548,36028,36626,24307,26228,28152,32893,33729,35531,38737,39894,64000,21059,26367,28053,28399,32224,35558,36910,36958,39636,21021,21119,21736,24980,25220,25307,26786,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26898,26970,27189,28818,28966,30813,30977,30990,31186,31245,32918,33400,33493,33609,34121,35970,36229,37218,37259,37294,20419,22225,29165,30679,34560,35320,23544,24534,26449,37032,21474,22618,23541,24740,24961,25696,32317,32880,34085,37507,25774,20652,23828,26368,22684,25277,25512,26894,27000,27166,28267,30394,31179,33467,33833,35535,36264,36861,37138,37195,37276,37648,37656,37786,38619,39478,39949,19985,30044,31069,31482,31569,31689,32302,33988,36441,36468,36600,36880,26149,26943,29763,20986,26414,40668,20805,24544,27798,34802,34909,34935,24756,33205,33795,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36101,21462,21561,22068,23094,23601,28810,32736,32858,33030,33261,36259,37257,39519,40434,20596,20164,21408,24827,28204,23652,20360,20516,21988,23769,24159,24677,26772,27835,28100,29118,30164,30196,30305,31258,31305,32199,32251,32622,33268,34473,36636,38601,39347,40786,21063,21189,39149,35242,19971,26578,28422,20405,23522,26517,27784,28024,29723,30759,37341,37756,34756,31204,31281,24555,20182,21668,21822,22702,22949,24816,25171,25302,26422,26965,33333,38464,39345,39389,20524,21331,21828,22396,64001,25176,64002,25826,26219,26589,28609,28655,29730,29752,35351,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,37944,21585,22022,22374,24392,24986,27470,28760,28845,32187,35477,22890,33067,25506,30472,32829,36010,22612,25645,27067,23445,24081,28271,64003,34153,20812,21488,22826,24608,24907,27526,27760,27888,31518,32974,33492,36294,37040,39089,64004,25799,28580,25745,25860,20814,21520,22303,35342,24927,26742,64005,30171,31570,32113,36890,22534,27084,33151,35114,36864,38969,20600,22871,22956,25237,36879,39722,24925,29305,38358,22369,23110,24052,25226,25773,25850,26487,27874,27966,29228,29750,30772,32631,33453,36315,38935,21028,22338,26495,29256,29923,36009,36774,37393,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38442,20843,21485,25420,20329,21764,24726,25943,27803,28031,29260,29437,31255,35207,35997,24429,28558,28921,33192,24846,20415,20559,25153,29255,31687,32232,32745,36941,38829,39449,36022,22378,24179,26544,33805,35413,21536,23318,24163,24290,24330,25987,32954,34109,38281,38491,20296,21253,21261,21263,21638,21754,22275,24067,24598,25243,25265,25429,64006,27873,28006,30129,30770,32990,33071,33502,33889,33970,34957,35090,36875,37610,39165,39825,24133,26292,26333,28689,29190,64007,20469,21117,24426,24915,26451,27161,28418,29922,31080,34920,35961,39111,39108,39491,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21697,31263,26963,35575,35914,39080,39342,24444,25259,30130,30382,34987,36991,38466,21305,24380,24517,27852,29644,30050,30091,31558,33534,39325,20047,36924,19979,20309,21414,22799,24264,26160,27827,29781,33655,34662,36032,36944,38686,39957,22737,23416,34384,35604,40372,23506,24680,24717,26097,27735,28450,28579,28698,32597,32752,38289,38290,38480,38867,21106,36676,20989,21547,21688,21859,21898,27323,28085,32216,33382,37532,38519,40569,21512,21704,30418,34532,38308,38356,38492,20130,20233,23022,23270,24055,24658,25239,26477,26689,27782,28207,32568,32923,33322,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,64008,64009,38917,20133,20565,21683,22419,22874,23401,23475,25032,26999,28023,28707,34809,35299,35442,35559,36994,39405,39608,21182,26680,20502,24184,26447,33607,34892,20139,21521,22190,29670,37141,38911,39177,39255,39321,22099,22687,34395,35377,25010,27382,29563,36562,27463,38570,39511,22869,29184,36203,38761,20436,23796,24358,25080,26203,27883,28843,29572,29625,29694,30505,30541,32067,32098,32291,33335,34898,64010,36066,37449,39023,23377,31348,34880,38913,23244,20448,21332,22846,23805,25406,28025,29433,33029,33031,33698,37583,38960,20136,20804,21009,22411,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,24418,27842,28366,28677,28752,28847,29074,29673,29801,33610,34722,34913,36872,37026,37795,39336,20846,24407,24800,24935,26291,34137,36426,37295,38795,20046,20114,21628,22741,22778,22909,23733,24359,25142,25160,26122,26215,27627,28009,28111,28246,28408,28564,28640,28649,28765,29392,29733,29786,29920,30355,31068,31946,32286,32993,33446,33899,33983,34382,34399,34676,35703,35946,37804,38912,39013,24785,25110,37239,23130,26127,28151,28222,29759,39746,24573,24794,31503,21700,24344,27742,27859,27946,28888,32005,34425,35340,40251,21270,21644,23301,27194,28779,30069,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31117,31166,33457,33775,35441,35649,36008,38772,64011,25844,25899,30906,30907,31339,20024,21914,22864,23462,24187,24739,25563,27489,26213,26707,28185,29029,29872,32008,36996,39529,39973,27963,28369,29502,35905,38346,20976,24140,24488,24653,24822,24880,24908,26179,26180,27045,27841,28255,28361,28514,29004,29852,30343,31681,31783,33618,34647,36945,38541,40643,21295,22238,24315,24458,24674,24724,25079,26214,26371,27292,28142,28590,28784,29546,32362,33214,33588,34516,35496,36036,21123,29554,23446,27243,37892,21742,22150,23389,25928,25989,26313,26783,28045,28102,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29243,32948,37237,39501,20399,20505,21402,21518,21564,21897,21957,24127,24460,26429,29030,29661,36869,21211,21235,22628,22734,28932,29071,29179,34224,35347,26248,34216,21927,26244,29002,33841,21321,21913,27585,24409,24509,25582,26249,28999,35569,36637,40638,20241,25658,28875,30054,34407,24676,35662,40440,20807,20982,21256,27958,33016,40657,26133,27427,28824,30165,21507,23673,32007,35350,27424,27453,27462,21560,24688,27965,32725,33288,20694,20958,21916,22123,22221,23020,23305,24076,24985,24984,25137,26206,26342,29081,29113,29114,29351,31143,31232,32690,35440,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],gb18030:[19970,19972,19973,19974,19983,19986,19991,19999,20000,20001,20003,20006,20009,20014,20015,20017,20019,20021,20023,20028,20032,20033,20034,20036,20038,20042,20049,20053,20055,20058,20059,20066,20067,20068,20069,20071,20072,20074,20075,20076,20077,20078,20079,20082,20084,20085,20086,20087,20088,20089,20090,20091,20092,20093,20095,20096,20097,20098,20099,20100,20101,20103,20106,20112,20118,20119,20121,20124,20125,20126,20131,20138,20143,20144,20145,20148,20150,20151,20152,20153,20156,20157,20158,20168,20172,20175,20176,20178,20186,20187,20188,20192,20194,20198,20199,20201,20205,20206,20207,20209,20212,20216,20217,20218,20220,20222,20224,20226,20227,20228,20229,20230,20231,20232,20235,20236,20242,20243,20244,20245,20246,20252,20253,20257,20259,20264,20265,20268,20269,20270,20273,20275,20277,20279,20281,20283,20286,20287,20288,20289,20290,20292,20293,20295,20296,20297,20298,20299,20300,20306,20308,20310,20321,20322,20326,20328,20330,20331,20333,20334,20337,20338,20341,20343,20344,20345,20346,20349,20352,20353,20354,20357,20358,20359,20362,20364,20366,20368,20370,20371,20373,20374,20376,20377,20378,20380,20382,20383,20385,20386,20388,20395,20397,20400,20401,20402,20403,20404,20406,20407,20408,20409,20410,20411,20412,20413,20414,20416,20417,20418,20422,20423,20424,20425,20427,20428,20429,20434,20435,20436,20437,20438,20441,20443,20448,20450,20452,20453,20455,20459,20460,20464,20466,20468,20469,20470,20471,20473,20475,20476,20477,20479,20480,20481,20482,20483,20484,20485,20486,20487,20488,20489,20490,20491,20494,20496,20497,20499,20501,20502,20503,20507,20509,20510,20512,20514,20515,20516,20519,20523,20527,20528,20529,20530,20531,20532,20533,20534,20535,20536,20537,20539,20541,20543,20544,20545,20546,20548,20549,20550,20553,20554,20555,20557,20560,20561,20562,20563,20564,20566,20567,20568,20569,20571,20573,20574,20575,20576,20577,20578,20579,20580,20582,20583,20584,20585,20586,20587,20589,20590,20591,20592,20593,20594,20595,20596,20597,20600,20601,20602,20604,20605,20609,20610,20611,20612,20614,20615,20617,20618,20619,20620,20622,20623,20624,20625,20626,20627,20628,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641,20642,20644,20646,20650,20651,20653,20654,20655,20656,20657,20659,20660,20661,20662,20663,20664,20665,20668,20669,20670,20671,20672,20673,20674,20675,20676,20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,20688,20689,20690,20691,20692,20693,20695,20696,20697,20699,20700,20701,20702,20703,20704,20705,20706,20707,20708,20709,20712,20713,20714,20715,20719,20720,20721,20722,20724,20726,20727,20728,20729,20730,20732,20733,20734,20735,20736,20737,20738,20739,20740,20741,20744,20745,20746,20748,20749,20750,20751,20752,20753,20755,20756,20757,20758,20759,20760,20761,20762,20763,20764,20765,20766,20767,20768,20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,20795,20796,20797,20798,20802,20807,20810,20812,20814,20815,20816,20818,20819,20823,20824,20825,20827,20829,20830,20831,20832,20833,20835,20836,20838,20839,20841,20842,20847,20850,20858,20862,20863,20867,20868,20870,20871,20874,20875,20878,20879,20880,20881,20883,20884,20888,20890,20893,20894,20895,20897,20899,20902,20903,20904,20905,20906,20909,20910,20916,20920,20921,20922,20926,20927,20929,20930,20931,20933,20936,20938,20941,20942,20944,20946,20947,20948,20949,20950,20951,20952,20953,20954,20956,20958,20959,20962,20963,20965,20966,20967,20968,20969,20970,20972,20974,20977,20978,20980,20983,20990,20996,20997,21001,21003,21004,21007,21008,21011,21012,21013,21020,21022,21023,21025,21026,21027,21029,21030,21031,21034,21036,21039,21041,21042,21044,21045,21052,21054,21060,21061,21062,21063,21064,21065,21067,21070,21071,21074,21075,21077,21079,21080,21081,21082,21083,21085,21087,21088,21090,21091,21092,21094,21096,21099,21100,21101,21102,21104,21105,21107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21118,21120,21123,21124,21125,21126,21127,21129,21130,21131,21132,21133,21134,21135,21137,21138,21140,21141,21142,21143,21144,21145,21146,21148,21156,21157,21158,21159,21166,21167,21168,21172,21173,21174,21175,21176,21177,21178,21179,21180,21181,21184,21185,21186,21188,21189,21190,21192,21194,21196,21197,21198,21199,21201,21203,21204,21205,21207,21209,21210,21211,21212,21213,21214,21216,21217,21218,21219,21221,21222,21223,21224,21225,21226,21227,21228,21229,21230,21231,21233,21234,21235,21236,21237,21238,21239,21240,21243,21244,21245,21249,21250,21251,21252,21255,21257,21258,21259,21260,21262,21265,21266,21267,21268,21272,21275,21276,21278,21279,21282,21284,21285,21287,21288,21289,21291,21292,21293,21295,21296,21297,21298,21299,21300,21301,21302,21303,21304,21308,21309,21312,21314,21316,21318,21323,21324,21325,21328,21332,21336,21337,21339,21341,21349,21352,21354,21356,21357,21362,21366,21369,21371,21372,21373,21374,21376,21377,21379,21383,21384,21386,21390,21391,21392,21393,21394,21395,21396,21398,21399,21401,21403,21404,21406,21408,21409,21412,21415,21418,21419,21420,21421,21423,21424,21425,21426,21427,21428,21429,21431,21432,21433,21434,21436,21437,21438,21440,21443,21444,21445,21446,21447,21454,21455,21456,21458,21459,21461,21466,21468,21469,21470,21473,21474,21479,21492,21498,21502,21503,21504,21506,21509,21511,21515,21524,21528,21529,21530,21532,21538,21540,21541,21546,21552,21555,21558,21559,21562,21565,21567,21569,21570,21572,21573,21575,21577,21580,21581,21582,21583,21585,21594,21597,21598,21599,21600,21601,21603,21605,21607,21609,21610,21611,21612,21613,21614,21615,21616,21620,21625,21626,21630,21631,21633,21635,21637,21639,21640,21641,21642,21645,21649,21651,21655,21656,21660,21662,21663,21664,21665,21666,21669,21678,21680,21682,21685,21686,21687,21689,21690,21692,21694,21699,21701,21706,21707,21718,21720,21723,21728,21729,21730,21731,21732,21739,21740,21743,21744,21745,21748,21749,21750,21751,21752,21753,21755,21758,21760,21762,21763,21764,21765,21768,21770,21771,21772,21773,21774,21778,21779,21781,21782,21783,21784,21785,21786,21788,21789,21790,21791,21793,21797,21798,21800,21801,21803,21805,21810,21812,21813,21814,21816,21817,21818,21819,21821,21824,21826,21829,21831,21832,21835,21836,21837,21838,21839,21841,21842,21843,21844,21847,21848,21849,21850,21851,21853,21854,21855,21856,21858,21859,21864,21865,21867,21871,21872,21873,21874,21875,21876,21881,21882,21885,21887,21893,21894,21900,21901,21902,21904,21906,21907,21909,21910,21911,21914,21915,21918,21920,21921,21922,21923,21924,21925,21926,21928,21929,21930,21931,21932,21933,21934,21935,21936,21938,21940,21942,21944,21946,21948,21951,21952,21953,21954,21955,21958,21959,21960,21962,21963,21966,21967,21968,21973,21975,21976,21977,21978,21979,21982,21984,21986,21991,21993,21997,21998,22000,22001,22004,22006,22008,22009,22010,22011,22012,22015,22018,22019,22020,22021,22022,22023,22026,22027,22029,22032,22033,22034,22035,22036,22037,22038,22039,22041,22042,22044,22045,22048,22049,22050,22053,22054,22056,22057,22058,22059,22062,22063,22064,22067,22069,22071,22072,22074,22076,22077,22078,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22095,22096,22097,22098,22099,22101,22102,22106,22107,22109,22110,22111,22112,22113,22115,22117,22118,22119,22125,22126,22127,22128,22130,22131,22132,22133,22135,22136,22137,22138,22141,22142,22143,22144,22145,22146,22147,22148,22151,22152,22153,22154,22155,22156,22157,22160,22161,22162,22164,22165,22166,22167,22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,22178,22180,22181,22182,22183,22184,22185,22186,22187,22188,22189,22190,22192,22193,22194,22195,22196,22197,22198,22200,22201,22202,22203,22205,22206,22207,22208,22209,22210,22211,22212,22213,22214,22215,22216,22217,22219,22220,22221,22222,22223,22224,22225,22226,22227,22229,22230,22232,22233,22236,22243,22245,22246,22247,22248,22249,22250,22252,22254,22255,22258,22259,22262,22263,22264,22267,22268,22272,22273,22274,22277,22279,22283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,22298,22299,22301,22302,22304,22305,22306,22308,22309,22310,22311,22315,22321,22322,22324,22325,22326,22327,22328,22332,22333,22335,22337,22339,22340,22341,22342,22344,22345,22347,22354,22355,22356,22357,22358,22360,22361,22370,22371,22373,22375,22380,22382,22384,22385,22386,22388,22389,22392,22393,22394,22397,22398,22399,22400,22401,22407,22408,22409,22410,22413,22414,22415,22416,22417,22420,22421,22422,22423,22424,22425,22426,22428,22429,22430,22431,22437,22440,22442,22444,22447,22448,22449,22451,22453,22454,22455,22457,22458,22459,22460,22461,22462,22463,22464,22465,22468,22469,22470,22471,22472,22473,22474,22476,22477,22480,22481,22483,22486,22487,22491,22492,22494,22497,22498,22499,22501,22502,22503,22504,22505,22506,22507,22508,22510,22512,22513,22514,22515,22517,22518,22519,22523,22524,22526,22527,22529,22531,22532,22533,22536,22537,22538,22540,22542,22543,22544,22546,22547,22548,22550,22551,22552,22554,22555,22556,22557,22559,22562,22563,22565,22566,22567,22568,22569,22571,22572,22573,22574,22575,22577,22578,22579,22580,22582,22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,22595,22597,22598,22599,22600,22601,22602,22603,22606,22607,22608,22610,22611,22613,22614,22615,22617,22618,22619,22620,22621,22623,22624,22625,22626,22627,22628,22630,22631,22632,22633,22634,22637,22638,22639,22640,22641,22642,22643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22655,22658,22660,22662,22663,22664,22666,22667,22668,22669,22670,22671,22672,22673,22676,22677,22678,22679,22680,22683,22684,22685,22688,22689,22690,22691,22692,22693,22694,22695,22698,22699,22700,22701,22702,22703,22704,22705,22706,22707,22708,22709,22710,22711,22712,22713,22714,22715,22717,22718,22719,22720,22722,22723,22724,22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22738,22739,22740,22742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753,22754,22755,22757,22758,22759,22760,22761,22762,22765,22767,22769,22770,22772,22773,22775,22776,22778,22779,22780,22781,22782,22783,22784,22785,22787,22789,22790,22792,22793,22794,22795,22796,22798,22800,22801,22802,22803,22807,22808,22811,22813,22814,22816,22817,22818,22819,22822,22824,22828,22832,22834,22835,22837,22838,22843,22845,22846,22847,22848,22851,22853,22854,22858,22860,22861,22864,22866,22867,22873,22875,22876,22877,22878,22879,22881,22883,22884,22886,22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,22898,22901,22903,22906,22907,22908,22910,22911,22912,22917,22921,22923,22924,22926,22927,22928,22929,22932,22933,22936,22938,22939,22940,22941,22943,22944,22945,22946,22950,22951,22956,22957,22960,22961,22963,22964,22965,22966,22967,22968,22970,22972,22973,22975,22976,22977,22978,22979,22980,22981,22983,22984,22985,22988,22989,22990,22991,22997,22998,23001,23003,23006,23007,23008,23009,23010,23012,23014,23015,23017,23018,23019,23021,23022,23023,23024,23025,23026,23027,23028,23029,23030,23031,23032,23034,23036,23037,23038,23040,23042,23050,23051,23053,23054,23055,23056,23058,23060,23061,23062,23063,23065,23066,23067,23069,23070,23073,23074,23076,23078,23079,23080,23082,23083,23084,23085,23086,23087,23088,23091,23093,23095,23096,23097,23098,23099,23101,23102,23103,23105,23106,23107,23108,23109,23111,23112,23115,23116,23117,23118,23119,23120,23121,23122,23123,23124,23126,23127,23128,23129,23131,23132,23133,23134,23135,23136,23137,23139,23140,23141,23142,23144,23145,23147,23148,23149,23150,23151,23152,23153,23154,23155,23160,23161,23163,23164,23165,23166,23168,23169,23170,23171,23172,23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,23187,23188,23189,23190,23191,23192,23193,23196,23197,23198,23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,23209,23211,23212,23213,23214,23215,23216,23217,23220,23222,23223,23225,23226,23227,23228,23229,23231,23232,23235,23236,23237,23238,23239,23240,23242,23243,23245,23246,23247,23248,23249,23251,23253,23255,23257,23258,23259,23261,23262,23263,23266,23268,23269,23271,23272,23274,23276,23277,23278,23279,23280,23282,23283,23284,23285,23286,23287,23288,23289,23290,23291,23292,23293,23294,23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,23306,23307,23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329,23330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,23342,23343,23344,23345,23347,23349,23350,23352,23353,23354,23355,23356,23357,23358,23359,23361,23362,23363,23364,23365,23366,23367,23368,23369,23370,23371,23372,23373,23374,23375,23378,23382,23390,23392,23393,23399,23400,23403,23405,23406,23407,23410,23412,23414,23415,23416,23417,23419,23420,23422,23423,23426,23430,23434,23437,23438,23440,23441,23442,23444,23446,23455,23463,23464,23465,23468,23469,23470,23471,23473,23474,23479,23482,23483,23484,23488,23489,23491,23496,23497,23498,23499,23501,23502,23503,23505,23508,23509,23510,23511,23512,23513,23514,23515,23516,23520,23522,23523,23526,23527,23529,23530,23531,23532,23533,23535,23537,23538,23539,23540,23541,23542,23543,23549,23550,23552,23554,23555,23557,23559,23560,23563,23564,23565,23566,23568,23570,23571,23575,23577,23579,23582,23583,23584,23585,23587,23590,23592,23593,23594,23595,23597,23598,23599,23600,23602,23603,23605,23606,23607,23619,23620,23622,23623,23628,23629,23634,23635,23636,23638,23639,23640,23642,23643,23644,23645,23647,23650,23652,23655,23656,23657,23658,23659,23660,23661,23664,23666,23667,23668,23669,23670,23671,23672,23675,23676,23677,23678,23680,23683,23684,23685,23686,23687,23689,23690,23691,23694,23695,23698,23699,23701,23709,23710,23711,23712,23713,23716,23717,23718,23719,23720,23722,23726,23727,23728,23730,23732,23734,23737,23738,23739,23740,23742,23744,23746,23747,23749,23750,23751,23752,23753,23754,23756,23757,23758,23759,23760,23761,23763,23764,23765,23766,23767,23768,23770,23771,23772,23773,23774,23775,23776,23778,23779,23783,23785,23787,23788,23790,23791,23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,23804,23805,23806,23807,23808,23809,23812,23813,23816,23817,23818,23819,23820,23821,23823,23824,23825,23826,23827,23829,23831,23832,23833,23834,23836,23837,23839,23840,23841,23842,23843,23845,23848,23850,23851,23852,23855,23856,23857,23858,23859,23861,23862,23863,23864,23865,23866,23867,23868,23871,23872,23873,23874,23875,23876,23877,23878,23880,23881,23885,23886,23887,23888,23889,23890,23891,23892,23893,23894,23895,23897,23898,23900,23902,23903,23904,23905,23906,23907,23908,23909,23910,23911,23912,23914,23917,23918,23920,23921,23922,23923,23925,23926,23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23939,23940,23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953,23954,23955,23956,23957,23958,23959,23960,23962,23963,23964,23966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,23978,23979,23980,23981,23982,23983,23984,23985,23986,23987,23988,23989,23990,23992,23993,23994,23995,23996,23997,23998,23999,24000,24001,24002,24003,24004,24006,24007,24008,24009,24010,24011,24012,24014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,24026,24028,24031,24032,24035,24036,24042,24044,24045,24048,24053,24054,24056,24057,24058,24059,24060,24063,24064,24068,24071,24073,24074,24075,24077,24078,24082,24083,24087,24094,24095,24096,24097,24098,24099,24100,24101,24104,24105,24106,24107,24108,24111,24112,24114,24115,24116,24117,24118,24121,24122,24126,24127,24128,24129,24131,24134,24135,24136,24137,24138,24139,24141,24142,24143,24144,24145,24146,24147,24150,24151,24152,24153,24154,24156,24157,24159,24160,24163,24164,24165,24166,24167,24168,24169,24170,24171,24172,24173,24174,24175,24176,24177,24181,24183,24185,24190,24193,24194,24195,24197,24200,24201,24204,24205,24206,24210,24216,24219,24221,24225,24226,24227,24228,24232,24233,24234,24235,24236,24238,24239,24240,24241,24242,24244,24250,24251,24252,24253,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24267,24268,24269,24270,24271,24272,24276,24277,24279,24280,24281,24282,24284,24285,24286,24287,24288,24289,24290,24291,24292,24293,24294,24295,24297,24299,24300,24301,24302,24303,24304,24305,24306,24307,24309,24312,24313,24315,24316,24317,24325,24326,24327,24329,24332,24333,24334,24336,24338,24340,24342,24345,24346,24348,24349,24350,24353,24354,24355,24356,24360,24363,24364,24366,24368,24370,24371,24372,24373,24374,24375,24376,24379,24381,24382,24383,24385,24386,24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,24398,24399,24401,24404,24409,24410,24411,24412,24414,24415,24416,24419,24421,24423,24424,24427,24430,24431,24434,24436,24437,24438,24440,24442,24445,24446,24447,24451,24454,24461,24462,24463,24465,24467,24468,24470,24474,24475,24477,24478,24479,24480,24482,24483,24484,24485,24486,24487,24489,24491,24492,24495,24496,24497,24498,24499,24500,24502,24504,24505,24506,24507,24510,24511,24512,24513,24514,24519,24520,24522,24523,24526,24531,24532,24533,24538,24539,24540,24542,24543,24546,24547,24549,24550,24552,24553,24556,24559,24560,24562,24563,24564,24566,24567,24569,24570,24572,24583,24584,24585,24587,24588,24592,24593,24595,24599,24600,24602,24606,24607,24610,24611,24612,24620,24621,24622,24624,24625,24626,24627,24628,24630,24631,24632,24633,24634,24637,24638,24640,24644,24645,24646,24647,24648,24649,24650,24652,24654,24655,24657,24659,24660,24662,24663,24664,24667,24668,24670,24671,24672,24673,24677,24678,24686,24689,24690,24692,24693,24695,24702,24704,24705,24706,24709,24710,24711,24712,24714,24715,24718,24719,24720,24721,24723,24725,24727,24728,24729,24732,24734,24737,24738,24740,24741,24743,24745,24746,24750,24752,24755,24757,24758,24759,24761,24762,24765,24766,24767,24768,24769,24770,24771,24772,24775,24776,24777,24780,24781,24782,24783,24784,24786,24787,24788,24790,24791,24793,24795,24798,24801,24802,24803,24804,24805,24810,24817,24818,24821,24823,24824,24827,24828,24829,24830,24831,24834,24835,24836,24837,24839,24842,24843,24844,24848,24849,24850,24851,24852,24854,24855,24856,24857,24859,24860,24861,24862,24865,24866,24869,24872,24873,24874,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,24887,24888,24889,24890,24891,24892,24893,24894,24896,24897,24898,24899,24900,24901,24902,24903,24905,24907,24909,24911,24912,24914,24915,24916,24918,24919,24920,24921,24922,24923,24924,24926,24927,24928,24929,24931,24932,24933,24934,24937,24938,24939,24940,24941,24942,24943,24945,24946,24947,24948,24950,24952,24953,24954,24955,24956,24957,24958,24959,24960,24961,24962,24963,24964,24965,24966,24967,24968,24969,24970,24972,24973,24975,24976,24977,24978,24979,24981,24982,24983,24984,24985,24986,24987,24988,24990,24991,24992,24993,24994,24995,24996,24997,24998,25002,25003,25005,25006,25007,25008,25009,25010,25011,25012,25013,25014,25016,25017,25018,25019,25020,25021,25023,25024,25025,25027,25028,25029,25030,25031,25033,25036,25037,25038,25039,25040,25043,25045,25046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,25058,25059,25060,25061,25063,25064,25065,25066,25067,25068,25069,25070,25071,25072,25073,25074,25075,25076,25078,25079,25080,25081,25082,25083,25084,25085,25086,25088,25089,25090,25091,25092,25093,25095,25097,25107,25108,25113,25116,25117,25118,25120,25123,25126,25127,25128,25129,25131,25133,25135,25136,25137,25138,25141,25142,25144,25145,25146,25147,25148,25154,25156,25157,25158,25162,25167,25168,25173,25174,25175,25177,25178,25180,25181,25182,25183,25184,25185,25186,25188,25189,25192,25201,25202,25204,25205,25207,25208,25210,25211,25213,25217,25218,25219,25221,25222,25223,25224,25227,25228,25229,25230,25231,25232,25236,25241,25244,25245,25246,25251,25254,25255,25257,25258,25261,25262,25263,25264,25266,25267,25268,25270,25271,25272,25274,25278,25280,25281,25283,25291,25295,25297,25301,25309,25310,25312,25313,25316,25322,25323,25328,25330,25333,25336,25337,25338,25339,25344,25347,25348,25349,25350,25354,25355,25356,25357,25359,25360,25362,25363,25364,25365,25367,25368,25369,25372,25382,25383,25385,25388,25389,25390,25392,25393,25395,25396,25397,25398,25399,25400,25403,25404,25406,25407,25408,25409,25412,25415,25416,25418,25425,25426,25427,25428,25430,25431,25432,25433,25434,25435,25436,25437,25440,25444,25445,25446,25448,25450,25451,25452,25455,25456,25458,25459,25460,25461,25464,25465,25468,25469,25470,25471,25473,25475,25476,25477,25478,25483,25485,25489,25491,25492,25493,25495,25497,25498,25499,25500,25501,25502,25503,25505,25508,25510,25515,25519,25521,25522,25525,25526,25529,25531,25533,25535,25536,25537,25538,25539,25541,25543,25544,25546,25547,25548,25553,25555,25556,25557,25559,25560,25561,25562,25563,25564,25565,25567,25570,25572,25573,25574,25575,25576,25579,25580,25582,25583,25584,25585,25587,25589,25591,25593,25594,25595,25596,25598,25603,25604,25606,25607,25608,25609,25610,25613,25614,25617,25618,25621,25622,25623,25624,25625,25626,25629,25631,25634,25635,25636,25637,25639,25640,25641,25643,25646,25647,25648,25649,25650,25651,25653,25654,25655,25656,25657,25659,25660,25662,25664,25666,25667,25673,25675,25676,25677,25678,25679,25680,25681,25683,25685,25686,25687,25689,25690,25691,25692,25693,25695,25696,25697,25698,25699,25700,25701,25702,25704,25706,25707,25708,25710,25711,25712,25713,25714,25715,25716,25717,25718,25719,25723,25724,25725,25726,25727,25728,25729,25731,25734,25736,25737,25738,25739,25740,25741,25742,25743,25744,25747,25748,25751,25752,25754,25755,25756,25757,25759,25760,25761,25762,25763,25765,25766,25767,25768,25770,25771,25775,25777,25778,25779,25780,25782,25785,25787,25789,25790,25791,25793,25795,25796,25798,25799,25800,25801,25802,25803,25804,25807,25809,25811,25812,25813,25814,25817,25818,25819,25820,25821,25823,25824,25825,25827,25829,25831,25832,25833,25834,25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846,25847,25848,25849,25850,25851,25852,25853,25854,25855,25857,25858,25859,25860,25861,25862,25863,25864,25866,25867,25868,25869,25870,25871,25872,25873,25875,25876,25877,25878,25879,25881,25882,25883,25884,25885,25886,25887,25888,25889,25890,25891,25892,25894,25895,25896,25897,25898,25900,25901,25904,25905,25906,25907,25911,25914,25916,25917,25920,25921,25922,25923,25924,25926,25927,25930,25931,25933,25934,25936,25938,25939,25940,25943,25944,25946,25948,25951,25952,25953,25956,25957,25959,25960,25961,25962,25965,25966,25967,25969,25971,25973,25974,25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,25986,25987,25988,25989,25990,25992,25993,25994,25997,25998,25999,26002,26004,26005,26006,26008,26010,26013,26014,26016,26018,26019,26022,26024,26026,26028,26030,26033,26034,26035,26036,26037,26038,26039,26040,26042,26043,26046,26047,26048,26050,26055,26056,26057,26058,26061,26064,26065,26067,26068,26069,26072,26073,26074,26075,26076,26077,26078,26079,26081,26083,26084,26090,26091,26098,26099,26100,26101,26104,26105,26107,26108,26109,26110,26111,26113,26116,26117,26119,26120,26121,26123,26125,26128,26129,26130,26134,26135,26136,26138,26139,26140,26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26162,26163,26167,26168,26169,26170,26171,26173,26175,26176,26178,26180,26181,26182,26183,26184,26185,26186,26189,26190,26192,26193,26200,26201,26203,26204,26205,26206,26208,26210,26211,26213,26215,26217,26218,26219,26220,26221,26225,26226,26227,26229,26232,26233,26235,26236,26237,26239,26240,26241,26243,26245,26246,26248,26249,26250,26251,26253,26254,26255,26256,26258,26259,26260,26261,26264,26265,26266,26267,26268,26270,26271,26272,26273,26274,26275,26276,26277,26278,26281,26282,26283,26284,26285,26287,26288,26289,26290,26291,26293,26294,26295,26296,26298,26299,26300,26301,26303,26304,26305,26306,26307,26308,26309,26310,26311,26312,26313,26314,26315,26316,26317,26318,26319,26320,26321,26322,26323,26324,26325,26326,26327,26328,26330,26334,26335,26336,26337,26338,26339,26340,26341,26343,26344,26346,26347,26348,26349,26350,26351,26353,26357,26358,26360,26362,26363,26365,26369,26370,26371,26372,26373,26374,26375,26380,26382,26383,26385,26386,26387,26390,26392,26393,26394,26396,26398,26400,26401,26402,26403,26404,26405,26407,26409,26414,26416,26418,26419,26422,26423,26424,26425,26427,26428,26430,26431,26433,26436,26437,26439,26442,26443,26445,26450,26452,26453,26455,26456,26457,26458,26459,26461,26466,26467,26468,26470,26471,26475,26476,26478,26481,26484,26486,26488,26489,26490,26491,26493,26496,26498,26499,26501,26502,26504,26506,26508,26509,26510,26511,26513,26514,26515,26516,26518,26521,26523,26527,26528,26529,26532,26534,26537,26540,26542,26545,26546,26548,26553,26554,26555,26556,26557,26558,26559,26560,26562,26565,26566,26567,26568,26569,26570,26571,26572,26573,26574,26581,26582,26583,26587,26591,26593,26595,26596,26598,26599,26600,26602,26603,26605,26606,26610,26613,26614,26615,26616,26617,26618,26619,26620,26622,26625,26626,26627,26628,26630,26637,26640,26642,26644,26645,26648,26649,26650,26651,26652,26654,26655,26656,26658,26659,26660,26661,26662,26663,26664,26667,26668,26669,26670,26671,26672,26673,26676,26677,26678,26682,26683,26687,26695,26699,26701,26703,26706,26710,26711,26712,26713,26714,26715,26716,26717,26718,26719,26730,26732,26733,26734,26735,26736,26737,26738,26739,26741,26744,26745,26746,26747,26748,26749,26750,26751,26752,26754,26756,26759,26760,26761,26762,26763,26764,26765,26766,26768,26769,26770,26772,26773,26774,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785,26787,26788,26789,26793,26794,26795,26796,26798,26801,26802,26804,26806,26807,26808,26809,26810,26811,26812,26813,26814,26815,26817,26819,26820,26821,26822,26823,26824,26826,26828,26830,26831,26832,26833,26835,26836,26838,26839,26841,26843,26844,26845,26846,26847,26849,26850,26852,26853,26854,26855,26856,26857,26858,26859,26860,26861,26863,26866,26867,26868,26870,26871,26872,26875,26877,26878,26879,26880,26882,26883,26884,26886,26887,26888,26889,26890,26892,26895,26897,26899,26900,26901,26902,26903,26904,26905,26906,26907,26908,26909,26910,26913,26914,26915,26917,26918,26919,26920,26921,26922,26923,26924,26926,26927,26929,26930,26931,26933,26934,26935,26936,26938,26939,26940,26942,26944,26945,26947,26948,26949,26950,26951,26952,26953,26954,26955,26956,26957,26958,26959,26960,26961,26962,26963,26965,26966,26968,26969,26971,26972,26975,26977,26978,26980,26981,26983,26984,26985,26986,26988,26989,26991,26992,26994,26995,26996,26997,26998,27002,27003,27005,27006,27007,27009,27011,27013,27018,27019,27020,27022,27023,27024,27025,27026,27027,27030,27031,27033,27034,27037,27038,27039,27040,27041,27042,27043,27044,27045,27046,27049,27050,27052,27054,27055,27056,27058,27059,27061,27062,27064,27065,27066,27068,27069,27070,27071,27072,27074,27075,27076,27077,27078,27079,27080,27081,27083,27085,27087,27089,27090,27091,27093,27094,27095,27096,27097,27098,27100,27101,27102,27105,27106,27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27118,27119,27120,27121,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27134,27136,27137,27138,27139,27140,27141,27142,27143,27144,27145,27147,27148,27149,27150,27151,27152,27153,27154,27155,27156,27157,27158,27161,27162,27163,27164,27165,27166,27168,27170,27171,27172,27173,27174,27175,27177,27179,27180,27181,27182,27184,27186,27187,27188,27190,27191,27192,27193,27194,27195,27196,27199,27200,27201,27202,27203,27205,27206,27208,27209,27210,27211,27212,27213,27214,27215,27217,27218,27219,27220,27221,27222,27223,27226,27228,27229,27230,27231,27232,27234,27235,27236,27238,27239,27240,27241,27242,27243,27244,27245,27246,27247,27248,27250,27251,27252,27253,27254,27255,27256,27258,27259,27261,27262,27263,27265,27266,27267,27269,27270,27271,27272,27273,27274,27275,27276,27277,27279,27282,27283,27284,27285,27286,27288,27289,27290,27291,27292,27293,27294,27295,27297,27298,27299,27300,27301,27302,27303,27304,27306,27309,27310,27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337,27338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,27362,27363,27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,27374,27375,27376,27377,27378,27379,27380,27381,27382,27383,27384,27385,27386,27387,27388,27389,27390,27391,27392,27393,27394,27395,27396,27397,27398,27399,27400,27401,27402,27403,27404,27405,27406,27407,27408,27409,27410,27411,27412,27413,27414,27415,27416,27417,27418,27419,27420,27421,27422,27423,27429,27430,27432,27433,27434,27435,27436,27437,27438,27439,27440,27441,27443,27444,27445,27446,27448,27451,27452,27453,27455,27456,27457,27458,27460,27461,27464,27466,27467,27469,27470,27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27482,27483,27484,27485,27486,27487,27488,27489,27496,27497,27499,27500,27501,27502,27503,27504,27505,27506,27507,27508,27509,27510,27511,27512,27514,27517,27518,27519,27520,27525,27528,27532,27534,27535,27536,27537,27540,27541,27543,27544,27545,27548,27549,27550,27551,27552,27554,27555,27556,27557,27558,27559,27560,27561,27563,27564,27565,27566,27567,27568,27569,27570,27574,27576,27577,27578,27579,27580,27581,27582,27584,27587,27588,27590,27591,27592,27593,27594,27596,27598,27600,27601,27608,27610,27612,27613,27614,27615,27616,27618,27619,27620,27621,27622,27623,27624,27625,27628,27629,27630,27632,27633,27634,27636,27638,27639,27640,27642,27643,27644,27646,27647,27648,27649,27650,27651,27652,27656,27657,27658,27659,27660,27662,27666,27671,27676,27677,27678,27680,27683,27685,27691,27692,27693,27697,27699,27702,27703,27705,27706,27707,27708,27710,27711,27715,27716,27717,27720,27723,27724,27725,27726,27727,27729,27730,27731,27734,27736,27737,27738,27746,27747,27749,27750,27751,27755,27756,27757,27758,27759,27761,27763,27765,27767,27768,27770,27771,27772,27775,27776,27780,27783,27786,27787,27789,27790,27793,27794,27797,27798,27799,27800,27802,27804,27805,27806,27808,27810,27816,27820,27823,27824,27828,27829,27830,27831,27834,27840,27841,27842,27843,27846,27847,27848,27851,27853,27854,27855,27857,27858,27864,27865,27866,27868,27869,27871,27876,27878,27879,27881,27884,27885,27890,27892,27897,27903,27904,27906,27907,27909,27910,27912,27913,27914,27917,27919,27920,27921,27923,27924,27925,27926,27928,27932,27933,27935,27936,27937,27938,27939,27940,27942,27944,27945,27948,27949,27951,27952,27956,27958,27959,27960,27962,27967,27968,27970,27972,27977,27980,27984,27989,27990,27991,27992,27995,27997,27999,28001,28002,28004,28005,28007,28008,28011,28012,28013,28016,28017,28018,28019,28021,28022,28025,28026,28027,28029,28030,28031,28032,28033,28035,28036,28038,28039,28042,28043,28045,28047,28048,28050,28054,28055,28056,28057,28058,28060,28066,28069,28076,28077,28080,28081,28083,28084,28086,28087,28089,28090,28091,28092,28093,28094,28097,28098,28099,28104,28105,28106,28109,28110,28111,28112,28114,28115,28116,28117,28119,28122,28123,28124,28127,28130,28131,28133,28135,28136,28137,28138,28141,28143,28144,28146,28148,28149,28150,28152,28154,28157,28158,28159,28160,28161,28162,28163,28164,28166,28167,28168,28169,28171,28175,28178,28179,28181,28184,28185,28187,28188,28190,28191,28194,28198,28199,28200,28202,28204,28206,28208,28209,28211,28213,28214,28215,28217,28219,28220,28221,28222,28223,28224,28225,28226,28229,28230,28231,28232,28233,28234,28235,28236,28239,28240,28241,28242,28245,28247,28249,28250,28252,28253,28254,28256,28257,28258,28259,28260,28261,28262,28263,28264,28265,28266,28268,28269,28271,28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,28288,28289,28290,28292,28295,28296,28298,28299,28300,28301,28302,28305,28306,28307,28308,28309,28310,28311,28313,28314,28315,28317,28318,28320,28321,28323,28324,28326,28328,28329,28331,28332,28333,28334,28336,28339,28341,28344,28345,28348,28350,28351,28352,28355,28356,28357,28358,28360,28361,28362,28364,28365,28366,28368,28370,28374,28376,28377,28379,28380,28381,28387,28391,28394,28395,28396,28397,28398,28399,28400,28401,28402,28403,28405,28406,28407,28408,28410,28411,28412,28413,28414,28415,28416,28417,28419,28420,28421,28423,28424,28426,28427,28428,28429,28430,28432,28433,28434,28438,28439,28440,28441,28442,28443,28444,28445,28446,28447,28449,28450,28451,28453,28454,28455,28456,28460,28462,28464,28466,28468,28469,28471,28472,28473,28474,28475,28476,28477,28479,28480,28481,28482,28483,28484,28485,28488,28489,28490,28492,28494,28495,28496,28497,28498,28499,28500,28501,28502,28503,28505,28506,28507,28509,28511,28512,28513,28515,28516,28517,28519,28520,28521,28522,28523,28524,28527,28528,28529,28531,28533,28534,28535,28537,28539,28541,28542,28543,28544,28545,28546,28547,28549,28550,28551,28554,28555,28559,28560,28561,28562,28563,28564,28565,28566,28567,28568,28569,28570,28571,28573,28574,28575,28576,28578,28579,28580,28581,28582,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594,28596,28597,28599,28600,28602,28603,28604,28605,28606,28607,28609,28611,28612,28613,28614,28615,28616,28618,28619,28620,28621,28622,28623,28624,28627,28628,28629,28630,28631,28632,28633,28634,28635,28636,28637,28639,28642,28643,28644,28645,28646,28647,28648,28649,28650,28651,28652,28653,28656,28657,28658,28659,28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,28670,28671,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28690,28691,28692,28693,28694,28695,28696,28697,28700,28701,28702,28703,28704,28705,28706,28708,28709,28710,28711,28712,28713,28714,28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28726,28727,28728,28730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,28742,28743,28744,28745,28746,28747,28749,28750,28752,28753,28754,28755,28756,28757,28758,28759,28760,28761,28762,28763,28764,28765,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,28778,28782,28785,28786,28787,28788,28791,28793,28794,28795,28797,28801,28802,28803,28804,28806,28807,28808,28811,28812,28813,28815,28816,28817,28819,28823,28824,28826,28827,28830,28831,28832,28833,28834,28835,28836,28837,28838,28839,28840,28841,28842,28848,28850,28852,28853,28854,28858,28862,28863,28868,28869,28870,28871,28873,28875,28876,28877,28878,28879,28880,28881,28882,28883,28884,28885,28886,28887,28890,28892,28893,28894,28896,28897,28898,28899,28901,28906,28910,28912,28913,28914,28915,28916,28917,28918,28920,28922,28923,28924,28926,28927,28928,28929,28930,28931,28932,28933,28934,28935,28936,28939,28940,28941,28942,28943,28945,28946,28948,28951,28955,28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28967,28968,28969,28970,28971,28972,28973,28974,28978,28979,28980,28981,28983,28984,28985,28986,28987,28988,28989,28990,28991,28992,28993,28994,28995,28996,28998,28999,29000,29001,29003,29005,29007,29008,29009,29010,29011,29012,29013,29014,29015,29016,29017,29018,29019,29021,29023,29024,29025,29026,29027,29029,29033,29034,29035,29036,29037,29039,29040,29041,29044,29045,29046,29047,29049,29051,29052,29054,29055,29056,29057,29058,29059,29061,29062,29063,29064,29065,29067,29068,29069,29070,29072,29073,29074,29075,29077,29078,29079,29082,29083,29084,29085,29086,29089,29090,29091,29092,29093,29094,29095,29097,29098,29099,29101,29102,29103,29104,29105,29106,29108,29110,29111,29112,29114,29115,29116,29117,29118,29119,29120,29121,29122,29124,29125,29126,29127,29128,29129,29130,29131,29132,29133,29135,29136,29137,29138,29139,29142,29143,29144,29145,29146,29147,29148,29149,29150,29151,29153,29154,29155,29156,29158,29160,29161,29162,29163,29164,29165,29167,29168,29169,29170,29171,29172,29173,29174,29175,29176,29178,29179,29180,29181,29182,29183,29184,29185,29186,29187,29188,29189,29191,29192,29193,29194,29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206,29207,29208,29209,29210,29211,29212,29214,29215,29216,29217,29218,29219,29220,29221,29222,29223,29225,29227,29229,29230,29231,29234,29235,29236,29242,29244,29246,29248,29249,29250,29251,29252,29253,29254,29257,29258,29259,29262,29263,29264,29265,29267,29268,29269,29271,29272,29274,29276,29278,29280,29283,29284,29285,29288,29290,29291,29292,29293,29296,29297,29299,29300,29302,29303,29304,29307,29308,29309,29314,29315,29317,29318,29319,29320,29321,29324,29326,29328,29329,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,29342,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,29354,29355,29358,29361,29362,29363,29365,29370,29371,29372,29373,29374,29375,29376,29381,29382,29383,29385,29386,29387,29388,29391,29393,29395,29396,29397,29398,29400,29402,29403,58566,58567,58568,58569,58570,58571,58572,58573,58574,58575,58576,58577,58578,58579,58580,58581,58582,58583,58584,58585,58586,58587,58588,58589,58590,58591,58592,58593,58594,58595,58596,58597,58598,58599,58600,58601,58602,58603,58604,58605,58606,58607,58608,58609,58610,58611,58612,58613,58614,58615,58616,58617,58618,58619,58620,58621,58622,58623,58624,58625,58626,58627,58628,58629,58630,58631,58632,58633,58634,58635,58636,58637,58638,58639,58640,58641,58642,58643,58644,58645,58646,58647,58648,58649,58650,58651,58652,58653,58654,58655,58656,58657,58658,58659,58660,58661,12288,12289,12290,183,713,711,168,12291,12293,8212,65374,8214,8230,8216,8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12310,12311,12304,12305,177,215,247,8758,8743,8744,8721,8719,8746,8745,8712,8759,8730,8869,8741,8736,8978,8857,8747,8750,8801,8780,8776,8765,8733,8800,8814,8815,8804,8805,8734,8757,8756,9794,9792,176,8242,8243,8451,65284,164,65504,65505,8240,167,8470,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,8251,8594,8592,8593,8595,12307,58662,58663,58664,58665,58666,58667,58668,58669,58670,58671,58672,58673,58674,58675,58676,58677,58678,58679,58680,58681,58682,58683,58684,58685,58686,58687,58688,58689,58690,58691,58692,58693,58694,58695,58696,58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707,58708,58709,58710,58711,58712,58713,58714,58715,58716,58717,58718,58719,58720,58721,58722,58723,58724,58725,58726,58727,58728,58729,58730,58731,58732,58733,58734,58735,58736,58737,58738,58739,58740,58741,58742,58743,58744,58745,58746,58747,58748,58749,58750,58751,58752,58753,58754,58755,58756,58757,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,59238,59239,59240,59241,59242,59243,9352,9353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,8364,59245,12832,12833,12834,12835,12836,12837,12838,12839,12840,12841,59246,59247,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,59248,59249,58758,58759,58760,58761,58762,58763,58764,58765,58766,58767,58768,58769,58770,58771,58772,58773,58774,58775,58776,58777,58778,58779,58780,58781,58782,58783,58784,58785,58786,58787,58788,58789,58790,58791,58792,58793,58794,58795,58796,58797,58798,58799,58800,58801,58802,58803,58804,58805,58806,58807,58808,58809,58810,58811,58812,58813,58814,58815,58816,58817,58818,58819,58820,58821,58822,58823,58824,58825,58826,58827,58828,58829,58830,58831,58832,58833,58834,58835,58836,58837,58838,58839,58840,58841,58842,58843,58844,58845,58846,58847,58848,58849,58850,58851,58852,12288,65281,65282,65283,65509,65285,65286,65287,65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339,65340,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,65373,65507,58854,58855,58856,58857,58858,58859,58860,58861,58862,58863,58864,58865,58866,58867,58868,58869,58870,58871,58872,58873,58874,58875,58876,58877,58878,58879,58880,58881,58882,58883,58884,58885,58886,58887,58888,58889,58890,58891,58892,58893,58894,58895,58896,58897,58898,58899,58900,58901,58902,58903,58904,58905,58906,58907,58908,58909,58910,58911,58912,58913,58914,58915,58916,58917,58918,58919,58920,58921,58922,58923,58924,58925,58926,58927,58928,58929,58930,58931,58932,58933,58934,58935,58936,58937,58938,58939,58940,58941,58942,58943,58944,58945,58946,58947,58948,58949,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,59250,59251,59252,59253,59254,59255,59256,59257,59258,59259,59260,58950,58951,58952,58953,58954,58955,58956,58957,58958,58959,58960,58961,58962,58963,58964,58965,58966,58967,58968,58969,58970,58971,58972,58973,58974,58975,58976,58977,58978,58979,58980,58981,58982,58983,58984,58985,58986,58987,58988,58989,58990,58991,58992,58993,58994,58995,58996,58997,58998,58999,59000,59001,59002,59003,59004,59005,59006,59007,59008,59009,59010,59011,59012,59013,59014,59015,59016,59017,59018,59019,59020,59021,59022,59023,59024,59025,59026,59027,59028,59029,59030,59031,59032,59033,59034,59035,59036,59037,59038,59039,59040,59041,59042,59043,59044,59045,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,59261,59262,59263,59264,59265,59266,59267,59268,59046,59047,59048,59049,59050,59051,59052,59053,59054,59055,59056,59057,59058,59059,59060,59061,59062,59063,59064,59065,59066,59067,59068,59069,59070,59071,59072,59073,59074,59075,59076,59077,59078,59079,59080,59081,59082,59083,59084,59085,59086,59087,59088,59089,59090,59091,59092,59093,59094,59095,59096,59097,59098,59099,59100,59101,59102,59103,59104,59105,59106,59107,59108,59109,59110,59111,59112,59113,59114,59115,59116,59117,59118,59119,59120,59121,59122,59123,59124,59125,59126,59127,59128,59129,59130,59131,59132,59133,59134,59135,59136,59137,59138,59139,59140,59141,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,59269,59270,59271,59272,59273,59274,59275,59276,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,59277,59278,59279,59280,59281,59282,59283,65077,65078,65081,65082,65087,65088,65085,65086,65089,65090,65091,65092,59284,59285,65083,65084,65079,65080,65073,59286,65075,65076,59287,59288,59289,59290,59291,59292,59293,59294,59295,59142,59143,59144,59145,59146,59147,59148,59149,59150,59151,59152,59153,59154,59155,59156,59157,59158,59159,59160,59161,59162,59163,59164,59165,59166,59167,59168,59169,59170,59171,59172,59173,59174,59175,59176,59177,59178,59179,59180,59181,59182,59183,59184,59185,59186,59187,59188,59189,59190,59191,59192,59193,59194,59195,59196,59197,59198,59199,59200,59201,59202,59203,59204,59205,59206,59207,59208,59209,59210,59211,59212,59213,59214,59215,59216,59217,59218,59219,59220,59221,59222,59223,59224,59225,59226,59227,59228,59229,59230,59231,59232,59233,59234,59235,59236,59237,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,59296,59297,59298,59299,59300,59301,59302,59303,59304,59305,59306,59307,59308,59309,59310,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,59311,59312,59313,59314,59315,59316,59317,59318,59319,59320,59321,59322,59323,714,715,729,8211,8213,8229,8245,8453,8457,8598,8599,8600,8601,8725,8735,8739,8786,8806,8807,8895,9552,9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9601,9602,9603,9604,9605,9606,9607,9608,9609,9610,9611,9612,9613,9614,9615,9619,9620,9621,9660,9661,9698,9699,9700,9701,9737,8853,12306,12317,12318,59324,59325,59326,59327,59328,59329,59330,59331,59332,59333,59334,257,225,462,224,275,233,283,232,299,237,464,236,333,243,466,242,363,250,468,249,470,472,474,476,252,234,593,7743,324,328,505,609,59337,59338,59339,59340,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,59341,59342,59343,59344,59345,59346,59347,59348,59349,59350,59351,59352,59353,59354,59355,59356,59357,59358,59359,59360,59361,12321,12322,12323,12324,12325,12326,12327,12328,12329,12963,13198,13199,13212,13213,13214,13217,13252,13262,13265,13266,13269,65072,65506,65508,59362,8481,12849,59363,8208,59364,59365,59366,12540,12443,12444,12541,12542,12294,12445,12446,65097,65098,65099,65100,65101,65102,65103,65104,65105,65106,65108,65109,65110,65111,65113,65114,65115,65116,65117,65118,65119,65120,65121,65122,65123,65124,65125,65126,65128,65129,65130,65131,12350,12272,12273,12274,12275,12276,12277,12278,12279,12280,12281,12282,12283,12295,59380,59381,59382,59383,59384,59385,59386,59387,59388,59389,59390,59391,59392,9472,9473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,59393,59394,59395,59396,59397,59398,59399,59400,59401,59402,59403,59404,59405,59406,59407,29404,29405,29407,29410,29411,29412,29413,29414,29415,29418,29419,29429,29430,29433,29437,29438,29439,29440,29442,29444,29445,29446,29447,29448,29449,29451,29452,29453,29455,29456,29457,29458,29460,29464,29465,29466,29471,29472,29475,29476,29478,29479,29480,29485,29487,29488,29490,29491,29493,29494,29498,29499,29500,29501,29504,29505,29506,29507,29508,29509,29510,29511,29512,29513,29514,29515,29516,29518,29519,29521,29523,29524,29525,29526,29528,29529,29530,29531,29532,29533,29534,29535,29537,29538,29539,29540,29541,29542,29543,29544,29545,29546,29547,29550,29552,29553,57344,57345,57346,57347,57348,57349,57350,57351,57352,57353,57354,57355,57356,57357,57358,57359,57360,57361,57362,57363,57364,57365,57366,57367,57368,57369,57370,57371,57372,57373,57374,57375,57376,57377,57378,57379,57380,57381,57382,57383,57384,57385,57386,57387,57388,57389,57390,57391,57392,57393,57394,57395,57396,57397,57398,57399,57400,57401,57402,57403,57404,57405,57406,57407,57408,57409,57410,57411,57412,57413,57414,57415,57416,57417,57418,57419,57420,57421,57422,57423,57424,57425,57426,57427,57428,57429,57430,57431,57432,57433,57434,57435,57436,57437,29554,29555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29567,29568,29569,29570,29571,29573,29574,29576,29578,29580,29581,29583,29584,29586,29587,29588,29589,29591,29592,29593,29594,29596,29597,29598,29600,29601,29603,29604,29605,29606,29607,29608,29610,29612,29613,29617,29620,29621,29622,29624,29625,29628,29629,29630,29631,29633,29635,29636,29637,29638,29639,29643,29644,29646,29650,29651,29652,29653,29654,29655,29656,29658,29659,29660,29661,29663,29665,29666,29667,29668,29670,29672,29674,29675,29676,29678,29679,29680,29681,29683,29684,29685,29686,29687,57438,57439,57440,57441,57442,57443,57444,57445,57446,57447,57448,57449,57450,57451,57452,57453,57454,57455,57456,57457,57458,57459,57460,57461,57462,57463,57464,57465,57466,57467,57468,57469,57470,57471,57472,57473,57474,57475,57476,57477,57478,57479,57480,57481,57482,57483,57484,57485,57486,57487,57488,57489,57490,57491,57492,57493,57494,57495,57496,57497,57498,57499,57500,57501,57502,57503,57504,57505,57506,57507,57508,57509,57510,57511,57512,57513,57514,57515,57516,57517,57518,57519,57520,57521,57522,57523,57524,57525,57526,57527,57528,57529,57530,57531,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697,29698,29700,29703,29704,29707,29708,29709,29710,29713,29714,29715,29716,29717,29718,29719,29720,29721,29724,29725,29726,29727,29728,29729,29731,29732,29735,29737,29739,29741,29743,29745,29746,29751,29752,29753,29754,29755,29757,29758,29759,29760,29762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772,29773,29774,29775,29776,29777,29778,29779,29780,29782,29784,29789,29792,29793,29794,29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29806,29807,29809,29810,29811,29812,29813,29816,29817,29818,57532,57533,57534,57535,57536,57537,57538,57539,57540,57541,57542,57543,57544,57545,57546,57547,57548,57549,57550,57551,57552,57553,57554,57555,57556,57557,57558,57559,57560,57561,57562,57563,57564,57565,57566,57567,57568,57569,57570,57571,57572,57573,57574,57575,57576,57577,57578,57579,57580,57581,57582,57583,57584,57585,57586,57587,57588,57589,57590,57591,57592,57593,57594,57595,57596,57597,57598,57599,57600,57601,57602,57603,57604,57605,57606,57607,57608,57609,57610,57611,57612,57613,57614,57615,57616,57617,57618,57619,57620,57621,57622,57623,57624,57625,29819,29820,29821,29823,29826,29828,29829,29830,29832,29833,29834,29836,29837,29839,29841,29842,29843,29844,29845,29846,29847,29848,29849,29850,29851,29853,29855,29856,29857,29858,29859,29860,29861,29862,29866,29867,29868,29869,29870,29871,29872,29873,29874,29875,29876,29877,29878,29879,29880,29881,29883,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,29894,29895,29896,29897,29898,29899,29900,29901,29902,29903,29904,29905,29907,29908,29909,29910,29911,29912,29913,29914,29915,29917,29919,29921,29925,29927,29928,29929,29930,29931,29932,29933,29936,29937,29938,57626,57627,57628,57629,57630,57631,57632,57633,57634,57635,57636,57637,57638,57639,57640,57641,57642,57643,57644,57645,57646,57647,57648,57649,57650,57651,57652,57653,57654,57655,57656,57657,57658,57659,57660,57661,57662,57663,57664,57665,57666,57667,57668,57669,57670,57671,57672,57673,57674,57675,57676,57677,57678,57679,57680,57681,57682,57683,57684,57685,57686,57687,57688,57689,57690,57691,57692,57693,57694,57695,57696,57697,57698,57699,57700,57701,57702,57703,57704,57705,57706,57707,57708,57709,57710,57711,57712,57713,57714,57715,57716,57717,57718,57719,29939,29941,29944,29945,29946,29947,29948,29949,29950,29952,29953,29954,29955,29957,29958,29959,29960,29961,29962,29963,29964,29966,29968,29970,29972,29973,29974,29975,29979,29981,29982,29984,29985,29986,29987,29988,29990,29991,29994,29998,30004,30006,30009,30012,30013,30015,30017,30018,30019,30020,30022,30023,30025,30026,30029,30032,30033,30034,30035,30037,30038,30039,30040,30045,30046,30047,30048,30049,30050,30051,30052,30055,30056,30057,30059,30060,30061,30062,30063,30064,30065,30067,30069,30070,30071,30074,30075,30076,30077,30078,30080,30081,30082,30084,30085,30087,57720,57721,57722,57723,57724,57725,57726,57727,57728,57729,57730,57731,57732,57733,57734,57735,57736,57737,57738,57739,57740,57741,57742,57743,57744,57745,57746,57747,57748,57749,57750,57751,57752,57753,57754,57755,57756,57757,57758,57759,57760,57761,57762,57763,57764,57765,57766,57767,57768,57769,57770,57771,57772,57773,57774,57775,57776,57777,57778,57779,57780,57781,57782,57783,57784,57785,57786,57787,57788,57789,57790,57791,57792,57793,57794,57795,57796,57797,57798,57799,57800,57801,57802,57803,57804,57805,57806,57807,57808,57809,57810,57811,57812,57813,30088,30089,30090,30092,30093,30094,30096,30099,30101,30104,30107,30108,30110,30114,30118,30119,30120,30121,30122,30125,30134,30135,30138,30139,30143,30144,30145,30150,30155,30156,30158,30159,30160,30161,30163,30167,30169,30170,30172,30173,30175,30176,30177,30181,30185,30188,30189,30190,30191,30194,30195,30197,30198,30199,30200,30202,30203,30205,30206,30210,30212,30214,30215,30216,30217,30219,30221,30222,30223,30225,30226,30227,30228,30230,30234,30236,30237,30238,30241,30243,30247,30248,30252,30254,30255,30257,30258,30262,30263,30265,30266,30267,30269,30273,30274,30276,57814,57815,57816,57817,57818,57819,57820,57821,57822,57823,57824,57825,57826,57827,57828,57829,57830,57831,57832,57833,57834,57835,57836,57837,57838,57839,57840,57841,57842,57843,57844,57845,57846,57847,57848,57849,57850,57851,57852,57853,57854,57855,57856,57857,57858,57859,57860,57861,57862,57863,57864,57865,57866,57867,57868,57869,57870,57871,57872,57873,57874,57875,57876,57877,57878,57879,57880,57881,57882,57883,57884,57885,57886,57887,57888,57889,57890,57891,57892,57893,57894,57895,57896,57897,57898,57899,57900,57901,57902,57903,57904,57905,57906,57907,30277,30278,30279,30280,30281,30282,30283,30286,30287,30288,30289,30290,30291,30293,30295,30296,30297,30298,30299,30301,30303,30304,30305,30306,30308,30309,30310,30311,30312,30313,30314,30316,30317,30318,30320,30321,30322,30323,30324,30325,30326,30327,30329,30330,30332,30335,30336,30337,30339,30341,30345,30346,30348,30349,30351,30352,30354,30356,30357,30359,30360,30362,30363,30364,30365,30366,30367,30368,30369,30370,30371,30373,30374,30375,30376,30377,30378,30379,30380,30381,30383,30384,30387,30389,30390,30391,30392,30393,30394,30395,30396,30397,30398,30400,30401,30403,21834,38463,22467,25384,21710,21769,21696,30353,30284,34108,30702,33406,30861,29233,38552,38797,27688,23433,20474,25353,26263,23736,33018,26696,32942,26114,30414,20985,25942,29100,32753,34948,20658,22885,25034,28595,33453,25420,25170,21485,21543,31494,20843,30116,24052,25300,36299,38774,25226,32793,22365,38712,32610,29240,30333,26575,30334,25670,20336,36133,25308,31255,26001,29677,25644,25203,33324,39041,26495,29256,25198,25292,20276,29923,21322,21150,32458,37030,24110,26758,27036,33152,32465,26834,30917,34444,38225,20621,35876,33502,32990,21253,35090,21093,30404,30407,30409,30411,30412,30419,30421,30425,30426,30428,30429,30430,30432,30433,30434,30435,30436,30438,30439,30440,30441,30442,30443,30444,30445,30448,30451,30453,30454,30455,30458,30459,30461,30463,30464,30466,30467,30469,30470,30474,30476,30478,30479,30480,30481,30482,30483,30484,30485,30486,30487,30488,30491,30492,30493,30494,30497,30499,30500,30501,30503,30506,30507,30508,30510,30512,30513,30514,30515,30516,30521,30523,30525,30526,30527,30530,30532,30533,30534,30536,30537,30538,30539,30540,30541,30542,30543,30546,30547,30548,30549,30550,30551,30552,30553,30556,34180,38649,20445,22561,39281,23453,25265,25253,26292,35961,40077,29190,26479,30865,24754,21329,21271,36744,32972,36125,38049,20493,29384,22791,24811,28953,34987,22868,33519,26412,31528,23849,32503,29997,27893,36454,36856,36924,40763,27604,37145,31508,24444,30887,34006,34109,27605,27609,27606,24065,24199,30201,38381,25949,24330,24517,36767,22721,33218,36991,38491,38829,36793,32534,36140,25153,20415,21464,21342,36776,36777,36779,36941,26631,24426,33176,34920,40150,24971,21035,30250,24428,25996,28626,28392,23486,25672,20853,20912,26564,19993,31177,39292,28851,30557,30558,30559,30560,30564,30567,30569,30570,30573,30574,30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30586,30587,30588,30593,30594,30595,30598,30599,30600,30601,30602,30603,30607,30608,30611,30612,30613,30614,30615,30616,30617,30618,30619,30620,30621,30622,30625,30627,30628,30630,30632,30635,30637,30638,30639,30641,30642,30644,30646,30647,30648,30649,30650,30652,30654,30656,30657,30658,30659,30660,30661,30662,30663,30664,30665,30666,30667,30668,30670,30671,30672,30673,30674,30675,30676,30677,30678,30680,30681,30682,30685,30686,30687,30688,30689,30692,30149,24182,29627,33760,25773,25320,38069,27874,21338,21187,25615,38082,31636,20271,24091,33334,33046,33162,28196,27850,39539,25429,21340,21754,34917,22496,19981,24067,27493,31807,37096,24598,25830,29468,35009,26448,25165,36130,30572,36393,37319,24425,33756,34081,39184,21442,34453,27531,24813,24808,28799,33485,33329,20179,27815,34255,25805,31961,27133,26361,33609,21397,31574,20391,20876,27979,23618,36461,25554,21449,33580,33590,26597,30900,25661,23519,23700,24046,35815,25286,26612,35962,25600,25530,34633,39307,35863,32544,38130,20135,38416,39076,26124,29462,30694,30696,30698,30703,30704,30705,30706,30708,30709,30711,30713,30714,30715,30716,30723,30724,30725,30726,30727,30728,30730,30731,30734,30735,30736,30739,30741,30745,30747,30750,30752,30753,30754,30756,30760,30762,30763,30766,30767,30769,30770,30771,30773,30774,30781,30783,30785,30786,30787,30788,30790,30792,30793,30794,30795,30797,30799,30801,30803,30804,30808,30809,30810,30811,30812,30814,30815,30816,30817,30818,30819,30820,30821,30822,30823,30824,30825,30831,30832,30833,30834,30835,30836,30837,30838,30840,30841,30842,30843,30845,30846,30847,30848,30849,30850,30851,22330,23581,24120,38271,20607,32928,21378,25950,30021,21809,20513,36229,25220,38046,26397,22066,28526,24034,21557,28818,36710,25199,25764,25507,24443,28552,37108,33251,36784,23576,26216,24561,27785,38472,36225,34924,25745,31216,22478,27225,25104,21576,20056,31243,24809,28548,35802,25215,36894,39563,31204,21507,30196,25345,21273,27744,36831,24347,39536,32827,40831,20360,23610,36196,32709,26021,28861,20805,20914,34411,23815,23456,25277,37228,30068,36364,31264,24833,31609,20167,32504,30597,19985,33261,21021,20986,27249,21416,36487,38148,38607,28353,38500,26970,30852,30853,30854,30856,30858,30859,30863,30864,30866,30868,30869,30870,30873,30877,30878,30880,30882,30884,30886,30888,30889,30890,30891,30892,30893,30894,30895,30901,30902,30903,30904,30906,30907,30908,30909,30911,30912,30914,30915,30916,30918,30919,30920,30924,30925,30926,30927,30929,30930,30931,30934,30935,30936,30938,30939,30940,30941,30942,30943,30944,30945,30946,30947,30948,30949,30950,30951,30953,30954,30955,30957,30958,30959,30960,30961,30963,30965,30966,30968,30969,30971,30972,30973,30974,30975,30976,30978,30979,30980,30982,30983,30984,30985,30986,30987,30988,30784,20648,30679,25616,35302,22788,25571,24029,31359,26941,20256,33337,21912,20018,30126,31383,24162,24202,38383,21019,21561,28810,25462,38180,22402,26149,26943,37255,21767,28147,32431,34850,25139,32496,30133,33576,30913,38604,36766,24904,29943,35789,27492,21050,36176,27425,32874,33905,22257,21254,20174,19995,20945,31895,37259,31751,20419,36479,31713,31388,25703,23828,20652,33030,30209,31929,28140,32736,26449,23384,23544,30923,25774,25619,25514,25387,38169,25645,36798,31572,30249,25171,22823,21574,27513,20643,25140,24102,27526,20195,36151,34955,24453,36910,30989,30990,30991,30992,30993,30994,30996,30997,30998,30999,31000,31001,31002,31003,31004,31005,31007,31008,31009,31010,31011,31013,31014,31015,31016,31017,31018,31019,31020,31021,31022,31023,31024,31025,31026,31027,31029,31030,31031,31032,31033,31037,31039,31042,31043,31044,31045,31047,31050,31051,31052,31053,31054,31055,31056,31057,31058,31060,31061,31064,31065,31073,31075,31076,31078,31081,31082,31083,31084,31086,31088,31089,31090,31091,31092,31093,31094,31097,31099,31100,31101,31102,31103,31106,31107,31110,31111,31112,31113,31115,31116,31117,31118,31120,31121,31122,24608,32829,25285,20025,21333,37112,25528,32966,26086,27694,20294,24814,28129,35806,24377,34507,24403,25377,20826,33633,26723,20992,25443,36424,20498,23707,31095,23548,21040,31291,24764,36947,30423,24503,24471,30340,36460,28783,30331,31561,30634,20979,37011,22564,20302,28404,36842,25932,31515,29380,28068,32735,23265,25269,24213,22320,33922,31532,24093,24351,36882,32532,39072,25474,28359,30872,28857,20856,38747,22443,30005,20291,30008,24215,24806,22880,28096,27583,30857,21500,38613,20939,20993,25481,21514,38035,35843,36300,29241,30879,34678,36845,35853,21472,31123,31124,31125,31126,31127,31128,31129,31131,31132,31133,31134,31135,31136,31137,31138,31139,31140,31141,31142,31144,31145,31146,31147,31148,31149,31150,31151,31152,31153,31154,31156,31157,31158,31159,31160,31164,31167,31170,31172,31173,31175,31176,31178,31180,31182,31183,31184,31187,31188,31190,31191,31193,31194,31195,31196,31197,31198,31200,31201,31202,31205,31208,31210,31212,31214,31217,31218,31219,31220,31221,31222,31223,31225,31226,31228,31230,31231,31233,31236,31237,31239,31240,31241,31242,31244,31247,31248,31249,31250,31251,31253,31254,31256,31257,31259,31260,19969,30447,21486,38025,39030,40718,38189,23450,35746,20002,19996,20908,33891,25026,21160,26635,20375,24683,20923,27934,20828,25238,26007,38497,35910,36887,30168,37117,30563,27602,29322,29420,35835,22581,30585,36172,26460,38208,32922,24230,28193,22930,31471,30701,38203,27573,26029,32526,22534,20817,38431,23545,22697,21544,36466,25958,39039,22244,38045,30462,36929,25479,21702,22810,22842,22427,36530,26421,36346,33333,21057,24816,22549,34558,23784,40517,20420,39069,35769,23077,24694,21380,25212,36943,37122,39295,24681,32780,20799,32819,23572,39285,27953,20108,31261,31263,31265,31266,31268,31269,31270,31271,31272,31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,31284,31285,31286,31288,31290,31294,31296,31297,31298,31299,31300,31301,31303,31304,31305,31306,31307,31308,31309,31310,31311,31312,31314,31315,31316,31317,31318,31320,31321,31322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31345,31346,31347,31349,31355,31356,31357,31358,31362,31365,31367,31369,31370,31371,31372,31374,31375,31376,31379,31380,31385,31386,31387,31390,31393,31394,36144,21457,32602,31567,20240,20047,38400,27861,29648,34281,24070,30058,32763,27146,30718,38034,32321,20961,28902,21453,36820,33539,36137,29359,39277,27867,22346,33459,26041,32938,25151,38450,22952,20223,35775,32442,25918,33778,38750,21857,39134,32933,21290,35837,21536,32954,24223,27832,36153,33452,37210,21545,27675,20998,32439,22367,28954,27774,31881,22859,20221,24575,24868,31914,20016,23553,26539,34562,23792,38155,39118,30127,28925,36898,20911,32541,35773,22857,20964,20315,21542,22827,25975,32932,23413,25206,25282,36752,24133,27679,31526,20239,20440,26381,31395,31396,31399,31401,31402,31403,31406,31407,31408,31409,31410,31412,31413,31414,31415,31416,31417,31418,31419,31420,31421,31422,31424,31425,31426,31427,31428,31429,31430,31431,31432,31433,31434,31436,31437,31438,31439,31440,31441,31442,31443,31444,31445,31447,31448,31450,31451,31452,31453,31457,31458,31460,31463,31464,31465,31466,31467,31468,31470,31472,31473,31474,31475,31476,31477,31478,31479,31480,31483,31484,31486,31488,31489,31490,31493,31495,31497,31500,31501,31502,31504,31506,31507,31510,31511,31512,31514,31516,31517,31519,31521,31522,31523,31527,31529,31533,28014,28074,31119,34993,24343,29995,25242,36741,20463,37340,26023,33071,33105,24220,33104,36212,21103,35206,36171,22797,20613,20184,38428,29238,33145,36127,23500,35747,38468,22919,32538,21648,22134,22030,35813,25913,27010,38041,30422,28297,24178,29976,26438,26577,31487,32925,36214,24863,31174,25954,36195,20872,21018,38050,32568,32923,32434,23703,28207,26464,31705,30347,39640,33167,32660,31957,25630,38224,31295,21578,21733,27468,25601,25096,40509,33011,30105,21106,38761,33883,26684,34532,38401,38548,38124,20010,21508,32473,26681,36319,32789,26356,24218,32697,31535,31536,31538,31540,31541,31542,31543,31545,31547,31549,31551,31552,31553,31554,31555,31556,31558,31560,31562,31565,31566,31571,31573,31575,31577,31580,31582,31583,31585,31587,31588,31589,31590,31591,31592,31593,31594,31595,31596,31597,31599,31600,31603,31604,31606,31608,31610,31612,31613,31615,31617,31618,31619,31620,31622,31623,31624,31625,31626,31627,31628,31630,31631,31633,31634,31635,31638,31640,31641,31642,31643,31646,31647,31648,31651,31652,31653,31662,31663,31664,31666,31667,31669,31670,31671,31673,31674,31675,31676,31677,31678,31679,31680,31682,31683,31684,22466,32831,26775,24037,25915,21151,24685,40858,20379,36524,20844,23467,24339,24041,27742,25329,36129,20849,38057,21246,27807,33503,29399,22434,26500,36141,22815,36764,33735,21653,31629,20272,27837,23396,22993,40723,21476,34506,39592,35895,32929,25925,39038,22266,38599,21038,29916,21072,23521,25346,35074,20054,25296,24618,26874,20851,23448,20896,35266,31649,39302,32592,24815,28748,36143,20809,24191,36891,29808,35268,22317,30789,24402,40863,38394,36712,39740,35809,30328,26690,26588,36330,36149,21053,36746,28378,26829,38149,37101,22269,26524,35065,36807,21704,31685,31688,31689,31690,31691,31693,31694,31695,31696,31698,31700,31701,31702,31703,31704,31707,31708,31710,31711,31712,31714,31715,31716,31719,31720,31721,31723,31724,31725,31727,31728,31730,31731,31732,31733,31734,31736,31737,31738,31739,31741,31743,31744,31745,31746,31747,31748,31749,31750,31752,31753,31754,31757,31758,31760,31761,31762,31763,31764,31765,31767,31768,31769,31770,31771,31772,31773,31774,31776,31777,31778,31779,31780,31781,31784,31785,31787,31788,31789,31790,31791,31792,31793,31794,31795,31796,31797,31798,31799,31801,31802,31803,31804,31805,31806,31810,39608,23401,28023,27686,20133,23475,39559,37219,25000,37039,38889,21547,28085,23506,20989,21898,32597,32752,25788,25421,26097,25022,24717,28938,27735,27721,22831,26477,33322,22741,22158,35946,27627,37085,22909,32791,21495,28009,21621,21917,33655,33743,26680,31166,21644,20309,21512,30418,35977,38402,27827,28088,36203,35088,40548,36154,22079,40657,30165,24456,29408,24680,21756,20136,27178,34913,24658,36720,21700,28888,34425,40511,27946,23439,24344,32418,21897,20399,29492,21564,21402,20505,21518,21628,20046,24573,29786,22774,33899,32993,34676,29392,31946,28246,31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31822,31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848,31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,31861,31862,31863,31864,31865,31866,31870,31871,31872,31873,31874,31875,31876,31877,31878,31879,31880,31882,31883,31884,31885,31886,31887,31888,31891,31892,31894,31897,31898,31899,31904,31905,31907,31910,31911,31912,31913,31915,31916,31917,31919,31920,31924,31925,31926,31927,31928,31930,31931,24359,34382,21804,25252,20114,27818,25143,33457,21719,21326,29502,28369,30011,21010,21270,35805,27088,24458,24576,28142,22351,27426,29615,26707,36824,32531,25442,24739,21796,30186,35938,28949,28067,23462,24187,33618,24908,40644,30970,34647,31783,30343,20976,24822,29004,26179,24140,24653,35854,28784,25381,36745,24509,24674,34516,22238,27585,24724,24935,21321,24800,26214,36159,31229,20250,28905,27719,35763,35826,32472,33636,26127,23130,39746,27985,28151,35905,27963,20249,28779,33719,25110,24785,38669,36135,31096,20987,22334,22522,26426,30072,31293,31215,31637,31935,31936,31938,31939,31940,31942,31945,31947,31950,31951,31952,31953,31954,31955,31956,31960,31962,31963,31965,31966,31969,31970,31971,31972,31973,31974,31975,31977,31978,31979,31980,31981,31982,31984,31985,31986,31987,31988,31989,31990,31991,31993,31994,31996,31997,31998,31999,32000,32001,32002,32003,32004,32005,32006,32007,32008,32009,32011,32012,32013,32014,32015,32016,32017,32018,32019,32020,32021,32022,32023,32024,32025,32026,32027,32028,32029,32030,32031,32033,32035,32036,32037,32038,32040,32041,32042,32044,32045,32046,32048,32049,32050,32051,32052,32053,32054,32908,39269,36857,28608,35749,40481,23020,32489,32521,21513,26497,26840,36753,31821,38598,21450,24613,30142,27762,21363,23241,32423,25380,20960,33034,24049,34015,25216,20864,23395,20238,31085,21058,24760,27982,23492,23490,35745,35760,26082,24524,38469,22931,32487,32426,22025,26551,22841,20339,23478,21152,33626,39050,36158,30002,38078,20551,31292,20215,26550,39550,23233,27516,30417,22362,23574,31546,38388,29006,20860,32937,33392,22904,32516,33575,26816,26604,30897,30839,25315,25441,31616,20461,21098,20943,33616,27099,37492,36341,36145,35265,38190,31661,20214,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,32066,32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,32078,32079,32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,32090,32091,32092,32093,32094,32095,32096,32097,32098,32099,32100,32101,32102,32103,32104,32105,32106,32107,32108,32109,32111,32112,32113,32114,32115,32116,32117,32118,32120,32121,32122,32123,32124,32125,32126,32127,32128,32129,32130,32131,32132,32133,32134,32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145,32146,32147,32148,32149,32150,32151,32152,20581,33328,21073,39279,28176,28293,28071,24314,20725,23004,23558,27974,27743,30086,33931,26728,22870,35762,21280,37233,38477,34121,26898,30977,28966,33014,20132,37066,27975,39556,23047,22204,25605,38128,30699,20389,33050,29409,35282,39290,32564,32478,21119,25945,37237,36735,36739,21483,31382,25581,25509,30342,31224,34903,38454,25130,21163,33410,26708,26480,25463,30571,31469,27905,32467,35299,22992,25106,34249,33445,30028,20511,20171,30117,35819,23626,24062,31563,26020,37329,20170,27941,35167,32039,38182,20165,35880,36827,38771,26187,31105,36817,28908,28024,32153,32154,32155,32156,32157,32158,32159,32160,32161,32162,32163,32164,32165,32167,32168,32169,32170,32171,32172,32173,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,32186,32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,32222,32223,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,32234,32235,32236,32237,32238,32239,32240,32241,32242,32243,32244,32245,32246,32247,32248,32249,32250,23613,21170,33606,20834,33550,30555,26230,40120,20140,24778,31934,31923,32463,20117,35686,26223,39048,38745,22659,25964,38236,24452,30153,38742,31455,31454,20928,28847,31384,25578,31350,32416,29590,38893,20037,28792,20061,37202,21417,25937,26087,33276,33285,21646,23601,30106,38816,25304,29401,30141,23621,39545,33738,23616,21632,30697,20030,27822,32858,25298,25454,24040,20855,36317,36382,38191,20465,21477,24807,28844,21095,25424,40515,23071,20518,30519,21367,32482,25733,25899,25225,25496,20500,29237,35273,20915,35776,32477,22343,33740,38055,20891,21531,23803,32251,32252,32253,32254,32255,32256,32257,32258,32259,32260,32261,32262,32263,32264,32265,32266,32267,32268,32269,32270,32271,32272,32273,32274,32275,32276,32277,32278,32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289,32290,32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302,32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,32314,32316,32317,32318,32319,32320,32322,32323,32324,32325,32326,32328,32329,32330,32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,32342,32343,32344,32345,32346,32347,32348,32349,20426,31459,27994,37089,39567,21888,21654,21345,21679,24320,25577,26999,20975,24936,21002,22570,21208,22350,30733,30475,24247,24951,31968,25179,25239,20130,28821,32771,25335,28900,38752,22391,33499,26607,26869,30933,39063,31185,22771,21683,21487,28212,20811,21051,23458,35838,32943,21827,22438,24691,22353,21549,31354,24656,23380,25511,25248,21475,25187,23495,26543,21741,31391,33510,37239,24211,35044,22840,22446,25358,36328,33007,22359,31607,20393,24555,23485,27454,21281,31568,29378,26694,30719,30518,26103,20917,20111,30420,23743,31397,33909,22862,39745,20608,32350,32351,32352,32353,32354,32355,32356,32357,32358,32359,32360,32361,32362,32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382,32383,32384,32385,32387,32388,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409,32410,32412,32413,32414,32430,32436,32443,32444,32470,32484,32492,32505,32522,32528,32542,32567,32569,32571,32572,32573,32574,32575,32576,32577,32579,32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32594,32595,39304,24871,28291,22372,26118,25414,22256,25324,25193,24275,38420,22403,25289,21895,34593,33098,36771,21862,33713,26469,36182,34013,23146,26639,25318,31726,38417,20848,28572,35888,25597,35272,25042,32518,28866,28389,29701,27028,29436,24266,37070,26391,28010,25438,21171,29282,32769,20332,23013,37226,28889,28061,21202,20048,38647,38253,34174,30922,32047,20769,22418,25794,32907,31867,27882,26865,26974,20919,21400,26792,29313,40654,31729,29432,31163,28435,29702,26446,37324,40100,31036,33673,33620,21519,26647,20029,21385,21169,30782,21382,21033,20616,20363,20432,32598,32601,32603,32604,32605,32606,32608,32611,32612,32613,32614,32615,32619,32620,32621,32623,32624,32627,32629,32630,32631,32632,32634,32635,32636,32637,32639,32640,32642,32643,32644,32645,32646,32647,32648,32649,32651,32653,32655,32656,32657,32658,32659,32661,32662,32663,32664,32665,32667,32668,32672,32674,32675,32677,32678,32680,32681,32682,32683,32684,32685,32686,32689,32691,32692,32693,32694,32695,32698,32699,32702,32704,32706,32707,32708,32710,32711,32712,32713,32715,32717,32719,32720,32721,32722,32723,32726,32727,32729,32730,32731,32732,32733,32734,32738,32739,30178,31435,31890,27813,38582,21147,29827,21737,20457,32852,33714,36830,38256,24265,24604,28063,24088,25947,33080,38142,24651,28860,32451,31918,20937,26753,31921,33391,20004,36742,37327,26238,20142,35845,25769,32842,20698,30103,29134,23525,36797,28518,20102,25730,38243,24278,26009,21015,35010,28872,21155,29454,29747,26519,30967,38678,20020,37051,40158,28107,20955,36161,21533,25294,29618,33777,38646,40836,38083,20278,32666,20940,28789,38517,23725,39046,21478,20196,28316,29705,27060,30827,39311,30041,21016,30244,27969,26611,20845,40857,32843,21657,31548,31423,32740,32743,32744,32746,32747,32748,32749,32751,32754,32756,32757,32758,32759,32760,32761,32762,32765,32766,32767,32770,32775,32776,32777,32778,32782,32783,32785,32787,32794,32795,32797,32798,32799,32801,32803,32804,32811,32812,32813,32814,32815,32816,32818,32820,32825,32826,32828,32830,32832,32833,32836,32837,32839,32840,32841,32846,32847,32848,32849,32851,32853,32854,32855,32857,32859,32860,32861,32862,32863,32864,32865,32866,32867,32868,32869,32870,32871,32872,32875,32876,32877,32878,32879,32880,32882,32883,32884,32885,32886,32887,32888,32889,32890,32891,32892,32893,38534,22404,25314,38471,27004,23044,25602,31699,28431,38475,33446,21346,39045,24208,28809,25523,21348,34383,40065,40595,30860,38706,36335,36162,40575,28510,31108,24405,38470,25134,39540,21525,38109,20387,26053,23653,23649,32533,34385,27695,24459,29575,28388,32511,23782,25371,23402,28390,21365,20081,25504,30053,25249,36718,20262,20177,27814,32438,35770,33821,34746,32599,36923,38179,31657,39585,35064,33853,27931,39558,32476,22920,40635,29595,30721,34434,39532,39554,22043,21527,22475,20080,40614,21334,36808,33033,30610,39314,34542,28385,34067,26364,24930,28459,32894,32897,32898,32901,32904,32906,32909,32910,32911,32912,32913,32914,32916,32917,32919,32921,32926,32931,32934,32935,32936,32940,32944,32947,32949,32950,32952,32953,32955,32965,32967,32968,32969,32970,32971,32975,32976,32977,32978,32979,32980,32981,32984,32991,32992,32994,32995,32998,33006,33013,33015,33017,33019,33022,33023,33024,33025,33027,33028,33029,33031,33032,33035,33036,33045,33047,33049,33051,33052,33053,33055,33056,33057,33058,33059,33060,33061,33062,33063,33064,33065,33066,33067,33069,33070,33072,33075,33076,33077,33079,33081,33082,33083,33084,33085,33087,35881,33426,33579,30450,27667,24537,33725,29483,33541,38170,27611,30683,38086,21359,33538,20882,24125,35980,36152,20040,29611,26522,26757,37238,38665,29028,27809,30473,23186,38209,27599,32654,26151,23504,22969,23194,38376,38391,20204,33804,33945,27308,30431,38192,29467,26790,23391,30511,37274,38753,31964,36855,35868,24357,31859,31192,35269,27852,34588,23494,24130,26825,30496,32501,20885,20813,21193,23081,32517,38754,33495,25551,30596,34256,31186,28218,24217,22937,34065,28781,27665,25279,30399,25935,24751,38397,26126,34719,40483,38125,21517,21629,35884,25720,33088,33089,33090,33091,33092,33093,33095,33097,33101,33102,33103,33106,33110,33111,33112,33115,33116,33117,33118,33119,33121,33122,33123,33124,33126,33128,33130,33131,33132,33135,33138,33139,33141,33142,33143,33144,33153,33155,33156,33157,33158,33159,33161,33163,33164,33165,33166,33168,33170,33171,33172,33173,33174,33175,33177,33178,33182,33183,33184,33185,33186,33188,33189,33191,33193,33195,33196,33197,33198,33199,33200,33201,33202,33204,33205,33206,33207,33208,33209,33212,33213,33214,33215,33220,33221,33223,33224,33225,33227,33229,33230,33231,33232,33233,33234,33235,25721,34321,27169,33180,30952,25705,39764,25273,26411,33707,22696,40664,27819,28448,23518,38476,35851,29279,26576,25287,29281,20137,22982,27597,22675,26286,24149,21215,24917,26408,30446,30566,29287,31302,25343,21738,21584,38048,37027,23068,32435,27670,20035,22902,32784,22856,21335,30007,38590,22218,25376,33041,24700,38393,28118,21602,39297,20869,23273,33021,22958,38675,20522,27877,23612,25311,20320,21311,33147,36870,28346,34091,25288,24180,30910,25781,25467,24565,23064,37247,40479,23615,25423,32834,23421,21870,38218,38221,28037,24744,26592,29406,20957,23425,33236,33237,33238,33239,33240,33241,33242,33243,33244,33245,33246,33247,33248,33249,33250,33252,33253,33254,33256,33257,33259,33262,33263,33264,33265,33266,33269,33270,33271,33272,33273,33274,33277,33279,33283,33287,33288,33289,33290,33291,33294,33295,33297,33299,33301,33302,33303,33304,33305,33306,33309,33312,33316,33317,33318,33319,33321,33326,33330,33338,33340,33341,33343,33344,33345,33346,33347,33349,33350,33352,33354,33356,33357,33358,33360,33361,33362,33363,33364,33365,33366,33367,33369,33371,33372,33373,33374,33376,33377,33378,33379,33380,33381,33382,33383,33385,25319,27870,29275,25197,38062,32445,33043,27987,20892,24324,22900,21162,24594,22899,26262,34384,30111,25386,25062,31983,35834,21734,27431,40485,27572,34261,21589,20598,27812,21866,36276,29228,24085,24597,29750,25293,25490,29260,24472,28227,27966,25856,28504,30424,30928,30460,30036,21028,21467,20051,24222,26049,32810,32982,25243,21638,21032,28846,34957,36305,27873,21624,32986,22521,35060,36180,38506,37197,20329,27803,21943,30406,30768,25256,28921,28558,24429,34028,26842,30844,31735,33192,26379,40527,25447,30896,22383,30738,38713,25209,25259,21128,29749,27607,33386,33387,33388,33389,33393,33397,33398,33399,33400,33403,33404,33408,33409,33411,33413,33414,33415,33417,33420,33424,33427,33428,33429,33430,33434,33435,33438,33440,33442,33443,33447,33458,33461,33462,33466,33467,33468,33471,33472,33474,33475,33477,33478,33481,33488,33494,33497,33498,33501,33506,33511,33512,33513,33514,33516,33517,33518,33520,33522,33523,33525,33526,33528,33530,33532,33533,33534,33535,33536,33546,33547,33549,33552,33554,33555,33558,33560,33561,33565,33566,33567,33568,33569,33570,33571,33572,33573,33574,33577,33578,33582,33584,33586,33591,33595,33597,21860,33086,30130,30382,21305,30174,20731,23617,35692,31687,20559,29255,39575,39128,28418,29922,31080,25735,30629,25340,39057,36139,21697,32856,20050,22378,33529,33805,24179,20973,29942,35780,23631,22369,27900,39047,23110,30772,39748,36843,31893,21078,25169,38138,20166,33670,33889,33769,33970,22484,26420,22275,26222,28006,35889,26333,28689,26399,27450,26646,25114,22971,19971,20932,28422,26578,27791,20854,26827,22855,27495,30054,23822,33040,40784,26071,31048,31041,39569,36215,23682,20062,20225,21551,22865,30732,22120,27668,36804,24323,27773,27875,35755,25488,33598,33599,33601,33602,33604,33605,33608,33610,33611,33612,33613,33614,33619,33621,33622,33623,33624,33625,33629,33634,33648,33649,33650,33651,33652,33653,33654,33657,33658,33662,33663,33664,33665,33666,33667,33668,33671,33672,33674,33675,33676,33677,33679,33680,33681,33684,33685,33686,33687,33689,33690,33693,33695,33697,33698,33699,33700,33701,33702,33703,33708,33709,33710,33711,33717,33723,33726,33727,33730,33731,33732,33734,33736,33737,33739,33741,33742,33744,33745,33746,33747,33749,33751,33753,33754,33755,33758,33762,33763,33764,33766,33767,33768,33771,33772,33773,24688,27965,29301,25190,38030,38085,21315,36801,31614,20191,35878,20094,40660,38065,38067,21069,28508,36963,27973,35892,22545,23884,27424,27465,26538,21595,33108,32652,22681,34103,24378,25250,27207,38201,25970,24708,26725,30631,20052,20392,24039,38808,25772,32728,23789,20431,31373,20999,33540,19988,24623,31363,38054,20405,20146,31206,29748,21220,33465,25810,31165,23517,27777,38738,36731,27682,20542,21375,28165,25806,26228,27696,24773,39031,35831,24198,29756,31351,31179,19992,37041,29699,27714,22234,37195,27845,36235,21306,34502,26354,36527,23624,39537,28192,33774,33775,33779,33780,33781,33782,33783,33786,33787,33788,33790,33791,33792,33794,33797,33799,33800,33801,33802,33808,33810,33811,33812,33813,33814,33815,33817,33818,33819,33822,33823,33824,33825,33826,33827,33833,33834,33835,33836,33837,33838,33839,33840,33842,33843,33844,33845,33846,33847,33849,33850,33851,33854,33855,33856,33857,33858,33859,33860,33861,33863,33864,33865,33866,33867,33868,33869,33870,33871,33872,33874,33875,33876,33877,33878,33880,33885,33886,33887,33888,33890,33892,33893,33894,33895,33896,33898,33902,33903,33904,33906,33908,33911,33913,33915,33916,21462,23094,40843,36259,21435,22280,39079,26435,37275,27849,20840,30154,25331,29356,21048,21149,32570,28820,30264,21364,40522,27063,30830,38592,35033,32676,28982,29123,20873,26579,29924,22756,25880,22199,35753,39286,25200,32469,24825,28909,22764,20161,20154,24525,38887,20219,35748,20995,22922,32427,25172,20173,26085,25102,33592,33993,33635,34701,29076,28342,23481,32466,20887,25545,26580,32905,33593,34837,20754,23418,22914,36785,20083,27741,20837,35109,36719,38446,34122,29790,38160,38384,28070,33509,24369,25746,27922,33832,33134,40131,22622,36187,19977,21441,33917,33918,33919,33920,33921,33923,33924,33925,33926,33930,33933,33935,33936,33937,33938,33939,33940,33941,33942,33944,33946,33947,33949,33950,33951,33952,33954,33955,33956,33957,33958,33959,33960,33961,33962,33963,33964,33965,33966,33968,33969,33971,33973,33974,33975,33979,33980,33982,33984,33986,33987,33989,33990,33991,33992,33995,33996,33998,33999,34002,34004,34005,34007,34008,34009,34010,34011,34012,34014,34017,34018,34020,34023,34024,34025,34026,34027,34029,34030,34031,34033,34034,34035,34036,34037,34038,34039,34040,34041,34042,34043,34045,34046,34048,34049,34050,20254,25955,26705,21971,20007,25620,39578,25195,23234,29791,33394,28073,26862,20711,33678,30722,26432,21049,27801,32433,20667,21861,29022,31579,26194,29642,33515,26441,23665,21024,29053,34923,38378,38485,25797,36193,33203,21892,27733,25159,32558,22674,20260,21830,36175,26188,19978,23578,35059,26786,25422,31245,28903,33421,21242,38902,23569,21736,37045,32461,22882,36170,34503,33292,33293,36198,25668,23556,24913,28041,31038,35774,30775,30003,21627,20280,36523,28145,23072,32453,31070,27784,23457,23158,29978,32958,24910,28183,22768,29983,29989,29298,21319,32499,34051,34052,34053,34054,34055,34056,34057,34058,34059,34061,34062,34063,34064,34066,34068,34069,34070,34072,34073,34075,34076,34077,34078,34080,34082,34083,34084,34085,34086,34087,34088,34089,34090,34093,34094,34095,34096,34097,34098,34099,34100,34101,34102,34110,34111,34112,34113,34114,34116,34117,34118,34119,34123,34124,34125,34126,34127,34128,34129,34130,34131,34132,34133,34135,34136,34138,34139,34140,34141,34143,34144,34145,34146,34147,34149,34150,34151,34153,34154,34155,34156,34157,34158,34159,34160,34161,34163,34165,34166,34167,34168,34172,34173,34175,34176,34177,30465,30427,21097,32988,22307,24072,22833,29422,26045,28287,35799,23608,34417,21313,30707,25342,26102,20160,39135,34432,23454,35782,21490,30690,20351,23630,39542,22987,24335,31034,22763,19990,26623,20107,25325,35475,36893,21183,26159,21980,22124,36866,20181,20365,37322,39280,27663,24066,24643,23460,35270,35797,25910,25163,39318,23432,23551,25480,21806,21463,30246,20861,34092,26530,26803,27530,25234,36755,21460,33298,28113,30095,20070,36174,23408,29087,34223,26257,26329,32626,34560,40653,40736,23646,26415,36848,26641,26463,25101,31446,22661,24246,25968,28465,34178,34179,34182,34184,34185,34186,34187,34188,34189,34190,34192,34193,34194,34195,34196,34197,34198,34199,34200,34201,34202,34205,34206,34207,34208,34209,34210,34211,34213,34214,34215,34217,34219,34220,34221,34225,34226,34227,34228,34229,34230,34232,34234,34235,34236,34237,34238,34239,34240,34242,34243,34244,34245,34246,34247,34248,34250,34251,34252,34253,34254,34257,34258,34260,34262,34263,34264,34265,34266,34267,34269,34270,34271,34272,34273,34274,34275,34277,34278,34279,34280,34282,34283,34284,34285,34286,34287,34288,34289,34290,34291,34292,34293,34294,34295,34296,24661,21047,32781,25684,34928,29993,24069,26643,25332,38684,21452,29245,35841,27700,30561,31246,21550,30636,39034,33308,35828,30805,26388,28865,26031,25749,22070,24605,31169,21496,19997,27515,32902,23546,21987,22235,20282,20284,39282,24051,26494,32824,24578,39042,36865,23435,35772,35829,25628,33368,25822,22013,33487,37221,20439,32032,36895,31903,20723,22609,28335,23487,35785,32899,37240,33948,31639,34429,38539,38543,32485,39635,30862,23681,31319,36930,38567,31071,23385,25439,31499,34001,26797,21766,32553,29712,32034,38145,25152,22604,20182,23427,22905,22612,34297,34298,34300,34301,34302,34304,34305,34306,34307,34308,34310,34311,34312,34313,34314,34315,34316,34317,34318,34319,34320,34322,34323,34324,34325,34327,34328,34329,34330,34331,34332,34333,34334,34335,34336,34337,34338,34339,34340,34341,34342,34344,34346,34347,34348,34349,34350,34351,34352,34353,34354,34355,34356,34357,34358,34359,34361,34362,34363,34365,34366,34367,34368,34369,34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34386,34387,34389,34390,34391,34392,34393,34395,34396,34397,34399,34400,34401,34403,34404,34405,34406,34407,34408,34409,34410,29549,25374,36427,36367,32974,33492,25260,21488,27888,37214,22826,24577,27760,22349,25674,36138,30251,28393,22363,27264,30192,28525,35885,35848,22374,27631,34962,30899,25506,21497,28845,27748,22616,25642,22530,26848,33179,21776,31958,20504,36538,28108,36255,28907,25487,28059,28372,32486,33796,26691,36867,28120,38518,35752,22871,29305,34276,33150,30140,35466,26799,21076,36386,38161,25552,39064,36420,21884,20307,26367,22159,24789,28053,21059,23625,22825,28155,22635,30000,29980,24684,33300,33094,25361,26465,36834,30522,36339,36148,38081,24086,21381,21548,28867,34413,34415,34416,34418,34419,34420,34421,34422,34423,34424,34435,34436,34437,34438,34439,34440,34441,34446,34447,34448,34449,34450,34452,34454,34455,34456,34457,34458,34459,34462,34463,34464,34465,34466,34469,34470,34475,34477,34478,34482,34483,34487,34488,34489,34491,34492,34493,34494,34495,34497,34498,34499,34501,34504,34508,34509,34514,34515,34517,34518,34519,34522,34524,34525,34528,34529,34530,34531,34533,34534,34535,34536,34538,34539,34540,34543,34549,34550,34551,34554,34555,34556,34557,34559,34561,34564,34565,34566,34571,34572,34574,34575,34576,34577,34580,34582,27712,24311,20572,20141,24237,25402,33351,36890,26704,37230,30643,21516,38108,24420,31461,26742,25413,31570,32479,30171,20599,25237,22836,36879,20984,31171,31361,22270,24466,36884,28034,23648,22303,21520,20820,28237,22242,25512,39059,33151,34581,35114,36864,21534,23663,33216,25302,25176,33073,40501,38464,39534,39548,26925,22949,25299,21822,25366,21703,34521,27964,23043,29926,34972,27498,22806,35916,24367,28286,29609,39037,20024,28919,23436,30871,25405,26202,30358,24779,23451,23113,19975,33109,27754,29579,20129,26505,32593,24448,26106,26395,24536,22916,23041,34585,34587,34589,34591,34592,34596,34598,34599,34600,34602,34603,34604,34605,34607,34608,34610,34611,34613,34614,34616,34617,34618,34620,34621,34624,34625,34626,34627,34628,34629,34630,34634,34635,34637,34639,34640,34641,34642,34644,34645,34646,34648,34650,34651,34652,34653,34654,34655,34657,34658,34662,34663,34664,34665,34666,34667,34668,34669,34671,34673,34674,34675,34677,34679,34680,34681,34682,34687,34688,34689,34692,34694,34695,34697,34698,34700,34702,34703,34704,34705,34706,34708,34709,34710,34712,34713,34714,34715,34716,34717,34718,34720,34721,34722,34723,34724,24013,24494,21361,38886,36829,26693,22260,21807,24799,20026,28493,32500,33479,33806,22996,20255,20266,23614,32428,26410,34074,21619,30031,32963,21890,39759,20301,28205,35859,23561,24944,21355,30239,28201,34442,25991,38395,32441,21563,31283,32010,38382,21985,32705,29934,25373,34583,28065,31389,25105,26017,21351,25569,27779,24043,21596,38056,20044,27745,35820,23627,26080,33436,26791,21566,21556,27595,27494,20116,25410,21320,33310,20237,20398,22366,25098,38654,26212,29289,21247,21153,24735,35823,26132,29081,26512,35199,30802,30717,26224,22075,21560,38177,29306,34725,34726,34727,34729,34730,34734,34736,34737,34738,34740,34742,34743,34744,34745,34747,34748,34750,34751,34753,34754,34755,34756,34757,34759,34760,34761,34764,34765,34766,34767,34768,34772,34773,34774,34775,34776,34777,34778,34780,34781,34782,34783,34785,34786,34787,34788,34790,34791,34792,34793,34795,34796,34797,34799,34800,34801,34802,34803,34804,34805,34806,34807,34808,34810,34811,34812,34813,34815,34816,34817,34818,34820,34821,34822,34823,34824,34825,34827,34828,34829,34830,34831,34832,34833,34834,34836,34839,34840,34841,34842,34844,34845,34846,34847,34848,34851,31232,24687,24076,24713,33181,22805,24796,29060,28911,28330,27728,29312,27268,34989,24109,20064,23219,21916,38115,27927,31995,38553,25103,32454,30606,34430,21283,38686,36758,26247,23777,20384,29421,19979,21414,22799,21523,25472,38184,20808,20185,40092,32420,21688,36132,34900,33335,38386,28046,24358,23244,26174,38505,29616,29486,21439,33146,39301,32673,23466,38519,38480,32447,30456,21410,38262,39321,31665,35140,28248,20065,32724,31077,35814,24819,21709,20139,39033,24055,27233,20687,21521,35937,33831,30813,38660,21066,21742,22179,38144,28040,23477,28102,26195,34852,34853,34854,34855,34856,34857,34858,34859,34860,34861,34862,34863,34864,34865,34867,34868,34869,34870,34871,34872,34874,34875,34877,34878,34879,34881,34882,34883,34886,34887,34888,34889,34890,34891,34894,34895,34896,34897,34898,34899,34901,34902,34904,34906,34907,34908,34909,34910,34911,34912,34918,34919,34922,34925,34927,34929,34931,34932,34933,34934,34936,34937,34938,34939,34940,34944,34947,34950,34951,34953,34954,34956,34958,34959,34960,34961,34963,34964,34965,34967,34968,34969,34970,34971,34973,34974,34975,34976,34977,34979,34981,34982,34983,34984,34985,34986,23567,23389,26657,32918,21880,31505,25928,26964,20123,27463,34638,38795,21327,25375,25658,37034,26012,32961,35856,20889,26800,21368,34809,25032,27844,27899,35874,23633,34218,33455,38156,27427,36763,26032,24571,24515,20449,34885,26143,33125,29481,24826,20852,21009,22411,24418,37026,34892,37266,24184,26447,24615,22995,20804,20982,33016,21256,27769,38596,29066,20241,20462,32670,26429,21957,38152,31168,34966,32483,22687,25100,38656,34394,22040,39035,24464,35768,33988,37207,21465,26093,24207,30044,24676,32110,23167,32490,32493,36713,21927,23459,24748,26059,29572,34988,34990,34991,34992,34994,34995,34996,34997,34998,35000,35001,35002,35003,35005,35006,35007,35008,35011,35012,35015,35016,35018,35019,35020,35021,35023,35024,35025,35027,35030,35031,35034,35035,35036,35037,35038,35040,35041,35046,35047,35049,35050,35051,35052,35053,35054,35055,35058,35061,35062,35063,35066,35067,35069,35071,35072,35073,35075,35076,35077,35078,35079,35080,35081,35083,35084,35085,35086,35087,35089,35092,35093,35094,35095,35096,35100,35101,35102,35103,35104,35106,35107,35108,35110,35111,35112,35113,35116,35117,35118,35119,35121,35122,35123,35125,35127,36873,30307,30505,32474,38772,34203,23398,31348,38634,34880,21195,29071,24490,26092,35810,23547,39535,24033,27529,27739,35757,35759,36874,36805,21387,25276,40486,40493,21568,20011,33469,29273,34460,23830,34905,28079,38597,21713,20122,35766,28937,21693,38409,28895,28153,30416,20005,30740,34578,23721,24310,35328,39068,38414,28814,27839,22852,25513,30524,34893,28436,33395,22576,29141,21388,30746,38593,21761,24422,28976,23476,35866,39564,27523,22830,40495,31207,26472,25196,20335,30113,32650,27915,38451,27687,20208,30162,20859,26679,28478,36992,33136,22934,29814,35128,35129,35130,35131,35132,35133,35134,35135,35136,35138,35139,35141,35142,35143,35144,35145,35146,35147,35148,35149,35150,35151,35152,35153,35154,35155,35156,35157,35158,35159,35160,35161,35162,35163,35164,35165,35168,35169,35170,35171,35172,35173,35175,35176,35177,35178,35179,35180,35181,35182,35183,35184,35185,35186,35187,35188,35189,35190,35191,35192,35193,35194,35196,35197,35198,35200,35202,35204,35205,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217,35218,35219,35220,35221,35222,35223,35224,35225,35226,35227,35228,35229,35230,35231,35232,35233,25671,23591,36965,31377,35875,23002,21676,33280,33647,35201,32768,26928,22094,32822,29239,37326,20918,20063,39029,25494,19994,21494,26355,33099,22812,28082,19968,22777,21307,25558,38129,20381,20234,34915,39056,22839,36951,31227,20202,33008,30097,27778,23452,23016,24413,26885,34433,20506,24050,20057,30691,20197,33402,25233,26131,37009,23673,20159,24441,33222,36920,32900,30123,20134,35028,24847,27589,24518,20041,30410,28322,35811,35758,35850,35793,24322,32764,32716,32462,33589,33643,22240,27575,38899,38452,23035,21535,38134,28139,23493,39278,23609,24341,38544,35234,35235,35236,35237,35238,35239,35240,35241,35242,35243,35244,35245,35246,35247,35248,35249,35250,35251,35252,35253,35254,35255,35256,35257,35258,35259,35260,35261,35262,35263,35264,35267,35277,35283,35284,35285,35287,35288,35289,35291,35293,35295,35296,35297,35298,35300,35303,35304,35305,35306,35308,35309,35310,35312,35313,35314,35316,35317,35318,35319,35320,35321,35322,35323,35324,35325,35326,35327,35329,35330,35331,35332,35333,35334,35336,35337,35338,35339,35340,35341,35342,35343,35344,35345,35346,35347,35348,35349,35350,35351,35352,35353,35354,35355,35356,35357,21360,33521,27185,23156,40560,24212,32552,33721,33828,33829,33639,34631,36814,36194,30408,24433,39062,30828,26144,21727,25317,20323,33219,30152,24248,38605,36362,34553,21647,27891,28044,27704,24703,21191,29992,24189,20248,24736,24551,23588,30001,37038,38080,29369,27833,28216,37193,26377,21451,21491,20305,37321,35825,21448,24188,36802,28132,20110,30402,27014,34398,24858,33286,20313,20446,36926,40060,24841,28189,28180,38533,20104,23089,38632,19982,23679,31161,23431,35821,32701,29577,22495,33419,37057,21505,36935,21947,23786,24481,24840,27442,29425,32946,35465,35358,35359,35360,35361,35362,35363,35364,35365,35366,35367,35368,35369,35370,35371,35372,35373,35374,35375,35376,35377,35378,35379,35380,35381,35382,35383,35384,35385,35386,35387,35388,35389,35391,35392,35393,35394,35395,35396,35397,35398,35399,35401,35402,35403,35404,35405,35406,35407,35408,35409,35410,35411,35412,35413,35414,35415,35416,35417,35418,35419,35420,35421,35422,35423,35424,35425,35426,35427,35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,35450,35451,35452,35453,35454,35455,35456,28020,23507,35029,39044,35947,39533,40499,28170,20900,20803,22435,34945,21407,25588,36757,22253,21592,22278,29503,28304,32536,36828,33489,24895,24616,38498,26352,32422,36234,36291,38053,23731,31908,26376,24742,38405,32792,20113,37095,21248,38504,20801,36816,34164,37213,26197,38901,23381,21277,30776,26434,26685,21705,28798,23472,36733,20877,22312,21681,25874,26242,36190,36163,33039,33900,36973,31967,20991,34299,26531,26089,28577,34468,36481,22122,36896,30338,28790,29157,36131,25321,21017,27901,36156,24590,22686,24974,26366,36192,25166,21939,28195,26413,36711,35457,35458,35459,35460,35461,35462,35463,35464,35467,35468,35469,35470,35471,35472,35473,35474,35476,35477,35478,35479,35480,35481,35482,35483,35484,35485,35486,35487,35488,35489,35490,35491,35492,35493,35494,35495,35496,35497,35498,35499,35500,35501,35502,35503,35504,35505,35506,35507,35508,35509,35510,35511,35512,35513,35514,35515,35516,35517,35518,35519,35520,35521,35522,35523,35524,35525,35526,35527,35528,35529,35530,35531,35532,35533,35534,35535,35536,35537,35538,35539,35540,35541,35542,35543,35544,35545,35546,35547,35548,35549,35550,35551,35552,35553,35554,35555,38113,38392,30504,26629,27048,21643,20045,28856,35784,25688,25995,23429,31364,20538,23528,30651,27617,35449,31896,27838,30415,26025,36759,23853,23637,34360,26632,21344,25112,31449,28251,32509,27167,31456,24432,28467,24352,25484,28072,26454,19976,24080,36134,20183,32960,30260,38556,25307,26157,25214,27836,36213,29031,32617,20806,32903,21484,36974,25240,21746,34544,36761,32773,38167,34071,36825,27993,29645,26015,30495,29956,30759,33275,36126,38024,20390,26517,30137,35786,38663,25391,38215,38453,33976,25379,30529,24449,29424,20105,24596,25972,25327,27491,25919,35556,35557,35558,35559,35560,35561,35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573,35574,35575,35576,35577,35578,35579,35580,35581,35582,35583,35584,35585,35586,35587,35588,35589,35590,35592,35593,35594,35595,35596,35597,35598,35599,35600,35601,35602,35603,35604,35605,35606,35607,35608,35609,35610,35611,35612,35613,35614,35615,35616,35617,35618,35619,35620,35621,35623,35624,35625,35626,35627,35628,35629,35630,35631,35632,35633,35634,35635,35636,35637,35638,35639,35640,35641,35642,35643,35644,35645,35646,35647,35648,35649,35650,35651,35652,35653,24103,30151,37073,35777,33437,26525,25903,21553,34584,30693,32930,33026,27713,20043,32455,32844,30452,26893,27542,25191,20540,20356,22336,25351,27490,36286,21482,26088,32440,24535,25370,25527,33267,33268,32622,24092,23769,21046,26234,31209,31258,36136,28825,30164,28382,27835,31378,20013,30405,24544,38047,34935,32456,31181,32959,37325,20210,20247,33311,21608,24030,27954,35788,31909,36724,32920,24090,21650,30385,23449,26172,39588,29664,26666,34523,26417,29482,35832,35803,36880,31481,28891,29038,25284,30633,22065,20027,33879,26609,21161,34496,36142,38136,31569,35654,35655,35656,35657,35658,35659,35660,35661,35662,35663,35664,35665,35666,35667,35668,35669,35670,35671,35672,35673,35674,35675,35676,35677,35678,35679,35680,35681,35682,35683,35684,35685,35687,35688,35689,35690,35691,35693,35694,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706,35707,35708,35709,35710,35711,35712,35713,35714,35715,35716,35717,35718,35719,35720,35721,35722,35723,35724,35725,35726,35727,35728,35729,35730,35731,35732,35733,35734,35735,35736,35737,35738,35739,35740,35741,35742,35743,35756,35761,35771,35783,35792,35818,35849,35870,20303,27880,31069,39547,25235,29226,25341,19987,30742,36716,25776,36186,31686,26729,24196,35013,22918,25758,22766,29366,26894,38181,36861,36184,22368,32512,35846,20934,25417,25305,21331,26700,29730,33537,37196,21828,30528,28796,27978,20857,21672,36164,23039,28363,28100,23388,32043,20180,31869,28371,23376,33258,28173,23383,39683,26837,36394,23447,32508,24635,32437,37049,36208,22863,25549,31199,36275,21330,26063,31062,35781,38459,32452,38075,32386,22068,37257,26368,32618,23562,36981,26152,24038,20304,26590,20570,20316,22352,24231,59408,59409,59410,59411,59412,35896,35897,35898,35899,35900,35901,35902,35903,35904,35906,35907,35908,35909,35912,35914,35915,35917,35918,35919,35920,35921,35922,35923,35924,35926,35927,35928,35929,35931,35932,35933,35934,35935,35936,35939,35940,35941,35942,35943,35944,35945,35948,35949,35950,35951,35952,35953,35954,35956,35957,35958,35959,35963,35964,35965,35966,35967,35968,35969,35971,35972,35974,35975,35976,35979,35981,35982,35983,35984,35985,35986,35987,35989,35990,35991,35993,35994,35995,35996,35997,35998,35999,36000,36001,36002,36003,36004,36005,36006,36007,36008,36009,36010,36011,36012,36013,20109,19980,20800,19984,24319,21317,19989,20120,19998,39730,23404,22121,20008,31162,20031,21269,20039,22829,29243,21358,27664,22239,32996,39319,27603,30590,40727,20022,20127,40720,20060,20073,20115,33416,23387,21868,22031,20164,21389,21405,21411,21413,21422,38757,36189,21274,21493,21286,21294,21310,36188,21350,21347,20994,21000,21006,21037,21043,21055,21056,21068,21086,21089,21084,33967,21117,21122,21121,21136,21139,20866,32596,20155,20163,20169,20162,20200,20193,20203,20190,20251,20211,20258,20324,20213,20261,20263,20233,20267,20318,20327,25912,20314,20317,36014,36015,36016,36017,36018,36019,36020,36021,36022,36023,36024,36025,36026,36027,36028,36029,36030,36031,36032,36033,36034,36035,36036,36037,36038,36039,36040,36041,36042,36043,36044,36045,36046,36047,36048,36049,36050,36051,36052,36053,36054,36055,36056,36057,36058,36059,36060,36061,36062,36063,36064,36065,36066,36067,36068,36069,36070,36071,36072,36073,36074,36075,36076,36077,36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089,36090,36091,36092,36093,36094,36095,36096,36097,36098,36099,36100,36101,36102,36103,36104,36105,36106,36107,36108,36109,20319,20311,20274,20285,20342,20340,20369,20361,20355,20367,20350,20347,20394,20348,20396,20372,20454,20456,20458,20421,20442,20451,20444,20433,20447,20472,20521,20556,20467,20524,20495,20526,20525,20478,20508,20492,20517,20520,20606,20547,20565,20552,20558,20588,20603,20645,20647,20649,20666,20694,20742,20717,20716,20710,20718,20743,20747,20189,27709,20312,20325,20430,40864,27718,31860,20846,24061,40649,39320,20865,22804,21241,21261,35335,21264,20971,22809,20821,20128,20822,20147,34926,34980,20149,33044,35026,31104,23348,34819,32696,20907,20913,20925,20924,36110,36111,36112,36113,36114,36115,36116,36117,36118,36119,36120,36121,36122,36123,36124,36128,36177,36178,36183,36191,36197,36200,36201,36202,36204,36206,36207,36209,36210,36216,36217,36218,36219,36220,36221,36222,36223,36224,36226,36227,36230,36231,36232,36233,36236,36237,36238,36239,36240,36242,36243,36245,36246,36247,36248,36249,36250,36251,36252,36253,36254,36256,36257,36258,36260,36261,36262,36263,36264,36265,36266,36267,36268,36269,36270,36271,36272,36274,36278,36279,36281,36283,36285,36288,36289,36290,36293,36295,36296,36297,36298,36301,36304,36306,36307,36308,20935,20886,20898,20901,35744,35750,35751,35754,35764,35765,35767,35778,35779,35787,35791,35790,35794,35795,35796,35798,35800,35801,35804,35807,35808,35812,35816,35817,35822,35824,35827,35830,35833,35836,35839,35840,35842,35844,35847,35852,35855,35857,35858,35860,35861,35862,35865,35867,35864,35869,35871,35872,35873,35877,35879,35882,35883,35886,35887,35890,35891,35893,35894,21353,21370,38429,38434,38433,38449,38442,38461,38460,38466,38473,38484,38495,38503,38508,38514,38516,38536,38541,38551,38576,37015,37019,37021,37017,37036,37025,37044,37043,37046,37050,36309,36312,36313,36316,36320,36321,36322,36325,36326,36327,36329,36333,36334,36336,36337,36338,36340,36342,36348,36350,36351,36352,36353,36354,36355,36356,36358,36359,36360,36363,36365,36366,36368,36369,36370,36371,36373,36374,36375,36376,36377,36378,36379,36380,36384,36385,36388,36389,36390,36391,36392,36395,36397,36400,36402,36403,36404,36406,36407,36408,36411,36412,36414,36415,36419,36421,36422,36428,36429,36430,36431,36432,36435,36436,36437,36438,36439,36440,36442,36443,36444,36445,36446,36447,36448,36449,36450,36451,36452,36453,36455,36456,36458,36459,36462,36465,37048,37040,37071,37061,37054,37072,37060,37063,37075,37094,37090,37084,37079,37083,37099,37103,37118,37124,37154,37150,37155,37169,37167,37177,37187,37190,21005,22850,21154,21164,21165,21182,21759,21200,21206,21232,21471,29166,30669,24308,20981,20988,39727,21430,24321,30042,24047,22348,22441,22433,22654,22716,22725,22737,22313,22316,22314,22323,22329,22318,22319,22364,22331,22338,22377,22405,22379,22406,22396,22395,22376,22381,22390,22387,22445,22436,22412,22450,22479,22439,22452,22419,22432,22485,22488,22490,22489,22482,22456,22516,22511,22520,22500,22493,36467,36469,36471,36472,36473,36474,36475,36477,36478,36480,36482,36483,36484,36486,36488,36489,36490,36491,36492,36493,36494,36497,36498,36499,36501,36502,36503,36504,36505,36506,36507,36509,36511,36512,36513,36514,36515,36516,36517,36518,36519,36520,36521,36522,36525,36526,36528,36529,36531,36532,36533,36534,36535,36536,36537,36539,36540,36541,36542,36543,36544,36545,36546,36547,36548,36549,36550,36551,36552,36553,36554,36555,36556,36557,36559,36560,36561,36562,36563,36564,36565,36566,36567,36568,36569,36570,36571,36572,36573,36574,36575,36576,36577,36578,36579,36580,22539,22541,22525,22509,22528,22558,22553,22596,22560,22629,22636,22657,22665,22682,22656,39336,40729,25087,33401,33405,33407,33423,33418,33448,33412,33422,33425,33431,33433,33451,33464,33470,33456,33480,33482,33507,33432,33463,33454,33483,33484,33473,33449,33460,33441,33450,33439,33476,33486,33444,33505,33545,33527,33508,33551,33543,33500,33524,33490,33496,33548,33531,33491,33553,33562,33542,33556,33557,33504,33493,33564,33617,33627,33628,33544,33682,33596,33588,33585,33691,33630,33583,33615,33607,33603,33631,33600,33559,33632,33581,33594,33587,33638,33637,36581,36582,36583,36584,36585,36586,36587,36588,36589,36590,36591,36592,36593,36594,36595,36596,36597,36598,36599,36600,36601,36602,36603,36604,36605,36606,36607,36608,36609,36610,36611,36612,36613,36614,36615,36616,36617,36618,36619,36620,36621,36622,36623,36624,36625,36626,36627,36628,36629,36630,36631,36632,36633,36634,36635,36636,36637,36638,36639,36640,36641,36642,36643,36644,36645,36646,36647,36648,36649,36650,36651,36652,36653,36654,36655,36656,36657,36658,36659,36660,36661,36662,36663,36664,36665,36666,36667,36668,36669,36670,36671,36672,36673,36674,36675,36676,33640,33563,33641,33644,33642,33645,33646,33712,33656,33715,33716,33696,33706,33683,33692,33669,33660,33718,33705,33661,33720,33659,33688,33694,33704,33722,33724,33729,33793,33765,33752,22535,33816,33803,33757,33789,33750,33820,33848,33809,33798,33748,33759,33807,33795,33784,33785,33770,33733,33728,33830,33776,33761,33884,33873,33882,33881,33907,33927,33928,33914,33929,33912,33852,33862,33897,33910,33932,33934,33841,33901,33985,33997,34000,34022,33981,34003,33994,33983,33978,34016,33953,33977,33972,33943,34021,34019,34060,29965,34104,34032,34105,34079,34106,36677,36678,36679,36680,36681,36682,36683,36684,36685,36686,36687,36688,36689,36690,36691,36692,36693,36694,36695,36696,36697,36698,36699,36700,36701,36702,36703,36704,36705,36706,36707,36708,36709,36714,36736,36748,36754,36765,36768,36769,36770,36772,36773,36774,36775,36778,36780,36781,36782,36783,36786,36787,36788,36789,36791,36792,36794,36795,36796,36799,36800,36803,36806,36809,36810,36811,36812,36813,36815,36818,36822,36823,36826,36832,36833,36835,36839,36844,36847,36849,36850,36852,36853,36854,36858,36859,36860,36862,36863,36871,36872,36876,36878,36883,36885,36888,34134,34107,34047,34044,34137,34120,34152,34148,34142,34170,30626,34115,34162,34171,34212,34216,34183,34191,34169,34222,34204,34181,34233,34231,34224,34259,34241,34268,34303,34343,34309,34345,34326,34364,24318,24328,22844,22849,32823,22869,22874,22872,21263,23586,23589,23596,23604,25164,25194,25247,25275,25290,25306,25303,25326,25378,25334,25401,25419,25411,25517,25590,25457,25466,25486,25524,25453,25516,25482,25449,25518,25532,25586,25592,25568,25599,25540,25566,25550,25682,25542,25534,25669,25665,25611,25627,25632,25612,25638,25633,25694,25732,25709,25750,36889,36892,36899,36900,36901,36903,36904,36905,36906,36907,36908,36912,36913,36914,36915,36916,36919,36921,36922,36925,36927,36928,36931,36933,36934,36936,36937,36938,36939,36940,36942,36948,36949,36950,36953,36954,36956,36957,36958,36959,36960,36961,36964,36966,36967,36969,36970,36971,36972,36975,36976,36977,36978,36979,36982,36983,36984,36985,36986,36987,36988,36990,36993,36996,36997,36998,36999,37001,37002,37004,37005,37006,37007,37008,37010,37012,37014,37016,37018,37020,37022,37023,37024,37028,37029,37031,37032,37033,37035,37037,37042,37047,37052,37053,37055,37056,25722,25783,25784,25753,25786,25792,25808,25815,25828,25826,25865,25893,25902,24331,24530,29977,24337,21343,21489,21501,21481,21480,21499,21522,21526,21510,21579,21586,21587,21588,21590,21571,21537,21591,21593,21539,21554,21634,21652,21623,21617,21604,21658,21659,21636,21622,21606,21661,21712,21677,21698,21684,21714,21671,21670,21715,21716,21618,21667,21717,21691,21695,21708,21721,21722,21724,21673,21674,21668,21725,21711,21726,21787,21735,21792,21757,21780,21747,21794,21795,21775,21777,21799,21802,21863,21903,21941,21833,21869,21825,21845,21823,21840,21820,37058,37059,37062,37064,37065,37067,37068,37069,37074,37076,37077,37078,37080,37081,37082,37086,37087,37088,37091,37092,37093,37097,37098,37100,37102,37104,37105,37106,37107,37109,37110,37111,37113,37114,37115,37116,37119,37120,37121,37123,37125,37126,37127,37128,37129,37130,37131,37132,37133,37134,37135,37136,37137,37138,37139,37140,37141,37142,37143,37144,37146,37147,37148,37149,37151,37152,37153,37156,37157,37158,37159,37160,37161,37162,37163,37164,37165,37166,37168,37170,37171,37172,37173,37174,37175,37176,37178,37179,37180,37181,37182,37183,37184,37185,37186,37188,21815,21846,21877,21878,21879,21811,21808,21852,21899,21970,21891,21937,21945,21896,21889,21919,21886,21974,21905,21883,21983,21949,21950,21908,21913,21994,22007,21961,22047,21969,21995,21996,21972,21990,21981,21956,21999,21989,22002,22003,21964,21965,21992,22005,21988,36756,22046,22024,22028,22017,22052,22051,22014,22016,22055,22061,22104,22073,22103,22060,22093,22114,22105,22108,22092,22100,22150,22116,22129,22123,22139,22140,22149,22163,22191,22228,22231,22237,22241,22261,22251,22265,22271,22276,22282,22281,22300,24079,24089,24084,24081,24113,24123,24124,37189,37191,37192,37201,37203,37204,37205,37206,37208,37209,37211,37212,37215,37216,37222,37223,37224,37227,37229,37235,37242,37243,37244,37248,37249,37250,37251,37252,37254,37256,37258,37262,37263,37267,37268,37269,37270,37271,37272,37273,37276,37277,37278,37279,37280,37281,37284,37285,37286,37287,37288,37289,37291,37292,37296,37297,37298,37299,37302,37303,37304,37305,37307,37308,37309,37310,37311,37312,37313,37314,37315,37316,37317,37318,37320,37323,37328,37330,37331,37332,37333,37334,37335,37336,37337,37338,37339,37341,37342,37343,37344,37345,37346,37347,37348,37349,24119,24132,24148,24155,24158,24161,23692,23674,23693,23696,23702,23688,23704,23705,23697,23706,23708,23733,23714,23741,23724,23723,23729,23715,23745,23735,23748,23762,23780,23755,23781,23810,23811,23847,23846,23854,23844,23838,23814,23835,23896,23870,23860,23869,23916,23899,23919,23901,23915,23883,23882,23913,23924,23938,23961,23965,35955,23991,24005,24435,24439,24450,24455,24457,24460,24469,24473,24476,24488,24493,24501,24508,34914,24417,29357,29360,29364,29367,29368,29379,29377,29390,29389,29394,29416,29423,29417,29426,29428,29431,29441,29427,29443,29434,37350,37351,37352,37353,37354,37355,37356,37357,37358,37359,37360,37361,37362,37363,37364,37365,37366,37367,37368,37369,37370,37371,37372,37373,37374,37375,37376,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37387,37388,37389,37390,37391,37392,37393,37394,37395,37396,37397,37398,37399,37400,37401,37402,37403,37404,37405,37406,37407,37408,37409,37410,37411,37412,37413,37414,37415,37416,37417,37418,37419,37420,37421,37422,37423,37424,37425,37426,37427,37428,37429,37430,37431,37432,37433,37434,37435,37436,37437,37438,37439,37440,37441,37442,37443,37444,37445,29435,29463,29459,29473,29450,29470,29469,29461,29474,29497,29477,29484,29496,29489,29520,29517,29527,29536,29548,29551,29566,33307,22821,39143,22820,22786,39267,39271,39272,39273,39274,39275,39276,39284,39287,39293,39296,39300,39303,39306,39309,39312,39313,39315,39316,39317,24192,24209,24203,24214,24229,24224,24249,24245,24254,24243,36179,24274,24273,24283,24296,24298,33210,24516,24521,24534,24527,24579,24558,24580,24545,24548,24574,24581,24582,24554,24557,24568,24601,24629,24614,24603,24591,24589,24617,24619,24586,24639,24609,24696,24697,24699,24698,24642,37446,37447,37448,37449,37450,37451,37452,37453,37454,37455,37456,37457,37458,37459,37460,37461,37462,37463,37464,37465,37466,37467,37468,37469,37470,37471,37472,37473,37474,37475,37476,37477,37478,37479,37480,37481,37482,37483,37484,37485,37486,37487,37488,37489,37490,37491,37493,37494,37495,37496,37497,37498,37499,37500,37501,37502,37503,37504,37505,37506,37507,37508,37509,37510,37511,37512,37513,37514,37515,37516,37517,37519,37520,37521,37522,37523,37524,37525,37526,37527,37528,37529,37530,37531,37532,37533,37534,37535,37536,37537,37538,37539,37540,37541,37542,37543,24682,24701,24726,24730,24749,24733,24707,24722,24716,24731,24812,24763,24753,24797,24792,24774,24794,24756,24864,24870,24853,24867,24820,24832,24846,24875,24906,24949,25004,24980,24999,25015,25044,25077,24541,38579,38377,38379,38385,38387,38389,38390,38396,38398,38403,38404,38406,38408,38410,38411,38412,38413,38415,38418,38421,38422,38423,38425,38426,20012,29247,25109,27701,27732,27740,27722,27811,27781,27792,27796,27788,27752,27753,27764,27766,27782,27817,27856,27860,27821,27895,27896,27889,27863,27826,27872,27862,27898,27883,27886,27825,27859,27887,27902,37544,37545,37546,37547,37548,37549,37551,37552,37553,37554,37555,37556,37557,37558,37559,37560,37561,37562,37563,37564,37565,37566,37567,37568,37569,37570,37571,37572,37573,37574,37575,37577,37578,37579,37580,37581,37582,37583,37584,37585,37586,37587,37588,37589,37590,37591,37592,37593,37594,37595,37596,37597,37598,37599,37600,37601,37602,37603,37604,37605,37606,37607,37608,37609,37610,37611,37612,37613,37614,37615,37616,37617,37618,37619,37620,37621,37622,37623,37624,37625,37626,37627,37628,37629,37630,37631,37632,37633,37634,37635,37636,37637,37638,37639,37640,37641,27961,27943,27916,27971,27976,27911,27908,27929,27918,27947,27981,27950,27957,27930,27983,27986,27988,27955,28049,28015,28062,28064,27998,28051,28052,27996,28000,28028,28003,28186,28103,28101,28126,28174,28095,28128,28177,28134,28125,28121,28182,28075,28172,28078,28203,28270,28238,28267,28338,28255,28294,28243,28244,28210,28197,28228,28383,28337,28312,28384,28461,28386,28325,28327,28349,28347,28343,28375,28340,28367,28303,28354,28319,28514,28486,28487,28452,28437,28409,28463,28470,28491,28532,28458,28425,28457,28553,28557,28556,28536,28530,28540,28538,28625,37642,37643,37644,37645,37646,37647,37648,37649,37650,37651,37652,37653,37654,37655,37656,37657,37658,37659,37660,37661,37662,37663,37664,37665,37666,37667,37668,37669,37670,37671,37672,37673,37674,37675,37676,37677,37678,37679,37680,37681,37682,37683,37684,37685,37686,37687,37688,37689,37690,37691,37692,37693,37695,37696,37697,37698,37699,37700,37701,37702,37703,37704,37705,37706,37707,37708,37709,37710,37711,37712,37713,37714,37715,37716,37717,37718,37719,37720,37721,37722,37723,37724,37725,37726,37727,37728,37729,37730,37731,37732,37733,37734,37735,37736,37737,37739,28617,28583,28601,28598,28610,28641,28654,28638,28640,28655,28698,28707,28699,28729,28725,28751,28766,23424,23428,23445,23443,23461,23480,29999,39582,25652,23524,23534,35120,23536,36423,35591,36790,36819,36821,36837,36846,36836,36841,36838,36851,36840,36869,36868,36875,36902,36881,36877,36886,36897,36917,36918,36909,36911,36932,36945,36946,36944,36968,36952,36962,36955,26297,36980,36989,36994,37000,36995,37003,24400,24407,24406,24408,23611,21675,23632,23641,23409,23651,23654,32700,24362,24361,24365,33396,24380,39739,23662,22913,22915,22925,22953,22954,22947,37740,37741,37742,37743,37744,37745,37746,37747,37748,37749,37750,37751,37752,37753,37754,37755,37756,37757,37758,37759,37760,37761,37762,37763,37764,37765,37766,37767,37768,37769,37770,37771,37772,37773,37774,37776,37777,37778,37779,37780,37781,37782,37783,37784,37785,37786,37787,37788,37789,37790,37791,37792,37793,37794,37795,37796,37797,37798,37799,37800,37801,37802,37803,37804,37805,37806,37807,37808,37809,37810,37811,37812,37813,37814,37815,37816,37817,37818,37819,37820,37821,37822,37823,37824,37825,37826,37827,37828,37829,37830,37831,37832,37833,37835,37836,37837,22935,22986,22955,22942,22948,22994,22962,22959,22999,22974,23045,23046,23005,23048,23011,23000,23033,23052,23049,23090,23092,23057,23075,23059,23104,23143,23114,23125,23100,23138,23157,33004,23210,23195,23159,23162,23230,23275,23218,23250,23252,23224,23264,23267,23281,23254,23270,23256,23260,23305,23319,23318,23346,23351,23360,23573,23580,23386,23397,23411,23377,23379,23394,39541,39543,39544,39546,39551,39549,39552,39553,39557,39560,39562,39568,39570,39571,39574,39576,39579,39580,39581,39583,39584,39586,39587,39589,39591,32415,32417,32419,32421,32424,32425,37838,37839,37840,37841,37842,37843,37844,37845,37847,37848,37849,37850,37851,37852,37853,37854,37855,37856,37857,37858,37859,37860,37861,37862,37863,37864,37865,37866,37867,37868,37869,37870,37871,37872,37873,37874,37875,37876,37877,37878,37879,37880,37881,37882,37883,37884,37885,37886,37887,37888,37889,37890,37891,37892,37893,37894,37895,37896,37897,37898,37899,37900,37901,37902,37903,37904,37905,37906,37907,37908,37909,37910,37911,37912,37913,37914,37915,37916,37917,37918,37919,37920,37921,37922,37923,37924,37925,37926,37927,37928,37929,37930,37931,37932,37933,37934,32429,32432,32446,32448,32449,32450,32457,32459,32460,32464,32468,32471,32475,32480,32481,32488,32491,32494,32495,32497,32498,32525,32502,32506,32507,32510,32513,32514,32515,32519,32520,32523,32524,32527,32529,32530,32535,32537,32540,32539,32543,32545,32546,32547,32548,32549,32550,32551,32554,32555,32556,32557,32559,32560,32561,32562,32563,32565,24186,30079,24027,30014,37013,29582,29585,29614,29602,29599,29647,29634,29649,29623,29619,29632,29641,29640,29669,29657,39036,29706,29673,29671,29662,29626,29682,29711,29738,29787,29734,29733,29736,29744,29742,29740,37935,37936,37937,37938,37939,37940,37941,37942,37943,37944,37945,37946,37947,37948,37949,37951,37952,37953,37954,37955,37956,37957,37958,37959,37960,37961,37962,37963,37964,37965,37966,37967,37968,37969,37970,37971,37972,37973,37974,37975,37976,37977,37978,37979,37980,37981,37982,37983,37984,37985,37986,37987,37988,37989,37990,37991,37992,37993,37994,37996,37997,37998,37999,38000,38001,38002,38003,38004,38005,38006,38007,38008,38009,38010,38011,38012,38013,38014,38015,38016,38017,38018,38019,38020,38033,38038,38040,38087,38095,38099,38100,38106,38118,38139,38172,38176,29723,29722,29761,29788,29783,29781,29785,29815,29805,29822,29852,29838,29824,29825,29831,29835,29854,29864,29865,29840,29863,29906,29882,38890,38891,38892,26444,26451,26462,26440,26473,26533,26503,26474,26483,26520,26535,26485,26536,26526,26541,26507,26487,26492,26608,26633,26584,26634,26601,26544,26636,26585,26549,26586,26547,26589,26624,26563,26552,26594,26638,26561,26621,26674,26675,26720,26721,26702,26722,26692,26724,26755,26653,26709,26726,26689,26727,26688,26686,26698,26697,26665,26805,26767,26740,26743,26771,26731,26818,26990,26876,26911,26912,26873,38183,38195,38205,38211,38216,38219,38229,38234,38240,38254,38260,38261,38263,38264,38265,38266,38267,38268,38269,38270,38272,38273,38274,38275,38276,38277,38278,38279,38280,38281,38282,38283,38284,38285,38286,38287,38288,38289,38290,38291,38292,38293,38294,38295,38296,38297,38298,38299,38300,38301,38302,38303,38304,38305,38306,38307,38308,38309,38310,38311,38312,38313,38314,38315,38316,38317,38318,38319,38320,38321,38322,38323,38324,38325,38326,38327,38328,38329,38330,38331,38332,38333,38334,38335,38336,38337,38338,38339,38340,38341,38342,38343,38344,38345,38346,38347,26916,26864,26891,26881,26967,26851,26896,26993,26937,26976,26946,26973,27012,26987,27008,27032,27000,26932,27084,27015,27016,27086,27017,26982,26979,27001,27035,27047,27067,27051,27053,27092,27057,27073,27082,27103,27029,27104,27021,27135,27183,27117,27159,27160,27237,27122,27204,27198,27296,27216,27227,27189,27278,27257,27197,27176,27224,27260,27281,27280,27305,27287,27307,29495,29522,27521,27522,27527,27524,27538,27539,27533,27546,27547,27553,27562,36715,36717,36721,36722,36723,36725,36726,36728,36727,36729,36730,36732,36734,36737,36738,36740,36743,36747,38348,38349,38350,38351,38352,38353,38354,38355,38356,38357,38358,38359,38360,38361,38362,38363,38364,38365,38366,38367,38368,38369,38370,38371,38372,38373,38374,38375,38380,38399,38407,38419,38424,38427,38430,38432,38435,38436,38437,38438,38439,38440,38441,38443,38444,38445,38447,38448,38455,38456,38457,38458,38462,38465,38467,38474,38478,38479,38481,38482,38483,38486,38487,38488,38489,38490,38492,38493,38494,38496,38499,38501,38502,38507,38509,38510,38511,38512,38513,38515,38520,38521,38522,38523,38524,38525,38526,38527,38528,38529,38530,38531,38532,38535,38537,38538,36749,36750,36751,36760,36762,36558,25099,25111,25115,25119,25122,25121,25125,25124,25132,33255,29935,29940,29951,29967,29969,29971,25908,26094,26095,26096,26122,26137,26482,26115,26133,26112,28805,26359,26141,26164,26161,26166,26165,32774,26207,26196,26177,26191,26198,26209,26199,26231,26244,26252,26279,26269,26302,26331,26332,26342,26345,36146,36147,36150,36155,36157,36160,36165,36166,36168,36169,36167,36173,36181,36185,35271,35274,35275,35276,35278,35279,35280,35281,29294,29343,29277,29286,29295,29310,29311,29316,29323,29325,29327,29330,25352,25394,25520,38540,38542,38545,38546,38547,38549,38550,38554,38555,38557,38558,38559,38560,38561,38562,38563,38564,38565,38566,38568,38569,38570,38571,38572,38573,38574,38575,38577,38578,38580,38581,38583,38584,38586,38587,38591,38594,38595,38600,38602,38603,38608,38609,38611,38612,38614,38615,38616,38617,38618,38619,38620,38621,38622,38623,38625,38626,38627,38628,38629,38630,38631,38635,38636,38637,38638,38640,38641,38642,38644,38645,38648,38650,38651,38652,38653,38655,38658,38659,38661,38666,38667,38668,38672,38673,38674,38676,38677,38679,38680,38681,38682,38683,38685,38687,38688,25663,25816,32772,27626,27635,27645,27637,27641,27653,27655,27654,27661,27669,27672,27673,27674,27681,27689,27684,27690,27698,25909,25941,25963,29261,29266,29270,29232,34402,21014,32927,32924,32915,32956,26378,32957,32945,32939,32941,32948,32951,32999,33000,33001,33002,32987,32962,32964,32985,32973,32983,26384,32989,33003,33009,33012,33005,33037,33038,33010,33020,26389,33042,35930,33078,33054,33068,33048,33074,33096,33100,33107,33140,33113,33114,33137,33120,33129,33148,33149,33133,33127,22605,23221,33160,33154,33169,28373,33187,33194,33228,26406,33226,33211,38689,38690,38691,38692,38693,38694,38695,38696,38697,38699,38700,38702,38703,38705,38707,38708,38709,38710,38711,38714,38715,38716,38717,38719,38720,38721,38722,38723,38724,38725,38726,38727,38728,38729,38730,38731,38732,38733,38734,38735,38736,38737,38740,38741,38743,38744,38746,38748,38749,38751,38755,38756,38758,38759,38760,38762,38763,38764,38765,38766,38767,38768,38769,38770,38773,38775,38776,38777,38778,38779,38781,38782,38783,38784,38785,38786,38787,38788,38790,38791,38792,38793,38794,38796,38798,38799,38800,38803,38805,38806,38807,38809,38810,38811,38812,38813,33217,33190,27428,27447,27449,27459,27462,27481,39121,39122,39123,39125,39129,39130,27571,24384,27586,35315,26000,40785,26003,26044,26054,26052,26051,26060,26062,26066,26070,28800,28828,28822,28829,28859,28864,28855,28843,28849,28904,28874,28944,28947,28950,28975,28977,29043,29020,29032,28997,29042,29002,29048,29050,29080,29107,29109,29096,29088,29152,29140,29159,29177,29213,29224,28780,28952,29030,29113,25150,25149,25155,25160,25161,31035,31040,31046,31049,31067,31068,31059,31066,31074,31063,31072,31087,31079,31098,31109,31114,31130,31143,31155,24529,24528,38814,38815,38817,38818,38820,38821,38822,38823,38824,38825,38826,38828,38830,38832,38833,38835,38837,38838,38839,38840,38841,38842,38843,38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856,38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869,38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882,38883,38884,38885,38888,38894,38895,38896,38897,38898,38900,38903,38904,38905,38906,38907,38908,38909,38910,38911,38912,38913,38914,38915,38916,38917,38918,38919,38920,38921,38922,38923,38924,38925,38926,24636,24669,24666,24679,24641,24665,24675,24747,24838,24845,24925,25001,24989,25035,25041,25094,32896,32895,27795,27894,28156,30710,30712,30720,30729,30743,30744,30737,26027,30765,30748,30749,30777,30778,30779,30751,30780,30757,30764,30755,30761,30798,30829,30806,30807,30758,30800,30791,30796,30826,30875,30867,30874,30855,30876,30881,30883,30898,30905,30885,30932,30937,30921,30956,30962,30981,30964,30995,31012,31006,31028,40859,40697,40699,40700,30449,30468,30477,30457,30471,30472,30490,30498,30489,30509,30502,30517,30520,30544,30545,30535,30531,30554,30568,38927,38928,38929,38930,38931,38932,38933,38934,38935,38936,38937,38938,38939,38940,38941,38942,38943,38944,38945,38946,38947,38948,38949,38950,38951,38952,38953,38954,38955,38956,38957,38958,38959,38960,38961,38962,38963,38964,38965,38966,38967,38968,38969,38970,38971,38972,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982,38983,38984,38985,38986,38987,38988,38989,38990,38991,38992,38993,38994,38995,38996,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39007,39008,39009,39010,39011,39012,39013,39014,39015,39016,39017,39018,39019,39020,39021,39022,30562,30565,30591,30605,30589,30592,30604,30609,30623,30624,30640,30645,30653,30010,30016,30030,30027,30024,30043,30066,30073,30083,32600,32609,32607,35400,32616,32628,32625,32633,32641,32638,30413,30437,34866,38021,38022,38023,38027,38026,38028,38029,38031,38032,38036,38039,38037,38042,38043,38044,38051,38052,38059,38058,38061,38060,38063,38064,38066,38068,38070,38071,38072,38073,38074,38076,38077,38079,38084,38088,38089,38090,38091,38092,38093,38094,38096,38097,38098,38101,38102,38103,38105,38104,38107,38110,38111,38112,38114,38116,38117,38119,38120,38122,39023,39024,39025,39026,39027,39028,39051,39054,39058,39061,39065,39075,39080,39081,39082,39083,39084,39085,39086,39087,39088,39089,39090,39091,39092,39093,39094,39095,39096,39097,39098,39099,39100,39101,39102,39103,39104,39105,39106,39107,39108,39109,39110,39111,39112,39113,39114,39115,39116,39117,39119,39120,39124,39126,39127,39131,39132,39133,39136,39137,39138,39139,39140,39141,39142,39145,39146,39147,39148,39149,39150,39151,39152,39153,39154,39155,39156,39157,39158,39159,39160,39161,39162,39163,39164,39165,39166,39167,39168,39169,39170,39171,39172,39173,39174,39175,38121,38123,38126,38127,38131,38132,38133,38135,38137,38140,38141,38143,38147,38146,38150,38151,38153,38154,38157,38158,38159,38162,38163,38164,38165,38166,38168,38171,38173,38174,38175,38178,38186,38187,38185,38188,38193,38194,38196,38198,38199,38200,38204,38206,38207,38210,38197,38212,38213,38214,38217,38220,38222,38223,38226,38227,38228,38230,38231,38232,38233,38235,38238,38239,38237,38241,38242,38244,38245,38246,38247,38248,38249,38250,38251,38252,38255,38257,38258,38259,38202,30695,30700,38601,31189,31213,31203,31211,31238,23879,31235,31234,31262,31252,39176,39177,39178,39179,39180,39182,39183,39185,39186,39187,39188,39189,39190,39191,39192,39193,39194,39195,39196,39197,39198,39199,39200,39201,39202,39203,39204,39205,39206,39207,39208,39209,39210,39211,39212,39213,39215,39216,39217,39218,39219,39220,39221,39222,39223,39224,39225,39226,39227,39228,39229,39230,39231,39232,39233,39234,39235,39236,39237,39238,39239,39240,39241,39242,39243,39244,39245,39246,39247,39248,39249,39250,39251,39254,39255,39256,39257,39258,39259,39260,39261,39262,39263,39264,39265,39266,39268,39270,39283,39288,39289,39291,39294,39298,39299,39305,31289,31287,31313,40655,39333,31344,30344,30350,30355,30361,30372,29918,29920,29996,40480,40482,40488,40489,40490,40491,40492,40498,40497,40502,40504,40503,40505,40506,40510,40513,40514,40516,40518,40519,40520,40521,40523,40524,40526,40529,40533,40535,40538,40539,40540,40542,40547,40550,40551,40552,40553,40554,40555,40556,40561,40557,40563,30098,30100,30102,30112,30109,30124,30115,30131,30132,30136,30148,30129,30128,30147,30146,30166,30157,30179,30184,30182,30180,30187,30183,30211,30193,30204,30207,30224,30208,30213,30220,30231,30218,30245,30232,30229,30233,39308,39310,39322,39323,39324,39325,39326,39327,39328,39329,39330,39331,39332,39334,39335,39337,39338,39339,39340,39341,39342,39343,39344,39345,39346,39347,39348,39349,39350,39351,39352,39353,39354,39355,39356,39357,39358,39359,39360,39361,39362,39363,39364,39365,39366,39367,39368,39369,39370,39371,39372,39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383,39384,39385,39386,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396,39397,39398,39399,39400,39401,39402,39403,39404,39405,39406,39407,39408,39409,39410,39411,39412,39413,39414,39415,39416,39417,30235,30268,30242,30240,30272,30253,30256,30271,30261,30275,30270,30259,30285,30302,30292,30300,30294,30315,30319,32714,31462,31352,31353,31360,31366,31368,31381,31398,31392,31404,31400,31405,31411,34916,34921,34930,34941,34943,34946,34978,35014,34999,35004,35017,35042,35022,35043,35045,35057,35098,35068,35048,35070,35056,35105,35097,35091,35099,35082,35124,35115,35126,35137,35174,35195,30091,32997,30386,30388,30684,32786,32788,32790,32796,32800,32802,32805,32806,32807,32809,32808,32817,32779,32821,32835,32838,32845,32850,32873,32881,35203,39032,39040,39043,39418,39419,39420,39421,39422,39423,39424,39425,39426,39427,39428,39429,39430,39431,39432,39433,39434,39435,39436,39437,39438,39439,39440,39441,39442,39443,39444,39445,39446,39447,39448,39449,39450,39451,39452,39453,39454,39455,39456,39457,39458,39459,39460,39461,39462,39463,39464,39465,39466,39467,39468,39469,39470,39471,39472,39473,39474,39475,39476,39477,39478,39479,39480,39481,39482,39483,39484,39485,39486,39487,39488,39489,39490,39491,39492,39493,39494,39495,39496,39497,39498,39499,39500,39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39511,39512,39513,39049,39052,39053,39055,39060,39066,39067,39070,39071,39073,39074,39077,39078,34381,34388,34412,34414,34431,34426,34428,34427,34472,34445,34443,34476,34461,34471,34467,34474,34451,34473,34486,34500,34485,34510,34480,34490,34481,34479,34505,34511,34484,34537,34545,34546,34541,34547,34512,34579,34526,34548,34527,34520,34513,34563,34567,34552,34568,34570,34573,34569,34595,34619,34590,34597,34606,34586,34622,34632,34612,34609,34601,34615,34623,34690,34594,34685,34686,34683,34656,34672,34636,34670,34699,34643,34659,34684,34660,34649,34661,34707,34735,34728,34770,39514,39515,39516,39517,39518,39519,39520,39521,39522,39523,39524,39525,39526,39527,39528,39529,39530,39531,39538,39555,39561,39565,39566,39572,39573,39577,39590,39593,39594,39595,39596,39597,39598,39599,39602,39603,39604,39605,39609,39611,39613,39614,39615,39619,39620,39622,39623,39624,39625,39626,39629,39630,39631,39632,39634,39636,39637,39638,39639,39641,39642,39643,39644,39645,39646,39648,39650,39651,39652,39653,39655,39656,39657,39658,39660,39662,39664,39665,39666,39667,39668,39669,39670,39671,39672,39674,39676,39677,39678,39679,39680,39681,39682,39684,39685,39686,34758,34696,34693,34733,34711,34691,34731,34789,34732,34741,34739,34763,34771,34749,34769,34752,34762,34779,34794,34784,34798,34838,34835,34814,34826,34843,34849,34873,34876,32566,32578,32580,32581,33296,31482,31485,31496,31491,31492,31509,31498,31531,31503,31559,31544,31530,31513,31534,31537,31520,31525,31524,31539,31550,31518,31576,31578,31557,31605,31564,31581,31584,31598,31611,31586,31602,31601,31632,31654,31655,31672,31660,31645,31656,31621,31658,31644,31650,31659,31668,31697,31681,31692,31709,31706,31717,31718,31722,31756,31742,31740,31759,31766,31755,39687,39689,39690,39691,39692,39693,39694,39696,39697,39698,39700,39701,39702,39703,39704,39705,39706,39707,39708,39709,39710,39712,39713,39714,39716,39717,39718,39719,39720,39721,39722,39723,39724,39725,39726,39728,39729,39731,39732,39733,39734,39735,39736,39737,39738,39741,39742,39743,39744,39750,39754,39755,39756,39758,39760,39762,39763,39765,39766,39767,39768,39769,39770,39771,39772,39773,39774,39775,39776,39777,39778,39779,39780,39781,39782,39783,39784,39785,39786,39787,39788,39789,39790,39791,39792,39793,39794,39795,39796,39797,39798,39799,39800,39801,39802,39803,31775,31786,31782,31800,31809,31808,33278,33281,33282,33284,33260,34884,33313,33314,33315,33325,33327,33320,33323,33336,33339,33331,33332,33342,33348,33353,33355,33359,33370,33375,33384,34942,34949,34952,35032,35039,35166,32669,32671,32679,32687,32688,32690,31868,25929,31889,31901,31900,31902,31906,31922,31932,31933,31937,31943,31948,31949,31944,31941,31959,31976,33390,26280,32703,32718,32725,32741,32737,32742,32745,32750,32755,31992,32119,32166,32174,32327,32411,40632,40628,36211,36228,36244,36241,36273,36199,36205,35911,35913,37194,37200,37198,37199,37220,39804,39805,39806,39807,39808,39809,39810,39811,39812,39813,39814,39815,39816,39817,39818,39819,39820,39821,39822,39823,39824,39825,39826,39827,39828,39829,39830,39831,39832,39833,39834,39835,39836,39837,39838,39839,39840,39841,39842,39843,39844,39845,39846,39847,39848,39849,39850,39851,39852,39853,39854,39855,39856,39857,39858,39859,39860,39861,39862,39863,39864,39865,39866,39867,39868,39869,39870,39871,39872,39873,39874,39875,39876,39877,39878,39879,39880,39881,39882,39883,39884,39885,39886,39887,39888,39889,39890,39891,39892,39893,39894,39895,39896,39897,39898,39899,37218,37217,37232,37225,37231,37245,37246,37234,37236,37241,37260,37253,37264,37261,37265,37282,37283,37290,37293,37294,37295,37301,37300,37306,35925,40574,36280,36331,36357,36441,36457,36277,36287,36284,36282,36292,36310,36311,36314,36318,36302,36303,36315,36294,36332,36343,36344,36323,36345,36347,36324,36361,36349,36372,36381,36383,36396,36398,36387,36399,36410,36416,36409,36405,36413,36401,36425,36417,36418,36433,36434,36426,36464,36470,36476,36463,36468,36485,36495,36500,36496,36508,36510,35960,35970,35978,35973,35992,35988,26011,35286,35294,35290,35292,39900,39901,39902,39903,39904,39905,39906,39907,39908,39909,39910,39911,39912,39913,39914,39915,39916,39917,39918,39919,39920,39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933,39934,39935,39936,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946,39947,39948,39949,39950,39951,39952,39953,39954,39955,39956,39957,39958,39959,39960,39961,39962,39963,39964,39965,39966,39967,39968,39969,39970,39971,39972,39973,39974,39975,39976,39977,39978,39979,39980,39981,39982,39983,39984,39985,39986,39987,39988,39989,39990,39991,39992,39993,39994,39995,35301,35307,35311,35390,35622,38739,38633,38643,38639,38662,38657,38664,38671,38670,38698,38701,38704,38718,40832,40835,40837,40838,40839,40840,40841,40842,40844,40702,40715,40717,38585,38588,38589,38606,38610,30655,38624,37518,37550,37576,37694,37738,37834,37775,37950,37995,40063,40066,40069,40070,40071,40072,31267,40075,40078,40080,40081,40082,40084,40085,40090,40091,40094,40095,40096,40097,40098,40099,40101,40102,40103,40104,40105,40107,40109,40110,40112,40113,40114,40115,40116,40117,40118,40119,40122,40123,40124,40125,40132,40133,40134,40135,40138,40139,39996,39997,39998,39999,40000,40001,40002,40003,40004,40005,40006,40007,40008,40009,40010,40011,40012,40013,40014,40015,40016,40017,40018,40019,40020,40021,40022,40023,40024,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,40035,40036,40037,40038,40039,40040,40041,40042,40043,40044,40045,40046,40047,40048,40049,40050,40051,40052,40053,40054,40055,40056,40057,40058,40059,40061,40062,40064,40067,40068,40073,40074,40076,40079,40083,40086,40087,40088,40089,40093,40106,40108,40111,40121,40126,40127,40128,40129,40130,40136,40137,40145,40146,40154,40155,40160,40161,40140,40141,40142,40143,40144,40147,40148,40149,40151,40152,40153,40156,40157,40159,40162,38780,38789,38801,38802,38804,38831,38827,38819,38834,38836,39601,39600,39607,40536,39606,39610,39612,39617,39616,39621,39618,39627,39628,39633,39749,39747,39751,39753,39752,39757,39761,39144,39181,39214,39253,39252,39647,39649,39654,39663,39659,39675,39661,39673,39688,39695,39699,39711,39715,40637,40638,32315,40578,40583,40584,40587,40594,37846,40605,40607,40667,40668,40669,40672,40671,40674,40681,40679,40677,40682,40687,40738,40748,40751,40761,40759,40765,40766,40772,40163,40164,40165,40166,40167,40168,40169,40170,40171,40172,40173,40174,40175,40176,40177,40178,40179,40180,40181,40182,40183,40184,40185,40186,40187,40188,40189,40190,40191,40192,40193,40194,40195,40196,40197,40198,40199,40200,40201,40202,40203,40204,40205,40206,40207,40208,40209,40210,40211,40212,40213,40214,40215,40216,40217,40218,40219,40220,40221,40222,40223,40224,40225,40226,40227,40228,40229,40230,40231,40232,40233,40234,40235,40236,40237,40238,40239,40240,40241,40242,40243,40244,40245,40246,40247,40248,40249,40250,40251,40252,40253,40254,40255,40256,40257,40258,57908,57909,57910,57911,57912,57913,57914,57915,57916,57917,57918,57919,57920,57921,57922,57923,57924,57925,57926,57927,57928,57929,57930,57931,57932,57933,57934,57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946,57947,57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959,57960,57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972,57973,57974,57975,57976,57977,57978,57979,57980,57981,57982,57983,57984,57985,57986,57987,57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998,57999,58000,58001,40259,40260,40261,40262,40263,40264,40265,40266,40267,40268,40269,40270,40271,40272,40273,40274,40275,40276,40277,40278,40279,40280,40281,40282,40283,40284,40285,40286,40287,40288,40289,40290,40291,40292,40293,40294,40295,40296,40297,40298,40299,40300,40301,40302,40303,40304,40305,40306,40307,40308,40309,40310,40311,40312,40313,40314,40315,40316,40317,40318,40319,40320,40321,40322,40323,40324,40325,40326,40327,40328,40329,40330,40331,40332,40333,40334,40335,40336,40337,40338,40339,40340,40341,40342,40343,40344,40345,40346,40347,40348,40349,40350,40351,40352,40353,40354,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011,58012,58013,58014,58015,58016,58017,58018,58019,58020,58021,58022,58023,58024,58025,58026,58027,58028,58029,58030,58031,58032,58033,58034,58035,58036,58037,58038,58039,58040,58041,58042,58043,58044,58045,58046,58047,58048,58049,58050,58051,58052,58053,58054,58055,58056,58057,58058,58059,58060,58061,58062,58063,58064,58065,58066,58067,58068,58069,58070,58071,58072,58073,58074,58075,58076,58077,58078,58079,58080,58081,58082,58083,58084,58085,58086,58087,58088,58089,58090,58091,58092,58093,58094,58095,40355,40356,40357,40358,40359,40360,40361,40362,40363,40364,40365,40366,40367,40368,40369,40370,40371,40372,40373,40374,40375,40376,40377,40378,40379,40380,40381,40382,40383,40384,40385,40386,40387,40388,40389,40390,40391,40392,40393,40394,40395,40396,40397,40398,40399,40400,40401,40402,40403,40404,40405,40406,40407,40408,40409,40410,40411,40412,40413,40414,40415,40416,40417,40418,40419,40420,40421,40422,40423,40424,40425,40426,40427,40428,40429,40430,40431,40432,40433,40434,40435,40436,40437,40438,40439,40440,40441,40442,40443,40444,40445,40446,40447,40448,40449,40450,58096,58097,58098,58099,58100,58101,58102,58103,58104,58105,58106,58107,58108,58109,58110,58111,58112,58113,58114,58115,58116,58117,58118,58119,58120,58121,58122,58123,58124,58125,58126,58127,58128,58129,58130,58131,58132,58133,58134,58135,58136,58137,58138,58139,58140,58141,58142,58143,58144,58145,58146,58147,58148,58149,58150,58151,58152,58153,58154,58155,58156,58157,58158,58159,58160,58161,58162,58163,58164,58165,58166,58167,58168,58169,58170,58171,58172,58173,58174,58175,58176,58177,58178,58179,58180,58181,58182,58183,58184,58185,58186,58187,58188,58189,40451,40452,40453,40454,40455,40456,40457,40458,40459,40460,40461,40462,40463,40464,40465,40466,40467,40468,40469,40470,40471,40472,40473,40474,40475,40476,40477,40478,40484,40487,40494,40496,40500,40507,40508,40512,40525,40528,40530,40531,40532,40534,40537,40541,40543,40544,40545,40546,40549,40558,40559,40562,40564,40565,40566,40567,40568,40569,40570,40571,40572,40573,40576,40577,40579,40580,40581,40582,40585,40586,40588,40589,40590,40591,40592,40593,40596,40597,40598,40599,40600,40601,40602,40603,40604,40606,40608,40609,40610,40611,40612,40613,40615,40616,40617,40618,58190,58191,58192,58193,58194,58195,58196,58197,58198,58199,58200,58201,58202,58203,58204,58205,58206,58207,58208,58209,58210,58211,58212,58213,58214,58215,58216,58217,58218,58219,58220,58221,58222,58223,58224,58225,58226,58227,58228,58229,58230,58231,58232,58233,58234,58235,58236,58237,58238,58239,58240,58241,58242,58243,58244,58245,58246,58247,58248,58249,58250,58251,58252,58253,58254,58255,58256,58257,58258,58259,58260,58261,58262,58263,58264,58265,58266,58267,58268,58269,58270,58271,58272,58273,58274,58275,58276,58277,58278,58279,58280,58281,58282,58283,40619,40620,40621,40622,40623,40624,40625,40626,40627,40629,40630,40631,40633,40634,40636,40639,40640,40641,40642,40643,40645,40646,40647,40648,40650,40651,40652,40656,40658,40659,40661,40662,40663,40665,40666,40670,40673,40675,40676,40678,40680,40683,40684,40685,40686,40688,40689,40690,40691,40692,40693,40694,40695,40696,40698,40701,40703,40704,40705,40706,40707,40708,40709,40710,40711,40712,40713,40714,40716,40719,40721,40722,40724,40725,40726,40728,40730,40731,40732,40733,40734,40735,40737,40739,40740,40741,40742,40743,40744,40745,40746,40747,40749,40750,40752,40753,58284,58285,58286,58287,58288,58289,58290,58291,58292,58293,58294,58295,58296,58297,58298,58299,58300,58301,58302,58303,58304,58305,58306,58307,58308,58309,58310,58311,58312,58313,58314,58315,58316,58317,58318,58319,58320,58321,58322,58323,58324,58325,58326,58327,58328,58329,58330,58331,58332,58333,58334,58335,58336,58337,58338,58339,58340,58341,58342,58343,58344,58345,58346,58347,58348,58349,58350,58351,58352,58353,58354,58355,58356,58357,58358,58359,58360,58361,58362,58363,58364,58365,58366,58367,58368,58369,58370,58371,58372,58373,58374,58375,58376,58377,40754,40755,40756,40757,40758,40760,40762,40764,40767,40768,40769,40770,40771,40773,40774,40775,40776,40777,40778,40779,40780,40781,40782,40783,40786,40787,40788,40789,40790,40791,40792,40793,40794,40795,40796,40797,40798,40799,40800,40801,40802,40803,40804,40805,40806,40807,40808,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818,40819,40820,40821,40822,40823,40824,40825,40826,40827,40828,40829,40830,40833,40834,40845,40846,40847,40848,40849,40850,40851,40852,40853,40854,40855,40856,40860,40861,40862,40865,40866,40867,40868,40869,63788,63865,63893,63975,63985,58378,58379,58380,58381,58382,58383,58384,58385,58386,58387,58388,58389,58390,58391,58392,58393,58394,58395,58396,58397,58398,58399,58400,58401,58402,58403,58404,58405,58406,58407,58408,58409,58410,58411,58412,58413,58414,58415,58416,58417,58418,58419,58420,58421,58422,58423,58424,58425,58426,58427,58428,58429,58430,58431,58432,58433,58434,58435,58436,58437,58438,58439,58440,58441,58442,58443,58444,58445,58446,58447,58448,58449,58450,58451,58452,58453,58454,58455,58456,58457,58458,58459,58460,58461,58462,58463,58464,58465,58466,58467,58468,58469,58470,58471,64012,64013,64014,64015,64017,64019,64020,64024,64031,64032,64033,64035,64036,64039,64040,64041,11905,59414,59415,59416,11908,13427,13383,11912,11915,59422,13726,13850,13838,11916,11927,14702,14616,59430,14799,14815,14963,14800,59435,59436,15182,15470,15584,11943,59441,59442,11946,16470,16735,11950,17207,11955,11958,11959,59451,17329,17324,11963,17373,17622,18017,17996,59459,18211,18217,18300,18317,11978,18759,18810,18813,18818,18819,18821,18822,18847,18843,18871,18870,59476,59477,19619,19615,19616,19617,19575,19618,19731,19732,19733,19734,19735,19736,19737,19886,59492,58472,58473,58474,58475,58476,58477,58478,58479,58480,58481,58482,58483,58484,58485,58486,58487,58488,58489,58490,58491,58492,58493,58494,58495,58496,58497,58498,58499,58500,58501,58502,58503,58504,58505,58506,58507,58508,58509,58510,58511,58512,58513,58514,58515,58516,58517,58518,58519,58520,58521,58522,58523,58524,58525,58526,58527,58528,58529,58530,58531,58532,58533,58534,58535,58536,58537,58538,58539,58540,58541,58542,58543,58544,58545,58546,58547,58548,58549,58550,58551,58552,58553,58554,58555,58556,58557,58558,58559,58560,58561,58562,58563,58564,58565],"gb18030-ranges":[[0,128],[36,165],[38,169],[45,178],[50,184],[81,216],[89,226],[95,235],[96,238],[100,244],[103,248],[104,251],[105,253],[109,258],[126,276],[133,284],[148,300],[172,325],[175,329],[179,334],[208,364],[306,463],[307,465],[308,467],[309,469],[310,471],[311,473],[312,475],[313,477],[341,506],[428,594],[443,610],[544,712],[545,716],[558,730],[741,930],[742,938],[749,962],[750,970],[805,1026],[819,1104],[820,1106],[7922,8209],[7924,8215],[7925,8218],[7927,8222],[7934,8231],[7943,8241],[7944,8244],[7945,8246],[7950,8252],[8062,8365],[8148,8452],[8149,8454],[8152,8458],[8164,8471],[8174,8482],[8236,8556],[8240,8570],[8262,8596],[8264,8602],[8374,8713],[8380,8720],[8381,8722],[8384,8726],[8388,8731],[8390,8737],[8392,8740],[8393,8742],[8394,8748],[8396,8751],[8401,8760],[8406,8766],[8416,8777],[8419,8781],[8424,8787],[8437,8802],[8439,8808],[8445,8816],[8482,8854],[8485,8858],[8496,8870],[8521,8896],[8603,8979],[8936,9322],[8946,9372],[9046,9548],[9050,9588],[9063,9616],[9066,9622],[9076,9634],[9092,9652],[9100,9662],[9108,9672],[9111,9676],[9113,9680],[9131,9702],[9162,9735],[9164,9738],[9218,9793],[9219,9795],[11329,11906],[11331,11909],[11334,11913],[11336,11917],[11346,11928],[11361,11944],[11363,11947],[11366,11951],[11370,11956],[11372,11960],[11375,11964],[11389,11979],[11682,12284],[11686,12292],[11687,12312],[11692,12319],[11694,12330],[11714,12351],[11716,12436],[11723,12447],[11725,12535],[11730,12543],[11736,12586],[11982,12842],[11989,12850],[12102,12964],[12336,13200],[12348,13215],[12350,13218],[12384,13253],[12393,13263],[12395,13267],[12397,13270],[12510,13384],[12553,13428],[12851,13727],[12962,13839],[12973,13851],[13738,14617],[13823,14703],[13919,14801],[13933,14816],[14080,14964],[14298,15183],[14585,15471],[14698,15585],[15583,16471],[15847,16736],[16318,17208],[16434,17325],[16438,17330],[16481,17374],[16729,17623],[17102,17997],[17122,18018],[17315,18212],[17320,18218],[17402,18301],[17418,18318],[17859,18760],[17909,18811],[17911,18814],[17915,18820],[17916,18823],[17936,18844],[17939,18848],[17961,18872],[18664,19576],[18703,19620],[18814,19738],[18962,19887],[19043,40870],[33469,59244],[33470,59336],[33471,59367],[33484,59413],[33485,59417],[33490,59423],[33497,59431],[33501,59437],[33505,59443],[33513,59452],[33520,59460],[33536,59478],[33550,59493],[37845,63789],[37921,63866],[37948,63894],[38029,63976],[38038,63986],[38064,64016],[38065,64018],[38066,64021],[38069,64025],[38075,64034],[38076,64037],[38078,64042],[39108,65074],[39109,65093],[39113,65107],[39114,65112],[39115,65127],[39116,65132],[39265,65375],[39394,65510],[189000,65536]],jis0208:[12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,12293,12294,12295,12540,8213,8208,65295,65340,65374,8741,65372,8230,8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371,65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291,65293,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756,9794,9792,176,8242,8243,8451,65509,65284,65504,65505,65285,65283,65286,65290,65312,167,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593,8595,12307,null,null,null,null,null,null,null,null,null,null,null,8712,8715,8838,8839,8834,8835,8746,8745,null,null,null,null,null,null,null,null,8743,8744,65506,8658,8660,8704,8707,null,null,null,null,null,null,null,null,null,null,null,8736,8869,8978,8706,8711,8801,8786,8810,8811,8730,8765,8733,8757,8747,8748,null,null,null,null,null,null,null,8491,8240,9839,9837,9834,8224,8225,182,null,null,null,null,9711,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,null,null,null,null,null,null,null,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,null,null,null,null,null,null,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,null,null,null,null,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,null,null,null,null,null,null,null,null,null,null,null,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,null,null,null,null,null,null,null,null,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,null,null,null,null,null,null,null,null,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,null,null,null,null,null,null,null,null,null,null,null,null,null,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,null,13129,13076,13090,13133,13080,13095,13059,13110,13137,13143,13069,13094,13091,13099,13130,13115,13212,13213,13214,13198,13199,13252,13217,null,null,null,null,null,null,null,null,13179,12317,12319,8470,13261,8481,12964,12965,12966,12967,12968,12849,12850,12857,13182,13181,13180,8786,8801,8747,8750,8721,8730,8869,8736,8735,8895,8757,8745,8746,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312,24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451,22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353,26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801,21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359,40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013,21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942,23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964,33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322,27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839,28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713,27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681,28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487,22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779,29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662,35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011,33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602,22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123,22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226,35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990,25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963,28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666,20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059,21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022,25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929,38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696,24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215,35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931,23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696,25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653,21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470,24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932,22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378,29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208,20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220,22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465,33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306,29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936,31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418,20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950,24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076,32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335,33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770,28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048,21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609,36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015,40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791,27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399,20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184,24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179,26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343,30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108,33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681,26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038,24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661,20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507,28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617,38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948,21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613,31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638,39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158,29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531,20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985,23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045,26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930,33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164,27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012,29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610,26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462,23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754,21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722,33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598,37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294,37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576,21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477,23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484,25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169,28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505,31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443,35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055,20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611,20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187,26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455,34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645,22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920,37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883,32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968,26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738,38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707,31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509,25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808,21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849,27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549,37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950,22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105,30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299,35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204,36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384,23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549,22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550,32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151,33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432,40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129,28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243,22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347,24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044,31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449,24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159,28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530,38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515,27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131,20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340,32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576,22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799,27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969,37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594,20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947,24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783,29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957,39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461,33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563,31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182,33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905,29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492,22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226,25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467,24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493,22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687,31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893,33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843,37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138,22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495,27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318,29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329,21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130,30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131,27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051,38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220,24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676,36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096,23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998,21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991,32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281,38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857,23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370,35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952,24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192,35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778,26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412,32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598,21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001,31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695,40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180,23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538,22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446,26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249,20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220,35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188,22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076,29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178,24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469,33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651,34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053,21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942,26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618,31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155,28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105,24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894,34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498,36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880,28286,30871,33109,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098,20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147,20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233,20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329,20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725,20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795,20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866,22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905,20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960,34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034,21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097,21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149,21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269,21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325,20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413,21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485,21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582,21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636,21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988,21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068,22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176,22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216,22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350,22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451,22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539,22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442,22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001,23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094,23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273,23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363,23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416,25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524,23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939,23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802,23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842,23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940,23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019,24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118,24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181,24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417,24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473,24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755,24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614,24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643,24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756,24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820,24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032,25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087,25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179,25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236,25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282,25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424,25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481,25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825,25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884,25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942,25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015,26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081,26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180,26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248,26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438,26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507,26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590,26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688,26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797,26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765,26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863,26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163,27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146,27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225,27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306,27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447,30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489,27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562,27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929,27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053,28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126,28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270,28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227,28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371,28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433,28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525,28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601,28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683,28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720,28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846,28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030,29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113,29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477,29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562,29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733,29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795,29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955,29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029,30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070,30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278,30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361,30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433,30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501,30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590,30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653,30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014,30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072,31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146,31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245,31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305,31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382,31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439,31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503,31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718,31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783,31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832,31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915,31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960,31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115,32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125,32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377,32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396,32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616,32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669,32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714,32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786,32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858,32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155,33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200,33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240,33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287,33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373,33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406,33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523,33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660,33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795,33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848,34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922,33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009,33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071,34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196,34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516,34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555,34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586,34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768,38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829,34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870,34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942,34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219,35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290,35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365,35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458,35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546,35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596,35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646,35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737,35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960,35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013,36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093,36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045,36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303,36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361,36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639,36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678,36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791,36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885,36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975,36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039,37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194,37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523,37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718,37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853,37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941,37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000,38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292,38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346,28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577,38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620,38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681,38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748,38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778,38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854,38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968,38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319,39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406,39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493,39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524,39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646,39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722,39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827,39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054,40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367,40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314,40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386,40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569,40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632,40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672,40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,22575,27079,36953,29796,20956,29081,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32394,35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013,21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864,33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,null,null,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,65506,65508,65287,65282,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,65506,65508,65287,65282,12849,8470,8481,8757,32394,35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013,21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864,33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],jis0212:[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,728,711,184,729,733,175,731,730,65374,900,901,null,null,null,null,null,null,null,null,161,166,191,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,186,170,169,174,8482,164,8470,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,902,904,905,906,938,null,908,null,910,939,null,911,null,null,null,null,940,941,942,943,970,912,972,962,973,971,944,974,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1038,1039,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1118,1119,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,198,272,null,294,null,306,null,321,319,null,330,216,338,null,358,222,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,230,273,240,295,305,307,312,322,320,329,331,248,339,223,359,254,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,193,192,196,194,258,461,256,260,197,195,262,264,268,199,266,270,201,200,203,202,282,278,274,280,null,284,286,290,288,292,205,204,207,206,463,304,298,302,296,308,310,313,317,315,323,327,325,209,211,210,214,212,465,336,332,213,340,344,342,346,348,352,350,356,354,218,217,220,219,364,467,368,362,370,366,360,471,475,473,469,372,221,376,374,377,381,379,null,null,null,null,null,null,null,225,224,228,226,259,462,257,261,229,227,263,265,269,231,267,271,233,232,235,234,283,279,275,281,501,285,287,null,289,293,237,236,239,238,464,null,299,303,297,309,311,314,318,316,324,328,326,241,243,242,246,244,466,337,333,245,341,345,343,347,349,353,351,357,355,250,249,252,251,365,468,369,363,371,367,361,472,476,474,470,373,253,255,375,378,382,380,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,19970,19972,19973,19980,19986,19999,20003,20004,20008,20011,20014,20015,20016,20021,20032,20033,20036,20039,20049,20058,20060,20067,20072,20073,20084,20085,20089,20095,20109,20118,20119,20125,20143,20153,20163,20176,20186,20187,20192,20193,20194,20200,20207,20209,20211,20213,20221,20222,20223,20224,20226,20227,20232,20235,20236,20242,20245,20246,20247,20249,20270,20273,20320,20275,20277,20279,20281,20283,20286,20288,20290,20296,20297,20299,20300,20306,20308,20310,20312,20319,20323,20330,20332,20334,20337,20343,20344,20345,20346,20349,20350,20353,20354,20356,20357,20361,20362,20364,20366,20368,20370,20371,20372,20375,20377,20378,20382,20383,20402,20407,20409,20411,20412,20413,20414,20416,20417,20421,20422,20424,20425,20427,20428,20429,20431,20434,20444,20448,20450,20464,20466,20476,20477,20479,20480,20481,20484,20487,20490,20492,20494,20496,20499,20503,20504,20507,20508,20509,20510,20514,20519,20526,20528,20530,20531,20533,20544,20545,20546,20549,20550,20554,20556,20558,20561,20562,20563,20567,20569,20575,20576,20578,20579,20582,20583,20586,20589,20592,20593,20539,20609,20611,20612,20614,20618,20622,20623,20624,20626,20627,20628,20630,20635,20636,20638,20639,20640,20641,20642,20650,20655,20656,20665,20666,20669,20672,20675,20676,20679,20684,20686,20688,20691,20692,20696,20700,20701,20703,20706,20708,20710,20712,20713,20719,20721,20726,20730,20734,20739,20742,20743,20744,20747,20748,20749,20750,20722,20752,20759,20761,20763,20764,20765,20766,20771,20775,20776,20780,20781,20783,20785,20787,20788,20789,20792,20793,20802,20810,20815,20819,20821,20823,20824,20831,20836,20838,20862,20867,20868,20875,20878,20888,20893,20897,20899,20909,20920,20922,20924,20926,20927,20930,20936,20943,20945,20946,20947,20949,20952,20958,20962,20965,20974,20978,20979,20980,20983,20993,20994,20997,21010,21011,21013,21014,21016,21026,21032,21041,21042,21045,21052,21061,21065,21077,21079,21080,21082,21084,21087,21088,21089,21094,21102,21111,21112,21113,21120,21122,21125,21130,21132,21139,21141,21142,21143,21144,21146,21148,21156,21157,21158,21159,21167,21168,21174,21175,21176,21178,21179,21181,21184,21188,21190,21192,21196,21199,21201,21204,21206,21211,21212,21217,21221,21224,21225,21226,21228,21232,21233,21236,21238,21239,21248,21251,21258,21259,21260,21265,21267,21272,21275,21276,21278,21279,21285,21287,21288,21289,21291,21292,21293,21296,21298,21301,21308,21309,21310,21314,21324,21323,21337,21339,21345,21347,21349,21356,21357,21362,21369,21374,21379,21383,21384,21390,21395,21396,21401,21405,21409,21412,21418,21419,21423,21426,21428,21429,21431,21432,21434,21437,21440,21445,21455,21458,21459,21461,21466,21469,21470,21472,21478,21479,21493,21506,21523,21530,21537,21543,21544,21546,21551,21553,21556,21557,21571,21572,21575,21581,21583,21598,21602,21604,21606,21607,21609,21611,21613,21614,21620,21631,21633,21635,21637,21640,21641,21645,21649,21653,21654,21660,21663,21665,21670,21671,21673,21674,21677,21678,21681,21687,21689,21690,21691,21695,21702,21706,21709,21710,21728,21738,21740,21743,21750,21756,21758,21759,21760,21761,21765,21768,21769,21772,21773,21774,21781,21802,21803,21810,21813,21814,21819,21820,21821,21825,21831,21833,21834,21837,21840,21841,21848,21850,21851,21854,21856,21857,21860,21862,21887,21889,21890,21894,21896,21902,21903,21905,21906,21907,21908,21911,21923,21924,21933,21938,21951,21953,21955,21958,21961,21963,21964,21966,21969,21970,21971,21975,21976,21979,21982,21986,21993,22006,22015,22021,22024,22026,22029,22030,22031,22032,22033,22034,22041,22060,22064,22067,22069,22071,22073,22075,22076,22077,22079,22080,22081,22083,22084,22086,22089,22091,22093,22095,22100,22110,22112,22113,22114,22115,22118,22121,22125,22127,22129,22130,22133,22148,22149,22152,22155,22156,22165,22169,22170,22173,22174,22175,22182,22183,22184,22185,22187,22188,22189,22193,22195,22199,22206,22213,22217,22218,22219,22223,22224,22220,22221,22233,22236,22237,22239,22241,22244,22245,22246,22247,22248,22257,22251,22253,22262,22263,22273,22274,22279,22282,22284,22289,22293,22298,22299,22301,22304,22306,22307,22308,22309,22313,22314,22316,22318,22319,22323,22324,22333,22334,22335,22341,22342,22348,22349,22354,22370,22373,22375,22376,22379,22381,22382,22383,22384,22385,22387,22388,22389,22391,22393,22394,22395,22396,22398,22401,22403,22412,22420,22423,22425,22426,22428,22429,22430,22431,22433,22421,22439,22440,22441,22444,22456,22461,22471,22472,22476,22479,22485,22493,22494,22500,22502,22503,22505,22509,22512,22517,22518,22520,22525,22526,22527,22531,22532,22536,22537,22497,22540,22541,22555,22558,22559,22560,22566,22567,22573,22578,22585,22591,22601,22604,22605,22607,22608,22613,22623,22625,22628,22631,22632,22648,22652,22655,22656,22657,22663,22664,22665,22666,22668,22669,22671,22672,22676,22678,22685,22688,22689,22690,22694,22697,22705,22706,22724,22716,22722,22728,22733,22734,22736,22738,22740,22742,22746,22749,22753,22754,22761,22771,22789,22790,22795,22796,22802,22803,22804,34369,22813,22817,22819,22820,22824,22831,22832,22835,22837,22838,22847,22851,22854,22866,22867,22873,22875,22877,22878,22879,22881,22883,22891,22893,22895,22898,22901,22902,22905,22907,22908,22923,22924,22926,22930,22933,22935,22943,22948,22951,22957,22958,22959,22960,22963,22967,22970,22972,22977,22979,22980,22984,22986,22989,22994,23005,23006,23007,23011,23012,23015,23022,23023,23025,23026,23028,23031,23040,23044,23052,23053,23054,23058,23059,23070,23075,23076,23079,23080,23082,23085,23088,23108,23109,23111,23112,23116,23120,23125,23134,23139,23141,23143,23149,23159,23162,23163,23166,23179,23184,23187,23190,23193,23196,23198,23199,23200,23202,23207,23212,23217,23218,23219,23221,23224,23226,23227,23231,23236,23238,23240,23247,23258,23260,23264,23269,23274,23278,23285,23286,23293,23296,23297,23304,23319,23348,23321,23323,23325,23329,23333,23341,23352,23361,23371,23372,23378,23382,23390,23400,23406,23407,23420,23421,23422,23423,23425,23428,23430,23434,23438,23440,23441,23443,23444,23446,23464,23465,23468,23469,23471,23473,23474,23479,23482,23484,23488,23489,23501,23503,23510,23511,23512,23513,23514,23520,23535,23537,23540,23549,23564,23575,23582,23583,23587,23590,23593,23595,23596,23598,23600,23602,23605,23606,23641,23642,23644,23650,23651,23655,23656,23657,23661,23664,23668,23669,23674,23675,23676,23677,23687,23688,23690,23695,23698,23709,23711,23712,23714,23715,23718,23722,23730,23732,23733,23738,23753,23755,23762,23773,23767,23790,23793,23794,23796,23809,23814,23821,23826,23851,23843,23844,23846,23847,23857,23860,23865,23869,23871,23874,23875,23878,23880,23893,23889,23897,23882,23903,23904,23905,23906,23908,23914,23917,23920,23929,23930,23934,23935,23937,23939,23944,23946,23954,23955,23956,23957,23961,23963,23967,23968,23975,23979,23984,23988,23992,23993,24003,24007,24011,24016,24014,24024,24025,24032,24036,24041,24056,24057,24064,24071,24077,24082,24084,24085,24088,24095,24096,24110,24104,24114,24117,24126,24139,24144,24137,24145,24150,24152,24155,24156,24158,24168,24170,24171,24172,24173,24174,24176,24192,24203,24206,24226,24228,24229,24232,24234,24236,24241,24243,24253,24254,24255,24262,24268,24267,24270,24273,24274,24276,24277,24284,24286,24293,24299,24322,24326,24327,24328,24334,24345,24348,24349,24353,24354,24355,24356,24360,24363,24364,24366,24368,24372,24374,24379,24381,24383,24384,24388,24389,24391,24397,24400,24404,24408,24411,24416,24419,24420,24423,24431,24434,24436,24437,24440,24442,24445,24446,24457,24461,24463,24470,24476,24477,24482,24487,24491,24484,24492,24495,24496,24497,24504,24516,24519,24520,24521,24523,24528,24529,24530,24531,24532,24542,24545,24546,24552,24553,24554,24556,24557,24558,24559,24562,24563,24566,24570,24572,24583,24586,24589,24595,24596,24599,24600,24602,24607,24612,24621,24627,24629,24640,24647,24648,24649,24652,24657,24660,24662,24663,24669,24673,24679,24689,24702,24703,24706,24710,24712,24714,24718,24721,24723,24725,24728,24733,24734,24738,24740,24741,24744,24752,24753,24759,24763,24766,24770,24772,24776,24777,24778,24779,24782,24783,24788,24789,24793,24795,24797,24798,24802,24805,24818,24821,24824,24828,24829,24834,24839,24842,24844,24848,24849,24850,24851,24852,24854,24855,24857,24860,24862,24866,24874,24875,24880,24881,24885,24886,24887,24889,24897,24901,24902,24905,24926,24928,24940,24946,24952,24955,24956,24959,24960,24961,24963,24964,24971,24973,24978,24979,24983,24984,24988,24989,24991,24992,24997,25000,25002,25005,25016,25017,25020,25024,25025,25026,25038,25039,25045,25052,25053,25054,25055,25057,25058,25063,25065,25061,25068,25069,25071,25089,25091,25092,25095,25107,25109,25116,25120,25122,25123,25127,25129,25131,25145,25149,25154,25155,25156,25158,25164,25168,25169,25170,25172,25174,25178,25180,25188,25197,25199,25203,25210,25213,25229,25230,25231,25232,25254,25256,25267,25270,25271,25274,25278,25279,25284,25294,25301,25302,25306,25322,25330,25332,25340,25341,25347,25348,25354,25355,25357,25360,25363,25366,25368,25385,25386,25389,25397,25398,25401,25404,25409,25410,25411,25412,25414,25418,25419,25422,25426,25427,25428,25432,25435,25445,25446,25452,25453,25457,25460,25461,25464,25468,25469,25471,25474,25476,25479,25482,25488,25492,25493,25497,25498,25502,25508,25510,25517,25518,25519,25533,25537,25541,25544,25550,25553,25555,25556,25557,25564,25568,25573,25578,25580,25586,25587,25589,25592,25593,25609,25610,25616,25618,25620,25624,25630,25632,25634,25636,25637,25641,25642,25647,25648,25653,25661,25663,25675,25679,25681,25682,25683,25684,25690,25691,25692,25693,25695,25696,25697,25699,25709,25715,25716,25723,25725,25733,25735,25743,25744,25745,25752,25753,25755,25757,25759,25761,25763,25766,25768,25772,25779,25789,25790,25791,25796,25801,25802,25803,25804,25806,25808,25809,25813,25815,25828,25829,25833,25834,25837,25840,25845,25847,25851,25855,25857,25860,25864,25865,25866,25871,25875,25876,25878,25881,25883,25886,25887,25890,25894,25897,25902,25905,25914,25916,25917,25923,25927,25929,25936,25938,25940,25951,25952,25959,25963,25978,25981,25985,25989,25994,26002,26005,26008,26013,26016,26019,26022,26030,26034,26035,26036,26047,26050,26056,26057,26062,26064,26068,26070,26072,26079,26096,26098,26100,26101,26105,26110,26111,26112,26116,26120,26121,26125,26129,26130,26133,26134,26141,26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26161,26163,26169,26167,26176,26181,26182,26186,26188,26193,26190,26199,26200,26201,26203,26204,26208,26209,26363,26218,26219,26220,26238,26227,26229,26239,26231,26232,26233,26235,26240,26236,26251,26252,26253,26256,26258,26265,26266,26267,26268,26271,26272,26276,26285,26289,26290,26293,26299,26303,26304,26306,26307,26312,26316,26318,26319,26324,26331,26335,26344,26347,26348,26350,26362,26373,26375,26382,26387,26393,26396,26400,26402,26419,26430,26437,26439,26440,26444,26452,26453,26461,26470,26476,26478,26484,26486,26491,26497,26500,26510,26511,26513,26515,26518,26520,26521,26523,26544,26545,26546,26549,26555,26556,26557,26617,26560,26562,26563,26565,26568,26569,26578,26583,26585,26588,26593,26598,26608,26610,26614,26615,26706,26644,26649,26653,26655,26664,26663,26668,26669,26671,26672,26673,26675,26683,26687,26692,26693,26698,26700,26709,26711,26712,26715,26731,26734,26735,26736,26737,26738,26741,26745,26746,26747,26748,26754,26756,26758,26760,26774,26776,26778,26780,26785,26787,26789,26793,26794,26798,26802,26811,26821,26824,26828,26831,26832,26833,26835,26838,26841,26844,26845,26853,26856,26858,26859,26860,26861,26864,26865,26869,26870,26875,26876,26877,26886,26889,26890,26896,26897,26899,26902,26903,26929,26931,26933,26936,26939,26946,26949,26953,26958,26967,26971,26979,26980,26981,26982,26984,26985,26988,26992,26993,26994,27002,27003,27007,27008,27021,27026,27030,27032,27041,27045,27046,27048,27051,27053,27055,27063,27064,27066,27068,27077,27080,27089,27094,27095,27106,27109,27118,27119,27121,27123,27125,27134,27136,27137,27139,27151,27153,27157,27162,27165,27168,27172,27176,27184,27186,27188,27191,27195,27198,27199,27205,27206,27209,27210,27214,27216,27217,27218,27221,27222,27227,27236,27239,27242,27249,27251,27262,27265,27267,27270,27271,27273,27275,27281,27291,27293,27294,27295,27301,27307,27311,27312,27313,27316,27325,27326,27327,27334,27337,27336,27340,27344,27348,27349,27350,27356,27357,27364,27367,27372,27376,27377,27378,27388,27389,27394,27395,27398,27399,27401,27407,27408,27409,27415,27419,27422,27428,27432,27435,27436,27439,27445,27446,27451,27455,27462,27466,27469,27474,27478,27480,27485,27488,27495,27499,27502,27504,27509,27517,27518,27522,27525,27543,27547,27551,27552,27554,27555,27560,27561,27564,27565,27566,27568,27576,27577,27581,27582,27587,27588,27593,27596,27606,27610,27617,27619,27622,27623,27630,27633,27639,27641,27647,27650,27652,27653,27657,27661,27662,27664,27666,27673,27679,27686,27687,27688,27692,27694,27699,27701,27702,27706,27707,27711,27722,27723,27725,27727,27730,27732,27737,27739,27740,27755,27757,27759,27764,27766,27768,27769,27771,27781,27782,27783,27785,27796,27797,27799,27800,27804,27807,27824,27826,27828,27842,27846,27853,27855,27856,27857,27858,27860,27862,27866,27868,27872,27879,27881,27883,27884,27886,27890,27892,27908,27911,27914,27918,27919,27921,27923,27930,27942,27943,27944,27751,27950,27951,27953,27961,27964,27967,27991,27998,27999,28001,28005,28007,28015,28016,28028,28034,28039,28049,28050,28052,28054,28055,28056,28074,28076,28084,28087,28089,28093,28095,28100,28104,28106,28110,28111,28118,28123,28125,28127,28128,28130,28133,28137,28143,28144,28148,28150,28156,28160,28164,28190,28194,28199,28210,28214,28217,28219,28220,28228,28229,28232,28233,28235,28239,28241,28242,28243,28244,28247,28252,28253,28254,28258,28259,28264,28275,28283,28285,28301,28307,28313,28320,28327,28333,28334,28337,28339,28347,28351,28352,28353,28355,28359,28360,28362,28365,28366,28367,28395,28397,28398,28409,28411,28413,28420,28424,28426,28428,28429,28438,28440,28442,28443,28454,28457,28458,28463,28464,28467,28470,28475,28476,28461,28495,28497,28498,28499,28503,28505,28506,28509,28510,28513,28514,28520,28524,28541,28542,28547,28551,28552,28555,28556,28557,28560,28562,28563,28564,28566,28570,28575,28576,28581,28582,28583,28584,28590,28591,28592,28597,28598,28604,28613,28615,28616,28618,28634,28638,28648,28649,28656,28661,28665,28668,28669,28672,28677,28678,28679,28685,28695,28704,28707,28719,28724,28727,28729,28732,28739,28740,28744,28745,28746,28747,28756,28757,28765,28766,28750,28772,28773,28780,28782,28789,28790,28798,28801,28805,28806,28820,28821,28822,28823,28824,28827,28836,28843,28848,28849,28852,28855,28874,28881,28883,28884,28885,28886,28888,28892,28900,28922,28931,28932,28933,28934,28935,28939,28940,28943,28958,28960,28971,28973,28975,28976,28977,28984,28993,28997,28998,28999,29002,29003,29008,29010,29015,29018,29020,29022,29024,29032,29049,29056,29061,29063,29068,29074,29082,29083,29088,29090,29103,29104,29106,29107,29114,29119,29120,29121,29124,29131,29132,29139,29142,29145,29146,29148,29176,29182,29184,29191,29192,29193,29203,29207,29210,29213,29215,29220,29227,29231,29236,29240,29241,29249,29250,29251,29253,29262,29263,29264,29267,29269,29270,29274,29276,29278,29280,29283,29288,29291,29294,29295,29297,29303,29304,29307,29308,29311,29316,29321,29325,29326,29331,29339,29352,29357,29358,29361,29364,29374,29377,29383,29385,29388,29397,29398,29400,29407,29413,29427,29428,29434,29435,29438,29442,29444,29445,29447,29451,29453,29458,29459,29464,29465,29470,29474,29476,29479,29480,29484,29489,29490,29493,29498,29499,29501,29507,29517,29520,29522,29526,29528,29533,29534,29535,29536,29542,29543,29545,29547,29548,29550,29551,29553,29559,29561,29564,29568,29569,29571,29573,29574,29582,29584,29587,29589,29591,29592,29596,29598,29599,29600,29602,29605,29606,29610,29611,29613,29621,29623,29625,29628,29629,29631,29637,29638,29641,29643,29644,29647,29650,29651,29654,29657,29661,29665,29667,29670,29671,29673,29684,29685,29687,29689,29690,29691,29693,29695,29696,29697,29700,29703,29706,29713,29722,29723,29732,29734,29736,29737,29738,29739,29740,29741,29742,29743,29744,29745,29753,29760,29763,29764,29766,29767,29771,29773,29777,29778,29783,29789,29794,29798,29799,29800,29803,29805,29806,29809,29810,29824,29825,29829,29830,29831,29833,29839,29840,29841,29842,29848,29849,29850,29852,29855,29856,29857,29859,29862,29864,29865,29866,29867,29870,29871,29873,29874,29877,29881,29883,29887,29896,29897,29900,29904,29907,29912,29914,29915,29918,29919,29924,29928,29930,29931,29935,29940,29946,29947,29948,29951,29958,29970,29974,29975,29984,29985,29988,29991,29993,29994,29999,30006,30009,30013,30014,30015,30016,30019,30023,30024,30030,30032,30034,30039,30046,30047,30049,30063,30065,30073,30074,30075,30076,30077,30078,30081,30085,30096,30098,30099,30101,30105,30108,30114,30116,30132,30138,30143,30144,30145,30148,30150,30156,30158,30159,30167,30172,30175,30176,30177,30180,30183,30188,30190,30191,30193,30201,30208,30210,30211,30212,30215,30216,30218,30220,30223,30226,30227,30229,30230,30233,30235,30236,30237,30238,30243,30245,30246,30249,30253,30258,30259,30261,30264,30265,30266,30268,30282,30272,30273,30275,30276,30277,30281,30283,30293,30297,30303,30308,30309,30317,30318,30319,30321,30324,30337,30341,30348,30349,30357,30363,30364,30365,30367,30368,30370,30371,30372,30373,30374,30375,30376,30378,30381,30397,30401,30405,30409,30411,30412,30414,30420,30425,30432,30438,30440,30444,30448,30449,30454,30457,30460,30464,30470,30474,30478,30482,30484,30485,30487,30489,30490,30492,30498,30504,30509,30510,30511,30516,30517,30518,30521,30525,30526,30530,30533,30534,30538,30541,30542,30543,30546,30550,30551,30556,30558,30559,30560,30562,30564,30567,30570,30572,30576,30578,30579,30580,30586,30589,30592,30596,30604,30605,30612,30613,30614,30618,30623,30626,30631,30634,30638,30639,30641,30645,30654,30659,30665,30673,30674,30677,30681,30686,30687,30688,30692,30694,30698,30700,30704,30705,30708,30712,30715,30725,30726,30729,30733,30734,30737,30749,30753,30754,30755,30765,30766,30768,30773,30775,30787,30788,30791,30792,30796,30798,30802,30812,30814,30816,30817,30819,30820,30824,30826,30830,30842,30846,30858,30863,30868,30872,30881,30877,30878,30879,30884,30888,30892,30893,30896,30897,30898,30899,30907,30909,30911,30919,30920,30921,30924,30926,30930,30931,30933,30934,30948,30939,30943,30944,30945,30950,30954,30962,30963,30976,30966,30967,30970,30971,30975,30982,30988,30992,31002,31004,31006,31007,31008,31013,31015,31017,31021,31025,31028,31029,31035,31037,31039,31044,31045,31046,31050,31051,31055,31057,31060,31064,31067,31068,31079,31081,31083,31090,31097,31099,31100,31102,31115,31116,31121,31123,31124,31125,31126,31128,31131,31132,31137,31144,31145,31147,31151,31153,31156,31160,31163,31170,31172,31175,31176,31178,31183,31188,31190,31194,31197,31198,31200,31202,31205,31210,31211,31213,31217,31224,31228,31234,31235,31239,31241,31242,31244,31249,31253,31259,31262,31265,31271,31275,31277,31279,31280,31284,31285,31288,31289,31290,31300,31301,31303,31304,31308,31317,31318,31321,31324,31325,31327,31328,31333,31335,31338,31341,31349,31352,31358,31360,31362,31365,31366,31370,31371,31376,31377,31380,31390,31392,31395,31404,31411,31413,31417,31419,31420,31430,31433,31436,31438,31441,31451,31464,31465,31467,31468,31473,31476,31483,31485,31486,31495,31508,31519,31523,31527,31529,31530,31531,31533,31534,31535,31536,31537,31540,31549,31551,31552,31553,31559,31566,31573,31584,31588,31590,31593,31594,31597,31599,31602,31603,31607,31620,31625,31630,31632,31633,31638,31643,31646,31648,31653,31660,31663,31664,31666,31669,31670,31674,31675,31676,31677,31682,31685,31688,31690,31700,31702,31703,31705,31706,31707,31720,31722,31730,31732,31733,31736,31737,31738,31740,31742,31745,31746,31747,31748,31750,31753,31755,31756,31758,31759,31769,31771,31776,31781,31782,31784,31788,31793,31795,31796,31798,31801,31802,31814,31818,31829,31825,31826,31827,31833,31834,31835,31836,31837,31838,31841,31843,31847,31849,31853,31854,31856,31858,31865,31868,31869,31878,31879,31887,31892,31902,31904,31910,31920,31926,31927,31930,31931,31932,31935,31940,31943,31944,31945,31949,31951,31955,31956,31957,31959,31961,31962,31965,31974,31977,31979,31989,32003,32007,32008,32009,32015,32017,32018,32019,32022,32029,32030,32035,32038,32042,32045,32049,32060,32061,32062,32064,32065,32071,32072,32077,32081,32083,32087,32089,32090,32092,32093,32101,32103,32106,32112,32120,32122,32123,32127,32129,32130,32131,32133,32134,32136,32139,32140,32141,32145,32150,32151,32157,32158,32166,32167,32170,32179,32182,32183,32185,32194,32195,32196,32197,32198,32204,32205,32206,32215,32217,32256,32226,32229,32230,32234,32235,32237,32241,32245,32246,32249,32250,32264,32272,32273,32277,32279,32284,32285,32288,32295,32296,32300,32301,32303,32307,32310,32319,32324,32325,32327,32334,32336,32338,32344,32351,32353,32354,32357,32363,32366,32367,32371,32376,32382,32385,32390,32391,32394,32397,32401,32405,32408,32410,32413,32414,32572,32571,32573,32574,32575,32579,32580,32583,32591,32594,32595,32603,32604,32605,32609,32611,32612,32613,32614,32621,32625,32637,32638,32639,32640,32651,32653,32655,32656,32657,32662,32663,32668,32673,32674,32678,32682,32685,32692,32700,32703,32704,32707,32712,32718,32719,32731,32735,32739,32741,32744,32748,32750,32751,32754,32762,32765,32766,32767,32775,32776,32778,32781,32782,32783,32785,32787,32788,32790,32797,32798,32799,32800,32804,32806,32812,32814,32816,32820,32821,32823,32825,32826,32828,32830,32832,32836,32864,32868,32870,32877,32881,32885,32897,32904,32910,32924,32926,32934,32935,32939,32952,32953,32968,32973,32975,32978,32980,32981,32983,32984,32992,33005,33006,33008,33010,33011,33014,33017,33018,33022,33027,33035,33046,33047,33048,33052,33054,33056,33060,33063,33068,33072,33077,33082,33084,33093,33095,33098,33100,33106,33111,33120,33121,33127,33128,33129,33133,33135,33143,33153,33168,33156,33157,33158,33163,33166,33174,33176,33179,33182,33186,33198,33202,33204,33211,33227,33219,33221,33226,33230,33231,33237,33239,33243,33245,33246,33249,33252,33259,33260,33264,33265,33266,33269,33270,33272,33273,33277,33279,33280,33283,33295,33299,33300,33305,33306,33309,33313,33314,33320,33330,33332,33338,33347,33348,33349,33350,33355,33358,33359,33361,33366,33372,33376,33379,33383,33389,33396,33403,33405,33407,33408,33409,33411,33412,33415,33417,33418,33422,33425,33428,33430,33432,33434,33435,33440,33441,33443,33444,33447,33448,33449,33450,33454,33456,33458,33460,33463,33466,33468,33470,33471,33478,33488,33493,33498,33504,33506,33508,33512,33514,33517,33519,33526,33527,33533,33534,33536,33537,33543,33544,33546,33547,33620,33563,33565,33566,33567,33569,33570,33580,33581,33582,33584,33587,33591,33594,33596,33597,33602,33603,33604,33607,33613,33614,33617,33621,33622,33623,33648,33656,33661,33663,33664,33666,33668,33670,33677,33682,33684,33685,33688,33689,33691,33692,33693,33702,33703,33705,33708,33726,33727,33728,33735,33737,33743,33744,33745,33748,33757,33619,33768,33770,33782,33784,33785,33788,33793,33798,33802,33807,33809,33813,33817,33709,33839,33849,33861,33863,33864,33866,33869,33871,33873,33874,33878,33880,33881,33882,33884,33888,33892,33893,33895,33898,33904,33907,33908,33910,33912,33916,33917,33921,33925,33938,33939,33941,33950,33958,33960,33961,33962,33967,33969,33972,33978,33981,33982,33984,33986,33991,33992,33996,33999,34003,34012,34023,34026,34031,34032,34033,34034,34039,34098,34042,34043,34045,34050,34051,34055,34060,34062,34064,34076,34078,34082,34083,34084,34085,34087,34090,34091,34095,34099,34100,34102,34111,34118,34127,34128,34129,34130,34131,34134,34137,34140,34141,34142,34143,34144,34145,34146,34148,34155,34159,34169,34170,34171,34173,34175,34177,34181,34182,34185,34187,34188,34191,34195,34200,34205,34207,34208,34210,34213,34215,34228,34230,34231,34232,34236,34237,34238,34239,34242,34247,34250,34251,34254,34221,34264,34266,34271,34272,34278,34280,34285,34291,34294,34300,34303,34304,34308,34309,34317,34318,34320,34321,34322,34328,34329,34331,34334,34337,34343,34345,34358,34360,34362,34364,34365,34368,34370,34374,34386,34387,34390,34391,34392,34393,34397,34400,34401,34402,34403,34404,34409,34412,34415,34421,34422,34423,34426,34445,34449,34454,34456,34458,34460,34465,34470,34471,34472,34477,34481,34483,34484,34485,34487,34488,34489,34495,34496,34497,34499,34501,34513,34514,34517,34519,34522,34524,34528,34531,34533,34535,34440,34554,34556,34557,34564,34565,34567,34571,34574,34575,34576,34579,34580,34585,34590,34591,34593,34595,34600,34606,34607,34609,34610,34617,34618,34620,34621,34622,34624,34627,34629,34637,34648,34653,34657,34660,34661,34671,34673,34674,34683,34691,34692,34693,34694,34695,34696,34697,34699,34700,34704,34707,34709,34711,34712,34713,34718,34720,34723,34727,34732,34733,34734,34737,34741,34750,34751,34753,34760,34761,34762,34766,34773,34774,34777,34778,34780,34783,34786,34787,34788,34794,34795,34797,34801,34803,34808,34810,34815,34817,34819,34822,34825,34826,34827,34832,34841,34834,34835,34836,34840,34842,34843,34844,34846,34847,34856,34861,34862,34864,34866,34869,34874,34876,34881,34883,34885,34888,34889,34890,34891,34894,34897,34901,34902,34904,34906,34908,34911,34912,34916,34921,34929,34937,34939,34944,34968,34970,34971,34972,34975,34976,34984,34986,35002,35005,35006,35008,35018,35019,35020,35021,35022,35025,35026,35027,35035,35038,35047,35055,35056,35057,35061,35063,35073,35078,35085,35086,35087,35093,35094,35096,35097,35098,35100,35104,35110,35111,35112,35120,35121,35122,35125,35129,35130,35134,35136,35138,35141,35142,35145,35151,35154,35159,35162,35163,35164,35169,35170,35171,35179,35182,35184,35187,35189,35194,35195,35196,35197,35209,35213,35216,35220,35221,35227,35228,35231,35232,35237,35248,35252,35253,35254,35255,35260,35284,35285,35286,35287,35288,35301,35305,35307,35309,35313,35315,35318,35321,35325,35327,35332,35333,35335,35343,35345,35346,35348,35349,35358,35360,35362,35364,35366,35371,35372,35375,35381,35383,35389,35390,35392,35395,35397,35399,35401,35405,35406,35411,35414,35415,35416,35420,35421,35425,35429,35431,35445,35446,35447,35449,35450,35451,35454,35455,35456,35459,35462,35467,35471,35472,35474,35478,35479,35481,35487,35495,35497,35502,35503,35507,35510,35511,35515,35518,35523,35526,35528,35529,35530,35537,35539,35540,35541,35543,35549,35551,35564,35568,35572,35573,35574,35580,35583,35589,35590,35595,35601,35612,35614,35615,35594,35629,35632,35639,35644,35650,35651,35652,35653,35654,35656,35666,35667,35668,35673,35661,35678,35683,35693,35702,35704,35705,35708,35710,35713,35716,35717,35723,35725,35727,35732,35733,35740,35742,35743,35896,35897,35901,35902,35909,35911,35913,35915,35919,35921,35923,35924,35927,35928,35931,35933,35929,35939,35940,35942,35944,35945,35949,35955,35957,35958,35963,35966,35974,35975,35979,35984,35986,35987,35993,35995,35996,36004,36025,36026,36037,36038,36041,36043,36047,36054,36053,36057,36061,36065,36072,36076,36079,36080,36082,36085,36087,36088,36094,36095,36097,36099,36105,36114,36119,36123,36197,36201,36204,36206,36223,36226,36228,36232,36237,36240,36241,36245,36254,36255,36256,36262,36267,36268,36271,36274,36277,36279,36281,36283,36288,36293,36294,36295,36296,36298,36302,36305,36308,36309,36311,36313,36324,36325,36327,36332,36336,36284,36337,36338,36340,36349,36353,36356,36357,36358,36363,36369,36372,36374,36384,36385,36386,36387,36390,36391,36401,36403,36406,36407,36408,36409,36413,36416,36417,36427,36429,36430,36431,36436,36443,36444,36445,36446,36449,36450,36457,36460,36461,36463,36464,36465,36473,36474,36475,36482,36483,36489,36496,36498,36501,36506,36507,36509,36510,36514,36519,36521,36525,36526,36531,36533,36538,36539,36544,36545,36547,36548,36551,36559,36561,36564,36572,36584,36590,36592,36593,36599,36601,36602,36589,36608,36610,36615,36616,36623,36624,36630,36631,36632,36638,36640,36641,36643,36645,36647,36648,36652,36653,36654,36660,36661,36662,36663,36666,36672,36673,36675,36679,36687,36689,36690,36691,36692,36693,36696,36701,36702,36709,36765,36768,36769,36772,36773,36774,36789,36790,36792,36798,36800,36801,36806,36810,36811,36813,36816,36818,36819,36821,36832,36835,36836,36840,36846,36849,36853,36854,36859,36862,36866,36868,36872,36876,36888,36891,36904,36905,36911,36906,36908,36909,36915,36916,36919,36927,36931,36932,36940,36955,36957,36962,36966,36967,36972,36976,36980,36985,36997,37000,37003,37004,37006,37008,37013,37015,37016,37017,37019,37024,37025,37026,37029,37040,37042,37043,37044,37046,37053,37068,37054,37059,37060,37061,37063,37064,37077,37079,37080,37081,37084,37085,37087,37093,37074,37110,37099,37103,37104,37108,37118,37119,37120,37124,37125,37126,37128,37133,37136,37140,37142,37143,37144,37146,37148,37150,37152,37157,37154,37155,37159,37161,37166,37167,37169,37172,37174,37175,37177,37178,37180,37181,37187,37191,37192,37199,37203,37207,37209,37210,37211,37217,37220,37223,37229,37236,37241,37242,37243,37249,37251,37253,37254,37258,37262,37265,37267,37268,37269,37272,37278,37281,37286,37288,37292,37293,37294,37296,37297,37298,37299,37302,37307,37308,37309,37311,37314,37315,37317,37331,37332,37335,37337,37338,37342,37348,37349,37353,37354,37356,37357,37358,37359,37360,37361,37367,37369,37371,37373,37376,37377,37380,37381,37382,37383,37385,37386,37388,37392,37394,37395,37398,37400,37404,37405,37411,37412,37413,37414,37416,37422,37423,37424,37427,37429,37430,37432,37433,37434,37436,37438,37440,37442,37443,37446,37447,37450,37453,37454,37455,37457,37464,37465,37468,37469,37472,37473,37477,37479,37480,37481,37486,37487,37488,37493,37494,37495,37496,37497,37499,37500,37501,37503,37512,37513,37514,37517,37518,37522,37527,37529,37535,37536,37540,37541,37543,37544,37547,37551,37554,37558,37560,37562,37563,37564,37565,37567,37568,37569,37570,37571,37573,37574,37575,37576,37579,37580,37581,37582,37584,37587,37589,37591,37592,37593,37596,37597,37599,37600,37601,37603,37605,37607,37608,37612,37614,37616,37625,37627,37631,37632,37634,37640,37645,37649,37652,37653,37660,37661,37662,37663,37665,37668,37669,37671,37673,37674,37683,37684,37686,37687,37703,37704,37705,37712,37713,37714,37717,37719,37720,37722,37726,37732,37733,37735,37737,37738,37741,37743,37744,37745,37747,37748,37750,37754,37757,37759,37760,37761,37762,37768,37770,37771,37773,37775,37778,37781,37784,37787,37790,37793,37795,37796,37798,37800,37803,37812,37813,37814,37818,37801,37825,37828,37829,37830,37831,37833,37834,37835,37836,37837,37843,37849,37852,37854,37855,37858,37862,37863,37881,37879,37880,37882,37883,37885,37889,37890,37892,37896,37897,37901,37902,37903,37909,37910,37911,37919,37934,37935,37937,37938,37939,37940,37947,37951,37949,37955,37957,37960,37962,37964,37973,37977,37980,37983,37985,37987,37992,37995,37997,37998,37999,38001,38002,38020,38019,38264,38265,38270,38276,38280,38284,38285,38286,38301,38302,38303,38305,38310,38313,38315,38316,38324,38326,38330,38333,38335,38342,38344,38345,38347,38352,38353,38354,38355,38361,38362,38365,38366,38367,38368,38372,38374,38429,38430,38434,38436,38437,38438,38444,38449,38451,38455,38456,38457,38458,38460,38461,38465,38482,38484,38486,38487,38488,38497,38510,38516,38523,38524,38526,38527,38529,38530,38531,38532,38537,38545,38550,38554,38557,38559,38564,38565,38566,38569,38574,38575,38579,38586,38602,38610,23986,38616,38618,38621,38622,38623,38633,38639,38641,38650,38658,38659,38661,38665,38682,38683,38685,38689,38690,38691,38696,38705,38707,38721,38723,38730,38734,38735,38741,38743,38744,38746,38747,38755,38759,38762,38766,38771,38774,38775,38776,38779,38781,38783,38784,38793,38805,38806,38807,38809,38810,38814,38815,38818,38828,38830,38833,38834,38837,38838,38840,38841,38842,38844,38846,38847,38849,38852,38853,38855,38857,38858,38860,38861,38862,38864,38865,38868,38871,38872,38873,38877,38878,38880,38875,38881,38884,38895,38897,38900,38903,38904,38906,38919,38922,38937,38925,38926,38932,38934,38940,38942,38944,38947,38950,38955,38958,38959,38960,38962,38963,38965,38949,38974,38980,38983,38986,38993,38994,38995,38998,38999,39001,39002,39010,39011,39013,39014,39018,39020,39083,39085,39086,39088,39092,39095,39096,39098,39099,39103,39106,39109,39112,39116,39137,39139,39141,39142,39143,39146,39155,39158,39170,39175,39176,39185,39189,39190,39191,39194,39195,39196,39199,39202,39206,39207,39211,39217,39218,39219,39220,39221,39225,39226,39227,39228,39232,39233,39238,39239,39240,39245,39246,39252,39256,39257,39259,39260,39262,39263,39264,39323,39325,39327,39334,39344,39345,39346,39349,39353,39354,39357,39359,39363,39369,39379,39380,39385,39386,39388,39390,39399,39402,39403,39404,39408,39412,39413,39417,39421,39422,39426,39427,39428,39435,39436,39440,39441,39446,39454,39456,39458,39459,39460,39463,39469,39470,39475,39477,39478,39480,39495,39489,39492,39498,39499,39500,39502,39505,39508,39510,39517,39594,39596,39598,39599,39602,39604,39605,39606,39609,39611,39614,39615,39617,39619,39622,39624,39630,39632,39634,39637,39638,39639,39643,39644,39648,39652,39653,39655,39657,39660,39666,39667,39669,39673,39674,39677,39679,39680,39681,39682,39683,39684,39685,39688,39689,39691,39692,39693,39694,39696,39698,39702,39705,39707,39708,39712,39718,39723,39725,39731,39732,39733,39735,39737,39738,39741,39752,39755,39756,39765,39766,39767,39771,39774,39777,39779,39781,39782,39784,39786,39787,39788,39789,39790,39795,39797,39799,39800,39801,39807,39808,39812,39813,39814,39815,39817,39818,39819,39821,39823,39824,39828,39834,39837,39838,39846,39847,39849,39852,39856,39857,39858,39863,39864,39867,39868,39870,39871,39873,39879,39880,39886,39888,39895,39896,39901,39903,39909,39911,39914,39915,39919,39923,39927,39928,39929,39930,39933,39935,39936,39938,39947,39951,39953,39958,39960,39961,39962,39964,39966,39970,39971,39974,39975,39976,39977,39978,39985,39989,39990,39991,39997,40001,40003,40004,40005,40009,40010,40014,40015,40016,40019,40020,40022,40024,40027,40029,40030,40031,40035,40041,40042,40028,40043,40040,40046,40048,40050,40053,40055,40059,40166,40178,40183,40185,40203,40194,40209,40215,40216,40220,40221,40222,40239,40240,40242,40243,40244,40250,40252,40261,40253,40258,40259,40263,40266,40275,40276,40287,40291,40290,40293,40297,40298,40299,40304,40310,40311,40315,40316,40318,40323,40324,40326,40330,40333,40334,40338,40339,40341,40342,40343,40344,40353,40362,40364,40366,40369,40373,40377,40380,40383,40387,40391,40393,40394,40404,40405,40406,40407,40410,40414,40415,40416,40421,40423,40425,40427,40430,40432,40435,40436,40446,40458,40450,40455,40462,40464,40465,40466,40469,40470,40473,40476,40477,40570,40571,40572,40576,40578,40579,40580,40581,40583,40590,40591,40598,40600,40603,40606,40612,40616,40620,40622,40623,40624,40627,40628,40629,40646,40648,40651,40661,40671,40676,40679,40684,40685,40686,40688,40689,40690,40693,40696,40703,40706,40707,40713,40719,40720,40721,40722,40724,40726,40727,40729,40730,40731,40735,40738,40742,40746,40747,40751,40753,40754,40756,40759,40761,40762,40764,40765,40767,40769,40771,40772,40773,40774,40775,40787,40789,40790,40791,40792,40794,40797,40798,40808,40809,40813,40814,40815,40816,40817,40819,40821,40826,40829,40847,40848,40849,40850,40852,40854,40855,40862,40865,40866,40867,40869,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],ibm866:[1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,9617,9618,9619,9474,9508,9569,9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,9492,9524,9516,9500,9472,9532,9566,9567,9562,9556,9577,9574,9568,9552,9580,9575,9576,9572,9573,9561,9560,9554,9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1025,1105,1028,1108,1031,1111,1038,1118,176,8729,183,8730,8470,164,9632,160],"iso-8859-2":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,728,321,164,317,346,167,168,352,350,356,377,173,381,379,176,261,731,322,180,318,347,711,184,353,351,357,378,733,382,380,340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270,272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223,341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271,273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729],"iso-8859-3":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,294,728,163,164,null,292,167,168,304,350,286,308,173,null,379,176,295,178,179,180,181,293,183,184,305,351,287,309,189,null,380,192,193,194,null,196,266,264,199,200,201,202,203,204,205,206,207,null,209,210,211,212,288,214,215,284,217,218,219,220,364,348,223,224,225,226,null,228,267,265,231,232,233,234,235,236,237,238,239,null,241,242,243,244,289,246,247,285,249,250,251,252,365,349,729],"iso-8859-4":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,312,342,164,296,315,167,168,352,274,290,358,173,381,175,176,261,731,343,180,297,316,711,184,353,275,291,359,330,382,331,256,193,194,195,196,197,198,302,268,201,280,203,278,205,206,298,272,325,332,310,212,213,214,215,216,370,218,219,220,360,362,223,257,225,226,227,228,229,230,303,269,233,281,235,279,237,238,299,273,326,333,311,244,245,246,247,248,371,250,251,252,361,363,729],"iso-8859-5":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,173,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,8470,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,167,1118,1119],"iso-8859-6":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,null,null,null,164,null,null,null,null,null,null,null,1548,173,null,null,null,null,null,null,null,null,null,null,null,null,null,1563,null,null,null,1567,null,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,null,null,null,null,null,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,null,null,null,null,null,null,null,null,null,null,null,null,null],"iso-8859-7":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,8216,8217,163,8364,8367,166,167,168,169,890,171,172,173,null,8213,176,177,178,179,900,901,902,183,904,905,906,187,908,189,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,null,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,null],"iso-8859-8":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,null,162,163,164,165,166,167,168,169,215,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,247,187,188,189,190,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,8215,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,null,null,8206,8207,null],"iso-8859-10":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,274,290,298,296,310,167,315,272,352,358,381,173,362,330,176,261,275,291,299,297,311,183,316,273,353,359,382,8213,363,331,256,193,194,195,196,197,198,302,268,201,280,203,278,205,206,207,208,325,332,211,212,213,214,360,216,370,218,219,220,221,222,223,257,225,226,227,228,229,230,303,269,233,281,235,279,237,238,239,240,326,333,243,244,245,246,361,248,371,250,251,252,253,254,312],"iso-8859-13":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,8221,162,163,164,8222,166,167,216,169,342,171,172,173,174,198,176,177,178,179,8220,181,182,183,248,185,343,187,188,189,190,230,260,302,256,262,196,197,280,274,268,201,377,278,290,310,298,315,352,323,325,211,332,213,214,215,370,321,346,362,220,379,381,223,261,303,257,263,228,229,281,275,269,233,378,279,291,311,299,316,353,324,326,243,333,245,246,247,371,322,347,363,252,380,382,8217],"iso-8859-14":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,7682,7683,163,266,267,7690,167,7808,169,7810,7691,7922,173,174,376,7710,7711,288,289,7744,7745,182,7766,7809,7767,7811,7776,7923,7812,7813,7777,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,372,209,210,211,212,213,214,7786,216,217,218,219,220,221,374,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,373,241,242,243,244,245,246,7787,248,249,250,251,252,253,375,255],"iso-8859-15":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,8364,165,352,167,353,169,170,171,172,173,174,175,176,177,178,179,381,181,182,183,382,185,186,187,338,339,376,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255],"iso-8859-16":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,261,321,8364,8222,352,167,353,169,536,171,377,173,378,379,176,177,268,322,381,8221,182,183,382,269,537,187,338,339,376,380,192,193,194,258,196,262,198,199,200,201,202,203,204,205,206,207,272,323,210,211,212,336,214,346,368,217,218,219,220,280,538,223,224,225,226,259,228,263,230,231,232,233,234,235,236,237,238,239,273,324,242,243,244,337,246,347,369,249,250,251,252,281,539,255],"koi8-r":[9472,9474,9484,9488,9492,9496,9500,9508,9516,9524,9532,9600,9604,9608,9612,9616,9617,9618,9619,8992,9632,8729,8730,8776,8804,8805,160,8993,176,178,183,247,9552,9553,9554,1105,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,1025,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,169,1102,1072,1073,1094,1076,1077,1092,1075,1093,1080,1081,1082,1083,1084,1085,1086,1087,1103,1088,1089,1090,1091,1078,1074,1100,1099,1079,1096,1101,1097,1095,1098,1070,1040,1041,1062,1044,1045,1060,1043,1061,1048,1049,1050,1051,1052,1053,1054,1055,1071,1056,1057,1058,1059,1046,1042,1068,1067,1047,1064,1069,1065,1063,1066],"koi8-u":[9472,9474,9484,9488,9492,9496,9500,9508,9516,9524,9532,9600,9604,9608,9612,9616,9617,9618,9619,8992,9632,8729,8730,8776,8804,8805,160,8993,176,178,183,247,9552,9553,9554,1105,1108,9556,1110,1111,9559,9560,9561,9562,9563,1169,1118,9566,9567,9568,9569,1025,1028,9571,1030,1031,9574,9575,9576,9577,9578,1168,1038,169,1102,1072,1073,1094,1076,1077,1092,1075,1093,1080,1081,1082,1083,1084,1085,1086,1087,1103,1088,1089,1090,1091,1078,1074,1100,1099,1079,1096,1101,1097,1095,1098,1070,1040,1041,1062,1044,1045,1060,1043,1061,1048,1049,1050,1051,1052,1053,1054,1055,1071,1056,1057,1058,1059,1046,1042,1068,1067,1047,1064,1069,1065,1063,1066],macintosh:[196,197,199,201,209,214,220,225,224,226,228,227,229,231,233,232,234,235,237,236,238,239,241,243,242,244,246,245,250,249,251,252,8224,176,162,163,167,8226,182,223,174,169,8482,180,168,8800,198,216,8734,177,8804,8805,165,181,8706,8721,8719,960,8747,170,186,937,230,248,191,161,172,8730,402,8776,8710,171,187,8230,160,192,195,213,338,339,8211,8212,8220,8221,8216,8217,247,9674,255,376,8260,8364,8249,8250,64257,64258,8225,183,8218,8222,8240,194,202,193,203,200,205,206,207,204,211,212,63743,210,218,219,217,305,710,732,175,728,729,730,184,733,731,711],"windows-874":[8364,129,130,131,132,8230,134,135,136,137,138,139,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,152,153,154,155,156,157,158,159,160,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,null,null,null,null,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,null,null,null,null],"windows-1250":[8364,129,8218,131,8222,8230,8224,8225,136,8240,352,8249,346,356,381,377,144,8216,8217,8220,8221,8226,8211,8212,152,8482,353,8250,347,357,382,378,160,711,728,321,164,260,166,167,168,169,350,171,172,173,174,379,176,177,731,322,180,181,182,183,184,261,351,187,317,733,318,380,340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270,272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223,341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271,273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729],"windows-1251":[1026,1027,8218,1107,8222,8230,8224,8225,8364,8240,1033,8249,1034,1036,1035,1039,1106,8216,8217,8220,8221,8226,8211,8212,152,8482,1113,8250,1114,1116,1115,1119,160,1038,1118,1032,164,1168,166,167,1025,169,1028,171,172,173,174,1031,176,177,1030,1110,1169,181,182,183,1105,8470,1108,187,1112,1029,1109,1111,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103],"windows-1252":[8364,129,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,381,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,382,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255],"windows-1253":[8364,129,8218,402,8222,8230,8224,8225,136,8240,138,8249,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,152,8482,154,8250,156,157,158,159,160,901,902,163,164,165,166,167,168,169,null,171,172,173,174,8213,176,177,178,179,900,181,182,183,904,905,906,187,908,189,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,null,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,null],"windows-1254":[8364,129,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,158,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,286,209,210,211,212,213,214,215,216,217,218,219,220,304,350,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,287,241,242,243,244,245,246,247,248,249,250,251,252,305,351,255],"windows-1255":[8364,129,8218,402,8222,8230,8224,8225,710,8240,138,8249,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,154,8250,156,157,158,159,160,161,162,163,8362,165,166,167,168,169,215,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,247,187,188,189,190,191,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1520,1521,1522,1523,1524,null,null,null,null,null,null,null,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,null,null,8206,8207,null],"windows-1256":[8364,1662,8218,402,8222,8230,8224,8225,710,8240,1657,8249,338,1670,1688,1672,1711,8216,8217,8220,8221,8226,8211,8212,1705,8482,1681,8250,339,8204,8205,1722,160,1548,162,163,164,165,166,167,168,169,1726,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,1563,187,188,189,190,1567,1729,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,215,1591,1592,1593,1594,1600,1601,1602,1603,224,1604,226,1605,1606,1607,1608,231,232,233,234,235,1609,1610,238,239,1611,1612,1613,1614,244,1615,1616,247,1617,249,1618,251,252,8206,8207,1746],"windows-1257":[8364,129,8218,131,8222,8230,8224,8225,136,8240,138,8249,140,168,711,184,144,8216,8217,8220,8221,8226,8211,8212,152,8482,154,8250,156,175,731,159,160,null,162,163,164,null,166,167,216,169,342,171,172,173,174,198,176,177,178,179,180,181,182,183,248,185,343,187,188,189,190,230,260,302,256,262,196,197,280,274,268,201,377,278,290,310,298,315,352,323,325,211,332,213,214,215,370,321,346,362,220,379,381,223,261,303,257,263,228,229,281,275,269,233,378,279,291,311,299,316,353,324,326,243,333,245,246,247,371,322,347,363,252,380,382,729],"windows-1258":[8364,129,8218,402,8222,8230,8224,8225,710,8240,138,8249,338,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,154,8250,339,157,158,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,258,196,197,198,199,200,201,202,203,768,205,206,207,272,209,777,211,212,416,214,215,216,217,218,219,220,431,771,223,224,225,226,259,228,229,230,231,232,233,234,235,769,237,238,239,273,241,803,243,244,417,246,247,248,249,250,251,252,432,8363,255],"x-mac-cyrillic":[1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,8224,176,1168,163,167,8226,182,1030,174,169,8482,1026,1106,8800,1027,1107,8734,177,8804,8805,1110,181,1169,1032,1028,1108,1031,1111,1033,1113,1034,1114,1112,1029,172,8730,402,8776,8710,171,187,8230,160,1035,1115,1036,1116,1109,8211,8212,8220,8221,8216,8217,247,8222,1038,1118,1039,1119,8470,1025,1105,1103,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,8364]}})(exports||{})});var require_encoding=__commonJS((exports,module)=>{(function(global){if(typeof module!=="undefined"&&module.exports&&!global["encoding-indexes"]){global["encoding-indexes"]=require_encoding_indexes()["encoding-indexes"]}function inRange(a,min,max){return min<=a&&a<=max}function includes(array,item){return array.indexOf(item)!==-1}var floor=Math.floor;function ToDictionary(o){if(o===undefined)return{};if(o===Object(o))return o;throw TypeError("Could not convert argument to dictionary")}function stringToCodePoints(string){var s=String(string);var n=s.length;var i=0;var u=[];while(i<n){var c=s.charCodeAt(i);if(c<55296||c>57343){u.push(c)}else if(56320<=c&&c<=57343){u.push(65533)}else if(55296<=c&&c<=56319){if(i===n-1){u.push(65533)}else{var d=s.charCodeAt(i+1);if(56320<=d&&d<=57343){var a=c&1023;var b=d&1023;u.push(65536+(a<<10)+b);i+=1}else{u.push(65533)}}}i+=1}return u}function codePointsToString(code_points){var s="";for(var i=0;i<code_points.length;++i){var cp=code_points[i];if(cp<=65535){s+=String.fromCharCode(cp)}else{cp-=65536;s+=String.fromCharCode((cp>>10)+55296,(cp&1023)+56320)}}return s}function isASCIIByte(a){return 0<=a&&a<=127}var isASCIICodePoint=isASCIIByte;var end_of_stream=-1;function Stream(tokens){this.tokens=[].slice.call(tokens);this.tokens.reverse()}Stream.prototype={endOfStream:function(){return!this.tokens.length},read:function(){if(!this.tokens.length)return end_of_stream;return this.tokens.pop()},prepend:function(token){if(Array.isArray(token)){var tokens=token;while(tokens.length)this.tokens.push(tokens.pop())}else{this.tokens.push(token)}},push:function(token){if(Array.isArray(token)){var tokens=token;while(tokens.length)this.tokens.unshift(tokens.shift())}else{this.tokens.unshift(token)}}};var finished=-1;function decoderError(fatal,opt_code_point){if(fatal)throw TypeError("Decoder error");return opt_code_point||65533}function encoderError(code_point){throw TypeError("The code point "+code_point+" could not be encoded.")}function Decoder(){}Decoder.prototype={handler:function(stream,bite){}};function Encoder(){}Encoder.prototype={handler:function(stream,code_point){}};function getEncoding(label){label=String(label).trim().toLowerCase();if(Object.prototype.hasOwnProperty.call(label_to_encoding,label)){return label_to_encoding[label]}return null}var encodings=[{encodings:[{labels:["unicode-1-1-utf-8","utf-8","utf8"],name:"UTF-8"}],heading:"The Encoding"},{encodings:[{labels:["866","cp866","csibm866","ibm866"],name:"IBM866"},{labels:["csisolatin2","iso-8859-2","iso-ir-101","iso8859-2","iso88592","iso_8859-2","iso_8859-2:1987","l2","latin2"],name:"ISO-8859-2"},{labels:["csisolatin3","iso-8859-3","iso-ir-109","iso8859-3","iso88593","iso_8859-3","iso_8859-3:1988","l3","latin3"],name:"ISO-8859-3"},{labels:["csisolatin4","iso-8859-4","iso-ir-110","iso8859-4","iso88594","iso_8859-4","iso_8859-4:1988","l4","latin4"],name:"ISO-8859-4"},{labels:["csisolatincyrillic","cyrillic","iso-8859-5","iso-ir-144","iso8859-5","iso88595","iso_8859-5","iso_8859-5:1988"],name:"ISO-8859-5"},{labels:["arabic","asmo-708","csiso88596e","csiso88596i","csisolatinarabic","ecma-114","iso-8859-6","iso-8859-6-e","iso-8859-6-i","iso-ir-127","iso8859-6","iso88596","iso_8859-6","iso_8859-6:1987"],name:"ISO-8859-6"},{labels:["csisolatingreek","ecma-118","elot_928","greek","greek8","iso-8859-7","iso-ir-126","iso8859-7","iso88597","iso_8859-7","iso_8859-7:1987","sun_eu_greek"],name:"ISO-8859-7"},{labels:["csiso88598e","csisolatinhebrew","hebrew","iso-8859-8","iso-8859-8-e","iso-ir-138","iso8859-8","iso88598","iso_8859-8","iso_8859-8:1988","visual"],name:"ISO-8859-8"},{labels:["csiso88598i","iso-8859-8-i","logical"],name:"ISO-8859-8-I"},{labels:["csisolatin6","iso-8859-10","iso-ir-157","iso8859-10","iso885910","l6","latin6"],name:"ISO-8859-10"},{labels:["iso-8859-13","iso8859-13","iso885913"],name:"ISO-8859-13"},{labels:["iso-8859-14","iso8859-14","iso885914"],name:"ISO-8859-14"},{labels:["csisolatin9","iso-8859-15","iso8859-15","iso885915","iso_8859-15","l9"],name:"ISO-8859-15"},{labels:["iso-8859-16"],name:"ISO-8859-16"},{labels:["cskoi8r","koi","koi8","koi8-r","koi8_r"],name:"KOI8-R"},{labels:["koi8-ru","koi8-u"],name:"KOI8-U"},{labels:["csmacintosh","mac","macintosh","x-mac-roman"],name:"macintosh"},{labels:["dos-874","iso-8859-11","iso8859-11","iso885911","tis-620","windows-874"],name:"windows-874"},{labels:["cp1250","windows-1250","x-cp1250"],name:"windows-1250"},{labels:["cp1251","windows-1251","x-cp1251"],name:"windows-1251"},{labels:["ansi_x3.4-1968","ascii","cp1252","cp819","csisolatin1","ibm819","iso-8859-1","iso-ir-100","iso8859-1","iso88591","iso_8859-1","iso_8859-1:1987","l1","latin1","us-ascii","windows-1252","x-cp1252"],name:"windows-1252"},{labels:["cp1253","windows-1253","x-cp1253"],name:"windows-1253"},{labels:["cp1254","csisolatin5","iso-8859-9","iso-ir-148","iso8859-9","iso88599","iso_8859-9","iso_8859-9:1989","l5","latin5","windows-1254","x-cp1254"],name:"windows-1254"},{labels:["cp1255","windows-1255","x-cp1255"],name:"windows-1255"},{labels:["cp1256","windows-1256","x-cp1256"],name:"windows-1256"},{labels:["cp1257","windows-1257","x-cp1257"],name:"windows-1257"},{labels:["cp1258","windows-1258","x-cp1258"],name:"windows-1258"},{labels:["x-mac-cyrillic","x-mac-ukrainian"],name:"x-mac-cyrillic"}],heading:"Legacy single-byte encodings"},{encodings:[{labels:["chinese","csgb2312","csiso58gb231280","gb2312","gb_2312","gb_2312-80","gbk","iso-ir-58","x-gbk"],name:"GBK"},{labels:["gb18030"],name:"gb18030"}],heading:"Legacy multi-byte Chinese (simplified) encodings"},{encodings:[{labels:["big5","big5-hkscs","cn-big5","csbig5","x-x-big5"],name:"Big5"}],heading:"Legacy multi-byte Chinese (traditional) encodings"},{encodings:[{labels:["cseucpkdfmtjapanese","euc-jp","x-euc-jp"],name:"EUC-JP"},{labels:["csiso2022jp","iso-2022-jp"],name:"ISO-2022-JP"},{labels:["csshiftjis","ms932","ms_kanji","shift-jis","shift_jis","sjis","windows-31j","x-sjis"],name:"Shift_JIS"}],heading:"Legacy multi-byte Japanese encodings"},{encodings:[{labels:["cseuckr","csksc56011987","euc-kr","iso-ir-149","korean","ks_c_5601-1987","ks_c_5601-1989","ksc5601","ksc_5601","windows-949"],name:"EUC-KR"}],heading:"Legacy multi-byte Korean encodings"},{encodings:[{labels:["csiso2022kr","hz-gb-2312","iso-2022-cn","iso-2022-cn-ext","iso-2022-kr"],name:"replacement"},{labels:["utf-16be"],name:"UTF-16BE"},{labels:["utf-16","utf-16le"],name:"UTF-16LE"},{labels:["x-user-defined"],name:"x-user-defined"}],heading:"Legacy miscellaneous encodings"}];var label_to_encoding={};encodings.forEach(function(category){category.encodings.forEach(function(encoding){encoding.labels.forEach(function(label){label_to_encoding[label]=encoding})})});var encoders={};var decoders={};function indexCodePointFor(pointer,index2){if(!index2)return null;return index2[pointer]||null}function indexPointerFor(code_point,index2){var pointer=index2.indexOf(code_point);return pointer===-1?null:pointer}function index(name){if(!("encoding-indexes"in global)){throw Error("Indexes missing."+" Did you forget to include encoding-indexes.js first?")}return global["encoding-indexes"][name]}function indexGB18030RangesCodePointFor(pointer){if(pointer>39419&&pointer<189000||pointer>1237575)return null;if(pointer===7457)return 59335;var offset=0;var code_point_offset=0;var idx=index("gb18030-ranges");var i;for(i=0;i<idx.length;++i){var entry=idx[i];if(entry[0]<=pointer){offset=entry[0];code_point_offset=entry[1]}else{break}}return code_point_offset+pointer-offset}function indexGB18030RangesPointerFor(code_point){if(code_point===59335)return 7457;var offset=0;var pointer_offset=0;var idx=index("gb18030-ranges");var i;for(i=0;i<idx.length;++i){var entry=idx[i];if(entry[1]<=code_point){offset=entry[1];pointer_offset=entry[0]}else{break}}return pointer_offset+code_point-offset}function indexShiftJISPointerFor(code_point){shift_jis_index=shift_jis_index||index("jis0208").map(function(code_point2,pointer){return inRange(pointer,8272,8835)?null:code_point2});var index_=shift_jis_index;return index_.indexOf(code_point)}var shift_jis_index;function indexBig5PointerFor(code_point){big5_index_no_hkscs=big5_index_no_hkscs||index("big5").map(function(code_point2,pointer){return pointer<(161-129)*157?null:code_point2});var index_=big5_index_no_hkscs;if(code_point===9552||code_point===9566||code_point===9569||code_point===9578||code_point===21313||code_point===21317){return index_.lastIndexOf(code_point)}return indexPointerFor(code_point,index_)}var big5_index_no_hkscs;var DEFAULT_ENCODING="utf-8";function TextDecoder(label,options){if(!(this instanceof TextDecoder))throw TypeError("Called as a function. Did you forget 'new'?");label=label!==undefined?String(label):DEFAULT_ENCODING;options=ToDictionary(options);this._encoding=null;this._decoder=null;this._ignoreBOM=false;this._BOMseen=false;this._error_mode="replacement";this._do_not_flush=false;var encoding=getEncoding(label);if(encoding===null||encoding.name==="replacement")throw RangeError("Unknown encoding: "+label);if(!decoders[encoding.name]){throw Error("Decoder not present."+" Did you forget to include encoding-indexes.js first?")}var dec=this;dec._encoding=encoding;if(Boolean(options["fatal"]))dec._error_mode="fatal";if(Boolean(options["ignoreBOM"]))dec._ignoreBOM=true;if(!Object.defineProperty){this.encoding=dec._encoding.name.toLowerCase();this.fatal=dec._error_mode==="fatal";this.ignoreBOM=dec._ignoreBOM}return dec}if(Object.defineProperty){Object.defineProperty(TextDecoder.prototype,"encoding",{get:function(){return this._encoding.name.toLowerCase()}});Object.defineProperty(TextDecoder.prototype,"fatal",{get:function(){return this._error_mode==="fatal"}});Object.defineProperty(TextDecoder.prototype,"ignoreBOM",{get:function(){return this._ignoreBOM}})}TextDecoder.prototype.decode=function decode(input,options){var bytes;if(typeof input==="object"&&input instanceof ArrayBuffer){bytes=new Uint8Array(input)}else if(typeof input==="object"&&"buffer"in input&&input.buffer instanceof ArrayBuffer){bytes=new Uint8Array(input.buffer,input.byteOffset,input.byteLength)}else{bytes=new Uint8Array(0)}options=ToDictionary(options);if(!this._do_not_flush){this._decoder=decoders[this._encoding.name]({fatal:this._error_mode==="fatal"});this._BOMseen=false}this._do_not_flush=Boolean(options["stream"]);var input_stream=new Stream(bytes);var output=[];var result;while(true){var token=input_stream.read();if(token===end_of_stream)break;result=this._decoder.handler(input_stream,token);if(result===finished)break;if(result!==null){if(Array.isArray(result))output.push.apply(output,result);else output.push(result)}}if(!this._do_not_flush){do{result=this._decoder.handler(input_stream,input_stream.read());if(result===finished)break;if(result===null)continue;if(Array.isArray(result))output.push.apply(output,result);else output.push(result)}while(!input_stream.endOfStream());this._decoder=null}function serializeStream(stream){if(includes(["UTF-8","UTF-16LE","UTF-16BE"],this._encoding.name)&&!this._ignoreBOM&&!this._BOMseen){if(stream.length>0&&stream[0]===65279){this._BOMseen=true;stream.shift()}else if(stream.length>0){this._BOMseen=true}else{}}return codePointsToString(stream)}return serializeStream.call(this,output)};function TextEncoder(label,options){if(!(this instanceof TextEncoder))throw TypeError("Called as a function. Did you forget 'new'?");options=ToDictionary(options);this._encoding=null;this._encoder=null;this._do_not_flush=false;this._fatal=Boolean(options["fatal"])?"fatal":"replacement";var enc=this;if(Boolean(options["NONSTANDARD_allowLegacyEncoding"])){label=label!==undefined?String(label):DEFAULT_ENCODING;var encoding=getEncoding(label);if(encoding===null||encoding.name==="replacement")throw RangeError("Unknown encoding: "+label);if(!encoders[encoding.name]){throw Error("Encoder not present."+" Did you forget to include encoding-indexes.js first?")}enc._encoding=encoding}else{enc._encoding=getEncoding("utf-8");if(label!==undefined&&"console"in global){console.warn("TextEncoder constructor called with encoding label, "+"which is ignored.")}}if(!Object.defineProperty)this.encoding=enc._encoding.name.toLowerCase();return enc}if(Object.defineProperty){Object.defineProperty(TextEncoder.prototype,"encoding",{get:function(){return this._encoding.name.toLowerCase()}})}TextEncoder.prototype.encode=function encode(opt_string,options){opt_string=opt_string===undefined?"":String(opt_string);options=ToDictionary(options);if(!this._do_not_flush)this._encoder=encoders[this._encoding.name]({fatal:this._fatal==="fatal"});this._do_not_flush=Boolean(options["stream"]);var input=new Stream(stringToCodePoints(opt_string));var output=[];var result;while(true){var token=input.read();if(token===end_of_stream)break;result=this._encoder.handler(input,token);if(result===finished)break;if(Array.isArray(result))output.push.apply(output,result);else output.push(result)}if(!this._do_not_flush){while(true){result=this._encoder.handler(input,input.read());if(result===finished)break;if(Array.isArray(result))output.push.apply(output,result);else output.push(result)}this._encoder=null}return new Uint8Array(output)};function UTF8Decoder(options){var fatal=options.fatal;var utf8_code_point=0,utf8_bytes_seen=0,utf8_bytes_needed=0,utf8_lower_boundary=128,utf8_upper_boundary=191;this.handler=function(stream,bite){if(bite===end_of_stream&&utf8_bytes_needed!==0){utf8_bytes_needed=0;return decoderError(fatal)}if(bite===end_of_stream)return finished;if(utf8_bytes_needed===0){if(inRange(bite,0,127)){return bite}else if(inRange(bite,194,223)){utf8_bytes_needed=1;utf8_code_point=bite&31}else if(inRange(bite,224,239)){if(bite===224)utf8_lower_boundary=160;if(bite===237)utf8_upper_boundary=159;utf8_bytes_needed=2;utf8_code_point=bite&15}else if(inRange(bite,240,244)){if(bite===240)utf8_lower_boundary=144;if(bite===244)utf8_upper_boundary=143;utf8_bytes_needed=3;utf8_code_point=bite&7}else{return decoderError(fatal)}return null}if(!inRange(bite,utf8_lower_boundary,utf8_upper_boundary)){utf8_code_point=utf8_bytes_needed=utf8_bytes_seen=0;utf8_lower_boundary=128;utf8_upper_boundary=191;stream.prepend(bite);return decoderError(fatal)}utf8_lower_boundary=128;utf8_upper_boundary=191;utf8_code_point=utf8_code_point<<6|bite&63;utf8_bytes_seen+=1;if(utf8_bytes_seen!==utf8_bytes_needed)return null;var code_point=utf8_code_point;utf8_code_point=utf8_bytes_needed=utf8_bytes_seen=0;return code_point}}function UTF8Encoder(options){var fatal=options.fatal;this.handler=function(stream,code_point){if(code_point===end_of_stream)return finished;if(isASCIICodePoint(code_point))return code_point;var count,offset;if(inRange(code_point,128,2047)){count=1;offset=192}else if(inRange(code_point,2048,65535)){count=2;offset=224}else if(inRange(code_point,65536,1114111)){count=3;offset=240}var bytes=[(code_point>>6*count)+offset];while(count>0){var temp=code_point>>6*(count-1);bytes.push(128|temp&63);count-=1}return bytes}}encoders["UTF-8"]=function(options){return new UTF8Encoder(options)};decoders["UTF-8"]=function(options){return new UTF8Decoder(options)};function SingleByteDecoder(index2,options){var fatal=options.fatal;this.handler=function(stream,bite){if(bite===end_of_stream)return finished;if(isASCIIByte(bite))return bite;var code_point=index2[bite-128];if(code_point===null)return decoderError(fatal);return code_point}}function SingleByteEncoder(index2,options){var fatal=options.fatal;this.handler=function(stream,code_point){if(code_point===end_of_stream)return finished;if(isASCIICodePoint(code_point))return code_point;var pointer=indexPointerFor(code_point,index2);if(pointer===null)encoderError(code_point);return pointer+128}}(function(){if(!("encoding-indexes"in global))return;encodings.forEach(function(category){if(category.heading!=="Legacy single-byte encodings")return;category.encodings.forEach(function(encoding){var name=encoding.name;var idx=index(name.toLowerCase());decoders[name]=function(options){return new SingleByteDecoder(idx,options)};encoders[name]=function(options){return new SingleByteEncoder(idx,options)}})})})();decoders["GBK"]=function(options){return new GB18030Decoder(options)};encoders["GBK"]=function(options){return new GB18030Encoder(options,true)};function GB18030Decoder(options){var fatal=options.fatal;var gb18030_first=0,gb18030_second=0,gb18030_third=0;this.handler=function(stream,bite){if(bite===end_of_stream&&gb18030_first===0&&gb18030_second===0&&gb18030_third===0){return finished}if(bite===end_of_stream&&(gb18030_first!==0||gb18030_second!==0||gb18030_third!==0)){gb18030_first=0;gb18030_second=0;gb18030_third=0;decoderError(fatal)}var code_point;if(gb18030_third!==0){code_point=null;if(inRange(bite,48,57)){code_point=indexGB18030RangesCodePointFor((((gb18030_first-129)*10+gb18030_second-48)*126+gb18030_third-129)*10+bite-48)}var buffer=[gb18030_second,gb18030_third,bite];gb18030_first=0;gb18030_second=0;gb18030_third=0;if(code_point===null){stream.prepend(buffer);return decoderError(fatal)}return code_point}if(gb18030_second!==0){if(inRange(bite,129,254)){gb18030_third=bite;return null}stream.prepend([gb18030_second,bite]);gb18030_first=0;gb18030_second=0;return decoderError(fatal)}if(gb18030_first!==0){if(inRange(bite,48,57)){gb18030_second=bite;return null}var lead=gb18030_first;var pointer=null;gb18030_first=0;var offset=bite<127?64:65;if(inRange(bite,64,126)||inRange(bite,128,254))pointer=(lead-129)*190+(bite-offset);code_point=pointer===null?null:indexCodePointFor(pointer,index("gb18030"));if(code_point===null&&isASCIIByte(bite))stream.prepend(bite);if(code_point===null)return decoderError(fatal);return code_point}if(isASCIIByte(bite))return bite;if(bite===128)return 8364;if(inRange(bite,129,254)){gb18030_first=bite;return null}return decoderError(fatal)}}function GB18030Encoder(options,gbk_flag){var fatal=options.fatal;this.handler=function(stream,code_point){if(code_point===end_of_stream)return finished;if(isASCIICodePoint(code_point))return code_point;if(code_point===58853)return encoderError(code_point);if(gbk_flag&&code_point===8364)return 128;var pointer=indexPointerFor(code_point,index("gb18030"));if(pointer!==null){var lead=floor(pointer/190)+129;var trail=pointer%190;var offset=trail<63?64:65;return[lead,trail+offset]}if(gbk_flag)return encoderError(code_point);pointer=indexGB18030RangesPointerFor(code_point);var byte1=floor(pointer/10/126/10);pointer=pointer-byte1*10*126*10;var byte2=floor(pointer/10/126);pointer=pointer-byte2*10*126;var byte3=floor(pointer/10);var byte4=pointer-byte3*10;return[byte1+129,byte2+48,byte3+129,byte4+48]}}encoders["gb18030"]=function(options){return new GB18030Encoder(options)};decoders["gb18030"]=function(options){return new GB18030Decoder(options)};function Big5Decoder(options){var fatal=options.fatal;var Big5_lead=0;this.handler=function(stream,bite){if(bite===end_of_stream&&Big5_lead!==0){Big5_lead=0;return decoderError(fatal)}if(bite===end_of_stream&&Big5_lead===0)return finished;if(Big5_lead!==0){var lead=Big5_lead;var pointer=null;Big5_lead=0;var offset=bite<127?64:98;if(inRange(bite,64,126)||inRange(bite,161,254))pointer=(lead-129)*157+(bite-offset);switch(pointer){case 1133:return[202,772];case 1135:return[202,780];case 1164:return[234,772];case 1166:return[234,780]}var code_point=pointer===null?null:indexCodePointFor(pointer,index("big5"));if(code_point===null&&isASCIIByte(bite))stream.prepend(bite);if(code_point===null)return decoderError(fatal);return code_point}if(isASCIIByte(bite))return bite;if(inRange(bite,129,254)){Big5_lead=bite;return null}return decoderError(fatal)}}function Big5Encoder(options){var fatal=options.fatal;this.handler=function(stream,code_point){if(code_point===end_of_stream)return finished;if(isASCIICodePoint(code_point))return code_point;var pointer=indexBig5PointerFor(code_point);if(pointer===null)return encoderError(code_point);var lead=floor(pointer/157)+129;if(lead<161)return encoderError(code_point);var trail=pointer%157;var offset=trail<63?64:98;return[lead,trail+offset]}}encoders["Big5"]=function(options){return new Big5Encoder(options)};decoders["Big5"]=function(options){return new Big5Decoder(options)};function EUCJPDecoder(options){var fatal=options.fatal;var eucjp_jis0212_flag=false,eucjp_lead=0;this.handler=function(stream,bite){if(bite===end_of_stream&&eucjp_lead!==0){eucjp_lead=0;return decoderError(fatal)}if(bite===end_of_stream&&eucjp_lead===0)return finished;if(eucjp_lead===142&&inRange(bite,161,223)){eucjp_lead=0;return 65377-161+bite}if(eucjp_lead===143&&inRange(bite,161,254)){eucjp_jis0212_flag=true;eucjp_lead=bite;return null}if(eucjp_lead!==0){var lead=eucjp_lead;eucjp_lead=0;var code_point=null;if(inRange(lead,161,254)&&inRange(bite,161,254)){code_point=indexCodePointFor((lead-161)*94+(bite-161),index(!eucjp_jis0212_flag?"jis0208":"jis0212"))}eucjp_jis0212_flag=false;if(!inRange(bite,161,254))stream.prepend(bite);if(code_point===null)return decoderError(fatal);return code_point}if(isASCIIByte(bite))return bite;if(bite===142||bite===143||inRange(bite,161,254)){eucjp_lead=bite;return null}return decoderError(fatal)}}function EUCJPEncoder(options){var fatal=options.fatal;this.handler=function(stream,code_point){if(code_point===end_of_stream)return finished;if(isASCIICodePoint(code_point))return code_point;if(code_point===165)return 92;if(code_point===8254)return 126;if(inRange(code_point,65377,65439))return[142,code_point-65377+161];if(code_point===8722)code_point=65293;var pointer=indexPointerFor(code_point,index("jis0208"));if(pointer===null)return encoderError(code_point);var lead=floor(pointer/94)+161;var trail=pointer%94+161;return[lead,trail]}}encoders["EUC-JP"]=function(options){return new EUCJPEncoder(options)};decoders["EUC-JP"]=function(options){return new EUCJPDecoder(options)};function ISO2022JPDecoder(options){var fatal=options.fatal;var states={ASCII:0,Roman:1,Katakana:2,LeadByte:3,TrailByte:4,EscapeStart:5,Escape:6};var{ASCII:iso2022jp_decoder_state,ASCII:iso2022jp_decoder_output_state}=states,iso2022jp_lead=0,iso2022jp_output_flag=false;this.handler=function(stream,bite){switch(iso2022jp_decoder_state){default:case states.ASCII:if(bite===27){iso2022jp_decoder_state=states.EscapeStart;return null}if(inRange(bite,0,127)&&bite!==14&&bite!==15&&bite!==27){iso2022jp_output_flag=false;return bite}if(bite===end_of_stream){return finished}iso2022jp_output_flag=false;return decoderError(fatal);case states.Roman:if(bite===27){iso2022jp_decoder_state=states.EscapeStart;return null}if(bite===92){iso2022jp_output_flag=false;return 165}if(bite===126){iso2022jp_output_flag=false;return 8254}if(inRange(bite,0,127)&&bite!==14&&bite!==15&&bite!==27&&bite!==92&&bite!==126){iso2022jp_output_flag=false;return bite}if(bite===end_of_stream){return finished}iso2022jp_output_flag=false;return decoderError(fatal);case states.Katakana:if(bite===27){iso2022jp_decoder_state=states.EscapeStart;return null}if(inRange(bite,33,95)){iso2022jp_output_flag=false;return 65377-33+bite}if(bite===end_of_stream){return finished}iso2022jp_output_flag=false;return decoderError(fatal);case states.LeadByte:if(bite===27){iso2022jp_decoder_state=states.EscapeStart;return null}if(inRange(bite,33,126)){iso2022jp_output_flag=false;iso2022jp_lead=bite;iso2022jp_decoder_state=states.TrailByte;return null}if(bite===end_of_stream){return finished}iso2022jp_output_flag=false;return decoderError(fatal);case states.TrailByte:if(bite===27){iso2022jp_decoder_state=states.EscapeStart;return decoderError(fatal)}if(inRange(bite,33,126)){iso2022jp_decoder_state=states.LeadByte;var pointer=(iso2022jp_lead-33)*94+bite-33;var code_point=indexCodePointFor(pointer,index("jis0208"));if(code_point===null)return decoderError(fatal);return code_point}if(bite===end_of_stream){iso2022jp_decoder_state=states.LeadByte;stream.prepend(bite);return decoderError(fatal)}iso2022jp_decoder_state=states.LeadByte;return decoderError(fatal);case states.EscapeStart:if(bite===36||bite===40){iso2022jp_lead=bite;iso2022jp_decoder_state=states.Escape;return null}stream.prepend(bite);iso2022jp_output_flag=false;iso2022jp_decoder_state=iso2022jp_decoder_output_state;return decoderError(fatal);case states.Escape:var lead=iso2022jp_lead;iso2022jp_lead=0;var state=null;if(lead===40&&bite===66)state=states.ASCII;if(lead===40&&bite===74)state=states.Roman;if(lead===40&&bite===73)state=states.Katakana;if(lead===36&&(bite===64||bite===66))state=states.LeadByte;if(state!==null){iso2022jp_decoder_state=iso2022jp_decoder_state=state;var output_flag=iso2022jp_output_flag;iso2022jp_output_flag=true;return!output_flag?null:decoderError(fatal)}stream.prepend([lead,bite]);iso2022jp_output_flag=false;iso2022jp_decoder_state=iso2022jp_decoder_output_state;return decoderError(fatal)}}}function ISO2022JPEncoder(options){var fatal=options.fatal;var states={ASCII:0,Roman:1,jis0208:2};var iso2022jp_state=states.ASCII;this.handler=function(stream,code_point){if(code_point===end_of_stream&&iso2022jp_state!==states.ASCII){stream.prepend(code_point);iso2022jp_state=states.ASCII;return[27,40,66]}if(code_point===end_of_stream&&iso2022jp_state===states.ASCII)return finished;if((iso2022jp_state===states.ASCII||iso2022jp_state===states.Roman)&&(code_point===14||code_point===15||code_point===27)){return encoderError(65533)}if(iso2022jp_state===states.ASCII&&isASCIICodePoint(code_point))return code_point;if(iso2022jp_state===states.Roman&&(isASCIICodePoint(code_point)&&code_point!==92&&code_point!==126||(code_point==165||code_point==8254))){if(isASCIICodePoint(code_point))return code_point;if(code_point===165)return 92;if(code_point===8254)return 126}if(isASCIICodePoint(code_point)&&iso2022jp_state!==states.ASCII){stream.prepend(code_point);iso2022jp_state=states.ASCII;return[27,40,66]}if((code_point===165||code_point===8254)&&iso2022jp_state!==states.Roman){stream.prepend(code_point);iso2022jp_state=states.Roman;return[27,40,74]}if(code_point===8722)code_point=65293;var pointer=indexPointerFor(code_point,index("jis0208"));if(pointer===null)return encoderError(code_point);if(iso2022jp_state!==states.jis0208){stream.prepend(code_point);iso2022jp_state=states.jis0208;return[27,36,66]}var lead=floor(pointer/94)+33;var trail=pointer%94+33;return[lead,trail]}}encoders["ISO-2022-JP"]=function(options){return new ISO2022JPEncoder(options)};decoders["ISO-2022-JP"]=function(options){return new ISO2022JPDecoder(options)};function ShiftJISDecoder(options){var fatal=options.fatal;var Shift_JIS_lead=0;this.handler=function(stream,bite){if(bite===end_of_stream&&Shift_JIS_lead!==0){Shift_JIS_lead=0;return decoderError(fatal)}if(bite===end_of_stream&&Shift_JIS_lead===0)return finished;if(Shift_JIS_lead!==0){var lead=Shift_JIS_lead;var pointer=null;Shift_JIS_lead=0;var offset=bite<127?64:65;var lead_offset=lead<160?129:193;if(inRange(bite,64,126)||inRange(bite,128,252))pointer=(lead-lead_offset)*188+bite-offset;if(inRange(pointer,8836,10715))return 57344-8836+pointer;var code_point=pointer===null?null:indexCodePointFor(pointer,index("jis0208"));if(code_point===null&&isASCIIByte(bite))stream.prepend(bite);if(code_point===null)return decoderError(fatal);return code_point}if(isASCIIByte(bite)||bite===128)return bite;if(inRange(bite,161,223))return 65377-161+bite;if(inRange(bite,129,159)||inRange(bite,224,252)){Shift_JIS_lead=bite;return null}return decoderError(fatal)}}function ShiftJISEncoder(options){var fatal=options.fatal;this.handler=function(stream,code_point){if(code_point===end_of_stream)return finished;if(isASCIICodePoint(code_point)||code_point===128)return code_point;if(code_point===165)return 92;if(code_point===8254)return 126;if(inRange(code_point,65377,65439))return code_point-65377+161;if(code_point===8722)code_point=65293;var pointer=indexShiftJISPointerFor(code_point);if(pointer===null)return encoderError(code_point);var lead=floor(pointer/188);var lead_offset=lead<31?129:193;var trail=pointer%188;var offset=trail<63?64:65;return[lead+lead_offset,trail+offset]}}encoders["Shift_JIS"]=function(options){return new ShiftJISEncoder(options)};decoders["Shift_JIS"]=function(options){return new ShiftJISDecoder(options)};function EUCKRDecoder(options){var fatal=options.fatal;var euckr_lead=0;this.handler=function(stream,bite){if(bite===end_of_stream&&euckr_lead!==0){euckr_lead=0;return decoderError(fatal)}if(bite===end_of_stream&&euckr_lead===0)return finished;if(euckr_lead!==0){var lead=euckr_lead;var pointer=null;euckr_lead=0;if(inRange(bite,65,254))pointer=(lead-129)*190+(bite-65);var code_point=pointer===null?null:indexCodePointFor(pointer,index("euc-kr"));if(pointer===null&&isASCIIByte(bite))stream.prepend(bite);if(code_point===null)return decoderError(fatal);return code_point}if(isASCIIByte(bite))return bite;if(inRange(bite,129,254)){euckr_lead=bite;return null}return decoderError(fatal)}}function EUCKREncoder(options){var fatal=options.fatal;this.handler=function(stream,code_point){if(code_point===end_of_stream)return finished;if(isASCIICodePoint(code_point))return code_point;var pointer=indexPointerFor(code_point,index("euc-kr"));if(pointer===null)return encoderError(code_point);var lead=floor(pointer/190)+129;var trail=pointer%190+65;return[lead,trail]}}encoders["EUC-KR"]=function(options){return new EUCKREncoder(options)};decoders["EUC-KR"]=function(options){return new EUCKRDecoder(options)};function convertCodeUnitToBytes(code_unit,utf16be){var byte1=code_unit>>8;var byte2=code_unit&255;if(utf16be)return[byte1,byte2];return[byte2,byte1]}function UTF16Decoder(utf16_be,options){var fatal=options.fatal;var utf16_lead_byte=null,utf16_lead_surrogate=null;this.handler=function(stream,bite){if(bite===end_of_stream&&(utf16_lead_byte!==null||utf16_lead_surrogate!==null)){return decoderError(fatal)}if(bite===end_of_stream&&utf16_lead_byte===null&&utf16_lead_surrogate===null){return finished}if(utf16_lead_byte===null){utf16_lead_byte=bite;return null}var code_unit;if(utf16_be){code_unit=(utf16_lead_byte<<8)+bite}else{code_unit=(bite<<8)+utf16_lead_byte}utf16_lead_byte=null;if(utf16_lead_surrogate!==null){var lead_surrogate=utf16_lead_surrogate;utf16_lead_surrogate=null;if(inRange(code_unit,56320,57343)){return 65536+(lead_surrogate-55296)*1024+(code_unit-56320)}stream.prepend(convertCodeUnitToBytes(code_unit,utf16_be));return decoderError(fatal)}if(inRange(code_unit,55296,56319)){utf16_lead_surrogate=code_unit;return null}if(inRange(code_unit,56320,57343))return decoderError(fatal);return code_unit}}function UTF16Encoder(utf16_be,options){var fatal=options.fatal;this.handler=function(stream,code_point){if(code_point===end_of_stream)return finished;if(inRange(code_point,0,65535))return convertCodeUnitToBytes(code_point,utf16_be);var lead=convertCodeUnitToBytes((code_point-65536>>10)+55296,utf16_be);var trail=convertCodeUnitToBytes((code_point-65536&1023)+56320,utf16_be);return lead.concat(trail)}}encoders["UTF-16BE"]=function(options){return new UTF16Encoder(true,options)};decoders["UTF-16BE"]=function(options){return new UTF16Decoder(true,options)};encoders["UTF-16LE"]=function(options){return new UTF16Encoder(false,options)};decoders["UTF-16LE"]=function(options){return new UTF16Decoder(false,options)};function XUserDefinedDecoder(options){var fatal=options.fatal;this.handler=function(stream,bite){if(bite===end_of_stream)return finished;if(isASCIIByte(bite))return bite;return 63360+bite-128}}function XUserDefinedEncoder(options){var fatal=options.fatal;this.handler=function(stream,code_point){if(code_point===end_of_stream)return finished;if(isASCIICodePoint(code_point))return code_point;if(inRange(code_point,63360,63487))return code_point-63360+128;return encoderError(code_point)}}encoders["x-user-defined"]=function(options){return new XUserDefinedEncoder(options)};decoders["x-user-defined"]=function(options){return new XUserDefinedDecoder(options)};if(!global["TextEncoder"])global["TextEncoder"]=TextEncoder;if(!global["TextDecoder"])global["TextDecoder"]=TextDecoder;if(typeof module!=="undefined"&&module.exports){module.exports={TextEncoder:global["TextEncoder"],TextDecoder:global["TextDecoder"],EncodingIndexes:global["encoding-indexes"]}}})(exports||{})});var require_text_encoding=__commonJS((exports,module)=>{var encoding=require_encoding();module.exports={TextEncoder:encoding.TextEncoder,TextDecoder:encoding.TextDecoder}});var require_jsbi_umd=__commonJS((exports,module)=>{(function(e,t){typeof exports=="object"&&typeof module!="undefined"?module.exports=t():typeof define=="function"&&define.amd?define(t):(e=e||self,e.JSBI=t())})(exports,function(){var{imul:e,clz32:t}=Math;function i(t2,i2){(i2==null||i2>t2.length)&&(i2=t2.length);for(var _2=0,o2=Array(i2);_2<i2;_2++)o2[_2]=t2[_2];return o2}function _(e2){if(Array.isArray(e2))return e2}function n(t2){if(t2===undefined)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t2}function o(i2,t2,_2){return t2=r(t2),v(i2,b()?Reflect.construct(t2,_2||[],r(i2).constructor):t2.apply(i2,_2))}function l(e2,t2){if(!(e2 instanceof t2))throw new TypeError("Cannot call a class as a function")}function g(i2,t2,e2){if(b())return Reflect.construct.apply(null,arguments);var _2=[null];_2.push.apply(_2,t2);var n2=new(i2.bind.apply(i2,_2));return e2&&y(n2,e2.prototype),n2}function a(i2,e2){for(var _2,n2=0;n2<e2.length;n2++)_2=e2[n2],_2.enumerable=_2.enumerable||false,_2.configurable=true,"value"in _2&&(_2.writable=true),Object.defineProperty(i2,D(_2.key),_2)}function s(i2,e2,_2){return e2&&a(i2.prototype,e2),_2&&a(i2,_2),Object.defineProperty(i2,"prototype",{writable:false}),i2}function u(i2,_2){var e2=typeof Symbol!="undefined"&&i2[Symbol.iterator]||i2["@@iterator"];if(!e2){if(Array.isArray(i2)||(e2=B(i2))||_2&&i2&&typeof i2.length=="number"){e2&&(i2=e2);var l2=0,g2=function(){};return{s:g2,n:function(){return l2>=i2.length?{done:true}:{done:false,value:i2[l2++]}},e:function(e3){throw e3},f:g2}}throw new TypeError(`Invalid attempt to iterate non-iterable instance.
+In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var s2,d2=true,h2=false;return{s:function(){e2=e2.call(i2)},n:function(){var t2=e2.next();return d2=t2.done,t2},e:function(e3){h2=true,s2=e3},f:function(){try{d2||e2.return==null||e2.return()}finally{if(h2)throw s2}}}}function r(e2){return r=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(e3){return e3.__proto__||Object.getPrototypeOf(e3)},r(e2)}function d(i2,t2){if(typeof t2!="function"&&t2!==null)throw new TypeError("Super expression must either be null or a function");i2.prototype=Object.create(t2&&t2.prototype,{constructor:{value:i2,writable:true,configurable:true}}),Object.defineProperty(i2,"prototype",{writable:false}),t2&&y(i2,t2)}function h(e2){try{return Function.toString.call(e2).indexOf("[native code]")!==-1}catch(t2){return typeof e2=="function"}}function b(){try{var e2=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e3){}return(b=function(){return!!e2})()}function m(_2,g2){var l2=_2==null?null:typeof Symbol!="undefined"&&_2[Symbol.iterator]||_2["@@iterator"];if(l2!=null){var s2,d2,r2,h2,b2=[],a2=true,m2=false;try{if(r2=(l2=l2.call(_2)).next,g2===0){if(Object(l2)!==l2)return;a2=false}else for(;!(a2=(s2=r2.call(l2)).done)&&(b2.push(s2.value),b2.length!==g2);a2=true);}catch(e2){m2=true,d2=e2}finally{try{if(!a2&&l2.return!=null&&(h2=l2.return(),Object(h2)!==h2))return}finally{if(m2)throw d2}}return b2}}function c(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
+In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function v(i2,t2){if(t2&&(typeof t2=="object"||typeof t2=="function"))return t2;if(t2!==undefined)throw new TypeError("Derived constructors may only return object or undefined");return n(i2)}function y(i2,t2){return y=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(i3,t3){return i3.__proto__=t3,i3},y(i2,t2)}function f(t2,i2){return _(t2)||m(t2,i2)||B(t2,i2)||c()}function k(_2,t2){if(typeof _2!="object"||!_2)return _2;var n2=_2[Symbol.toPrimitive];if(n2!==undefined){var e2=n2.call(_2,t2||"default");if(typeof e2!="object")return e2;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t2==="string"?String:Number)(_2)}function D(e2){var t2=k(e2,"string");return typeof t2=="symbol"?t2:t2+""}function p(e2){"@babel/helpers - typeof";return p=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e3){return typeof e3}:function(e3){return e3&&typeof Symbol=="function"&&e3.constructor===Symbol&&e3!==Symbol.prototype?"symbol":typeof e3},p(e2)}function B(e2,_2){if(e2){if(typeof e2=="string")return i(e2,_2);var n2={}.toString.call(e2).slice(8,-1);return n2==="Object"&&e2.constructor&&(n2=e2.constructor.name),n2==="Map"||n2==="Set"?Array.from(e2):n2==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n2)?i(e2,_2):undefined}}function S(e2){var i2=typeof Map=="function"?new Map:undefined;return S=function(e3){function t2(){return g(e3,arguments,r(this).constructor)}if(e3===null||!h(e3))return e3;if(typeof e3!="function")throw new TypeError("Super expression must either be null or a function");if(i2!==undefined){if(i2.has(e3))return i2.get(e3);i2.set(e3,t2)}return t2.prototype=Object.create(e3.prototype,{constructor:{value:t2,enumerable:false,writable:true,configurable:true}}),y(t2,e3)},S(e2)}var C=function(e2){var{abs:t2,max:i2,floor:_2}=Math;function g2(e3,t3){var i3;if(l(this,g2),i3=o(this,g2,[e3]),i3.sign=t3,Object.setPrototypeOf(i3,g2.prototype),e3>g2.__kMaxLength)throw new RangeError("Maximum BigInt size exceeded");return i3}return d(g2,e2),s(g2,[{key:"toDebugString",value:function e3(){var t3,i3=["BigInt["],_3=u(this);try{for(_3.s();!(t3=_3.n()).done;){var n2=t3.value;i3.push((n2?(n2>>>0).toString(16):n2)+", ")}}catch(e4){_3.e(e4)}finally{_3.f()}return i3.push("]"),i3.join("")}},{key:"toString",value:function e3(){var t3=0<arguments.length&&arguments[0]!==undefined?arguments[0]:10;if(2>t3||36<t3)throw new RangeError("toString() radix argument must be between 2 and 36");return this.length===0?"0":(t3&t3-1)==0?g2.__toStringBasePowerOfTwo(this,t3):g2.__toStringGeneric(this,t3,false)}},{key:"valueOf",value:function e3(){throw new Error("Convert JSBI instances to native numbers using `toNumber`.")}},{key:"__copy",value:function e3(){for(var t3=new g2(this.length,this.sign),_3=0;_3<this.length;_3++)t3[_3]=this[_3];return t3}},{key:"__trim",value:function e3(){for(var t3=this.length,i3=this[t3-1];i3===0;)t3--,i3=this[t3-1],this.pop();return t3===0&&(this.sign=false),this}},{key:"__initializeDigits",value:function e3(){for(var t3=0;t3<this.length;t3++)this[t3]=0}},{key:"__clzmsd",value:function e3(){return g2.__clz30(this.__digit(this.length-1))}},{key:"__inplaceMultiplyAdd",value:function n2(e3,t3,_3){_3>this.length&&(_3=this.length);for(var o2=32767&e3,l2=e3>>>15,a2=0,s2=t3,u2=0;u2<_3;u2++){var r2=this.__digit(u2),h2=32767&r2,b2=r2>>>15,m2=g2.__imul(h2,o2),c2=g2.__imul(h2,l2),v2=g2.__imul(b2,o2),y2=g2.__imul(b2,l2),f2=s2+m2+a2;a2=f2>>>30,f2&=1073741823,f2+=((32767&c2)<<15)+((32767&v2)<<15),a2+=f2>>>30,s2=y2+(c2>>>15)+(v2>>>15),this.__setDigit(u2,1073741823&f2)}if(a2!==0||s2!==0)throw new Error("implementation bug")}},{key:"__inplaceAdd",value:function n2(e3,t3,_3){for(var o2,l2=0,g3=0;g3<_3;g3++)o2=this.__halfDigit(t3+g3)+e3.__halfDigit(g3)+l2,l2=o2>>>15,this.__setHalfDigit(t3+g3,32767&o2);return l2}},{key:"__inplaceSub",value:function n2(e3,t3,_3){var o2=_3-1>>>1,l2=0;if(1&t3){t3>>=1;for(var g3=this.__digit(t3),a2=32767&g3,s2=0;s2<o2;s2++){var u2=e3.__digit(s2),r2=(g3>>>15)-(32767&u2)-l2;l2=1&r2>>>15,this.__setDigit(t3+s2,(32767&r2)<<15|32767&a2),g3=this.__digit(t3+s2+1),a2=(32767&g3)-(u2>>>15)-l2,l2=1&a2>>>15}var d2=e3.__digit(s2),h2=(g3>>>15)-(32767&d2)-l2;l2=1&h2>>>15,this.__setDigit(t3+s2,(32767&h2)<<15|32767&a2);var b2=d2>>>15;if(t3+s2+1>=this.length)throw new RangeError("out of bounds");(1&_3)==0&&(g3=this.__digit(t3+s2+1),a2=(32767&g3)-b2-l2,l2=1&a2>>>15,this.__setDigit(t3+e3.length,1073709056&g3|32767&a2))}else{t3>>=1;for(var m2=0;m2<e3.length-1;m2++){var c2=this.__digit(t3+m2),v2=e3.__digit(m2),y2=(32767&c2)-(32767&v2)-l2;l2=1&y2>>>15;var f2=(c2>>>15)-(v2>>>15)-l2;l2=1&f2>>>15,this.__setDigit(t3+m2,(32767&f2)<<15|32767&y2)}var k2=this.__digit(t3+m2),D2=e3.__digit(m2),p2=(32767&k2)-(32767&D2)-l2;l2=1&p2>>>15;var B2=0;(1&_3)==0&&(B2=(k2>>>15)-(D2>>>15)-l2,l2=1&B2>>>15),this.__setDigit(t3+m2,(32767&B2)<<15|32767&p2)}return l2}},{key:"__inplaceRightShift",value:function t3(e3){if(e3!==0){for(var _3,n2=this.__digit(0)>>>e3,o2=this.length-1,l2=0;l2<o2;l2++)_3=this.__digit(l2+1),this.__setDigit(l2,1073741823&_3<<30-e3|n2),n2=_3>>>e3;this.__setDigit(o2,n2)}}},{key:"__digit",value:function t3(e3){return this[e3]}},{key:"__unsignedDigit",value:function t3(e3){return this[e3]>>>0}},{key:"__setDigit",value:function i3(e3,t3){this[e3]=0|t3}},{key:"__setDigitGrow",value:function i3(e3,t3){this[e3]=0|t3}},{key:"__halfDigitLength",value:function e3(){var t3=this.length;return 32767>=this.__unsignedDigit(t3-1)?2*t3-1:2*t3}},{key:"__halfDigit",value:function t3(e3){return 32767&this[e3>>>1]>>>15*(1&e3)}},{key:"__setHalfDigit",value:function i3(e3,t3){var _3=e3>>>1,n2=this.__digit(_3),o2=1&e3?32767&n2|t3<<15:1073709056&n2|32767&t3;this.__setDigit(_3,o2)}}],[{key:"BigInt",value:function t3(e3){var i3=Number.isFinite;if(typeof e3=="number"){if(e3===0)return g2.__zero();if(g2.__isOneDigitInt(e3))return 0>e3?g2.__oneDigit(-e3,true):g2.__oneDigit(e3,false);if(!i3(e3)||_2(e3)!==e3)throw new RangeError("The number "+e3+" cannot be converted to BigInt because it is not an integer");return g2.__fromDouble(e3)}if(typeof e3=="string"){var n2=g2.__fromString(e3);if(n2===null)throw new SyntaxError("Cannot convert "+e3+" to a BigInt");return n2}if(typeof e3=="boolean")return e3===true?g2.__oneDigit(1,false):g2.__zero();if(p(e3)==="object"){if(e3.constructor===g2)return e3;var o2=g2.__toPrimitive(e3);return g2.BigInt(o2)}throw new TypeError("Cannot convert "+e3+" to a BigInt")}},{key:"toNumber",value:function t3(e3){var i3=e3.length;if(i3===0)return 0;if(i3===1){var _3=e3.__unsignedDigit(0);return e3.sign?-_3:_3}var n2=e3.__digit(i3-1),o2=g2.__clz30(n2),l2=30*i3-o2;if(1024<l2)return e3.sign?-Infinity:1/0;var a2=l2-1,s2=n2,u2=i3-1,r2=o2+3,d2=r2===32?0:s2<<r2;d2>>>=12;var h2=r2-12,b2=12<=r2?0:s2<<20+r2,m2=20+r2;for(0<h2&&0<u2&&(u2--,s2=e3.__digit(u2),d2|=s2>>>30-h2,b2=s2<<h2+2,m2=h2+2);0<m2&&0<u2;)u2--,s2=e3.__digit(u2),b2|=30<=m2?s2<<m2-30:s2>>>30-m2,m2-=30;var c2=g2.__decideRounding(e3,m2,u2,s2);if((c2===1||c2===0&&(1&b2)==1)&&(b2=b2+1>>>0,b2===0&&(d2++,d2>>>20!=0&&(d2=0,a2++,1023<a2))))return e3.sign?-Infinity:1/0;var v2=e3.sign?-2147483648:0;return a2=a2+1023<<20,g2.__kBitConversionInts[g2.__kBitConversionIntHigh]=v2|a2|d2,g2.__kBitConversionInts[g2.__kBitConversionIntLow]=b2,g2.__kBitConversionDouble[0]}},{key:"unaryMinus",value:function t3(e3){if(e3.length===0)return e3;var i3=e3.__copy();return i3.sign=!e3.sign,i3}},{key:"bitwiseNot",value:function t3(e3){return e3.sign?g2.__absoluteSubOne(e3).__trim():g2.__absoluteAddOne(e3,true)}},{key:"exponentiate",value:function i3(e3,t3){if(t3.sign)throw new RangeError("Exponent must be positive");if(t3.length===0)return g2.__oneDigit(1,false);if(e3.length===0)return e3;if(e3.length===1&&e3.__digit(0)===1)return e3.sign&&(1&t3.__digit(0))==0?g2.unaryMinus(e3):e3;if(1<t3.length)throw new RangeError("BigInt too big");var _3=t3.__unsignedDigit(0);if(_3===1)return e3;if(_3>=g2.__kMaxLengthBits)throw new RangeError("BigInt too big");if(e3.length===1&&e3.__digit(0)===2){var n2=1+(0|_3/30),o2=e3.sign&&(1&_3)!=0,l2=new g2(n2,o2);l2.__initializeDigits();var a2=1<<_3%30;return l2.__setDigit(n2-1,a2),l2}var s2=null,u2=e3;for((1&_3)!=0&&(s2=e3),_3>>=1;_3!==0;_3>>=1)u2=g2.multiply(u2,u2),(1&_3)!=0&&(s2===null?s2=u2:s2=g2.multiply(s2,u2));return s2}},{key:"multiply",value:function _3(e3,t3){if(e3.length===0)return e3;if(t3.length===0)return t3;var n2=e3.length+t3.length;30<=e3.__clzmsd()+t3.__clzmsd()&&n2--;var o2=new g2(n2,e3.sign!==t3.sign);o2.__initializeDigits();for(var l2=0;l2<e3.length;l2++)g2.__multiplyAccumulate(t3,e3.__digit(l2),o2,l2);return o2.__trim()}},{key:"divide",value:function i3(e3,t3){if(t3.length===0)throw new RangeError("Division by zero");if(0>g2.__absoluteCompare(e3,t3))return g2.__zero();var _3,n2=e3.sign!==t3.sign,o2=t3.__unsignedDigit(0);if(t3.length===1&&32767>=o2){if(o2===1)return n2===e3.sign?e3:g2.unaryMinus(e3);_3=g2.__absoluteDivSmall(e3,o2,null)}else _3=g2.__absoluteDivLarge(e3,t3,true,false);return _3.sign=n2,_3.__trim()}},{key:"remainder",value:function i3(e3,t3){if(t3.length===0)throw new RangeError("Division by zero");if(0>g2.__absoluteCompare(e3,t3))return e3;var _3=t3.__unsignedDigit(0);if(t3.length===1&&32767>=_3){if(_3===1)return g2.__zero();var n2=g2.__absoluteModSmall(e3,_3);return n2===0?g2.__zero():g2.__oneDigit(n2,e3.sign)}var i4=g2.__absoluteDivLarge(e3,t3,false,true);return i4.sign=e3.sign,i4.__trim()}},{key:"add",value:function i3(e3,t3){var _3=e3.sign;return _3===t3.sign?g2.__absoluteAdd(e3,t3,_3):0<=g2.__absoluteCompare(e3,t3)?g2.__absoluteSub(e3,t3,_3):g2.__absoluteSub(t3,e3,!_3)}},{key:"subtract",value:function i3(e3,t3){var _3=e3.sign;return _3===t3.sign?0<=g2.__absoluteCompare(e3,t3)?g2.__absoluteSub(e3,t3,_3):g2.__absoluteSub(t3,e3,!_3):g2.__absoluteAdd(e3,t3,_3)}},{key:"leftShift",value:function i3(e3,t3){return t3.length===0||e3.length===0?e3:t3.sign?g2.__rightShiftByAbsolute(e3,t3):g2.__leftShiftByAbsolute(e3,t3)}},{key:"signedRightShift",value:function i3(e3,t3){return t3.length===0||e3.length===0?e3:t3.sign?g2.__leftShiftByAbsolute(e3,t3):g2.__rightShiftByAbsolute(e3,t3)}},{key:"unsignedRightShift",value:function e3(){throw new TypeError("BigInts have no unsigned right shift; use >> instead")}},{key:"lessThan",value:function i3(e3,t3){return 0>g2.__compareToBigInt(e3,t3)}},{key:"lessThanOrEqual",value:function i3(e3,t3){return 0>=g2.__compareToBigInt(e3,t3)}},{key:"greaterThan",value:function i3(e3,t3){return 0<g2.__compareToBigInt(e3,t3)}},{key:"greaterThanOrEqual",value:function i3(e3,t3){return 0<=g2.__compareToBigInt(e3,t3)}},{key:"equal",value:function _3(e3,t3){if(e3.sign!==t3.sign)return false;if(e3.length!==t3.length)return false;for(var n2=0;n2<e3.length;n2++)if(e3.__digit(n2)!==t3.__digit(n2))return false;return true}},{key:"notEqual",value:function i3(e3,t3){return!g2.equal(e3,t3)}},{key:"bitwiseAnd",value:function _3(e3,t3){if(!e3.sign&&!t3.sign)return g2.__absoluteAnd(e3,t3).__trim();if(e3.sign&&t3.sign){var n2=i2(e3.length,t3.length)+1,o2=g2.__absoluteSubOne(e3,n2),l2=g2.__absoluteSubOne(t3);return o2=g2.__absoluteOr(o2,l2,o2),g2.__absoluteAddOne(o2,true,o2).__trim()}if(e3.sign){var a2=[t3,e3];e3=a2[0],t3=a2[1]}return g2.__absoluteAndNot(e3,g2.__absoluteSubOne(t3)).__trim()}},{key:"bitwiseXor",value:function _3(e3,t3){if(!e3.sign&&!t3.sign)return g2.__absoluteXor(e3,t3).__trim();if(e3.sign&&t3.sign){var n2=i2(e3.length,t3.length),o2=g2.__absoluteSubOne(e3,n2),l2=g2.__absoluteSubOne(t3);return g2.__absoluteXor(o2,l2,o2).__trim()}var a2=i2(e3.length,t3.length)+1;if(e3.sign){var s2=[t3,e3];e3=s2[0],t3=s2[1]}var u2=g2.__absoluteSubOne(t3,a2);return u2=g2.__absoluteXor(u2,e3,u2),g2.__absoluteAddOne(u2,true,u2).__trim()}},{key:"bitwiseOr",value:function _3(e3,t3){var n2=i2(e3.length,t3.length);if(!e3.sign&&!t3.sign)return g2.__absoluteOr(e3,t3).__trim();if(e3.sign&&t3.sign){var o2=g2.__absoluteSubOne(e3,n2),l2=g2.__absoluteSubOne(t3);return o2=g2.__absoluteAnd(o2,l2,o2),g2.__absoluteAddOne(o2,true,o2).__trim()}if(e3.sign){var a2=[t3,e3];e3=a2[0],t3=a2[1]}var s2=g2.__absoluteSubOne(t3,n2);return s2=g2.__absoluteAndNot(s2,e3,s2),g2.__absoluteAddOne(s2,true,s2).__trim()}},{key:"asIntN",value:function o2(e3,t3){if(t3.length===0)return t3;if(e3=_2(e3),0>e3)throw new RangeError("Invalid value: not (convertible to) a safe integer");if(e3===0)return g2.__zero();if(e3>=g2.__kMaxLengthBits)return t3;var l2=0|(e3+29)/30;if(t3.length<l2)return t3;var a2=t3.__unsignedDigit(l2-1),s2=1<<(e3-1)%30;if(t3.length===l2&&a2<s2)return t3;var u2=(a2&s2)===s2;if(!u2)return g2.__truncateToNBits(e3,t3);if(!t3.sign)return g2.__truncateAndSubFromPowerOfTwo(e3,t3,true);if((a2&s2-1)==0){for(var r2=l2-2;0<=r2;r2--)if(t3.__digit(r2)!==0)return g2.__truncateAndSubFromPowerOfTwo(e3,t3,false);return t3.length===l2&&a2===s2?t3:g2.__truncateToNBits(e3,t3)}return g2.__truncateAndSubFromPowerOfTwo(e3,t3,false)}},{key:"asUintN",value:function i3(e3,t3){if(t3.length===0)return t3;if(e3=_2(e3),0>e3)throw new RangeError("Invalid value: not (convertible to) a safe integer");if(e3===0)return g2.__zero();if(t3.sign){if(e3>g2.__kMaxLengthBits)throw new RangeError("BigInt too big");return g2.__truncateAndSubFromPowerOfTwo(e3,t3,false)}if(e3>=g2.__kMaxLengthBits)return t3;var o2=0|(e3+29)/30;if(t3.length<o2)return t3;var l2=e3%30;if(t3.length==o2){if(l2===0)return t3;var a2=t3.__digit(o2-1);if(a2>>>l2==0)return t3}return g2.__truncateToNBits(e3,t3)}},{key:"ADD",value:function i3(e3,t3){if(e3=g2.__toPrimitive(e3),t3=g2.__toPrimitive(t3),typeof e3=="string")return typeof t3!="string"&&(t3=t3.toString()),e3+t3;if(typeof t3=="string")return e3.toString()+t3;if(e3=g2.__toNumeric(e3),t3=g2.__toNumeric(t3),g2.__isBigInt(e3)&&g2.__isBigInt(t3))return g2.add(e3,t3);if(typeof e3=="number"&&typeof t3=="number")return e3+t3;throw new TypeError("Cannot mix BigInt and other types, use explicit conversions")}},{key:"LT",value:function i3(e3,t3){return g2.__compare(e3,t3,0)}},{key:"LE",value:function i3(e3,t3){return g2.__compare(e3,t3,1)}},{key:"GT",value:function i3(e3,t3){return g2.__compare(e3,t3,2)}},{key:"GE",value:function i3(e3,t3){return g2.__compare(e3,t3,3)}},{key:"EQ",value:function i3(e3,t3){for(;;){if(g2.__isBigInt(e3))return g2.__isBigInt(t3)?g2.equal(e3,t3):g2.EQ(t3,e3);if(typeof e3=="number"){if(g2.__isBigInt(t3))return g2.__equalToNumber(t3,e3);if(p(t3)!=="object")return e3==t3;t3=g2.__toPrimitive(t3)}else if(typeof e3=="string"){if(g2.__isBigInt(t3))return e3=g2.__fromString(e3),e3!==null&&g2.equal(e3,t3);if(p(t3)!=="object")return e3==t3;t3=g2.__toPrimitive(t3)}else if(typeof e3=="boolean"){if(g2.__isBigInt(t3))return g2.__equalToNumber(t3,+e3);if(p(t3)!=="object")return e3==t3;t3=g2.__toPrimitive(t3)}else if(p(e3)==="symbol"){if(g2.__isBigInt(t3))return false;if(p(t3)!=="object")return e3==t3;t3=g2.__toPrimitive(t3)}else if(p(e3)==="object"){if(p(t3)==="object"&&t3.constructor!==g2)return e3==t3;e3=g2.__toPrimitive(e3)}else return e3==t3}}},{key:"NE",value:function i3(e3,t3){return!g2.EQ(e3,t3)}},{key:"DataViewGetBigInt64",value:function i3(e3,t3){var _3=!!(2<arguments.length&&arguments[2]!==undefined)&&arguments[2];return g2.asIntN(64,g2.DataViewGetBigUint64(e3,t3,_3))}},{key:"DataViewGetBigUint64",value:function i3(e3,t3){var _3=!!(2<arguments.length&&arguments[2]!==undefined)&&arguments[2],n2=_3?[4,0]:[0,4],o2=f(n2,2),a2=o2[0],s2=o2[1],l2=e3.getUint32(t3+a2,_3),u2=e3.getUint32(t3+s2,_3),r2=new g2(3,false);return r2.__setDigit(0,1073741823&u2),r2.__setDigit(1,(268435455&l2)<<2|u2>>>30),r2.__setDigit(2,l2>>>28),r2.__trim()}},{key:"DataViewSetBigInt64",value:function _3(e3,t3,i3){var n2=!!(3<arguments.length&&arguments[3]!==undefined)&&arguments[3];g2.DataViewSetBigUint64(e3,t3,i3,n2)}},{key:"DataViewSetBigUint64",value:function _3(e3,t3,i3){var n2=!!(3<arguments.length&&arguments[3]!==undefined)&&arguments[3];i3=g2.asUintN(64,i3);var o2=0,a2=0;if(0<i3.length&&(a2=i3.__digit(0),1<i3.length)){var s2=i3.__digit(1);a2|=s2<<30,o2=s2>>>2,2<i3.length&&(o2|=i3.__digit(2)<<28)}var u2=n2?[4,0]:[0,4],r2=f(u2,2),d2=r2[0],h2=r2[1];e3.setUint32(t3+d2,o2,n2),e3.setUint32(t3+h2,a2,n2)}},{key:"__zero",value:function e3(){return new g2(0,false)}},{key:"__oneDigit",value:function i3(e3,t3){var _3=new g2(1,t3);return _3.__setDigit(0,e3),_3}},{key:"__decideRounding",value:function n2(e3,t3,i3,_3){if(0<t3)return-1;var o2;if(0>t3)o2=-t3-1;else{if(i3===0)return-1;i3--,_3=e3.__digit(i3),o2=29}var l2=1<<o2;if((_3&l2)==0)return-1;if(l2-=1,(_3&l2)!=0)return 1;for(;0<i3;)if(i3--,e3.__digit(i3)!==0)return 1;return 0}},{key:"__fromDouble",value:function t3(e3){var i3=0>e3;g2.__kBitConversionDouble[0]=e3;var _3,n2=2047&g2.__kBitConversionInts[g2.__kBitConversionIntHigh]>>>20,o2=n2-1023,l2=(0|o2/30)+1,a2=new g2(l2,i3),s2=1048576,u2=1048575&g2.__kBitConversionInts[g2.__kBitConversionIntHigh]|s2,r2=g2.__kBitConversionInts[g2.__kBitConversionIntLow],d2=20,h2=o2%30,b2=0;if(h2<d2){var m2=d2-h2;b2=m2+32,_3=u2>>>m2,u2=u2<<32-m2|r2>>>m2,r2<<=32-m2}else if(h2===d2)b2=32,_3=u2,u2=r2,r2=0;else{var c2=h2-d2;b2=32-c2,_3=u2<<c2|r2>>>32-c2,u2=r2<<c2,r2=0}a2.__setDigit(l2-1,_3);for(var v2=l2-2;0<=v2;v2--)0<b2?(b2-=30,_3=u2>>>2,u2=u2<<30|r2>>>2,r2<<=30):_3=0,a2.__setDigit(v2,_3);return a2.__trim()}},{key:"__isWhitespace",value:function t3(e3){return!!(13>=e3&&9<=e3)||(159>=e3?e3==32:131071>=e3?e3==160||e3==5760:196607>=e3?(e3&=131071,10>=e3||e3==40||e3==41||e3==47||e3==95||e3==4096):e3==65279)}},{key:"__fromString",value:function t3(e3){var i3=1<arguments.length&&arguments[1]!==undefined?arguments[1]:0,_3=0,n2=e3.length,o2=0;if(o2===n2)return g2.__zero();for(var l2=e3.charCodeAt(o2);g2.__isWhitespace(l2);){if(++o2===n2)return g2.__zero();l2=e3.charCodeAt(o2)}if(l2===43){if(++o2===n2)return null;l2=e3.charCodeAt(o2),_3=1}else if(l2===45){if(++o2===n2)return null;l2=e3.charCodeAt(o2),_3=-1}if(i3===0){if(i3=10,l2===48){if(++o2===n2)return g2.__zero();if(l2=e3.charCodeAt(o2),l2===88||l2===120){if(i3=16,++o2===n2)return null;l2=e3.charCodeAt(o2)}else if(l2===79||l2===111){if(i3=8,++o2===n2)return null;l2=e3.charCodeAt(o2)}else if(l2===66||l2===98){if(i3=2,++o2===n2)return null;l2=e3.charCodeAt(o2)}}}else if(i3===16&&l2===48){if(++o2===n2)return g2.__zero();if(l2=e3.charCodeAt(o2),l2===88||l2===120){if(++o2===n2)return null;l2=e3.charCodeAt(o2)}}if(_3!==0&&i3!==10)return null;for(;l2===48;){if(++o2===n2)return g2.__zero();l2=e3.charCodeAt(o2)}var a2=n2-o2,s2=g2.__kMaxBitsPerChar[i3],u2=g2.__kBitsPerCharTableMultiplier-1;if(a2>1073741824/s2)return null;var r2=s2*a2+u2>>>g2.__kBitsPerCharTableShift,h2=0|(r2+29)/30,b2=new g2(h2,false),c2=10>i3?i3:10,v2=10<i3?i3-10:0;if((i3&i3-1)==0){s2>>=g2.__kBitsPerCharTableShift;var y2=[],f2=[],k2=false;do{for(var D2,p2=0,B2=0;;){if(D2=undefined,l2-48>>>0<c2)D2=l2-48;else if((32|l2)-97>>>0<v2)D2=(32|l2)-87;else{k2=true;break}if(B2+=s2,p2=p2<<s2|D2,++o2===n2){k2=true;break}if(l2=e3.charCodeAt(o2),30<B2+s2)break}y2.push(p2),f2.push(B2)}while(!k2);g2.__fillFromParts(b2,y2,f2)}else{b2.__initializeDigits();var S2=false,C2=0;do{for(var I,A=0,T=1;;){if(I=undefined,l2-48>>>0<c2)I=l2-48;else if((32|l2)-97>>>0<v2)I=(32|l2)-87;else{S2=true;break}var P=T*i3;if(1073741823<P)break;if(T=P,A=A*i3+I,C2++,++o2===n2){S2=true;break}l2=e3.charCodeAt(o2)}u2=30*g2.__kBitsPerCharTableMultiplier-1;var O=0|(s2*C2+u2>>>g2.__kBitsPerCharTableShift)/30;b2.__inplaceMultiplyAdd(T,A,O)}while(!S2)}if(o2!==n2){if(!g2.__isWhitespace(l2))return null;for(o2++;o2<n2;o2++)if(l2=e3.charCodeAt(o2),!g2.__isWhitespace(l2))return null}return b2.sign=_3===-1,b2.__trim()}},{key:"__fillFromParts",value:function n2(e3,t3,_3){for(var o2=0,l2=0,g3=0,a2=t3.length-1;0<=a2;a2--){var s2=t3[a2],u2=_3[a2];l2|=s2<<g3,g3+=u2,g3===30?(e3.__setDigit(o2++,l2),g3=0,l2=0):30<g3&&(e3.__setDigit(o2++,1073741823&l2),g3-=30,l2=s2>>>u2-g3)}if(l2!==0){if(o2>=e3.length)throw new Error("implementation bug");e3.__setDigit(o2++,l2)}for(;o2<e3.length;o2++)e3.__setDigit(o2,0)}},{key:"__toStringBasePowerOfTwo",value:function _3(e3,t3){var n2=e3.length,o2=t3-1;o2=(85&o2>>>1)+(85&o2),o2=(51&o2>>>2)+(51&o2),o2=(15&o2>>>4)+(15&o2);var l2=o2,a2=t3-1,s2=e3.__digit(n2-1),u2=g2.__clz30(s2),r2=30*n2-u2,d2=0|(r2+l2-1)/l2;if(e3.sign&&d2++,268435456<d2)throw new Error("string too long");for(var h2=Array(d2),b2=d2-1,m2=0,c2=0,v2=0;v2<n2-1;v2++){var y2=e3.__digit(v2),f2=(m2|y2<<c2)&a2;h2[b2--]=g2.__kConversionChars[f2];var k2=l2-c2;for(m2=y2>>>k2,c2=30-k2;c2>=l2;)h2[b2--]=g2.__kConversionChars[m2&a2],m2>>>=l2,c2-=l2}var D2=(m2|s2<<c2)&a2;for(h2[b2--]=g2.__kConversionChars[D2],m2=s2>>>l2-c2;m2!==0;)h2[b2--]=g2.__kConversionChars[m2&a2],m2>>>=l2;if(e3.sign&&(h2[b2--]="-"),b2!==-1)throw new Error("implementation bug");return h2.join("")}},{key:"__toStringGeneric",value:function n2(e3,t3,_3){var o2=e3.length;if(o2===0)return"";if(o2===1){var l2=e3.__unsignedDigit(0).toString(t3);return _3===false&&e3.sign&&(l2="-"+l2),l2}var a2=30*o2-g2.__clz30(e3.__digit(o2-1)),s2=g2.__kMaxBitsPerChar[t3],u2=s2-1,r2=a2*g2.__kBitsPerCharTableMultiplier;r2+=u2-1,r2=0|r2/u2;var d2,h2,b2=r2+1>>1,m2=g2.exponentiate(g2.__oneDigit(t3,false),g2.__oneDigit(b2,false)),c2=m2.__unsignedDigit(0);if(m2.length===1&&32767>=c2){d2=new g2(e3.length,false),d2.__initializeDigits();for(var v2,y2=0,f2=2*e3.length-1;0<=f2;f2--)v2=y2<<15|e3.__halfDigit(f2),d2.__setHalfDigit(f2,0|v2/c2),y2=0|v2%c2;h2=y2.toString(t3)}else{var k2=g2.__absoluteDivLarge(e3,m2,true,true);d2=k2.quotient;var D2=k2.remainder.__trim();h2=g2.__toStringGeneric(D2,t3,true)}d2.__trim();for(var p2=g2.__toStringGeneric(d2,t3,true);h2.length<b2;)h2="0"+h2;return _3===false&&e3.sign&&(p2="-"+p2),p2+h2}},{key:"__unequalSign",value:function t3(e3){return e3?-1:1}},{key:"__absoluteGreater",value:function t3(e3){return e3?-1:1}},{key:"__absoluteLess",value:function t3(e3){return e3?1:-1}},{key:"__compareToBigInt",value:function i3(e3,t3){var _3=e3.sign;if(_3!==t3.sign)return g2.__unequalSign(_3);var n2=g2.__absoluteCompare(e3,t3);return 0<n2?g2.__absoluteGreater(_3):0>n2?g2.__absoluteLess(_3):0}},{key:"__compareToNumber",value:function _3(e3,i3){if(g2.__isOneDigitInt(i3)){var n2=e3.sign,o2=0>i3;if(n2!==o2)return g2.__unequalSign(n2);if(e3.length===0){if(o2)throw new Error("implementation bug");return i3===0?0:-1}if(1<e3.length)return g2.__absoluteGreater(n2);var l2=t2(i3),a2=e3.__unsignedDigit(0);return a2>l2?g2.__absoluteGreater(n2):a2<l2?g2.__absoluteLess(n2):0}return g2.__compareToDouble(e3,i3)}},{key:"__compareToDouble",value:function i3(e3,t3){if(t3!==t3)return t3;if(t3===1/0)return-1;if(t3===-Infinity)return 1;var _3=e3.sign,n2=0>t3;if(_3!==n2)return g2.__unequalSign(_3);if(t3===0)throw new Error("implementation bug: should be handled elsewhere");if(e3.length===0)return-1;g2.__kBitConversionDouble[0]=t3;var o2=2047&g2.__kBitConversionInts[g2.__kBitConversionIntHigh]>>>20;if(o2==2047)throw new Error("implementation bug: handled elsewhere");var l2=o2-1023;if(0>l2)return g2.__absoluteGreater(_3);var a2=e3.length,s2=e3.__digit(a2-1),u2=g2.__clz30(s2),r2=30*a2-u2,d2=l2+1;if(r2<d2)return g2.__absoluteLess(_3);if(r2>d2)return g2.__absoluteGreater(_3);var h2=1048576,b2=1048576|1048575&g2.__kBitConversionInts[g2.__kBitConversionIntHigh],m2=g2.__kBitConversionInts[g2.__kBitConversionIntLow],c2=20,v2=29-u2;if(v2!==(0|(r2-1)%30))throw new Error("implementation bug");var y2,f2=0;if(v2<c2){var k2=c2-v2;f2=k2+32,y2=b2>>>k2,b2=b2<<32-k2|m2>>>k2,m2<<=32-k2}else if(v2===c2)f2=32,y2=b2,b2=m2,m2=0;else{var D2=v2-c2;f2=32-D2,y2=b2<<D2|m2>>>32-D2,b2=m2<<D2,m2=0}if(s2>>>=0,y2>>>=0,s2>y2)return g2.__absoluteGreater(_3);if(s2<y2)return g2.__absoluteLess(_3);for(var p2=a2-2;0<=p2;p2--){0<f2?(f2-=30,y2=b2>>>2,b2=b2<<30|m2>>>2,m2<<=30):y2=0;var B2=e3.__unsignedDigit(p2);if(B2>y2)return g2.__absoluteGreater(_3);if(B2<y2)return g2.__absoluteLess(_3)}if(b2!==0||m2!==0){if(f2===0)throw new Error("implementation bug");return g2.__absoluteLess(_3)}return 0}},{key:"__equalToNumber",value:function _3(e3,i3){return g2.__isOneDigitInt(i3)?i3===0?e3.length===0:e3.length===1&&e3.sign===0>i3&&e3.__unsignedDigit(0)===t2(i3):g2.__compareToDouble(e3,i3)===0}},{key:"__comparisonResultToBool",value:function i3(e3,t3){return t3===0?0>e3:t3===1?0>=e3:t3===2?0<e3:t3===3?0<=e3:undefined}},{key:"__compare",value:function _3(e3,t3,i3){if(e3=g2.__toPrimitive(e3),t3=g2.__toPrimitive(t3),typeof e3=="string"&&typeof t3=="string")switch(i3){case 0:return e3<t3;case 1:return e3<=t3;case 2:return e3>t3;case 3:return e3>=t3}if(g2.__isBigInt(e3)&&typeof t3=="string")return t3=g2.__fromString(t3),t3!==null&&g2.__comparisonResultToBool(g2.__compareToBigInt(e3,t3),i3);if(typeof e3=="string"&&g2.__isBigInt(t3))return e3=g2.__fromString(e3),e3!==null&&g2.__comparisonResultToBool(g2.__compareToBigInt(e3,t3),i3);if(e3=g2.__toNumeric(e3),t3=g2.__toNumeric(t3),g2.__isBigInt(e3)){if(g2.__isBigInt(t3))return g2.__comparisonResultToBool(g2.__compareToBigInt(e3,t3),i3);if(typeof t3!="number")throw new Error("implementation bug");return g2.__comparisonResultToBool(g2.__compareToNumber(e3,t3),i3)}if(typeof e3!="number")throw new Error("implementation bug");if(g2.__isBigInt(t3))return g2.__comparisonResultToBool(g2.__compareToNumber(t3,e3),2^i3);if(typeof t3!="number")throw new Error("implementation bug");return i3===0?e3<t3:i3===1?e3<=t3:i3===2?e3>t3:i3===3?e3>=t3:undefined}},{key:"__absoluteAdd",value:function n2(e3,t3,_3){if(e3.length<t3.length)return g2.__absoluteAdd(t3,e3,_3);if(e3.length===0)return e3;if(t3.length===0)return e3.sign===_3?e3:g2.unaryMinus(e3);var o2=e3.length;(e3.__clzmsd()===0||t3.length===e3.length&&t3.__clzmsd()===0)&&o2++;for(var l2,a2=new g2(o2,_3),s2=0,u2=0;u2<t3.length;u2++)l2=e3.__digit(u2)+t3.__digit(u2)+s2,s2=l2>>>30,a2.__setDigit(u2,1073741823&l2);for(;u2<e3.length;u2++){var d2=e3.__digit(u2)+s2;s2=d2>>>30,a2.__setDigit(u2,1073741823&d2)}return u2<a2.length&&a2.__setDigit(u2,s2),a2.__trim()}},{key:"__absoluteSub",value:function n2(e3,t3,_3){if(e3.length===0)return e3;if(t3.length===0)return e3.sign===_3?e3:g2.unaryMinus(e3);for(var o2,l2=new g2(e3.length,_3),a2=0,s2=0;s2<t3.length;s2++)o2=e3.__digit(s2)-t3.__digit(s2)-a2,a2=1&o2>>>30,l2.__setDigit(s2,1073741823&o2);for(;s2<e3.length;s2++){var u2=e3.__digit(s2)-a2;a2=1&u2>>>30,l2.__setDigit(s2,1073741823&u2)}return l2.__trim()}},{key:"__absoluteAddOne",value:function _3(e3,t3){var n2=2<arguments.length&&arguments[2]!==undefined?arguments[2]:null,o2=e3.length;n2===null?n2=new g2(o2,t3):n2.sign=t3;for(var l2,a2=1,s2=0;s2<o2;s2++)l2=e3.__digit(s2)+a2,a2=l2>>>30,n2.__setDigit(s2,1073741823&l2);return a2!==0&&n2.__setDigitGrow(o2,1),n2}},{key:"__absoluteSubOne",value:function _3(e3,t3){var n2=e3.length;t3=t3||n2;for(var o2,l2=new g2(t3,false),a2=1,s2=0;s2<n2;s2++)o2=e3.__digit(s2)-a2,a2=1&o2>>>30,l2.__setDigit(s2,1073741823&o2);if(a2!==0)throw new Error("implementation bug");for(var u2=n2;u2<t3;u2++)l2.__setDigit(u2,0);return l2}},{key:"__absoluteAnd",value:function _3(e3,t3){var n2=2<arguments.length&&arguments[2]!==undefined?arguments[2]:null,o2=e3.length,l2=t3.length,a2=l2;if(o2<l2){a2=o2;var s2=e3,u2=o2;e3=t3,o2=l2,t3=s2,l2=u2}var r2=a2;n2===null?n2=new g2(r2,false):r2=n2.length;for(var d2=0;d2<a2;d2++)n2.__setDigit(d2,e3.__digit(d2)&t3.__digit(d2));for(;d2<r2;d2++)n2.__setDigit(d2,0);return n2}},{key:"__absoluteAndNot",value:function _3(e3,t3){var n2=2<arguments.length&&arguments[2]!==undefined?arguments[2]:null,o2=e3.length,l2=t3.length,a2=l2;o2<l2&&(a2=o2);var s2=o2;n2===null?n2=new g2(s2,false):s2=n2.length;for(var u2=0;u2<a2;u2++)n2.__setDigit(u2,e3.__digit(u2)&~t3.__digit(u2));for(;u2<o2;u2++)n2.__setDigit(u2,e3.__digit(u2));for(;u2<s2;u2++)n2.__setDigit(u2,0);return n2}},{key:"__absoluteOr",value:function _3(e3,t3){var n2=2<arguments.length&&arguments[2]!==undefined?arguments[2]:null,o2=e3.length,l2=t3.length,a2=l2;if(o2<l2){a2=o2;var s2=e3,u2=o2;e3=t3,o2=l2,t3=s2,l2=u2}var r2=o2;n2===null?n2=new g2(r2,false):r2=n2.length;for(var d2=0;d2<a2;d2++)n2.__setDigit(d2,e3.__digit(d2)|t3.__digit(d2));for(;d2<o2;d2++)n2.__setDigit(d2,e3.__digit(d2));for(;d2<r2;d2++)n2.__setDigit(d2,0);return n2}},{key:"__absoluteXor",value:function _3(e3,t3){var n2=2<arguments.length&&arguments[2]!==undefined?arguments[2]:null,o2=e3.length,l2=t3.length,a2=l2;if(o2<l2){a2=o2;var s2=e3,u2=o2;e3=t3,o2=l2,t3=s2,l2=u2}var r2=o2;n2===null?n2=new g2(r2,false):r2=n2.length;for(var d2=0;d2<a2;d2++)n2.__setDigit(d2,e3.__digit(d2)^t3.__digit(d2));for(;d2<o2;d2++)n2.__setDigit(d2,e3.__digit(d2));for(;d2<r2;d2++)n2.__setDigit(d2,0);return n2}},{key:"__absoluteCompare",value:function _3(e3,t3){var n2=e3.length-t3.length;if(n2!=0)return n2;for(var o2=e3.length-1;0<=o2&&e3.__digit(o2)===t3.__digit(o2);)o2--;return 0>o2?0:e3.__unsignedDigit(o2)>t3.__unsignedDigit(o2)?1:-1}},{key:"__multiplyAccumulate",value:function o2(e3,t3,_3,n2){if(t3!==0){for(var l2=32767&t3,a2=t3>>>15,s2=0,u2=0,r2=0;r2<e3.length;r2++,n2++){var d2=_3.__digit(n2),h2=e3.__digit(r2),b2=32767&h2,m2=h2>>>15,c2=g2.__imul(b2,l2),v2=g2.__imul(b2,a2),y2=g2.__imul(m2,l2),f2=g2.__imul(m2,a2);d2+=u2+c2+s2,s2=d2>>>30,d2&=1073741823,d2+=((32767&v2)<<15)+((32767&y2)<<15),s2+=d2>>>30,u2=f2+(v2>>>15)+(y2>>>15),_3.__setDigit(n2,1073741823&d2)}for(;s2!==0||u2!==0;n2++){var k2=_3.__digit(n2);k2+=s2+u2,u2=0,s2=k2>>>30,_3.__setDigit(n2,1073741823&k2)}}}},{key:"__internalMultiplyAdd",value:function a2(e3,t3,_3,o2,l2){for(var s2=_3,u2=0,d2=0;d2<o2;d2++){var h2=e3.__digit(d2),b2=g2.__imul(32767&h2,t3),m2=g2.__imul(h2>>>15,t3),c2=b2+((32767&m2)<<15)+u2+s2;s2=c2>>>30,u2=m2>>>15,l2.__setDigit(d2,1073741823&c2)}if(l2.length>o2)for(l2.__setDigit(o2++,s2+u2);o2<l2.length;)l2.__setDigit(o2++,0);else if(s2+u2!==0)throw new Error("implementation bug")}},{key:"__absoluteDivSmall",value:function _3(e3,t3){var n2=2<arguments.length&&arguments[2]!==undefined?arguments[2]:null;n2===null&&(n2=new g2(e3.length,false));for(var o2=0,l2=2*e3.length-1;0<=l2;l2-=2){var a2=(o2<<15|e3.__halfDigit(l2))>>>0,s2=0|a2/t3;o2=0|a2%t3,a2=(o2<<15|e3.__halfDigit(l2-1))>>>0;var u2=0|a2/t3;o2=0|a2%t3,n2.__setDigit(l2>>>1,s2<<15|u2)}return n2}},{key:"__absoluteModSmall",value:function _3(e3,t3){for(var n2,o2=0,l2=2*e3.length-1;0<=l2;l2--)n2=(o2<<15|e3.__halfDigit(l2))>>>0,o2=0|n2%t3;return o2}},{key:"__absoluteDivLarge",value:function o2(e3,t3,i3,_3){var l2=t3.__halfDigitLength(),n2=t3.length,a2=e3.__halfDigitLength()-l2,s2=null;i3&&(s2=new g2(a2+2>>>1,false),s2.__initializeDigits());var r2=new g2(l2+2>>>1,false);r2.__initializeDigits();var d2=g2.__clz15(t3.__halfDigit(l2-1));0<d2&&(t3=g2.__specialLeftShift(t3,d2,0));for(var h2=g2.__specialLeftShift(e3,d2,1),u2=t3.__halfDigit(l2-1),b2=0,m2=a2;0<=m2;m2--){var v2=32767,y2=h2.__halfDigit(m2+l2);if(y2!==u2){var f2=(y2<<15|h2.__halfDigit(m2+l2-1))>>>0;v2=0|f2/u2;for(var k2=0|f2%u2,D2=t3.__halfDigit(l2-2),p2=h2.__halfDigit(m2+l2-2);g2.__imul(v2,D2)>>>0>(k2<<16|p2)>>>0&&(v2--,k2+=u2,!(32767<k2)););}g2.__internalMultiplyAdd(t3,v2,0,n2,r2);var B2=h2.__inplaceSub(r2,m2,l2+1);B2!==0&&(B2=h2.__inplaceAdd(t3,m2,l2),h2.__setHalfDigit(m2+l2,32767&h2.__halfDigit(m2+l2)+B2),v2--),i3&&(1&m2?b2=v2<<15:s2.__setDigit(m2>>>1,b2|v2))}if(_3)return h2.__inplaceRightShift(d2),i3?{quotient:s2,remainder:h2}:h2;if(i3)return s2;throw new Error("unreachable")}},{key:"__clz15",value:function t3(e3){return g2.__clz30(e3)-15}},{key:"__specialLeftShift",value:function o2(e3,t3,_3){var l2=e3.length,n2=l2+_3,a2=new g2(n2,false);if(t3===0){for(var s2=0;s2<l2;s2++)a2.__setDigit(s2,e3.__digit(s2));return 0<_3&&a2.__setDigit(l2,0),a2}for(var u2,r2=0,h2=0;h2<l2;h2++)u2=e3.__digit(h2),a2.__setDigit(h2,1073741823&u2<<t3|r2),r2=u2>>>30-t3;return 0<_3&&a2.__setDigit(l2,r2),a2}},{key:"__leftShiftByAbsolute",value:function _3(e3,t3){var n2=g2.__toShiftAmount(t3);if(0>n2)throw new RangeError("BigInt too big");var o2=0|n2/30,l2=n2%30,a2=e3.length,s2=l2!==0&&e3.__digit(a2-1)>>>30-l2!=0,u2=a2+o2+(s2?1:0),r2=new g2(u2,e3.sign);if(l2===0){for(var h2=0;h2<o2;h2++)r2.__setDigit(h2,0);for(;h2<u2;h2++)r2.__setDigit(h2,e3.__digit(h2-o2))}else{for(var b2=0,m2=0;m2<o2;m2++)r2.__setDigit(m2,0);for(var c2,v2=0;v2<a2;v2++)c2=e3.__digit(v2),r2.__setDigit(v2+o2,1073741823&c2<<l2|b2),b2=c2>>>30-l2;if(s2)r2.__setDigit(a2+o2,b2);else if(b2!==0)throw new Error("implementation bug")}return r2.__trim()}},{key:"__rightShiftByAbsolute",value:function _3(e3,t3){var{length:n2,sign:o2}=e3,l2=g2.__toShiftAmount(t3);if(0>l2)return g2.__rightShiftByMaximum(o2);var a2=0|l2/30,s2=l2%30,u2=n2-a2;if(0>=u2)return g2.__rightShiftByMaximum(o2);var r2=false;if(o2){var h2=(1<<s2)-1;if((e3.__digit(a2)&h2)!=0)r2=true;else for(var b2=0;b2<a2;b2++)if(e3.__digit(b2)!==0){r2=true;break}}if(r2&&s2===0){var m2=e3.__digit(n2-1),c2=~m2==0;c2&&u2++}var v2=new g2(u2,o2);if(s2===0){v2.__setDigit(u2-1,0);for(var y2=a2;y2<n2;y2++)v2.__setDigit(y2-a2,e3.__digit(y2))}else{for(var f2,k2=e3.__digit(a2)>>>s2,D2=n2-a2-1,p2=0;p2<D2;p2++)f2=e3.__digit(p2+a2+1),v2.__setDigit(p2,1073741823&f2<<30-s2|k2),k2=f2>>>s2;v2.__setDigit(D2,k2)}return r2&&(v2=g2.__absoluteAddOne(v2,true,v2)),v2.__trim()}},{key:"__rightShiftByMaximum",value:function t3(e3){return e3?g2.__oneDigit(1,true):g2.__zero()}},{key:"__toShiftAmount",value:function t3(e3){if(1<e3.length)return-1;var i3=e3.__unsignedDigit(0);return i3>g2.__kMaxLengthBits?-1:i3}},{key:"__toPrimitive",value:function t3(e3){var i3=1<arguments.length&&arguments[1]!==undefined?arguments[1]:"default";if(p(e3)!=="object")return e3;if(e3.constructor===g2)return e3;if(typeof Symbol!="undefined"&&p(Symbol.toPrimitive)==="symbol"&&e3[Symbol.toPrimitive]){var _3=e3[Symbol.toPrimitive](i3);if(p(_3)!=="object")return _3;throw new TypeError("Cannot convert object to primitive value")}var n2=e3.valueOf;if(n2){var o2=n2.call(e3);if(p(o2)!=="object")return o2}var l2=e3.toString;if(l2){var a2=l2.call(e3);if(p(a2)!=="object")return a2}throw new TypeError("Cannot convert object to primitive value")}},{key:"__toNumeric",value:function t3(e3){return g2.__isBigInt(e3)?e3:+e3}},{key:"__isBigInt",value:function t3(e3){return p(e3)==="object"&&e3!==null&&e3.constructor===g2}},{key:"__truncateToNBits",value:function _3(e3,t3){for(var n2=0|(e3+29)/30,o2=new g2(n2,t3.sign),l2=n2-1,a2=0;a2<l2;a2++)o2.__setDigit(a2,t3.__digit(a2));var s2=t3.__digit(l2);if(e3%30!=0){var u2=32-e3%30;s2=s2<<u2>>>u2}return o2.__setDigit(l2,s2),o2.__trim()}},{key:"__truncateAndSubFromPowerOfTwo",value:function n2(e3,t3,_3){for(var o2=Math.min,l2,a2=0|(e3+29)/30,s2=new g2(a2,_3),u2=0,d2=a2-1,h2=0,b2=o2(d2,t3.length);u2<b2;u2++)l2=0-t3.__digit(u2)-h2,h2=1&l2>>>30,s2.__setDigit(u2,1073741823&l2);for(;u2<d2;u2++)s2.__setDigit(u2,0|1073741823&-h2);var m2,c2=d2<t3.length?t3.__digit(d2):0,v2=e3%30;if(v2===0)m2=0-c2-h2,m2&=1073741823;else{var y2=32-v2;c2=c2<<y2>>>y2;var f2=1<<32-y2;m2=f2-c2-h2,m2&=f2-1}return s2.__setDigit(d2,m2),s2.__trim()}},{key:"__digitPow",value:function i3(e3,t3){for(var _3=1;0<t3;)1&t3&&(_3*=e3),t3>>>=1,e3*=e3;return _3}},{key:"__detectBigEndian",value:function e3(){return g2.__kBitConversionDouble[0]=-0,g2.__kBitConversionInts[0]!==0}},{key:"__isOneDigitInt",value:function t3(e3){return(1073741823&e3)===e3}}])}(S(Array));return C.__kMaxLength=33554432,C.__kMaxLengthBits=C.__kMaxLength<<5,C.__kMaxBitsPerChar=[0,0,32,51,64,75,83,90,96,102,107,111,115,119,122,126,128,131,134,136,139,141,143,145,147,149,151,153,154,156,158,159,160,162,163,165,166],C.__kBitsPerCharTableShift=5,C.__kBitsPerCharTableMultiplier=1<<C.__kBitsPerCharTableShift,C.__kConversionChars=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],C.__kBitConversionBuffer=new ArrayBuffer(8),C.__kBitConversionDouble=new Float64Array(C.__kBitConversionBuffer),C.__kBitConversionInts=new Int32Array(C.__kBitConversionBuffer),C.__kBitConversionIntHigh=C.__detectBigEndian()?0:1,C.__kBitConversionIntLow=C.__detectBigEndian()?1:0,C.__clz30=t?function(e2){return t(e2)-2}:function(e2){var{LN2:t2,log:i2}=Math;return e2===0?30:0|29-(0|i2(e2>>>0)/t2)},C.__imul=e||function(e2,t2){return 0|e2*t2},C})});var import_text_encoding=__toESM(require_text_encoding(),1);var import_jsbi=__toESM(require_jsbi_umd(),1);var version="1.13.0.0";function onBTS(){return typeof __BACKGROUND__!=="undefined"&&__BACKGROUND__}function onMTS(){return typeof __MAIN_THREAD__!=="undefined"&&__MAIN_THREAD__}function callFocus(id,delay){var setFocus=function(){var e=document.getElementById(id);if(e&&e.focus)e.focus()};delay>0?setTimeout(setFocus,delay):setFocus()}function callBlur(id,delay){var setBlur=function(){var e=document.getElementById(id);if(e&&e.blur)e.blur()};delay>0?setTimeout(setBlur,delay):setBlur()}function callSelect(id,delay){var setSelect=function(){var e=document.getElementById(id);if(e&&typeof e["select"]==="function")e.select()};delay>0?setTimeout(setSelect,delay):setSelect()}function callSetSelectionRange(id,start,end,delay){var setSetSelectionRange=function(){var e=document.getElementById(id);if(e&&typeof e["setSelectionRange"]==="function")e.setSelectionRange(start,end,"none")};delay>0?setTimeout(setSetSelectionRange,delay):setSetSelectionRange()}function fetchCore(url,method,body,requestHeaders,successful,errorful,responseType){var options={method,headers:requestHeaders};if(body){options["body"]=body}let headers={};let status=null;try{fetch(url,options).then((response)=>{status=response.status;for(const[key,value]of response.headers){headers[key]=value}if(response.status<200||response.status>=300){throw new Error(response.statusText||"HTTP "+response.status)}if(responseType=="json"){return response.json()}else if(responseType=="text"){return response.text()}else if(responseType==="arrayBuffer"){return response.arrayBuffer()}else if(responseType==="blob"){return response.blob()}else if(responseType==="bytes"){return response.bytes()}else if(responseType==="formData"){return response.formData()}else if(responseType==="none"){return null}}).then((body2)=>successful({error:null,body:body2,headers,status})).catch((body2)=>errorful({error:null,body:body2,headers,status}))}catch(err){errorful({body:null,error:err.message,headers,status})}}function websocketConnect(url,onOpen,onClose,onMessageText,onMessageJSON,onMessageBLOB,onMessageArrayBuffer,onError,textOnly){try{let socket=new WebSocket(url);socket.onopen=function(){onOpen()};socket.onclose=function(e){onClose(e)};socket.onerror=function(error){console.error(error);onError("WebSocket error received")};socket.onmessage=function(msg){if(typeof msg.data==="string"){try{if(textOnly){if(onMessageText)onMessageText(msg.data);return}const json=JSON.parse(msg.data);if(onMessageJSON)onMessageJSON(json)}catch(err){if(textOnly&&onMessageText){onMessageText(msg.data)}else{onError(err.message)}}}else if(msg.data instanceof Blob){if(onMessageBLOB)onMessageBLOB(msg.data)}else if(msg.data instanceof ArrayBuffer){if(onMessageArrayBuffer)onMessageArrayBuffer(msg.data)}else{console.error("Received unknown message type from WebSocket",msg);onError("Unknown message received from WebSocket")}};return socket}catch(err){onError(err.message)}}function websocketClose(socket){if(socket){socket.close();socket=null}}function websocketSend(socket,message){if(message&&socket&&socket.readyState===WebSocket.OPEN){socket.send(message)}}function eventSourceConnect(url,onOpen,onMessageText,onMessageJSON,onError,textOnly){try{let eventSource=new EventSource(url);eventSource.onopen=function(){onOpen()};eventSource.onerror=function(){onError("EventSource error received")};eventSource.onmessage=function(msg){try{if(textOnly){if(onMessageText)onMessageText(msg.data);return}const json=JSON.parse(msg.data);if(onMessageJSON)onMessageJSON(json)}catch(err){if(textOnly&&onMessageText){onMessageText(msg.data)}else{onError(err.message)}}};return eventSource}catch(err){onError(err.message)}}function eventSourceClose(eventSource){if(eventSource){eventSource.close();eventSource=null}}function populateClass(vnode,classes){if(!vnode.classList){vnode.classList=new Set}for(const str of classes){for(const c of str.trim().split(" ")){if(c)vnode.classList.add(c)}}}function updateRef(current,latest){if(!current.parent){return}latest.nextSibling=current.nextSibling;latest.parent=current.parent;current.parent.child=latest}function inline(code,context={}){const keys=Object.keys(context);const values=Object.values(context);const func=new Function(...keys,code);return func(...values)}function typeOf(x){if(x===null||x===undefined)return 0;if(typeof x==="number")return 1;if(typeof x==="string")return 2;if(typeof x==="boolean")return 3;if(Array.isArray(x))return 4;return 5}function splitmix32(a){return function(){a|=0;a=a+2654435769|0;var t=a^a>>>15;t=Math.imul(t,2246822507);t=t^t>>>13;t=Math.imul(t,3266489909);return((t^t>>>16)>>>0)/4294967296}}function getRandomValues(){const array=new Uint32Array(1);return crypto.getRandomValues(array)[0]}function mathRandom(){return Math.random()}function forEachDOMRef(tree,cb){switch(tree.type){case 3:for(const child of tree.children)forEachDOMRef(child,cb);break;case 0:if(tree.child)forEachDOMRef(tree.child,cb);break;default:cb(tree.domRef);break}}function getFirstDOMRef(tree){switch(tree.type){case 3:{if(!tree.children||tree.children.length===0)return null;return getFirstDOMRef(tree.children[0])}case 0:if(!tree.child)return null;return getFirstDOMRef(tree.child);default:return tree.domRef}}function getLastDOMRef(tree){switch(tree.type){case 3:{if(!tree.children||tree.children.length===0)return null;return getLastDOMRef(tree.children[tree.children.length-1])}case 0:if(!tree.child)return null;return getLastDOMRef(tree.child);default:return tree.domRef}}function getDOMRef(tree){return getFirstDOMRef(tree)}function cookieGet(name,errorful,successful){try{globalThis.cookieStore.get(name).then((c)=>successful(c?c.value:null)).catch((err)=>errorful(err.message))}catch(err){errorful(err.message)}}function cookieGetAll(errorful,successful){try{globalThis.cookieStore.getAll().then(successful).catch((err)=>errorful(err.message))}catch(err){errorful(err.message)}}function cookieSet(cookie,errorful,successful){try{globalThis.cookieStore.set(cookie).then(successful).catch((err)=>errorful(err.message))}catch(err){errorful(err.message)}}function cookieDelete(name,errorful,successful){try{globalThis.cookieStore.delete(name).then(successful).catch((err)=>errorful(err.message))}catch(err){errorful(err.message)}}function cookieDeleteWith(cookie,errorful,successful){const opts={name:cookie.name};if(cookie.path!=null)opts.path=cookie.path;if(cookie.domain!=null)opts.domain=cookie.domain;if(cookie.partitioned!=null)opts.partitioned=cookie.partitioned;try{globalThis.cookieStore.delete(opts).then(successful).catch((err)=>errorful(err.message))}catch(err){errorful(err.message)}}function diff(c,n,parent,context){if(!c&&!n)return;else if(!c)create(n,parent,context);else if(!n)destroy(c,parent,context);else if(c.type===2&&n.type===2){diffVText(c,n,context)}else if(c.type===0&&n.type===0){if(n.key===c.key){n.child=c.child;n.componentId=c.componentId;if(c.child)c.child.parent=n;if(n.diffProps)n.diffProps();return}replace(c,n,parent,context)}else if(c.type===3&&n.type===3){if(n.key===c.key){const lastRef=getLastDOMRef(c);const endAnchor=lastRef?lastRef.nextSibling:context.nextSibling(c);diffChildren(c.children,n.children,parent,context,endAnchor)}else{replace(c,n,parent,context)}}else if(c.type===1&&n.type===1){if(n.tag===c.tag&&n.key===c.key){n.domRef=c.domRef;diffAttrs(c,n,context)}else{replace(c,n,parent,context)}}else replace(c,n,parent,context)}function diffVText(c,n,context){if(c.text!==n.text)context.setTextContent(c.domRef,n.text);n.domRef=c.domRef;return}function replace(c,n,parent,context){if(c.type===3){const lastRef2=getLastDOMRef(c);const anchor=lastRef2?lastRef2.nextSibling:context.nextSibling(c);destroy(c,parent,context);if(anchor){createElement(parent,2,anchor,n,context)}else{create(n,parent,context)}return}switch(c.type){case 2:break;default:callBeforeDestroyedRecursive(c);break}const firstRef=getFirstDOMRef(c);const lastRef=getLastDOMRef(c);if(!firstRef||!lastRef){const anchor=context.nextSibling(c);if(anchor){createElement(parent,2,anchor,n,context)}else{create(n,parent,context)}}else if(firstRef!==lastRef){const anchor=lastRef.nextSibling;forEachDOMRef(c,(ref)=>context.removeChild(parent,ref));if(anchor){createElement(parent,2,anchor,n,context)}else{create(n,parent,context)}}else{createElement(parent,1,firstRef,n,context)}switch(c.type){case 2:break;default:callDestroyedRecursive(c);break}}function destroy(c,parent,context){switch(c.type){case 2:break;case 3:for(const child of c.children)destroy(child,parent,context);return;default:callBeforeDestroyedRecursive(c);break}forEachDOMRef(c,(ref)=>context.removeChild(parent,ref));switch(c.type){case 2:break;default:callDestroyedRecursive(c);break}}function callDestroyedRecursive(c){if(c.type===3){for(const child of c.children)if(child.type!==2)callDestroyedRecursive(child);return}callDestroyed(c);switch(c.type){case 1:for(const child of c.children)if(child.type!==2)callDestroyedRecursive(child);break;case 0:if(c.child&&c.child.type!==2)callDestroyedRecursive(c.child);break}}function callDestroyed(c){if(c.type===1&&c.onDestroyed)c.onDestroyed();if(c.type===0)unmountComponent(c)}function callBeforeDestroyed(c){switch(c.type){case 0:break;case 1:if(c.onBeforeDestroyed)c.onBeforeDestroyed();break;default:break}}function callBeforeDestroyedRecursive(c){if(c.type===3){for(const child of c.children)if(child.type!==2)callBeforeDestroyedRecursive(child);return}callBeforeDestroyed(c);switch(c.type){case 1:for(const child of c.children){if(child.type===2)continue;callBeforeDestroyedRecursive(child)}break;case 0:if(c.child&&c.child.type!==2)callBeforeDestroyedRecursive(c.child);break}}function diffAttrs(c,n,context){diffProps(c?c.props:{},n.props,n.domRef,n.ns==="svg",context);diffClass(c?c.classList:null,n.classList,n.domRef,context);diffCss(c?c.css:{},n.css,n.domRef,context);diffEvents(c,n,context);diffChildren(c?c.children:[],n.children,n.domRef,context);drawCanvas(n)}function diffEvents(c,n,context){if(!onBTS()&&!onMTS())return;if(c===null&&n.directEvents){for(const name of n.directEvents){context.addEvent(n.domRef,name,{capture:false,direct:true})}}for(const capture of[true,false]){const cKeys=eventEntries(c,capture);const nKeys=eventEntries(n,capture);for(const name in cKeys){if(!(name in nKeys))context.removeEvent(n.domRef,name,capture)}for(const name in nKeys){const nk=nKeys[name],ck=cKeys[name];if(!ck||!sameEventKey(nk,ck))context.addEvent(n.domRef,name,nk)}}}function diffClass(c,n,domRef,context){if(!c&&!n){return}if(!c){for(const className of n){context.addClass(className,domRef)}return}if(!n){for(const className of c){context.removeClass(className,domRef)}return}for(const className of c){if(!n.has(className)){context.removeClass(className,domRef)}}for(const className of n){if(!c.has(className)){context.addClass(className,domRef)}}return}function diffProps(cProps,nProps,node,isSvg,context){var newProp;const native=onBTS()||onMTS();for(const c in cProps){newProp=nProps[c];if(newProp===undefined){if(isSvg||native||!(c in node)||c==="disabled"){context.removeAttribute(node,c)}else{context.setAttribute(node,c,"")}}else{if(newProp===cProps[c]&&c!=="checked"&&c!=="value")continue;if(isSvg){if(c==="href"){context.setAttributeNS(node,"http://www.w3.org/1999/xlink","href",newProp)}else{context.setAttribute(node,c,newProp)}}else if(!native&&c in node&&!(c==="list"||c==="form")){node[c]=newProp}else{context.setAttribute(node,c,newProp)}}}for(const n in nProps){if(cProps&&n in cProps)continue;newProp=nProps[n];if(isSvg){if(n==="href"){context.setAttributeNS(node,"http://www.w3.org/1999/xlink","href",newProp)}else{context.setAttribute(node,n,newProp)}}else if(!native&&n in node&&!(n==="list"||n==="form")){node[n]=nProps[n]}else{context.setAttribute(node,n,newProp)}}}function diffCss(cCss,nCss,node,context){context.setInlineStyle(cCss,nCss,node)}function shouldSync(cs,ns){if(cs.length===0||ns.length===0)return false;for(var i=0;i<cs.length;i++){if(cs[i].key===null||cs[i].key===undefined){return false}}for(var i=0;i<ns.length;i++){if(ns[i].key===null||ns[i].key===undefined){return false}}return true}function diffChildren(cs,ns,parent,context,endAnchor=null){if(shouldSync(cs,ns)){syncChildren(cs,ns,parent,context,endAnchor)}else{for(let i=0;i<Math.max(ns.length,cs.length);i++){const c=cs[i],n=ns[i];if(!c&&n){if(endAnchor){createElement(parent,2,endAnchor,n,context)}else{create(n,parent,context)}}else{diff(c,n,parent,context)}}}}function eventEntries(c,capture){const out={};if(!c)return out;const phase=capture?c.events.captures:c.events.bubbles;for(const name in phase){const{staticKey,componentId,options}=phase[name];if(staticKey!==undefined&&componentId!==undefined){out[name]={capture,staticKey,componentId,options}}}return out}function sameEventKey(a,b){return a.staticKey===b.staticKey&&a.componentId===b.componentId&&a.options?.preventDefault===b.options?.preventDefault&&a.options?.stopPropagation===b.options?.stopPropagation}function populateDomRef(c,context){if(c.ns==="svg"){c.domRef=context.createElementNS("http://www.w3.org/2000/svg",c.tag)}else if(c.ns==="mathml"){c.domRef=context.createElementNS("http://www.w3.org/1998/Math/MathML",c.tag)}else{c.domRef=context.createElement(c.tag)}}function callCreated(parent,n,context){if(n.onCreated)n.onCreated(n.domRef)}function createElement(parent,op,replacing,n,context){switch(n.type){case 2:n.domRef=context.createTextNode(n.text);switch(op){case 2:context.insertBefore(parent,n.domRef,replacing);break;case 0:context.appendChild(parent,n.domRef);break;case 1:context.replaceChild(parent,n.domRef,replacing);break}break;case 3:for(const child of n.children){createElement(parent,2,replacing,child,context)}if(op===1&&replacing){context.removeChild(parent,replacing)}break;case 0:mountComponent(parent,op,replacing,n,context);break;case 1:if(n.onBeforeCreated)n.onBeforeCreated();populateDomRef(n,context);if(n.onCreated)n.onCreated(n.domRef);diffAttrs(null,n,context);switch(op){case 2:context.insertBefore(parent,n.domRef,replacing);break;case 0:context.appendChild(parent,n.domRef);break;case 1:context.replaceChild(parent,n.domRef,replacing);break}break}}function drawCanvas(c){if(c.tag==="canvas"&&c.draw)c.draw(c.domRef)}function unmountComponent(c){c.unmount(c.componentId)}function mountComponent(parent,op,replacing,n,context){let mounted=n.mount(parent);n.componentId=mounted.componentId;n.child=mounted.componentTree;mounted.componentTree.parent=n;const componentDOMRef=getFirstDOMRef(mounted.componentTree);if(mounted.componentTree.type!==0){if(op===1&&replacing){if(!componentDOMRef){context.removeChild(parent,replacing)}else if(mounted.componentTree.type===3){forEachDOMRef(mounted.componentTree,(ref)=>context.insertBefore(parent,ref,replacing));context.removeChild(parent,replacing)}else{context.replaceChild(parent,componentDOMRef,replacing)}}else if(op===2){if(replacing){forEachDOMRef(mounted.componentTree,(ref)=>context.insertBefore(parent,ref,replacing))}else{forEachDOMRef(mounted.componentTree,(ref)=>context.appendChild(parent,ref))}}}}function create(n,parent,context){createElement(parent,0,null,n,context)}function insertBefore(parent,n,o,context){const anchor=o?getFirstDOMRef(o)??context.nextSibling(o):null;if(anchor){forEachDOMRef(n,(ref)=>context.insertBefore(parent,ref,anchor))}else{forEachDOMRef(n,(ref)=>context.appendChild(parent,ref))}}function swapDOMRef(oLast,oFirst,parent,context){const oLastRef=getFirstDOMRef(oLast);const oFirstRef=getFirstDOMRef(oFirst);if(oLastRef&&oFirstRef&&(oLast.type===1||oLast.type===2)&&(oFirst.type===1||oFirst.type===2)){context.swapDOMRefs(oLastRef,oFirstRef,parent);return}const lastRef=getLastDOMRef(oLast);const tmp=lastRef?lastRef.nextSibling:context.nextSibling(oLast);const anchor=getFirstDOMRef(oFirst)??context.nextSibling(oFirst);if(anchor){forEachDOMRef(oLast,(ref)=>context.insertBefore(parent,ref,anchor))}else{forEachDOMRef(oLast,(ref)=>context.appendChild(parent,ref))}if(tmp){forEachDOMRef(oFirst,(ref)=>context.insertBefore(parent,ref,tmp))}else{forEachDOMRef(oFirst,(ref)=>context.appendChild(parent,ref))}}function syncChildren(os,ns,parent,context,endAnchor=null){var oldFirstIndex=0,newFirstIndex=0,oldLastIndex=os.length-1,newLastIndex=ns.length-1,tmp,nFirst,nLast,oLast,oFirst,found,node;for(;;){if(newFirstIndex>newLastIndex&&oldFirstIndex>oldLastIndex){break}nFirst=ns[newFirstIndex];nLast=ns[newLastIndex];oFirst=os[oldFirstIndex];oLast=os[oldLastIndex];if(oldFirstIndex>oldLastIndex){const oFirstRef=oFirst?getFirstDOMRef(oFirst)??context.nextSibling(oFirst):null;const anchor=oFirstRef??endAnchor;if(anchor){createElement(parent,2,anchor,nFirst,context)}else{create(nFirst,parent,context)}os.splice(newFirstIndex,0,nFirst);newFirstIndex++}else if(newFirstIndex>newLastIndex){tmp=oldLastIndex;while(oldLastIndex>=oldFirstIndex){destroy(os[oldLastIndex--],parent,context)}os.splice(oldFirstIndex,tmp-oldFirstIndex+1);break}else if(oFirst.key===nFirst.key){diff(os[oldFirstIndex++],ns[newFirstIndex++],parent,context)}else if(oLast.key===nLast.key){diff(os[oldLastIndex--],ns[newLastIndex--],parent,context)}else if(oFirst.key===nLast.key&&nFirst.key===oLast.key){swapDOMRef(oLast,oFirst,parent,context);swap(os,oldFirstIndex,oldLastIndex);diff(os[oldFirstIndex++],ns[newFirstIndex++],parent,context);diff(os[oldLastIndex--],ns[newLastIndex--],parent,context)}else if(oFirst.key===nLast.key){const lastRef=getLastDOMRef(oLast);const afterOLast=lastRef?lastRef.nextSibling:context.nextSibling(oLast);if(afterOLast){forEachDOMRef(oFirst,(ref)=>context.insertBefore(parent,ref,afterOLast))}else{forEachDOMRef(oFirst,(ref)=>context.appendChild(parent,ref))}os.splice(oldLastIndex,0,os.splice(oldFirstIndex,1)[0]);diff(os[oldLastIndex--],ns[newLastIndex--],parent,context)}else if(oLast.key===nFirst.key){insertBefore(parent,oLast,oFirst,context);os.splice(oldFirstIndex,0,os.splice(oldLastIndex,1)[0]);diff(os[oldFirstIndex++],nFirst,parent,context);newFirstIndex++}else{found=false;tmp=oldFirstIndex;while(tmp<=oldLastIndex){if(os[tmp].key===nFirst.key){found=true;node=os[tmp];break}tmp++}if(found){os.splice(oldFirstIndex,0,os.splice(tmp,1)[0]);diff(os[oldFirstIndex++],nFirst,parent,context);insertBefore(parent,node,os[oldFirstIndex],context);newFirstIndex++}else{const anchor=getFirstDOMRef(oFirst)??context.nextSibling(oFirst);if(anchor){createElement(parent,2,anchor,nFirst,context)}else{create(nFirst,parent,context)}os.splice(oldFirstIndex++,0,nFirst);newFirstIndex++;oldLastIndex++}}}}function swap(os,l,r){const k=os[l];os[l]=os[r];os[r]=k}function delegateEvent(event,obj,stack,debug,context){if(!stack.length){if(debug){console.warn('Event "'+event.type+'" did not find an event handler to dispatch on',obj,event)}return}else if(stack.length>1){if(obj.type===2){return}else if(obj.type===3){for(const child of obj.children){if(containsDOMRef(child,stack[0],context)){delegateEvent(event,child,stack,debug,context);return}}return}else if(obj.type===0){if(!obj.child){if(debug){console.error("VComp has no child property set during event delegation",obj);console.error("This means the Component has not been fully mounted, this should never happen");throw new Error("VComp has no .child property set during event delegation")}return}return delegateEvent(event,obj.child,stack,debug,context)}else if(obj.type===1){if(context.isEqual(obj.domRef,stack[0])){const eventObj=obj.events.captures[event.type];if(eventObj){const options=eventObj.options;if(options.preventDefault)event.preventDefault();if(!event["captureStopped"]){eventObj.runEvent(event,obj.domRef)}if(options.stopPropagation){event["captureStopped"]=true}}stack.splice(0,1);for(const child of obj.children){if(containsDOMRef(child,stack[0],context)){delegateEvent(event,child,stack,debug,context);return}}}return}}else{if(obj.type===0){if(obj.child){delegateEvent(event,obj.child,stack,debug,context)}}else if(obj.type===3){for(const child of obj.children){if(containsDOMRef(child,stack[0],context)){delegateEvent(event,child,stack,debug,context);return}}}else if(obj.type===1){const eventCaptureObj=obj.events.captures[event.type];if(eventCaptureObj&&!event["captureStopped"]){const options=eventCaptureObj.options;if(context.isEqual(stack[0],obj.domRef)){if(options.preventDefault)event.preventDefault();eventCaptureObj.runEvent(event,stack[0]);if(options.stopPropagation)event["captureStopped"]=true}}const eventObj=obj.events.bubbles[event.type];if(eventObj&&!event["captureStopped"]){const options=eventObj.options;if(context.isEqual(stack[0],obj.domRef)){if(options.preventDefault)event.preventDefault();eventObj.runEvent(event,stack[0]);if(!options.stopPropagation){propagateWhileAble(obj.parent,event)}}}else{if(!event["captureStopped"]){propagateWhileAble(obj.parent,event)}}}}}function propagateWhileAble(vtree,event){while(vtree){switch(vtree.type){case 2:break;case 3:vtree=vtree.parent;break;case 1:const eventObj=vtree.events.bubbles[event.type];if(eventObj){const options=eventObj.options;if(options.preventDefault)event.preventDefault();eventObj.runEvent(event,vtree.domRef);if(options.stopPropagation){return}}vtree=vtree.parent;break;case 0:if(!vtree.eventPropagation)return;vtree=vtree.parent;break}}}function eventJSON(at,obj){if(typeof at[0]==="object"){var ret=[];for(var i=0;i<at.length;i++){ret.push(eventJSON(at[i],obj))}return ret}for(const a of at)obj=obj[a];var newObj;if(obj instanceof Array||"length"in obj&&obj["localName"]!=="select"){newObj=[];for(var j=0;j<obj.length;j++){newObj.push(eventJSON([],obj[j]))}return newObj}newObj={};for(var key in getAllPropertyNames(obj)){if(obj["localName"]==="input"&&(key==="selectionDirection"||key==="selectionStart"||key==="selectionEnd")){continue}if(typeof obj[key]=="string"||typeof obj[key]=="number"||typeof obj[key]=="boolean"){newObj[key]=obj[key]}}return newObj}function containsDOMRef(vtree,target,context){switch(vtree.type){case 3:for(const child of vtree.children)if(containsDOMRef(child,target,context))return true;return false;case 0:return vtree.child?containsDOMRef(vtree.child,target,context):false;default:return context.isEqual(vtree.domRef,target)}}function getAllPropertyNames(obj){var props={},i=0;do{var names=Object.getOwnPropertyNames(obj);for(i=0;i<names.length;i++){props[names[i]]=null}}while(obj=Object.getPrototypeOf(obj));return props}function collapseSiblingTextNodes(vs){var ax=0,adjusted=vs.length>0?[vs[0]]:[];for(var ix=1;ix<vs.length;ix++){if(adjusted[ax].type===2&&vs[ix].type===2){adjusted[ax].text+=vs[ix].text;continue}adjusted[++ax]=vs[ix]}for(const v of adjusted){if(v.type===3){v.children=collapseSiblingTextNodes(v.children)}}return adjusted}function hydrate(logLevel,mountPoint,vtree,context,drawingContext){if(!vtree||!mountPoint)return false;if(mountPoint.nodeType===3)return false;if(!walk(logLevel,vtree,context.firstChild(mountPoint),context,drawingContext)){if(logLevel){console.warn("[DEBUG_HYDRATE] Could not copy DOM into virtual DOM, falling back to diff")}while(context.firstChild(mountPoint))drawingContext.removeChild(mountPoint,context.lastChild(mountPoint));return false}else{if(logLevel){console.info("[DEBUG_HYDRATE] Successfully prerendered page")}}return true}function diagnoseError(logLevel,vtree,node){if(logLevel)console.warn("[DEBUG_HYDRATE] VTree differed from node",vtree,node)}function nextAfter(tree,current){const lastRef=getLastDOMRef(tree);return lastRef?lastRef.nextSibling:current}function walk(logLevel,vtree,node,context,drawingContext){switch(vtree.type){case 0:let mounted=vtree.mount(node.parentNode);vtree.componentId=mounted.componentId;vtree.child=mounted.componentTree;mounted.componentTree.parent=vtree;if(!walk(logLevel,vtree.child,node,context,drawingContext)){return false}break;case 3:vtree.children=collapseSiblingTextNodes(vtree.children);for(const child of vtree.children){if(!node){diagnoseError(logLevel,child,null);return false}if(!walk(logLevel,child,node,context,drawingContext))return false;node=nextAfter(child,node)}break;case 2:if(node.nodeType!==3||vtree.text.trim()!==node.textContent.trim()){diagnoseError(logLevel,vtree,node);return false}vtree.domRef=node;break;case 1:if(node.nodeType!==1){diagnoseError(logLevel,vtree,node);return false}vtree.domRef=node;vtree.children=collapseSiblingTextNodes(vtree.children);callCreated(node,vtree,drawingContext);let domCursor=node.firstChild;for(var i=0;i<vtree.children.length;i++){const vdomChild=vtree.children[i];if(!domCursor){diagnoseError(logLevel,vdomChild,null);return false}if(!walk(logLevel,vdomChild,domCursor,context,drawingContext)){return false}domCursor=nextAfter(vdomChild,domCursor)}break}return true}function bts(){"background only"}function buildStack(root,target,ctx){const stack=[];while(!ctx.isEqual(root,target)){const nid=__GetConfig(target)?.nodeId;if(nid!==undefined)stack.unshift(nid);const parent=ctx.parentNode(target);if(parent){target=parent}else{return stack}}return stack}function nextNodeId(){return globalThis["nodeId"]++}var listStates=new Map;var mainThreadKeys=new Map;var directBindings=new Map;function destroyNodeEvents(node,nodeId){const direct=directBindings.get(nodeId);if(direct){for(const name of direct)__AddEvent(node,"catchEvent",name,undefined);directBindings.delete(nodeId)}mainThreadKeys.delete(nodeId)}function nodeIdOf(node){return __GetConfig(node)?.nodeId}function listStateOf(parent){return listStates.get(__GetElementUniqueID(parent))}function commitListInfo(st){const cur=st.items.length;if(cur===st.known)return;const insertAction=[];const removeAction=[];if(cur>st.known){for(let i=st.known;i<cur;i++){const el=st.items[i];const itemKey=__GetAttributeByName(el,"item-key");const reuseId=__GetAttributeByName(el,"reuse-identifier");const action={position:i,type:"list-item","item-key":itemKey};if(reuseId!=null)action["reuse-identifier"]=reuseId;insertAction.push(action)}}else{for(let i=st.known-1;i>=cur;i--)removeAction.push({position:i})}__SetAttribute(st.node,"update-list-info",{insertAction,removeAction});st.known=cur}function routeEvent(e,name,capture,mount,ctx){const target=ctx.getTarget(e);const phase=capture?"captures":"bubbles";const chain=[];for(let node=target;node;node=ctx.parentNode(node)){chain.push(node);if(ctx.isEqual(node,mount))break}const order=capture?chain.slice().reverse():chain;const other=phase==="bubbles"?"captures":"bubbles";let fired=false;for(const node of order){const nid=nodeIdOf(node);const reg=nid!==undefined?mainThreadKeys.get(nid):undefined;const entry=reg?reg[phase]?.[name]??reg[other]?.[name]:undefined;if(!entry)continue;fired=true;if(entry.options.preventDefault&&e.preventDefault)e.preventDefault();globalThis["runtime"]["dispatchMainThreadEvent"]({componentId:entry.componentId,staticKey:entry.staticKey,event:e,target:node});if(entry.options.stopPropagation)break}if(!fired){const jsContext=lynx.getJSContext();const stack=buildStack(mount,target,ctx);const msg={event:e,stack,type:"processEvent"};jsContext.dispatchEvent({type:"Miso.events",data:msg})}}var eventContext2={delegator:(mount,events,_getVTree,_debug,ctx)=>{for(const{name,capture}of events){ctx.addEventListener(mount,name,(event)=>{const evts=Array.isArray(event)?event:[event];for(const e of evts)routeEvent(e,name,capture,mount,ctx)},capture,null)}},addEventListener:(mount,event,listener,capture)=>{const eventType=capture?"capture-catch":"catchEvent";return __AddEvent(mount,eventType,event,{type:"worklet",value:listener})},isEqual:(x,y)=>{return __ElementIsEqual(x,y)},getTarget:(e)=>{return e.target.elementRefptr},parentNode:(node)=>{return __GetParent(node)}};var drawingContext2={addClass:(className,domRef)=>{__AddClass(domRef,className)},removeClass:(className,domRef)=>{const classes=__GetClasses(domRef);if(classes.includes(className)){const updated=classes.filter((x)=>x!==className);__SetClasses(domRef,updated.join(" "))}},addEvent:(node,name,key)=>{if(key.direct){__AddEvent(node,"catchEvent",name,{type:"worklet",value:(event)=>{const evts=Array.isArray(event)?event:[event];for(const e of evts)routeEvent(e,name,false,globalThis["page"],eventContext2)}});const directId=nodeIdOf(node);if(directId!==undefined){const set=directBindings.get(directId)??new Set;set.add(name);directBindings.set(directId,set)}}if(key.staticKey===undefined)return;const nodeId=nodeIdOf(node);if(nodeId===undefined){console.error("[miso mts] REG SKIPPED (no nodeId on node) name="+name);return}const reg=mainThreadKeys.get(nodeId)??{captures:{},bubbles:{}};const phase=key.capture?"captures":"bubbles";reg[phase][name]={staticKey:key.staticKey,componentId:key.componentId,options:key.options};mainThreadKeys.set(nodeId,reg)},removeEvent:(node,name,capture)=>{const nodeId=nodeIdOf(node);const reg=nodeId!==undefined?mainThreadKeys.get(nodeId):undefined;if(!reg)return;const phase=capture?"captures":"bubbles";delete reg[phase][name]},nextSibling:(x)=>{let sibling=x.nextSibling;while(sibling){switch(sibling.type){case 0:case 3:{const ref=getDOMRef(sibling);if(ref)return ref;sibling=sibling.nextSibling;break}default:return sibling.domRef}}return null},createTextNode:(s)=>{const node=__CreateRawText(s);__SetCSSId([node],0);if(globalThis["initialDraw"]){const nodeId=nextNodeId();globalThis["runtime"]["nodes"][nodeId]=node;__SetConfig(node,{nodeId})}return node},createElementNS:(_ns,tag)=>{return drawingContext2.createElement(tag)},createElement:(tag)=>{var pageId=globalThis["native"]["currentPageId"];var node=undefined;switch(tag){case"view":node=__CreateView(pageId);break;case"scroll-view":node=__CreateScrollView(pageId);break;case"text":node=__CreateText(pageId);break;case"list":{node=__CreateList(pageId,(list,listID,cellIndex,opId)=>{const st=listStates.get(__GetElementUniqueID(list));const root=st&&st.items[cellIndex];if(!root)return;__AppendElement(list,root);const sign=__GetElementUniqueID(root);__FlushElementTree(root,{triggerLayout:true,operationID:opId,elementID:sign,listID});return sign},()=>{},null);listStates.set(__GetElementUniqueID(node),{node,items:[],known:0});break}case"image":node=__CreateImage(pageId);break;case"frame":node=__CreateFrame(pageId);break;default:node=__CreateElement(tag,pageId);break}if(!node){console.error('[createElement]: native creator returned nil for tag "'+tag+'" — falling back to <view>');node=__CreateView(pageId)}__SetCSSId([node],0);if(globalThis["initialDraw"]){const nodeId=nextNodeId();globalThis["runtime"]["nodes"][nodeId]=node;__SetConfig(node,{nodeId})}return node},appendChild:(parent,child)=>{const st=listStateOf(parent);if(st){st.items.push(child);return child}return __AppendElement(parent,child)},replaceChild:(parent,n,o)=>{return __ReplaceElements(parent,[n],[o])},removeChild:(parent,child)=>{const st=listStateOf(parent);if(st){const i=st.items.indexOf(child);if(i>=0)st.items.splice(i,1);return child}listStates.delete(__GetElementUniqueID(child));return __RemoveElement(parent,child)},insertBefore:(parent,child,node)=>{const st=listStateOf(parent);if(st){const i=st.items.indexOf(node);if(i<0)st.items.push(child);else st.items.splice(i,0,child);return child}return __InsertElementBefore(parent,child,node)},swapDOMRefs:(a,b,p)=>{return __SwapElement(a,b)},setAttribute:(node,key,value)=>{if(key==="id")return __SetID(node,value);return __SetAttribute(node,key,value)},removeAttribute:(node,key)=>{return __SetAttribute(node,key,null)},setAttributeNS:(node,ns,key,value)=>{return __SetAttribute(node,key,value)},setTextContent:(node,text)=>{return __SetAttribute(node,"text",text)},setInlineStyle:(cCss,nCss,node)=>{if(cCss!=nCss)return __SetInlineStyles(node,nCss)},flush:()=>{for(const st of listStates.values())commitListInfo(st);return __FlushElementTree()},getRoot:()=>{return globalThis["page"]},getHead:()=>{return null}};function mts(){const page=__CreatePage("0",0);const pageId=__GetElementUniqueID(page);__SetCSSId([page],0);globalThis["native"]["currentPageId"]=pageId;globalThis["page"]=page;globalThis["document"]={};globalThis["document"]["body"]=page;initMainThreadProcessing()}function initMainThreadProcessing(){const context=lynx.getJSContext();const runtime={nodes:{}};runtime.nodes[0]=globalThis["page"];globalThis["runtime"]=runtime;context.addEventListener("Miso.patches",(messages)=>{for(const m of messages.data){processMessage(m,runtime)}if(messages.data.length>0){drawingContext2.flush()}})}function processMessage(m,runtime){let node=null;switch(m.type){case"createElement":node=drawingContext2.createElement(m.tag);__SetConfig(node,{nodeId:m.nodeId});runtime.nodes[m.nodeId]=node;break;case"createTextNode":node=drawingContext2.createTextNode(m.text);__SetConfig(node,{nodeId:m.nodeId});runtime.nodes[m.nodeId]=node;break;case"createElementNS":node=drawingContext2.createElementNS(m.namespace,m.tag);__SetConfig(node,{nodeId:m.nodeId});runtime.nodes[m.nodeId]=node;break;case"swapDOMRefs":drawingContext2.swapDOMRefs(runtime.nodes[m.nodeA],runtime.nodes[m.nodeB],runtime.nodes[m.parent]);break;case"insertBefore":drawingContext2.insertBefore(runtime.nodes[m.parent],runtime.nodes[m.node],runtime.nodes[m.child]);break;case"setAttribute":drawingContext2.setAttribute(runtime.nodes[m.nodeId],m.key,m.value);break;case"setAttributeNS":drawingContext2.setAttributeNS(runtime.nodes[m.nodeId],m.namespace,m.key,m.value);break;case"setTextContent":drawingContext2.setTextContent(runtime.nodes[m.nodeId],m.text);break;case"appendChild":drawingContext2.appendChild(runtime.nodes[m.parent],runtime.nodes[m.child]);break;case"removeChild":{const removed=runtime.nodes[m.child];drawingContext2.removeChild(runtime.nodes[m.parent],removed);dropChildren(runtime.nodes,removed);break}case"replaceChild":{const replaced=runtime.nodes[m.current];drawingContext2.replaceChild(runtime.nodes[m.parent],runtime.nodes[m.new],replaced);dropChildren(runtime.nodes,replaced);break}case"removeAttribute":drawingContext2.removeAttribute(runtime.nodes[m.nodeId],m.key);break;case"setInlineStyle":drawingContext2.setInlineStyle(m.current,m.new,runtime.nodes[m.nodeId]);break;case"addClass":drawingContext2.addClass(m.key,runtime.nodes[m.nodeId]);break;case"removeClass":drawingContext2.removeClass(m.key,runtime.nodes[m.nodeId]);break;case"addEvent":drawingContext2.addEvent(runtime.nodes[m.nodeId],m.name,{capture:m.capture,staticKey:m.staticKey,componentId:m.componentId,options:m.options,direct:m.direct});break;case"removeEvent":drawingContext2.removeEvent(runtime.nodes[m.nodeId],m.name,m.capture);break;case"flush":drawingContext2.flush();break;default:console.error("Unknown message received",m);break}}function dropChildren(nodeMap,node){const nodeId=__GetConfig(node)?.nodeId;if(nodeId!==undefined){delete nodeMap[nodeId];destroyNodeEvents(node,nodeId)}for(let child=__FirstElement(node);child;child=__NextElement(child)){dropChildren(nodeMap,child)}}function nextNodeId2(){"background only";return globalThis["nodeId"]++}function addPatch(patch2){"background only";globalThis["patches"].push(patch2)}var eventContext3={delegator:(mount,events,getVTree,debug,eventContext4)=>{const context=lynx.getCoreContext();if(!context)return;context.addEventListener("Miso.events",(m)=>{let stack=m.data.stack.map(function(x){return{nodeId:x}});getVTree((vtree)=>{return delegateEvent(m.data.event,vtree,stack,debug,eventContext4)})})},addEventListener:(mount,event,listener,capture)=>{return},isEqual:(x,y)=>{return x.nodeId===y.nodeId},getTarget:(_)=>{return{nodeId:0}},parentNode:(_)=>{return{nodeId:0}}};var drawingContext3={addClass:(key,n)=>{let patch2={type:"addClass",nodeId:n.nodeId,key};addPatch(patch2);return},removeClass:(key,n)=>{const patch2={type:"removeClass",nodeId:n.nodeId,key};addPatch(patch2);return},addEvent:(n,name,key)=>{const patch2={type:"addEvent",nodeId:n.nodeId,name,capture:key.capture,staticKey:key.staticKey,componentId:key.componentId,options:key.options,direct:key.direct};addPatch(patch2);return},removeEvent:(n,name,capture)=>{const patch2={type:"removeEvent",nodeId:n.nodeId,name,capture};addPatch(patch2);return},nextSibling:(x)=>{let sibling=x.nextSibling;while(sibling){switch(sibling.type){case 0:case 3:{const ref=getDOMRef(sibling);if(ref)return ref;sibling=sibling.nextSibling;break}default:return sibling.domRef}}return null},createTextNode:(text)=>{const nodeId=nextNodeId2();addPatch({type:"createTextNode",text,nodeId});return{nodeId}},createElementNS:(ns,tag)=>{const nodeId=nextNodeId2();let patch2={type:"createElementNS",namespace:ns,nodeId,tag};addPatch(patch2);return{nodeId}},createElement:(tag)=>{const nodeId=nextNodeId2();let patch2={type:"createElement",nodeId,tag};addPatch(patch2);return{nodeId}},appendChild:(parent,child)=>{let patch2={type:"appendChild",parent:parent.nodeId,child:child.nodeId};addPatch(patch2);return},replaceChild:(parent,n,current)=>{let patch2={type:"replaceChild",parent:parent.nodeId,new:n.nodeId,current:current.nodeId};addPatch(patch2);return},removeChild:(parent,child)=>{let patch2={type:"removeChild",parent:parent.nodeId,child:child.nodeId};addPatch(patch2);return},insertBefore:(parent,node,child)=>{if(child===null){drawingContext3.appendChild(parent,node);return}let patch2={type:"insertBefore",parent:parent.nodeId,child:child.nodeId,node:node.nodeId};addPatch(patch2);return},swapDOMRefs:(nodeA,nodeB,parent)=>{let patch2={type:"swapDOMRefs",parent:parent.nodeId,nodeA:nodeA.nodeId,nodeB:nodeB.nodeId};addPatch(patch2);return},setAttribute:(n,key,value)=>{let patch2={type:"setAttribute",nodeId:n.nodeId,key,value};addPatch(patch2);return},removeAttribute:(n,key)=>{let patch2={type:"removeAttribute",nodeId:n.nodeId,key};addPatch(patch2);return},setAttributeNS:(n,namespace,key,value)=>{let patch2={type:"setAttributeNS",nodeId:n.nodeId,key,value,namespace};addPatch(patch2);return},setTextContent:(n,text)=>{const patch2={type:"setTextContent",nodeId:n.nodeId,text};addPatch(patch2);return},setInlineStyle:(cCss,nCss,node)=>{if(areEqual(cCss,nCss))return;let patch2={type:"setInlineStyle",nodeId:node.nodeId,new:nCss,current:cCss};addPatch(patch2);return},flush:()=>{const patches=globalThis["patches"];if(!globalThis["initialDraw"]&&patches.length>0){const context=lynx.getCoreContext();if(context)context.dispatchEvent({type:"Miso.patches",data:patches})}globalThis["patches"]=[]},getHead:function(){return null},getRoot:function(){return{nodeId:0}}};function areEqual(a,b){"background only";const keysA=Object.keys(a);const keysB=Object.keys(b);if(keysA.length!==keysB.length)return false;return keysA.every((key)=>a[key]===b[key])}globalThis["TextEncoder"]=import_text_encoding.TextEncoder;globalThis["TextDecoder"]=import_text_encoding.TextDecoder;globalThis["BigInt"]=import_jsbi.default.BigInt;globalThis["JSBI"]=import_jsbi.default;if(typeof globalThis["fetch"]==="undefined"){globalThis["fetch"]=(input,init)=>globalThis["lynx"].fetch(input,init)}try{if(typeof lynx["reportError"]==="function"){const report=(msg)=>{try{lynx.reportError(new Error(msg))}catch(_e){}};const origError=console.error.bind(console);console.error=(...args)=>{origError(...args);if(globalThis["debug"])report("[miso] "+args.map((a)=>{try{return String(a)}catch(_e){return"<?>"}}).join(" "))}}}catch(_e){}globalThis["nodeId"]=1;globalThis["initialDraw"]=true;var drawingContext4=onBTS()?drawingContext3:drawingContext2;var eventContext4=onBTS()?eventContext3:eventContext2;globalThis["native"]={drawingContext:drawingContext4,eventContext:eventContext4,currentPageId:undefined};globalThis["miso"]={drawingContext:drawingContext4,eventContext:eventContext4,diff,hydrate,version,onBTS,onMTS,callBlur,callFocus,callSelect,callSetSelectionRange,eventJSON,fetchCore,eventSourceConnect,eventSourceClose,websocketConnect,websocketClose,websocketSend,updateRef,inline,typeOf,mathRandom,getRandomValues,splitmix32,populateClass,delegateEvent,cookieGet,cookieGetAll,cookieSet,cookieDelete,cookieDeleteWith,delegator:eventContext4.delegator,setDrawingContext:function(name){const drawing=globalThis[name]["drawingContext"];const events=globalThis[name]["eventContext"];if(!drawing)console.error('"drawingContext" not defined at globalThis['+name+"].drawingContext");if(!events)console.error('"eventContext" not defined at globalThis['+name+"].eventContext");globalThis["miso"]["drawingContext"]=drawing;globalThis["miso"]["eventContext"]=events}};globalThis["invokeExec"]=function(selector,method,params,success,fail){if(typeof lynx.createSelectorQuery!=="function")return;const args={params,method,success,fail};return lynx.createSelectorQuery().select(selector).invoke(args).exec()};if(onBTS()){globalThis["lynx"]=lynx;globalThis["patches"]=[];bts()}else{globalThis["renderPage"]=()=>mts();globalThis["runWorklet"]=(worklet,params)=>worklet(params)}if(typeof lynx!=="undefined"){globalThis["requestAnimationFrame"]=lynx["requestAnimationFrame"];globalThis["cancelAnimationFrame"]=lynx["cancelAnimationFrame"]}globalThis["processData"]=()=>{};
diff --git a/js/miso-native.prod.js b/js/miso-native.prod.js
new file mode 100644
--- /dev/null
+++ b/js/miso-native.prod.js
@@ -0,0 +1,3 @@
+var sY=Object.create;var{getPrototypeOf:rY,defineProperty:DY,getOwnPropertyNames:iY}=Object;var oY=Object.prototype.hasOwnProperty;function nY(Q){return this[Q]}var tY,eY,EY=(Q,Z,z)=>{var X=Q!=null&&typeof Q==="object";if(X){var N=Z?tY??=new WeakMap:eY??=new WeakMap,S=N.get(Q);if(S)return S}z=Q!=null?sY(rY(Q)):{};let O=Z||!Q||!Q.__esModule?DY(z,"default",{value:Q,enumerable:!0}):z;for(let B of iY(Q))if(!oY.call(O,B))DY(O,B,{get:nY.bind(Q,B),enumerable:!0});if(X)N.set(Q,O);return O};var yQ=(Q,Z)=>()=>(Z||Q((Z={exports:{}}).exports,Z),Z.exports);var RY=yQ((OY,hQ)=>{(function(Q){if(typeof hQ<"u"&&hQ.exports)hQ.exports=Q;Q["encoding-indexes"]={big5:[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,17392,19506,17923,17830,17784,160359,19831,17843,162993,19682,163013,15253,18230,18244,19527,19520,148159,144919,160594,159371,159954,19543,172881,18255,17882,19589,162924,19719,19108,18081,158499,29221,154196,137827,146950,147297,26189,22267,null,32149,22813,166841,15860,38708,162799,23515,138590,23204,13861,171696,23249,23479,23804,26478,34195,170309,29793,29853,14453,138579,145054,155681,16108,153822,15093,31484,40855,147809,166157,143850,133770,143966,17162,33924,40854,37935,18736,34323,22678,38730,37400,31184,31282,26208,27177,34973,29772,31685,26498,31276,21071,36934,13542,29636,155065,29894,40903,22451,18735,21580,16689,145038,22552,31346,162661,35727,18094,159368,16769,155033,31662,140476,40904,140481,140489,140492,40905,34052,144827,16564,40906,17633,175615,25281,28782,40907,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,12736,12737,12738,12739,12740,131340,12741,131281,131277,12742,12743,131275,139240,12744,131274,12745,12746,12747,12748,131342,12749,12750,256,193,461,192,274,201,282,200,332,211,465,210,null,7870,null,7872,202,257,225,462,224,593,275,233,283,232,299,237,464,236,333,243,466,242,363,250,468,249,470,472,474,476,252,null,7871,null,7873,234,609,9178,9179,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,172969,135493,null,25866,null,null,20029,28381,40270,37343,null,null,161589,25745,20250,20264,20392,20822,20852,20892,20964,21153,21160,21307,21326,21457,21464,22242,22768,22788,22791,22834,22836,23398,23454,23455,23706,24198,24635,25993,26622,26628,26725,27982,28860,30005,32420,32428,32442,32455,32463,32479,32518,32567,33402,33487,33647,35270,35774,35810,36710,36711,36718,29713,31996,32205,26950,31433,21031,null,null,null,null,37260,30904,37214,32956,null,36107,33014,133607,null,null,32927,40647,19661,40393,40460,19518,171510,159758,40458,172339,13761,null,28314,33342,29977,null,18705,39532,39567,40857,31111,164972,138698,132560,142054,20004,20097,20096,20103,20159,20203,20279,13388,20413,15944,20483,20616,13437,13459,13477,20870,22789,20955,20988,20997,20105,21113,21136,21287,13767,21417,13649,21424,13651,21442,21539,13677,13682,13953,21651,21667,21684,21689,21712,21743,21784,21795,21800,13720,21823,13733,13759,21975,13765,163204,21797,null,134210,134421,151851,21904,142534,14828,131905,36422,150968,169189,16467,164030,30586,142392,14900,18389,164189,158194,151018,25821,134524,135092,134357,135412,25741,36478,134806,134155,135012,142505,164438,148691,null,134470,170573,164073,18420,151207,142530,39602,14951,169460,16365,13574,152263,169940,161992,142660,40302,38933,null,17369,155813,25780,21731,142668,142282,135287,14843,135279,157402,157462,162208,25834,151634,134211,36456,139681,166732,132913,null,18443,131497,16378,22643,142733,null,148936,132348,155799,134988,134550,21881,16571,17338,null,19124,141926,135325,33194,39157,134556,25465,14846,141173,36288,22177,25724,15939,null,173569,134665,142031,142537,null,135368,145858,14738,14854,164507,13688,155209,139463,22098,134961,142514,169760,13500,27709,151099,null,null,161140,142987,139784,173659,167117,134778,134196,157724,32659,135375,141315,141625,13819,152035,134796,135053,134826,16275,134960,134471,135503,134732,null,134827,134057,134472,135360,135485,16377,140950,25650,135085,144372,161337,142286,134526,134527,142417,142421,14872,134808,135367,134958,173618,158544,167122,167321,167114,38314,21708,33476,21945,null,171715,39974,39606,161630,142830,28992,33133,33004,23580,157042,33076,14231,21343,164029,37302,134906,134671,134775,134907,13789,151019,13833,134358,22191,141237,135369,134672,134776,135288,135496,164359,136277,134777,151120,142756,23124,135197,135198,135413,135414,22428,134673,161428,164557,135093,134779,151934,14083,135094,135552,152280,172733,149978,137274,147831,164476,22681,21096,13850,153405,31666,23400,18432,19244,40743,18919,39967,39821,154484,143677,22011,13810,22153,20008,22786,138177,194680,38737,131206,20059,20155,13630,23587,24401,24516,14586,25164,25909,27514,27701,27706,28780,29227,20012,29357,149737,32594,31035,31993,32595,156266,13505,null,156491,32770,32896,157202,158033,21341,34916,35265,161970,35744,36125,38021,38264,38271,38376,167439,38886,39029,39118,39134,39267,170000,40060,40479,40644,27503,63751,20023,131207,38429,25143,38050,null,20539,28158,171123,40870,15817,34959,147790,28791,23797,19232,152013,13657,154928,24866,166450,36775,37366,29073,26393,29626,144001,172295,15499,137600,19216,30948,29698,20910,165647,16393,27235,172730,16931,34319,133743,31274,170311,166634,38741,28749,21284,139390,37876,30425,166371,40871,30685,20131,20464,20668,20015,20247,40872,21556,32139,22674,22736,138678,24210,24217,24514,141074,25995,144377,26905,27203,146531,27903,null,29184,148741,29580,16091,150035,23317,29881,35715,154788,153237,31379,31724,31939,32364,33528,34199,40873,34960,40874,36537,40875,36815,34143,39392,37409,40876,167353,136255,16497,17058,23066,null,null,null,39016,26475,17014,22333,null,34262,149883,33471,160013,19585,159092,23931,158485,159678,40877,40878,23446,40879,26343,32347,28247,31178,15752,17603,143958,141206,17306,17718,null,23765,146202,35577,23672,15634,144721,23928,40882,29015,17752,147692,138787,19575,14712,13386,131492,158785,35532,20404,131641,22975,33132,38998,170234,24379,134047,null,139713,166253,16642,18107,168057,16135,40883,172469,16632,14294,18167,158790,16764,165554,160767,17773,14548,152730,17761,17691,19849,19579,19830,17898,16328,150287,13921,17630,17597,16877,23870,23880,23894,15868,14351,23972,23993,14368,14392,24130,24253,24357,24451,14600,14612,14655,14669,24791,24893,23781,14729,25015,25017,25039,14776,25132,25232,25317,25368,14840,22193,14851,25570,25595,25607,25690,14923,25792,23829,22049,40863,14999,25990,15037,26111,26195,15090,26258,15138,26390,15170,26532,26624,15192,26698,26756,15218,15217,15227,26889,26947,29276,26980,27039,27013,15292,27094,15325,27237,27252,27249,27266,15340,27289,15346,27307,27317,27348,27382,27521,27585,27626,27765,27818,15563,27906,27910,27942,28033,15599,28068,28081,28181,28184,28201,28294,166336,28347,28386,28378,40831,28392,28393,28452,28468,15686,147265,28545,28606,15722,15733,29111,23705,15754,28716,15761,28752,28756,28783,28799,28809,131877,17345,13809,134872,147159,22462,159443,28990,153568,13902,27042,166889,23412,31305,153825,169177,31333,31357,154028,31419,31408,31426,31427,29137,156813,16842,31450,31453,31466,16879,21682,154625,31499,31573,31529,152334,154878,31650,31599,33692,154548,158847,31696,33825,31634,31672,154912,15789,154725,33938,31738,31750,31797,154817,31812,31875,149634,31910,26237,148856,31945,31943,31974,31860,31987,31989,31950,32359,17693,159300,32093,159446,29837,32137,32171,28981,32179,32210,147543,155689,32228,15635,32245,137209,32229,164717,32285,155937,155994,32366,32402,17195,37996,32295,32576,32577,32583,31030,156368,39393,32663,156497,32675,136801,131176,17756,145254,17667,164666,32762,156809,32773,32776,32797,32808,32815,172167,158915,32827,32828,32865,141076,18825,157222,146915,157416,26405,32935,166472,33031,33050,22704,141046,27775,156824,151480,25831,136330,33304,137310,27219,150117,150165,17530,33321,133901,158290,146814,20473,136445,34018,33634,158474,149927,144688,137075,146936,33450,26907,194964,16859,34123,33488,33562,134678,137140,14017,143741,144730,33403,33506,33560,147083,159139,158469,158615,144846,15807,33565,21996,33669,17675,159141,33708,33729,33747,13438,159444,27223,34138,13462,159298,143087,33880,154596,33905,15827,17636,27303,33866,146613,31064,33960,158614,159351,159299,34014,33807,33681,17568,33939,34020,154769,16960,154816,17731,34100,23282,159385,17703,34163,17686,26559,34326,165413,165435,34241,159880,34306,136578,159949,194994,17770,34344,13896,137378,21495,160666,34430,34673,172280,34798,142375,34737,34778,34831,22113,34412,26710,17935,34885,34886,161248,146873,161252,34910,34972,18011,34996,34997,25537,35013,30583,161551,35207,35210,35238,35241,35239,35260,166437,35303,162084,162493,35484,30611,37374,35472,162393,31465,162618,147343,18195,162616,29052,35596,35615,152624,152933,35647,35660,35661,35497,150138,35728,35739,35503,136927,17941,34895,35995,163156,163215,195028,14117,163155,36054,163224,163261,36114,36099,137488,36059,28764,36113,150729,16080,36215,36265,163842,135188,149898,15228,164284,160012,31463,36525,36534,36547,37588,36633,36653,164709,164882,36773,37635,172703,133712,36787,18730,166366,165181,146875,24312,143970,36857,172052,165564,165121,140069,14720,159447,36919,165180,162494,36961,165228,165387,37032,165651,37060,165606,37038,37117,37223,15088,37289,37316,31916,166195,138889,37390,27807,37441,37474,153017,37561,166598,146587,166668,153051,134449,37676,37739,166625,166891,28815,23235,166626,166629,18789,37444,166892,166969,166911,37747,37979,36540,38277,38310,37926,38304,28662,17081,140922,165592,135804,146990,18911,27676,38523,38550,16748,38563,159445,25050,38582,30965,166624,38589,21452,18849,158904,131700,156688,168111,168165,150225,137493,144138,38705,34370,38710,18959,17725,17797,150249,28789,23361,38683,38748,168405,38743,23370,168427,38751,37925,20688,143543,143548,38793,38815,38833,38846,38848,38866,38880,152684,38894,29724,169011,38911,38901,168989,162170,19153,38964,38963,38987,39014,15118,160117,15697,132656,147804,153350,39114,39095,39112,39111,19199,159015,136915,21936,39137,39142,39148,37752,39225,150057,19314,170071,170245,39413,39436,39483,39440,39512,153381,14020,168113,170965,39648,39650,170757,39668,19470,39700,39725,165376,20532,39732,158120,14531,143485,39760,39744,171326,23109,137315,39822,148043,39938,39935,39948,171624,40404,171959,172434,172459,172257,172323,172511,40318,40323,172340,40462,26760,40388,139611,172435,172576,137531,172595,40249,172217,172724,40592,40597,40606,40610,19764,40618,40623,148324,40641,15200,14821,15645,20274,14270,166955,40706,40712,19350,37924,159138,40727,40726,40761,22175,22154,40773,39352,168075,38898,33919,40802,40809,31452,40846,29206,19390,149877,149947,29047,150008,148296,150097,29598,166874,137466,31135,166270,167478,37737,37875,166468,37612,37761,37835,166252,148665,29207,16107,30578,31299,28880,148595,148472,29054,137199,28835,137406,144793,16071,137349,152623,137208,14114,136955,137273,14049,137076,137425,155467,14115,136896,22363,150053,136190,135848,136134,136374,34051,145062,34051,33877,149908,160101,146993,152924,147195,159826,17652,145134,170397,159526,26617,14131,15381,15847,22636,137506,26640,16471,145215,147681,147595,147727,158753,21707,22174,157361,22162,135135,134056,134669,37830,166675,37788,20216,20779,14361,148534,20156,132197,131967,20299,20362,153169,23144,131499,132043,14745,131850,132116,13365,20265,131776,167603,131701,35546,131596,20120,20685,20749,20386,20227,150030,147082,20290,20526,20588,20609,20428,20453,20568,20732,20825,20827,20829,20830,28278,144789,147001,147135,28018,137348,147081,20904,20931,132576,17629,132259,132242,132241,36218,166556,132878,21081,21156,133235,21217,37742,18042,29068,148364,134176,149932,135396,27089,134685,29817,16094,29849,29716,29782,29592,19342,150204,147597,21456,13700,29199,147657,21940,131909,21709,134086,22301,37469,38644,37734,22493,22413,22399,13886,22731,23193,166470,136954,137071,136976,23084,22968,37519,23166,23247,23058,153926,137715,137313,148117,14069,27909,29763,23073,155267,23169,166871,132115,37856,29836,135939,28933,18802,37896,166395,37821,14240,23582,23710,24158,24136,137622,137596,146158,24269,23375,137475,137476,14081,137376,14045,136958,14035,33066,166471,138682,144498,166312,24332,24334,137511,137131,23147,137019,23364,34324,161277,34912,24702,141408,140843,24539,16056,140719,140734,168072,159603,25024,131134,131142,140827,24985,24984,24693,142491,142599,149204,168269,25713,149093,142186,14889,142114,144464,170218,142968,25399,173147,25782,25393,25553,149987,142695,25252,142497,25659,25963,26994,15348,143502,144045,149897,144043,21773,144096,137433,169023,26318,144009,143795,15072,16784,152964,166690,152975,136956,152923,152613,30958,143619,137258,143924,13412,143887,143746,148169,26254,159012,26219,19347,26160,161904,138731,26211,144082,144097,26142,153714,14545,145466,145340,15257,145314,144382,29904,15254,26511,149034,26806,26654,15300,27326,14435,145365,148615,27187,27218,27337,27397,137490,25873,26776,27212,15319,27258,27479,147392,146586,37792,37618,166890,166603,37513,163870,166364,37991,28069,28427,149996,28007,147327,15759,28164,147516,23101,28170,22599,27940,30786,28987,148250,148086,28913,29264,29319,29332,149391,149285,20857,150180,132587,29818,147192,144991,150090,149783,155617,16134,16049,150239,166947,147253,24743,16115,29900,29756,37767,29751,17567,159210,17745,30083,16227,150745,150790,16216,30037,30323,173510,15129,29800,166604,149931,149902,15099,15821,150094,16127,149957,149747,37370,22322,37698,166627,137316,20703,152097,152039,30584,143922,30478,30479,30587,149143,145281,14942,149744,29752,29851,16063,150202,150215,16584,150166,156078,37639,152961,30750,30861,30856,30930,29648,31065,161601,153315,16654,31131,33942,31141,27181,147194,31290,31220,16750,136934,16690,37429,31217,134476,149900,131737,146874,137070,13719,21867,13680,13994,131540,134157,31458,23129,141045,154287,154268,23053,131675,30960,23082,154566,31486,16889,31837,31853,16913,154547,155324,155302,31949,150009,137136,31886,31868,31918,27314,32220,32263,32211,32590,156257,155996,162632,32151,155266,17002,158581,133398,26582,131150,144847,22468,156690,156664,149858,32733,31527,133164,154345,154947,31500,155150,39398,34373,39523,27164,144447,14818,150007,157101,39455,157088,33920,160039,158929,17642,33079,17410,32966,33033,33090,157620,39107,158274,33378,33381,158289,33875,159143,34320,160283,23174,16767,137280,23339,137377,23268,137432,34464,195004,146831,34861,160802,23042,34926,20293,34951,35007,35046,35173,35149,153219,35156,161669,161668,166901,166873,166812,166393,16045,33955,18165,18127,14322,35389,35356,169032,24397,37419,148100,26068,28969,28868,137285,40301,35999,36073,163292,22938,30659,23024,17262,14036,36394,36519,150537,36656,36682,17140,27736,28603,140065,18587,28537,28299,137178,39913,14005,149807,37051,37015,21873,18694,37307,37892,166475,16482,166652,37927,166941,166971,34021,35371,38297,38311,38295,38294,167220,29765,16066,149759,150082,148458,16103,143909,38543,167655,167526,167525,16076,149997,150136,147438,29714,29803,16124,38721,168112,26695,18973,168083,153567,38749,37736,166281,166950,166703,156606,37562,23313,35689,18748,29689,147995,38811,38769,39224,134950,24001,166853,150194,38943,169178,37622,169431,37349,17600,166736,150119,166756,39132,166469,16128,37418,18725,33812,39227,39245,162566,15869,39323,19311,39338,39516,166757,153800,27279,39457,23294,39471,170225,19344,170312,39356,19389,19351,37757,22642,135938,22562,149944,136424,30788,141087,146872,26821,15741,37976,14631,24912,141185,141675,24839,40015,40019,40059,39989,39952,39807,39887,171565,39839,172533,172286,40225,19630,147716,40472,19632,40204,172468,172269,172275,170287,40357,33981,159250,159711,158594,34300,17715,159140,159364,159216,33824,34286,159232,145367,155748,31202,144796,144960,18733,149982,15714,37851,37566,37704,131775,30905,37495,37965,20452,13376,36964,152925,30781,30804,30902,30795,137047,143817,149825,13978,20338,28634,28633,28702,28702,21524,147893,22459,22771,22410,40214,22487,28980,13487,147884,29163,158784,151447,23336,137141,166473,24844,23246,23051,17084,148616,14124,19323,166396,37819,37816,137430,134941,33906,158912,136211,148218,142374,148417,22932,146871,157505,32168,155995,155812,149945,149899,166394,37605,29666,16105,29876,166755,137375,16097,150195,27352,29683,29691,16086,150078,150164,137177,150118,132007,136228,149989,29768,149782,28837,149878,37508,29670,37727,132350,37681,166606,166422,37766,166887,153045,18741,166530,29035,149827,134399,22180,132634,134123,134328,21762,31172,137210,32254,136898,150096,137298,17710,37889,14090,166592,149933,22960,137407,137347,160900,23201,14050,146779,14000,37471,23161,166529,137314,37748,15565,133812,19094,14730,20724,15721,15692,136092,29045,17147,164376,28175,168164,17643,27991,163407,28775,27823,15574,147437,146989,28162,28428,15727,132085,30033,14012,13512,18048,16090,18545,22980,37486,18750,36673,166940,158656,22546,22472,14038,136274,28926,148322,150129,143331,135856,140221,26809,26983,136088,144613,162804,145119,166531,145366,144378,150687,27162,145069,158903,33854,17631,17614,159014,159057,158850,159710,28439,160009,33597,137018,33773,158848,159827,137179,22921,23170,137139,23137,23153,137477,147964,14125,23023,137020,14023,29070,37776,26266,148133,23150,23083,148115,27179,147193,161590,148571,148170,28957,148057,166369,20400,159016,23746,148686,163405,148413,27148,148054,135940,28838,28979,148457,15781,27871,194597,150095,32357,23019,23855,15859,24412,150109,137183,32164,33830,21637,146170,144128,131604,22398,133333,132633,16357,139166,172726,28675,168283,23920,29583,31955,166489,168992,20424,32743,29389,29456,162548,29496,29497,153334,29505,29512,16041,162584,36972,29173,149746,29665,33270,16074,30476,16081,27810,22269,29721,29726,29727,16098,16112,16116,16122,29907,16142,16211,30018,30061,30066,30093,16252,30152,30172,16320,30285,16343,30324,16348,30330,151388,29064,22051,35200,22633,16413,30531,16441,26465,16453,13787,30616,16490,16495,23646,30654,30667,22770,30744,28857,30748,16552,30777,30791,30801,30822,33864,152885,31027,26627,31026,16643,16649,31121,31129,36795,31238,36796,16743,31377,16818,31420,33401,16836,31439,31451,16847,20001,31586,31596,31611,31762,31771,16992,17018,31867,31900,17036,31928,17044,31981,36755,28864,134351,32207,32212,32208,32253,32686,32692,29343,17303,32800,32805,31545,32814,32817,32852,15820,22452,28832,32951,33001,17389,33036,29482,33038,33042,30048,33044,17409,15161,33110,33113,33114,17427,22586,33148,33156,17445,33171,17453,33189,22511,33217,33252,33364,17551,33446,33398,33482,33496,33535,17584,33623,38505,27018,33797,28917,33892,24803,33928,17668,33982,34017,34040,34064,34104,34130,17723,34159,34160,34272,17783,34418,34450,34482,34543,38469,34699,17926,17943,34990,35071,35108,35143,35217,162151,35369,35384,35476,35508,35921,36052,36082,36124,18328,22623,36291,18413,20206,36410,21976,22356,36465,22005,36528,18487,36558,36578,36580,36589,36594,36791,36801,36810,36812,36915,39364,18605,39136,37395,18718,37416,37464,37483,37553,37550,37567,37603,37611,37619,37620,37629,37699,37764,37805,18757,18769,40639,37911,21249,37917,37933,37950,18794,37972,38009,38189,38306,18855,38388,38451,18917,26528,18980,38720,18997,38834,38850,22100,19172,24808,39097,19225,39153,22596,39182,39193,20916,39196,39223,39234,39261,39266,19312,39365,19357,39484,39695,31363,39785,39809,39901,39921,39924,19565,39968,14191,138178,40265,39994,40702,22096,40339,40381,40384,40444,38134,36790,40571,40620,40625,40637,40646,38108,40674,40689,40696,31432,40772,131220,131767,132000,26906,38083,22956,132311,22592,38081,14265,132565,132629,132726,136890,22359,29043,133826,133837,134079,21610,194619,134091,21662,134139,134203,134227,134245,134268,24807,134285,22138,134325,134365,134381,134511,134578,134600,26965,39983,34725,134660,134670,134871,135056,134957,134771,23584,135100,24075,135260,135247,135286,26398,135291,135304,135318,13895,135359,135379,135471,135483,21348,33965,135907,136053,135990,35713,136567,136729,137155,137159,20088,28859,137261,137578,137773,137797,138282,138352,138412,138952,25283,138965,139029,29080,26709,139333,27113,14024,139900,140247,140282,141098,141425,141647,33533,141671,141715,142037,35237,142056,36768,142094,38840,142143,38983,39613,142412,null,142472,142519,154600,142600,142610,142775,142741,142914,143220,143308,143411,143462,144159,144350,24497,26184,26303,162425,144743,144883,29185,149946,30679,144922,145174,32391,131910,22709,26382,26904,146087,161367,155618,146961,147129,161278,139418,18640,19128,147737,166554,148206,148237,147515,148276,148374,150085,132554,20946,132625,22943,138920,15294,146687,148484,148694,22408,149108,14747,149295,165352,170441,14178,139715,35678,166734,39382,149522,149755,150037,29193,150208,134264,22885,151205,151430,132985,36570,151596,21135,22335,29041,152217,152601,147274,150183,21948,152646,152686,158546,37332,13427,152895,161330,152926,18200,152930,152934,153543,149823,153693,20582,13563,144332,24798,153859,18300,166216,154286,154505,154630,138640,22433,29009,28598,155906,162834,36950,156082,151450,35682,156674,156746,23899,158711,36662,156804,137500,35562,150006,156808,147439,156946,19392,157119,157365,141083,37989,153569,24981,23079,194765,20411,22201,148769,157436,20074,149812,38486,28047,158909,13848,35191,157593,157806,156689,157790,29151,157895,31554,168128,133649,157990,37124,158009,31301,40432,158202,39462,158253,13919,156777,131105,31107,158260,158555,23852,144665,33743,158621,18128,158884,30011,34917,159150,22710,14108,140685,159819,160205,15444,160384,160389,37505,139642,160395,37680,160486,149968,27705,38047,160848,134904,34855,35061,141606,164979,137137,28344,150058,137248,14756,14009,23568,31203,17727,26294,171181,170148,35139,161740,161880,22230,16607,136714,14753,145199,164072,136133,29101,33638,162269,168360,23143,19639,159919,166315,162301,162314,162571,163174,147834,31555,31102,163849,28597,172767,27139,164632,21410,159239,37823,26678,38749,164207,163875,158133,136173,143919,163912,23941,166960,163971,22293,38947,166217,23979,149896,26046,27093,21458,150181,147329,15377,26422,163984,164084,164142,139169,164175,164233,164271,164378,164614,164655,164746,13770,164968,165546,18682,25574,166230,30728,37461,166328,17394,166375,17375,166376,166726,166868,23032,166921,36619,167877,168172,31569,168208,168252,15863,168286,150218,36816,29327,22155,169191,169449,169392,169400,169778,170193,170313,170346,170435,170536,170766,171354,171419,32415,171768,171811,19620,38215,172691,29090,172799,19857,36882,173515,19868,134300,36798,21953,36794,140464,36793,150163,17673,32383,28502,27313,20202,13540,166700,161949,14138,36480,137205,163876,166764,166809,162366,157359,15851,161365,146615,153141,153942,20122,155265,156248,22207,134765,36366,23405,147080,150686,25566,25296,137206,137339,25904,22061,154698,21530,152337,15814,171416,19581,22050,22046,32585,155352,22901,146752,34672,19996,135146,134473,145082,33047,40286,36120,30267,40005,30286,30649,37701,21554,33096,33527,22053,33074,33816,32957,21994,31074,22083,21526,134813,13774,22021,22001,26353,164578,13869,30004,22000,21946,21655,21874,134209,134294,24272,151880,134774,142434,134818,40619,32090,21982,135285,25245,38765,21652,36045,29174,37238,25596,25529,25598,21865,142147,40050,143027,20890,13535,134567,20903,21581,21790,21779,30310,36397,157834,30129,32950,34820,34694,35015,33206,33820,135361,17644,29444,149254,23440,33547,157843,22139,141044,163119,147875,163187,159440,160438,37232,135641,37384,146684,173737,134828,134905,29286,138402,18254,151490,163833,135147,16634,40029,25887,142752,18675,149472,171388,135148,134666,24674,161187,135149,null,155720,135559,29091,32398,40272,19994,19972,13687,23309,27826,21351,13996,14812,21373,13989,149016,22682,150382,33325,21579,22442,154261,133497,null,14930,140389,29556,171692,19721,39917,146686,171824,19547,151465,169374,171998,33884,146870,160434,157619,145184,25390,32037,147191,146988,14890,36872,21196,15988,13946,17897,132238,30272,23280,134838,30842,163630,22695,16575,22140,39819,23924,30292,173108,40581,19681,30201,14331,24857,143578,148466,null,22109,135849,22439,149859,171526,21044,159918,13741,27722,40316,31830,39737,22494,137068,23635,25811,169168,156469,160100,34477,134440,159010,150242,134513,null,20990,139023,23950,38659,138705,40577,36940,31519,39682,23761,31651,25192,25397,39679,31695,39722,31870,39726,31810,31878,39957,31740,39689,40727,39963,149822,40794,21875,23491,20477,40600,20466,21088,15878,21201,22375,20566,22967,24082,38856,40363,36700,21609,38836,39232,38842,21292,24880,26924,21466,39946,40194,19515,38465,27008,20646,30022,137069,39386,21107,null,37209,38529,37212,null,37201,167575,25471,159011,27338,22033,37262,30074,25221,132092,29519,31856,154657,146685,null,149785,30422,39837,20010,134356,33726,34882,null,23626,27072,20717,22394,21023,24053,20174,27697,131570,20281,21660,21722,21146,36226,13822,24332,13811,null,27474,37244,40869,39831,38958,39092,39610,40616,40580,29050,31508,null,27642,34840,32632,null,22048,173642,36471,40787,null,36308,36431,40476,36353,25218,164733,36392,36469,31443,150135,31294,30936,27882,35431,30215,166490,40742,27854,34774,30147,172722,30803,194624,36108,29410,29553,35629,29442,29937,36075,150203,34351,24506,34976,17591,null,137275,159237,null,35454,140571,null,24829,30311,39639,40260,37742,39823,34805,null,34831,36087,29484,38689,39856,13782,29362,19463,31825,39242,155993,24921,19460,40598,24957,null,22367,24943,25254,25145,25294,14940,25058,21418,144373,25444,26626,13778,23895,166850,36826,167481,null,20697,138566,30982,21298,38456,134971,16485,null,30718,null,31938,155418,31962,31277,32870,32867,32077,29957,29938,35220,33306,26380,32866,160902,32859,29936,33027,30500,35209,157644,30035,159441,34729,34766,33224,34700,35401,36013,35651,30507,29944,34010,13877,27058,36262,null,35241,29800,28089,34753,147473,29927,15835,29046,24740,24988,15569,29026,24695,null,32625,166701,29264,24809,19326,21024,15384,146631,155351,161366,152881,137540,135934,170243,159196,159917,23745,156077,166415,145015,131310,157766,151310,17762,23327,156492,40784,40614,156267,12288,65292,12289,12290,65294,8231,65307,65306,65311,65281,65072,8230,8229,65104,65105,65106,183,65108,65109,65110,65111,65372,8211,65073,8212,65075,9588,65076,65103,65288,65289,65077,65078,65371,65373,65079,65080,12308,12309,65081,65082,12304,12305,65083,65084,12298,12299,65085,65086,12296,12297,65087,65088,12300,12301,65089,65090,12302,12303,65091,65092,65113,65114,65115,65116,65117,65118,8216,8217,8220,8221,12317,12318,8245,8242,65283,65286,65290,8251,167,12291,9675,9679,9651,9650,9678,9734,9733,9671,9670,9633,9632,9661,9660,12963,8453,175,65507,65343,717,65097,65098,65101,65102,65099,65100,65119,65120,65121,65291,65293,215,247,177,8730,65308,65310,65309,8806,8807,8800,8734,8786,8801,65122,65123,65124,65125,65126,65374,8745,8746,8869,8736,8735,8895,13266,13265,8747,8750,8757,8756,9792,9794,8853,8857,8593,8595,8592,8594,8598,8599,8601,8600,8741,8739,65295,65340,8725,65128,65284,65509,12306,65504,65505,65285,65312,8451,8457,65129,65130,65131,13269,13212,13213,13214,13262,13217,13198,13199,13252,176,20825,20827,20830,20829,20833,20835,21991,29929,31950,9601,9602,9603,9604,9605,9606,9607,9608,9615,9614,9613,9612,9611,9610,9609,9532,9524,9516,9508,9500,9620,9472,9474,9621,9484,9488,9492,9496,9581,9582,9584,9583,9552,9566,9578,9569,9698,9699,9701,9700,9585,9586,9587,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,12321,12322,12323,12324,12325,12326,12327,12328,12329,21313,21316,21317,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,729,713,714,711,715,9216,9217,9218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9246,9247,9249,8364,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,19968,20057,19969,19971,20035,20061,20102,20108,20154,20799,20837,20843,20960,20992,20993,21147,21269,21313,21340,21448,19977,19979,19976,19978,20011,20024,20961,20037,20040,20063,20062,20110,20129,20800,20995,21242,21315,21449,21475,22303,22763,22805,22823,22899,23376,23377,23379,23544,23567,23586,23608,23665,24029,24037,24049,24050,24051,24062,24178,24318,24331,24339,25165,19985,19984,19981,20013,20016,20025,20043,23609,20104,20113,20117,20114,20116,20130,20161,20160,20163,20166,20167,20173,20170,20171,20164,20803,20801,20839,20845,20846,20844,20887,20982,20998,20999,21000,21243,21246,21247,21270,21305,21320,21319,21317,21342,21380,21451,21450,21453,22764,22825,22827,22826,22829,23380,23569,23588,23610,23663,24052,24187,24319,24340,24341,24515,25096,25142,25163,25166,25903,25991,26007,26020,26041,26085,26352,26376,26408,27424,27490,27513,27595,27604,27611,27663,27700,28779,29226,29238,29243,29255,29273,29275,29356,29579,19993,19990,19989,19988,19992,20027,20045,20047,20046,20197,20184,20180,20181,20182,20183,20195,20196,20185,20190,20805,20804,20873,20874,20908,20985,20986,20984,21002,21152,21151,21253,21254,21271,21277,20191,21322,21321,21345,21344,21359,21358,21435,21487,21476,21491,21484,21486,21481,21480,21500,21496,21493,21483,21478,21482,21490,21489,21488,21477,21485,21499,22235,22234,22806,22830,22833,22900,22902,23381,23427,23612,24040,24039,24038,24066,24067,24179,24188,24321,24344,24343,24517,25098,25171,25172,25170,25169,26021,26086,26414,26412,26410,26411,26413,27491,27597,27665,27664,27704,27713,27712,27710,29359,29572,29577,29916,29926,29976,29983,29992,29993,30000,30001,30002,30003,30091,30333,30382,30399,30446,30683,30690,30707,31034,31166,31348,31435,19998,19999,20050,20051,20073,20121,20132,20134,20133,20223,20233,20249,20234,20245,20237,20240,20241,20239,20210,20214,20219,20208,20211,20221,20225,20235,20809,20807,20806,20808,20840,20849,20877,20912,21015,21009,21010,21006,21014,21155,21256,21281,21280,21360,21361,21513,21519,21516,21514,21520,21505,21515,21508,21521,21517,21512,21507,21518,21510,21522,22240,22238,22237,22323,22320,22312,22317,22316,22319,22313,22809,22810,22839,22840,22916,22904,22915,22909,22905,22914,22913,23383,23384,23431,23432,23429,23433,23546,23574,23673,24030,24070,24182,24180,24335,24347,24537,24534,25102,25100,25101,25104,25187,25179,25176,25910,26089,26088,26092,26093,26354,26355,26377,26429,26420,26417,26421,27425,27492,27515,27670,27741,27735,27737,27743,27744,27728,27733,27745,27739,27725,27726,28784,29279,29277,30334,31481,31859,31992,32566,32650,32701,32769,32771,32780,32786,32819,32895,32905,32907,32908,33251,33258,33267,33276,33292,33307,33311,33390,33394,33406,34411,34880,34892,34915,35199,38433,20018,20136,20301,20303,20295,20311,20318,20276,20315,20309,20272,20304,20305,20285,20282,20280,20291,20308,20284,20294,20323,20316,20320,20271,20302,20278,20313,20317,20296,20314,20812,20811,20813,20853,20918,20919,21029,21028,21033,21034,21032,21163,21161,21162,21164,21283,21363,21365,21533,21549,21534,21566,21542,21582,21543,21574,21571,21555,21576,21570,21531,21545,21578,21561,21563,21560,21550,21557,21558,21536,21564,21568,21553,21547,21535,21548,22250,22256,22244,22251,22346,22353,22336,22349,22343,22350,22334,22352,22351,22331,22767,22846,22941,22930,22952,22942,22947,22937,22934,22925,22948,22931,22922,22949,23389,23388,23386,23387,23436,23435,23439,23596,23616,23617,23615,23614,23696,23697,23700,23692,24043,24076,24207,24199,24202,24311,24324,24351,24420,24418,24439,24441,24536,24524,24535,24525,24561,24555,24568,24554,25106,25105,25220,25239,25238,25216,25206,25225,25197,25226,25212,25214,25209,25203,25234,25199,25240,25198,25237,25235,25233,25222,25913,25915,25912,26097,26356,26463,26446,26447,26448,26449,26460,26454,26462,26441,26438,26464,26451,26455,27493,27599,27714,27742,27801,27777,27784,27785,27781,27803,27754,27770,27792,27760,27788,27752,27798,27794,27773,27779,27762,27774,27764,27782,27766,27789,27796,27800,27778,28790,28796,28797,28792,29282,29281,29280,29380,29378,29590,29996,29995,30007,30008,30338,30447,30691,31169,31168,31167,31350,31995,32597,32918,32915,32925,32920,32923,32922,32946,33391,33426,33419,33421,35211,35282,35328,35895,35910,35925,35997,36196,36208,36275,36523,36554,36763,36784,36802,36806,36805,36804,24033,37009,37026,37034,37030,37027,37193,37318,37324,38450,38446,38449,38442,38444,20006,20054,20083,20107,20123,20126,20139,20140,20335,20381,20365,20339,20351,20332,20379,20363,20358,20355,20336,20341,20360,20329,20347,20374,20350,20367,20369,20346,20820,20818,20821,20841,20855,20854,20856,20925,20989,21051,21048,21047,21050,21040,21038,21046,21057,21182,21179,21330,21332,21331,21329,21350,21367,21368,21369,21462,21460,21463,21619,21621,21654,21624,21653,21632,21627,21623,21636,21650,21638,21628,21648,21617,21622,21644,21658,21602,21608,21643,21629,21646,22266,22403,22391,22378,22377,22369,22374,22372,22396,22812,22857,22855,22856,22852,22868,22974,22971,22996,22969,22958,22993,22982,22992,22989,22987,22995,22986,22959,22963,22994,22981,23391,23396,23395,23447,23450,23448,23452,23449,23451,23578,23624,23621,23622,23735,23713,23736,23721,23723,23729,23731,24088,24090,24086,24085,24091,24081,24184,24218,24215,24220,24213,24214,24310,24358,24359,24361,24448,24449,24447,24444,24541,24544,24573,24565,24575,24591,24596,24623,24629,24598,24618,24597,24609,24615,24617,24619,24603,25110,25109,25151,25150,25152,25215,25289,25292,25284,25279,25282,25273,25298,25307,25259,25299,25300,25291,25288,25256,25277,25276,25296,25305,25287,25293,25269,25306,25265,25304,25302,25303,25286,25260,25294,25918,26023,26044,26106,26132,26131,26124,26118,26114,26126,26112,26127,26133,26122,26119,26381,26379,26477,26507,26517,26481,26524,26483,26487,26503,26525,26519,26479,26480,26495,26505,26494,26512,26485,26522,26515,26492,26474,26482,27427,27494,27495,27519,27667,27675,27875,27880,27891,27825,27852,27877,27827,27837,27838,27836,27874,27819,27861,27859,27832,27844,27833,27841,27822,27863,27845,27889,27839,27835,27873,27867,27850,27820,27887,27868,27862,27872,28821,28814,28818,28810,28825,29228,29229,29240,29256,29287,29289,29376,29390,29401,29399,29392,29609,29608,29599,29611,29605,30013,30109,30105,30106,30340,30402,30450,30452,30693,30717,31038,31040,31041,31177,31176,31354,31353,31482,31998,32596,32652,32651,32773,32954,32933,32930,32945,32929,32939,32937,32948,32938,32943,33253,33278,33293,33459,33437,33433,33453,33469,33439,33465,33457,33452,33445,33455,33464,33443,33456,33470,33463,34382,34417,21021,34920,36555,36814,36820,36817,37045,37048,37041,37046,37319,37329,38263,38272,38428,38464,38463,38459,38468,38466,38585,38632,38738,38750,20127,20141,20142,20449,20405,20399,20415,20448,20433,20431,20445,20419,20406,20440,20447,20426,20439,20398,20432,20420,20418,20442,20430,20446,20407,20823,20882,20881,20896,21070,21059,21066,21069,21068,21067,21063,21191,21193,21187,21185,21261,21335,21371,21402,21467,21676,21696,21672,21710,21705,21688,21670,21683,21703,21698,21693,21674,21697,21700,21704,21679,21675,21681,21691,21673,21671,21695,22271,22402,22411,22432,22435,22434,22478,22446,22419,22869,22865,22863,22862,22864,23004,23000,23039,23011,23016,23043,23013,23018,23002,23014,23041,23035,23401,23459,23462,23460,23458,23461,23553,23630,23631,23629,23627,23769,23762,24055,24093,24101,24095,24189,24224,24230,24314,24328,24365,24421,24456,24453,24458,24459,24455,24460,24457,24594,24605,24608,24613,24590,24616,24653,24688,24680,24674,24646,24643,24684,24683,24682,24676,25153,25308,25366,25353,25340,25325,25345,25326,25341,25351,25329,25335,25327,25324,25342,25332,25361,25346,25919,25925,26027,26045,26082,26149,26157,26144,26151,26159,26143,26152,26161,26148,26359,26623,26579,26609,26580,26576,26604,26550,26543,26613,26601,26607,26564,26577,26548,26586,26597,26552,26575,26590,26611,26544,26585,26594,26589,26578,27498,27523,27526,27573,27602,27607,27679,27849,27915,27954,27946,27969,27941,27916,27953,27934,27927,27963,27965,27966,27958,27931,27893,27961,27943,27960,27945,27950,27957,27918,27947,28843,28858,28851,28844,28847,28845,28856,28846,28836,29232,29298,29295,29300,29417,29408,29409,29623,29642,29627,29618,29645,29632,29619,29978,29997,30031,30028,30030,30027,30123,30116,30117,30114,30115,30328,30342,30343,30344,30408,30406,30403,30405,30465,30457,30456,30473,30475,30462,30460,30471,30684,30722,30740,30732,30733,31046,31049,31048,31047,31161,31162,31185,31186,31179,31359,31361,31487,31485,31869,32002,32005,32000,32009,32007,32004,32006,32568,32654,32703,32772,32784,32781,32785,32822,32982,32997,32986,32963,32964,32972,32993,32987,32974,32990,32996,32989,33268,33314,33511,33539,33541,33507,33499,33510,33540,33509,33538,33545,33490,33495,33521,33537,33500,33492,33489,33502,33491,33503,33519,33542,34384,34425,34427,34426,34893,34923,35201,35284,35336,35330,35331,35998,36000,36212,36211,36276,36557,36556,36848,36838,36834,36842,36837,36845,36843,36836,36840,37066,37070,37057,37059,37195,37194,37325,38274,38480,38475,38476,38477,38754,38761,38859,38893,38899,38913,39080,39131,39135,39318,39321,20056,20147,20492,20493,20515,20463,20518,20517,20472,20521,20502,20486,20540,20511,20506,20498,20497,20474,20480,20500,20520,20465,20513,20491,20505,20504,20467,20462,20525,20522,20478,20523,20489,20860,20900,20901,20898,20941,20940,20934,20939,21078,21084,21076,21083,21085,21290,21375,21407,21405,21471,21736,21776,21761,21815,21756,21733,21746,21766,21754,21780,21737,21741,21729,21769,21742,21738,21734,21799,21767,21757,21775,22275,22276,22466,22484,22475,22467,22537,22799,22871,22872,22874,23057,23064,23068,23071,23067,23059,23020,23072,23075,23081,23077,23052,23049,23403,23640,23472,23475,23478,23476,23470,23477,23481,23480,23556,23633,23637,23632,23789,23805,23803,23786,23784,23792,23798,23809,23796,24046,24109,24107,24235,24237,24231,24369,24466,24465,24464,24665,24675,24677,24656,24661,24685,24681,24687,24708,24735,24730,24717,24724,24716,24709,24726,25159,25331,25352,25343,25422,25406,25391,25429,25410,25414,25423,25417,25402,25424,25405,25386,25387,25384,25421,25420,25928,25929,26009,26049,26053,26178,26185,26191,26179,26194,26188,26181,26177,26360,26388,26389,26391,26657,26680,26696,26694,26707,26681,26690,26708,26665,26803,26647,26700,26705,26685,26612,26704,26688,26684,26691,26666,26693,26643,26648,26689,27530,27529,27575,27683,27687,27688,27686,27684,27888,28010,28053,28040,28039,28006,28024,28023,27993,28051,28012,28041,28014,27994,28020,28009,28044,28042,28025,28037,28005,28052,28874,28888,28900,28889,28872,28879,29241,29305,29436,29433,29437,29432,29431,29574,29677,29705,29678,29664,29674,29662,30036,30045,30044,30042,30041,30142,30149,30151,30130,30131,30141,30140,30137,30146,30136,30347,30384,30410,30413,30414,30505,30495,30496,30504,30697,30768,30759,30776,30749,30772,30775,30757,30765,30752,30751,30770,31061,31056,31072,31071,31062,31070,31069,31063,31066,31204,31203,31207,31199,31206,31209,31192,31364,31368,31449,31494,31505,31881,32033,32023,32011,32010,32032,32034,32020,32016,32021,32026,32028,32013,32025,32027,32570,32607,32660,32709,32705,32774,32792,32789,32793,32791,32829,32831,33009,33026,33008,33029,33005,33012,33030,33016,33011,33032,33021,33034,33020,33007,33261,33260,33280,33296,33322,33323,33320,33324,33467,33579,33618,33620,33610,33592,33616,33609,33589,33588,33615,33586,33593,33590,33559,33600,33585,33576,33603,34388,34442,34474,34451,34468,34473,34444,34467,34460,34928,34935,34945,34946,34941,34937,35352,35344,35342,35340,35349,35338,35351,35347,35350,35343,35345,35912,35962,35961,36001,36002,36215,36524,36562,36564,36559,36785,36865,36870,36855,36864,36858,36852,36867,36861,36869,36856,37013,37089,37085,37090,37202,37197,37196,37336,37341,37335,37340,37337,38275,38498,38499,38497,38491,38493,38500,38488,38494,38587,39138,39340,39592,39640,39717,39730,39740,20094,20602,20605,20572,20551,20547,20556,20570,20553,20581,20598,20558,20565,20597,20596,20599,20559,20495,20591,20589,20828,20885,20976,21098,21103,21202,21209,21208,21205,21264,21263,21273,21311,21312,21310,21443,26364,21830,21866,21862,21828,21854,21857,21827,21834,21809,21846,21839,21845,21807,21860,21816,21806,21852,21804,21859,21811,21825,21847,22280,22283,22281,22495,22533,22538,22534,22496,22500,22522,22530,22581,22519,22521,22816,22882,23094,23105,23113,23142,23146,23104,23100,23138,23130,23110,23114,23408,23495,23493,23492,23490,23487,23494,23561,23560,23559,23648,23644,23645,23815,23814,23822,23835,23830,23842,23825,23849,23828,23833,23844,23847,23831,24034,24120,24118,24115,24119,24247,24248,24246,24245,24254,24373,24375,24407,24428,24425,24427,24471,24473,24478,24472,24481,24480,24476,24703,24739,24713,24736,24744,24779,24756,24806,24765,24773,24763,24757,24796,24764,24792,24789,24774,24799,24760,24794,24775,25114,25115,25160,25504,25511,25458,25494,25506,25509,25463,25447,25496,25514,25457,25513,25481,25475,25499,25451,25512,25476,25480,25497,25505,25516,25490,25487,25472,25467,25449,25448,25466,25949,25942,25937,25945,25943,21855,25935,25944,25941,25940,26012,26011,26028,26063,26059,26060,26062,26205,26202,26212,26216,26214,26206,26361,21207,26395,26753,26799,26786,26771,26805,26751,26742,26801,26791,26775,26800,26755,26820,26797,26758,26757,26772,26781,26792,26783,26785,26754,27442,27578,27627,27628,27691,28046,28092,28147,28121,28082,28129,28108,28132,28155,28154,28165,28103,28107,28079,28113,28078,28126,28153,28088,28151,28149,28101,28114,28186,28085,28122,28139,28120,28138,28145,28142,28136,28102,28100,28074,28140,28095,28134,28921,28937,28938,28925,28911,29245,29309,29313,29468,29467,29462,29459,29465,29575,29701,29706,29699,29702,29694,29709,29920,29942,29943,29980,29986,30053,30054,30050,30064,30095,30164,30165,30133,30154,30157,30350,30420,30418,30427,30519,30526,30524,30518,30520,30522,30827,30787,30798,31077,31080,31085,31227,31378,31381,31520,31528,31515,31532,31526,31513,31518,31534,31890,31895,31893,32070,32067,32113,32046,32057,32060,32064,32048,32051,32068,32047,32066,32050,32049,32573,32670,32666,32716,32718,32722,32796,32842,32838,33071,33046,33059,33067,33065,33072,33060,33282,33333,33335,33334,33337,33678,33694,33688,33656,33698,33686,33725,33707,33682,33674,33683,33673,33696,33655,33659,33660,33670,33703,34389,24426,34503,34496,34486,34500,34485,34502,34507,34481,34479,34505,34899,34974,34952,34987,34962,34966,34957,34955,35219,35215,35370,35357,35363,35365,35377,35373,35359,35355,35362,35913,35930,36009,36012,36011,36008,36010,36007,36199,36198,36286,36282,36571,36575,36889,36877,36890,36887,36899,36895,36893,36880,36885,36894,36896,36879,36898,36886,36891,36884,37096,37101,37117,37207,37326,37365,37350,37347,37351,37357,37353,38281,38506,38517,38515,38520,38512,38516,38518,38519,38508,38592,38634,38633,31456,31455,38914,38915,39770,40165,40565,40575,40613,40635,20642,20621,20613,20633,20625,20608,20630,20632,20634,26368,20977,21106,21108,21109,21097,21214,21213,21211,21338,21413,21883,21888,21927,21884,21898,21917,21912,21890,21916,21930,21908,21895,21899,21891,21939,21934,21919,21822,21938,21914,21947,21932,21937,21886,21897,21931,21913,22285,22575,22570,22580,22564,22576,22577,22561,22557,22560,22777,22778,22880,23159,23194,23167,23186,23195,23207,23411,23409,23506,23500,23507,23504,23562,23563,23601,23884,23888,23860,23879,24061,24133,24125,24128,24131,24190,24266,24257,24258,24260,24380,24429,24489,24490,24488,24785,24801,24754,24758,24800,24860,24867,24826,24853,24816,24827,24820,24936,24817,24846,24822,24841,24832,24850,25119,25161,25507,25484,25551,25536,25577,25545,25542,25549,25554,25571,25552,25569,25558,25581,25582,25462,25588,25578,25563,25682,25562,25593,25950,25958,25954,25955,26001,26000,26031,26222,26224,26228,26230,26223,26257,26234,26238,26231,26366,26367,26399,26397,26874,26837,26848,26840,26839,26885,26847,26869,26862,26855,26873,26834,26866,26851,26827,26829,26893,26898,26894,26825,26842,26990,26875,27454,27450,27453,27544,27542,27580,27631,27694,27695,27692,28207,28216,28244,28193,28210,28263,28234,28192,28197,28195,28187,28251,28248,28196,28246,28270,28205,28198,28271,28212,28237,28218,28204,28227,28189,28222,28363,28297,28185,28238,28259,28228,28274,28265,28255,28953,28954,28966,28976,28961,28982,29038,28956,29260,29316,29312,29494,29477,29492,29481,29754,29738,29747,29730,29733,29749,29750,29748,29743,29723,29734,29736,29989,29990,30059,30058,30178,30171,30179,30169,30168,30174,30176,30331,30332,30358,30355,30388,30428,30543,30701,30813,30828,30831,31245,31240,31243,31237,31232,31384,31383,31382,31461,31459,31561,31574,31558,31568,31570,31572,31565,31563,31567,31569,31903,31909,32094,32080,32104,32085,32043,32110,32114,32097,32102,32098,32112,32115,21892,32724,32725,32779,32850,32901,33109,33108,33099,33105,33102,33081,33094,33086,33100,33107,33140,33298,33308,33769,33795,33784,33805,33760,33733,33803,33729,33775,33777,33780,33879,33802,33776,33804,33740,33789,33778,33738,33848,33806,33796,33756,33799,33748,33759,34395,34527,34521,34541,34516,34523,34532,34512,34526,34903,35009,35010,34993,35203,35222,35387,35424,35413,35422,35388,35393,35412,35419,35408,35398,35380,35386,35382,35414,35937,35970,36015,36028,36019,36029,36033,36027,36032,36020,36023,36022,36031,36024,36234,36229,36225,36302,36317,36299,36314,36305,36300,36315,36294,36603,36600,36604,36764,36910,36917,36913,36920,36914,36918,37122,37109,37129,37118,37219,37221,37327,37396,37397,37411,37385,37406,37389,37392,37383,37393,38292,38287,38283,38289,38291,38290,38286,38538,38542,38539,38525,38533,38534,38541,38514,38532,38593,38597,38596,38598,38599,38639,38642,38860,38917,38918,38920,39143,39146,39151,39145,39154,39149,39342,39341,40643,40653,40657,20098,20653,20661,20658,20659,20677,20670,20652,20663,20667,20655,20679,21119,21111,21117,21215,21222,21220,21218,21219,21295,21983,21992,21971,21990,21966,21980,21959,21969,21987,21988,21999,21978,21985,21957,21958,21989,21961,22290,22291,22622,22609,22616,22615,22618,22612,22635,22604,22637,22602,22626,22610,22603,22887,23233,23241,23244,23230,23229,23228,23219,23234,23218,23913,23919,24140,24185,24265,24264,24338,24409,24492,24494,24858,24847,24904,24863,24819,24859,24825,24833,24840,24910,24908,24900,24909,24894,24884,24871,24845,24838,24887,25121,25122,25619,25662,25630,25642,25645,25661,25644,25615,25628,25620,25613,25654,25622,25623,25606,25964,26015,26032,26263,26249,26247,26248,26262,26244,26264,26253,26371,27028,26989,26970,26999,26976,26964,26997,26928,27010,26954,26984,26987,26974,26963,27001,27014,26973,26979,26971,27463,27506,27584,27583,27603,27645,28322,28335,28371,28342,28354,28304,28317,28359,28357,28325,28312,28348,28346,28331,28369,28310,28316,28356,28372,28330,28327,28340,29006,29017,29033,29028,29001,29031,29020,29036,29030,29004,29029,29022,28998,29032,29014,29242,29266,29495,29509,29503,29502,29807,29786,29781,29791,29790,29761,29759,29785,29787,29788,30070,30072,30208,30192,30209,30194,30193,30202,30207,30196,30195,30430,30431,30555,30571,30566,30558,30563,30585,30570,30572,30556,30565,30568,30562,30702,30862,30896,30871,30872,30860,30857,30844,30865,30867,30847,31098,31103,31105,33836,31165,31260,31258,31264,31252,31263,31262,31391,31392,31607,31680,31584,31598,31591,31921,31923,31925,32147,32121,32145,32129,32143,32091,32622,32617,32618,32626,32681,32680,32676,32854,32856,32902,32900,33137,33136,33144,33125,33134,33139,33131,33145,33146,33126,33285,33351,33922,33911,33853,33841,33909,33894,33899,33865,33900,33883,33852,33845,33889,33891,33897,33901,33862,34398,34396,34399,34553,34579,34568,34567,34560,34558,34555,34562,34563,34566,34570,34905,35039,35028,35033,35036,35032,35037,35041,35018,35029,35026,35228,35299,35435,35442,35443,35430,35433,35440,35463,35452,35427,35488,35441,35461,35437,35426,35438,35436,35449,35451,35390,35432,35938,35978,35977,36042,36039,36040,36036,36018,36035,36034,36037,36321,36319,36328,36335,36339,36346,36330,36324,36326,36530,36611,36617,36606,36618,36767,36786,36939,36938,36947,36930,36948,36924,36949,36944,36935,36943,36942,36941,36945,36926,36929,37138,37143,37228,37226,37225,37321,37431,37463,37432,37437,37440,37438,37467,37451,37476,37457,37428,37449,37453,37445,37433,37439,37466,38296,38552,38548,38549,38605,38603,38601,38602,38647,38651,38649,38646,38742,38772,38774,38928,38929,38931,38922,38930,38924,39164,39156,39165,39166,39347,39345,39348,39649,40169,40578,40718,40723,40736,20711,20718,20709,20694,20717,20698,20693,20687,20689,20721,20686,20713,20834,20979,21123,21122,21297,21421,22014,22016,22043,22039,22013,22036,22022,22025,22029,22030,22007,22038,22047,22024,22032,22006,22296,22294,22645,22654,22659,22675,22666,22649,22661,22653,22781,22821,22818,22820,22890,22889,23265,23270,23273,23255,23254,23256,23267,23413,23518,23527,23521,23525,23526,23528,23522,23524,23519,23565,23650,23940,23943,24155,24163,24149,24151,24148,24275,24278,24330,24390,24432,24505,24903,24895,24907,24951,24930,24931,24927,24922,24920,24949,25130,25735,25688,25684,25764,25720,25695,25722,25681,25703,25652,25709,25723,25970,26017,26071,26070,26274,26280,26269,27036,27048,27029,27073,27054,27091,27083,27035,27063,27067,27051,27060,27088,27085,27053,27084,27046,27075,27043,27465,27468,27699,28467,28436,28414,28435,28404,28457,28478,28448,28460,28431,28418,28450,28415,28399,28422,28465,28472,28466,28451,28437,28459,28463,28552,28458,28396,28417,28402,28364,28407,29076,29081,29053,29066,29060,29074,29246,29330,29334,29508,29520,29796,29795,29802,29808,29805,29956,30097,30247,30221,30219,30217,30227,30433,30435,30596,30589,30591,30561,30913,30879,30887,30899,30889,30883,31118,31119,31117,31278,31281,31402,31401,31469,31471,31649,31637,31627,31605,31639,31645,31636,31631,31672,31623,31620,31929,31933,31934,32187,32176,32156,32189,32190,32160,32202,32180,32178,32177,32186,32162,32191,32181,32184,32173,32210,32199,32172,32624,32736,32737,32735,32862,32858,32903,33104,33152,33167,33160,33162,33151,33154,33255,33274,33287,33300,33310,33355,33993,33983,33990,33988,33945,33950,33970,33948,33995,33976,33984,34003,33936,33980,34001,33994,34623,34588,34619,34594,34597,34612,34584,34645,34615,34601,35059,35074,35060,35065,35064,35069,35048,35098,35055,35494,35468,35486,35491,35469,35489,35475,35492,35498,35493,35496,35480,35473,35482,35495,35946,35981,35980,36051,36049,36050,36203,36249,36245,36348,36628,36626,36629,36627,36771,36960,36952,36956,36963,36953,36958,36962,36957,36955,37145,37144,37150,37237,37240,37239,37236,37496,37504,37509,37528,37526,37499,37523,37532,37544,37500,37521,38305,38312,38313,38307,38309,38308,38553,38556,38555,38604,38610,38656,38780,38789,38902,38935,38936,39087,39089,39171,39173,39180,39177,39361,39599,39600,39654,39745,39746,40180,40182,40179,40636,40763,40778,20740,20736,20731,20725,20729,20738,20744,20745,20741,20956,21127,21128,21129,21133,21130,21232,21426,22062,22075,22073,22066,22079,22068,22057,22099,22094,22103,22132,22070,22063,22064,22656,22687,22686,22707,22684,22702,22697,22694,22893,23305,23291,23307,23285,23308,23304,23534,23532,23529,23531,23652,23653,23965,23956,24162,24159,24161,24290,24282,24287,24285,24291,24288,24392,24433,24503,24501,24950,24935,24942,24925,24917,24962,24956,24944,24939,24958,24999,24976,25003,24974,25004,24986,24996,24980,25006,25134,25705,25711,25721,25758,25778,25736,25744,25776,25765,25747,25749,25769,25746,25774,25773,25771,25754,25772,25753,25762,25779,25973,25975,25976,26286,26283,26292,26289,27171,27167,27112,27137,27166,27161,27133,27169,27155,27146,27123,27138,27141,27117,27153,27472,27470,27556,27589,27590,28479,28540,28548,28497,28518,28500,28550,28525,28507,28536,28526,28558,28538,28528,28516,28567,28504,28373,28527,28512,28511,29087,29100,29105,29096,29270,29339,29518,29527,29801,29835,29827,29822,29824,30079,30240,30249,30239,30244,30246,30241,30242,30362,30394,30436,30606,30599,30604,30609,30603,30923,30917,30906,30922,30910,30933,30908,30928,31295,31292,31296,31293,31287,31291,31407,31406,31661,31665,31684,31668,31686,31687,31681,31648,31692,31946,32224,32244,32239,32251,32216,32236,32221,32232,32227,32218,32222,32233,32158,32217,32242,32249,32629,32631,32687,32745,32806,33179,33180,33181,33184,33178,33176,34071,34109,34074,34030,34092,34093,34067,34065,34083,34081,34068,34028,34085,34047,34054,34690,34676,34678,34656,34662,34680,34664,34649,34647,34636,34643,34907,34909,35088,35079,35090,35091,35093,35082,35516,35538,35527,35524,35477,35531,35576,35506,35529,35522,35519,35504,35542,35533,35510,35513,35547,35916,35918,35948,36064,36062,36070,36068,36076,36077,36066,36067,36060,36074,36065,36205,36255,36259,36395,36368,36381,36386,36367,36393,36383,36385,36382,36538,36637,36635,36639,36649,36646,36650,36636,36638,36645,36969,36974,36968,36973,36983,37168,37165,37159,37169,37255,37257,37259,37251,37573,37563,37559,37610,37548,37604,37569,37555,37564,37586,37575,37616,37554,38317,38321,38660,38662,38663,38665,38752,38797,38795,38799,38945,38955,38940,39091,39178,39187,39186,39192,39389,39376,39391,39387,39377,39381,39378,39385,39607,39662,39663,39719,39749,39748,39799,39791,40198,40201,40195,40617,40638,40654,22696,40786,20754,20760,20756,20752,20757,20864,20906,20957,21137,21139,21235,22105,22123,22137,22121,22116,22136,22122,22120,22117,22129,22127,22124,22114,22134,22721,22718,22727,22725,22894,23325,23348,23416,23536,23566,24394,25010,24977,25001,24970,25037,25014,25022,25034,25032,25136,25797,25793,25803,25787,25788,25818,25796,25799,25794,25805,25791,25810,25812,25790,25972,26310,26313,26297,26308,26311,26296,27197,27192,27194,27225,27243,27224,27193,27204,27234,27233,27211,27207,27189,27231,27208,27481,27511,27653,28610,28593,28577,28611,28580,28609,28583,28595,28608,28601,28598,28582,28576,28596,29118,29129,29136,29138,29128,29141,29113,29134,29145,29148,29123,29124,29544,29852,29859,29848,29855,29854,29922,29964,29965,30260,30264,30266,30439,30437,30624,30622,30623,30629,30952,30938,30956,30951,31142,31309,31310,31302,31308,31307,31418,31705,31761,31689,31716,31707,31713,31721,31718,31957,31958,32266,32273,32264,32283,32291,32286,32285,32265,32272,32633,32690,32752,32753,32750,32808,33203,33193,33192,33275,33288,33368,33369,34122,34137,34120,34152,34153,34115,34121,34157,34154,34142,34691,34719,34718,34722,34701,34913,35114,35122,35109,35115,35105,35242,35238,35558,35578,35563,35569,35584,35548,35559,35566,35582,35585,35586,35575,35565,35571,35574,35580,35947,35949,35987,36084,36420,36401,36404,36418,36409,36405,36667,36655,36664,36659,36776,36774,36981,36980,36984,36978,36988,36986,37172,37266,37664,37686,37624,37683,37679,37666,37628,37675,37636,37658,37648,37670,37665,37653,37678,37657,38331,38567,38568,38570,38613,38670,38673,38678,38669,38675,38671,38747,38748,38758,38808,38960,38968,38971,38967,38957,38969,38948,39184,39208,39198,39195,39201,39194,39405,39394,39409,39608,39612,39675,39661,39720,39825,40213,40227,40230,40232,40210,40219,40664,40660,40845,40860,20778,20767,20769,20786,21237,22158,22144,22160,22149,22151,22159,22741,22739,22737,22734,23344,23338,23332,23418,23607,23656,23996,23994,23997,23992,24171,24396,24509,25033,25026,25031,25062,25035,25138,25140,25806,25802,25816,25824,25840,25830,25836,25841,25826,25837,25986,25987,26329,26326,27264,27284,27268,27298,27292,27355,27299,27262,27287,27280,27296,27484,27566,27610,27656,28632,28657,28639,28640,28635,28644,28651,28655,28544,28652,28641,28649,28629,28654,28656,29159,29151,29166,29158,29157,29165,29164,29172,29152,29237,29254,29552,29554,29865,29872,29862,29864,30278,30274,30284,30442,30643,30634,30640,30636,30631,30637,30703,30967,30970,30964,30959,30977,31143,31146,31319,31423,31751,31757,31742,31735,31756,31712,31968,31964,31966,31970,31967,31961,31965,32302,32318,32326,32311,32306,32323,32299,32317,32305,32325,32321,32308,32313,32328,32309,32319,32303,32580,32755,32764,32881,32882,32880,32879,32883,33222,33219,33210,33218,33216,33215,33213,33225,33214,33256,33289,33393,34218,34180,34174,34204,34193,34196,34223,34203,34183,34216,34186,34407,34752,34769,34739,34770,34758,34731,34747,34746,34760,34763,35131,35126,35140,35128,35133,35244,35598,35607,35609,35611,35594,35616,35613,35588,35600,35905,35903,35955,36090,36093,36092,36088,36091,36264,36425,36427,36424,36426,36676,36670,36674,36677,36671,36991,36989,36996,36993,36994,36992,37177,37283,37278,37276,37709,37762,37672,37749,37706,37733,37707,37656,37758,37740,37723,37744,37722,37716,38346,38347,38348,38344,38342,38577,38584,38614,38684,38686,38816,38867,38982,39094,39221,39425,39423,39854,39851,39850,39853,40251,40255,40587,40655,40670,40668,40669,40667,40766,40779,21474,22165,22190,22745,22744,23352,24413,25059,25139,25844,25842,25854,25862,25850,25851,25847,26039,26332,26406,27315,27308,27331,27323,27320,27330,27310,27311,27487,27512,27567,28681,28683,28670,28678,28666,28689,28687,29179,29180,29182,29176,29559,29557,29863,29887,29973,30294,30296,30290,30653,30655,30651,30652,30990,31150,31329,31330,31328,31428,31429,31787,31783,31786,31774,31779,31777,31975,32340,32341,32350,32346,32353,32338,32345,32584,32761,32763,32887,32886,33229,33231,33290,34255,34217,34253,34256,34249,34224,34234,34233,34214,34799,34796,34802,34784,35206,35250,35316,35624,35641,35628,35627,35920,36101,36441,36451,36454,36452,36447,36437,36544,36681,36685,36999,36995,37000,37291,37292,37328,37780,37770,37782,37794,37811,37806,37804,37808,37784,37786,37783,38356,38358,38352,38357,38626,38620,38617,38619,38622,38692,38819,38822,38829,38905,38989,38991,38988,38990,38995,39098,39230,39231,39229,39214,39333,39438,39617,39683,39686,39759,39758,39757,39882,39881,39933,39880,39872,40273,40285,40288,40672,40725,40748,20787,22181,22750,22751,22754,23541,40848,24300,25074,25079,25078,25077,25856,25871,26336,26333,27365,27357,27354,27347,28699,28703,28712,28698,28701,28693,28696,29190,29197,29272,29346,29560,29562,29885,29898,29923,30087,30086,30303,30305,30663,31001,31153,31339,31337,31806,31807,31800,31805,31799,31808,32363,32365,32377,32361,32362,32645,32371,32694,32697,32696,33240,34281,34269,34282,34261,34276,34277,34295,34811,34821,34829,34809,34814,35168,35167,35158,35166,35649,35676,35672,35657,35674,35662,35663,35654,35673,36104,36106,36476,36466,36487,36470,36460,36474,36468,36692,36686,36781,37002,37003,37297,37294,37857,37841,37855,37827,37832,37852,37853,37846,37858,37837,37848,37860,37847,37864,38364,38580,38627,38698,38695,38753,38876,38907,39006,39000,39003,39100,39237,39241,39446,39449,39693,39912,39911,39894,39899,40329,40289,40306,40298,40300,40594,40599,40595,40628,21240,22184,22199,22198,22196,22204,22756,23360,23363,23421,23542,24009,25080,25082,25880,25876,25881,26342,26407,27372,28734,28720,28722,29200,29563,29903,30306,30309,31014,31018,31020,31019,31431,31478,31820,31811,31821,31983,31984,36782,32381,32380,32386,32588,32768,33242,33382,34299,34297,34321,34298,34310,34315,34311,34314,34836,34837,35172,35258,35320,35696,35692,35686,35695,35679,35691,36111,36109,36489,36481,36485,36482,37300,37323,37912,37891,37885,38369,38704,39108,39250,39249,39336,39467,39472,39479,39477,39955,39949,40569,40629,40680,40751,40799,40803,40801,20791,20792,22209,22208,22210,22804,23660,24013,25084,25086,25885,25884,26005,26345,27387,27396,27386,27570,28748,29211,29351,29910,29908,30313,30675,31824,32399,32396,32700,34327,34349,34330,34851,34850,34849,34847,35178,35180,35261,35700,35703,35709,36115,36490,36493,36491,36703,36783,37306,37934,37939,37941,37946,37944,37938,37931,38370,38712,38713,38706,38911,39015,39013,39255,39493,39491,39488,39486,39631,39764,39761,39981,39973,40367,40372,40386,40376,40605,40687,40729,40796,40806,40807,20796,20795,22216,22218,22217,23423,24020,24018,24398,25087,25892,27402,27489,28753,28760,29568,29924,30090,30318,30316,31155,31840,31839,32894,32893,33247,35186,35183,35324,35712,36118,36119,36497,36499,36705,37192,37956,37969,37970,38717,38718,38851,38849,39019,39253,39509,39501,39634,39706,40009,39985,39998,39995,40403,40407,40756,40812,40810,40852,22220,24022,25088,25891,25899,25898,26348,27408,29914,31434,31844,31843,31845,32403,32406,32404,33250,34360,34367,34865,35722,37008,37007,37987,37984,37988,38760,39023,39260,39514,39515,39511,39635,39636,39633,40020,40023,40022,40421,40607,40692,22225,22761,25900,28766,30321,30322,30679,32592,32648,34870,34873,34914,35731,35730,35734,33399,36123,37312,37994,38722,38728,38724,38854,39024,39519,39714,39768,40031,40441,40442,40572,40573,40711,40823,40818,24307,27414,28771,31852,31854,34875,35264,36513,37313,38002,38000,39025,39262,39638,39715,40652,28772,30682,35738,38007,38857,39522,39525,32412,35740,36522,37317,38013,38014,38012,40055,40056,40695,35924,38015,40474,29224,39530,39729,40475,40478,31858,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,20022,20031,20101,20128,20866,20886,20907,21241,21304,21353,21430,22794,23424,24027,12083,24191,24308,24400,24417,25908,26080,30098,30326,36789,38582,168,710,12541,12542,12445,12446,12291,20189,12293,12294,12295,12540,65339,65341,10045,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,8679,8632,8633,12751,131276,20058,131210,20994,17553,40880,20872,40881,161287,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,65506,65508,65287,65282,12849,8470,8481,12443,12444,11904,11908,11910,11911,11912,11914,11916,11917,11925,11932,11933,11941,11943,11946,11948,11950,11958,11964,11966,11974,11978,11980,11981,11983,11990,11991,11998,12003,null,null,null,643,592,603,596,629,339,248,331,650,618,20034,20060,20981,21274,21378,19975,19980,20039,20109,22231,64012,23662,24435,19983,20871,19982,20014,20115,20162,20169,20168,20888,21244,21356,21433,22304,22787,22828,23568,24063,26081,27571,27596,27668,29247,20017,20028,20200,20188,20201,20193,20189,20186,21004,21276,21324,22306,22307,22807,22831,23425,23428,23570,23611,23668,23667,24068,24192,24194,24521,25097,25168,27669,27702,27715,27711,27707,29358,29360,29578,31160,32906,38430,20238,20248,20268,20213,20244,20209,20224,20215,20232,20253,20226,20229,20258,20243,20228,20212,20242,20913,21011,21001,21008,21158,21282,21279,21325,21386,21511,22241,22239,22318,22314,22324,22844,22912,22908,22917,22907,22910,22903,22911,23382,23573,23589,23676,23674,23675,23678,24031,24181,24196,24322,24346,24436,24533,24532,24527,25180,25182,25188,25185,25190,25186,25177,25184,25178,25189,26095,26094,26430,26425,26424,26427,26426,26431,26428,26419,27672,27718,27730,27740,27727,27722,27732,27723,27724,28785,29278,29364,29365,29582,29994,30335,31349,32593,33400,33404,33408,33405,33407,34381,35198,37017,37015,37016,37019,37012,38434,38436,38432,38435,20310,20283,20322,20297,20307,20324,20286,20327,20306,20319,20289,20312,20269,20275,20287,20321,20879,20921,21020,21022,21025,21165,21166,21257,21347,21362,21390,21391,21552,21559,21546,21588,21573,21529,21532,21541,21528,21565,21583,21569,21544,21540,21575,22254,22247,22245,22337,22341,22348,22345,22347,22354,22790,22848,22950,22936,22944,22935,22926,22946,22928,22927,22951,22945,23438,23442,23592,23594,23693,23695,23688,23691,23689,23698,23690,23686,23699,23701,24032,24074,24078,24203,24201,24204,24200,24205,24325,24349,24440,24438,24530,24529,24528,24557,24552,24558,24563,24545,24548,24547,24570,24559,24567,24571,24576,24564,25146,25219,25228,25230,25231,25236,25223,25201,25211,25210,25200,25217,25224,25207,25213,25202,25204,25911,26096,26100,26099,26098,26101,26437,26439,26457,26453,26444,26440,26461,26445,26458,26443,27600,27673,27674,27768,27751,27755,27780,27787,27791,27761,27759,27753,27802,27757,27783,27797,27804,27750,27763,27749,27771,27790,28788,28794,29283,29375,29373,29379,29382,29377,29370,29381,29589,29591,29587,29588,29586,30010,30009,30100,30101,30337,31037,32820,32917,32921,32912,32914,32924,33424,33423,33413,33422,33425,33427,33418,33411,33412,35960,36809,36799,37023,37025,37029,37022,37031,37024,38448,38440,38447,38445,20019,20376,20348,20357,20349,20352,20359,20342,20340,20361,20356,20343,20300,20375,20330,20378,20345,20353,20344,20368,20380,20372,20382,20370,20354,20373,20331,20334,20894,20924,20926,21045,21042,21043,21062,21041,21180,21258,21259,21308,21394,21396,21639,21631,21633,21649,21634,21640,21611,21626,21630,21605,21612,21620,21606,21645,21615,21601,21600,21656,21603,21607,21604,22263,22265,22383,22386,22381,22379,22385,22384,22390,22400,22389,22395,22387,22388,22370,22376,22397,22796,22853,22965,22970,22991,22990,22962,22988,22977,22966,22972,22979,22998,22961,22973,22976,22984,22964,22983,23394,23397,23443,23445,23620,23623,23726,23716,23712,23733,23727,23720,23724,23711,23715,23725,23714,23722,23719,23709,23717,23734,23728,23718,24087,24084,24089,24360,24354,24355,24356,24404,24450,24446,24445,24542,24549,24621,24614,24601,24626,24587,24628,24586,24599,24627,24602,24606,24620,24610,24589,24592,24622,24595,24593,24588,24585,24604,25108,25149,25261,25268,25297,25278,25258,25270,25290,25262,25267,25263,25275,25257,25264,25272,25917,26024,26043,26121,26108,26116,26130,26120,26107,26115,26123,26125,26117,26109,26129,26128,26358,26378,26501,26476,26510,26514,26486,26491,26520,26502,26500,26484,26509,26508,26490,26527,26513,26521,26499,26493,26497,26488,26489,26516,27429,27520,27518,27614,27677,27795,27884,27883,27886,27865,27830,27860,27821,27879,27831,27856,27842,27834,27843,27846,27885,27890,27858,27869,27828,27786,27805,27776,27870,27840,27952,27853,27847,27824,27897,27855,27881,27857,28820,28824,28805,28819,28806,28804,28817,28822,28802,28826,28803,29290,29398,29387,29400,29385,29404,29394,29396,29402,29388,29393,29604,29601,29613,29606,29602,29600,29612,29597,29917,29928,30015,30016,30014,30092,30104,30383,30451,30449,30448,30453,30712,30716,30713,30715,30714,30711,31042,31039,31173,31352,31355,31483,31861,31997,32821,32911,32942,32931,32952,32949,32941,33312,33440,33472,33451,33434,33432,33435,33461,33447,33454,33468,33438,33466,33460,33448,33441,33449,33474,33444,33475,33462,33442,34416,34415,34413,34414,35926,36818,36811,36819,36813,36822,36821,36823,37042,37044,37039,37043,37040,38457,38461,38460,38458,38467,20429,20421,20435,20402,20425,20427,20417,20436,20444,20441,20411,20403,20443,20423,20438,20410,20416,20409,20460,21060,21065,21184,21186,21309,21372,21399,21398,21401,21400,21690,21665,21677,21669,21711,21699,33549,21687,21678,21718,21686,21701,21702,21664,21616,21692,21666,21694,21618,21726,21680,22453,22430,22431,22436,22412,22423,22429,22427,22420,22424,22415,22425,22437,22426,22421,22772,22797,22867,23009,23006,23022,23040,23025,23005,23034,23037,23036,23030,23012,23026,23031,23003,23017,23027,23029,23008,23038,23028,23021,23464,23628,23760,23768,23756,23767,23755,23771,23774,23770,23753,23751,23754,23766,23763,23764,23759,23752,23750,23758,23775,23800,24057,24097,24098,24099,24096,24100,24240,24228,24226,24219,24227,24229,24327,24366,24406,24454,24631,24633,24660,24690,24670,24645,24659,24647,24649,24667,24652,24640,24642,24671,24612,24644,24664,24678,24686,25154,25155,25295,25357,25355,25333,25358,25347,25323,25337,25359,25356,25336,25334,25344,25363,25364,25338,25365,25339,25328,25921,25923,26026,26047,26166,26145,26162,26165,26140,26150,26146,26163,26155,26170,26141,26164,26169,26158,26383,26384,26561,26610,26568,26554,26588,26555,26616,26584,26560,26551,26565,26603,26596,26591,26549,26573,26547,26615,26614,26606,26595,26562,26553,26574,26599,26608,26546,26620,26566,26605,26572,26542,26598,26587,26618,26569,26570,26563,26602,26571,27432,27522,27524,27574,27606,27608,27616,27680,27681,27944,27956,27949,27935,27964,27967,27922,27914,27866,27955,27908,27929,27962,27930,27921,27904,27933,27970,27905,27928,27959,27907,27919,27968,27911,27936,27948,27912,27938,27913,27920,28855,28831,28862,28849,28848,28833,28852,28853,28841,29249,29257,29258,29292,29296,29299,29294,29386,29412,29416,29419,29407,29418,29414,29411,29573,29644,29634,29640,29637,29625,29622,29621,29620,29675,29631,29639,29630,29635,29638,29624,29643,29932,29934,29998,30023,30024,30119,30122,30329,30404,30472,30467,30468,30469,30474,30455,30459,30458,30695,30696,30726,30737,30738,30725,30736,30735,30734,30729,30723,30739,31050,31052,31051,31045,31044,31189,31181,31183,31190,31182,31360,31358,31441,31488,31489,31866,31864,31865,31871,31872,31873,32003,32008,32001,32600,32657,32653,32702,32775,32782,32783,32788,32823,32984,32967,32992,32977,32968,32962,32976,32965,32995,32985,32988,32970,32981,32969,32975,32983,32998,32973,33279,33313,33428,33497,33534,33529,33543,33512,33536,33493,33594,33515,33494,33524,33516,33505,33522,33525,33548,33531,33526,33520,33514,33508,33504,33530,33523,33517,34423,34420,34428,34419,34881,34894,34919,34922,34921,35283,35332,35335,36210,36835,36833,36846,36832,37105,37053,37055,37077,37061,37054,37063,37067,37064,37332,37331,38484,38479,38481,38483,38474,38478,20510,20485,20487,20499,20514,20528,20507,20469,20468,20531,20535,20524,20470,20471,20503,20508,20512,20519,20533,20527,20529,20494,20826,20884,20883,20938,20932,20933,20936,20942,21089,21082,21074,21086,21087,21077,21090,21197,21262,21406,21798,21730,21783,21778,21735,21747,21732,21786,21759,21764,21768,21739,21777,21765,21745,21770,21755,21751,21752,21728,21774,21763,21771,22273,22274,22476,22578,22485,22482,22458,22470,22461,22460,22456,22454,22463,22471,22480,22457,22465,22798,22858,23065,23062,23085,23086,23061,23055,23063,23050,23070,23091,23404,23463,23469,23468,23555,23638,23636,23788,23807,23790,23793,23799,23808,23801,24105,24104,24232,24238,24234,24236,24371,24368,24423,24669,24666,24679,24641,24738,24712,24704,24722,24705,24733,24707,24725,24731,24727,24711,24732,24718,25113,25158,25330,25360,25430,25388,25412,25413,25398,25411,25572,25401,25419,25418,25404,25385,25409,25396,25432,25428,25433,25389,25415,25395,25434,25425,25400,25431,25408,25416,25930,25926,26054,26051,26052,26050,26186,26207,26183,26193,26386,26387,26655,26650,26697,26674,26675,26683,26699,26703,26646,26673,26652,26677,26667,26669,26671,26702,26692,26676,26653,26642,26644,26662,26664,26670,26701,26682,26661,26656,27436,27439,27437,27441,27444,27501,32898,27528,27622,27620,27624,27619,27618,27623,27685,28026,28003,28004,28022,27917,28001,28050,27992,28002,28013,28015,28049,28045,28143,28031,28038,27998,28007,28000,28055,28016,28028,27999,28034,28056,27951,28008,28043,28030,28032,28036,27926,28035,28027,28029,28021,28048,28892,28883,28881,28893,28875,32569,28898,28887,28882,28894,28896,28884,28877,28869,28870,28871,28890,28878,28897,29250,29304,29303,29302,29440,29434,29428,29438,29430,29427,29435,29441,29651,29657,29669,29654,29628,29671,29667,29673,29660,29650,29659,29652,29661,29658,29655,29656,29672,29918,29919,29940,29941,29985,30043,30047,30128,30145,30139,30148,30144,30143,30134,30138,30346,30409,30493,30491,30480,30483,30482,30499,30481,30485,30489,30490,30498,30503,30755,30764,30754,30773,30767,30760,30766,30763,30753,30761,30771,30762,30769,31060,31067,31055,31068,31059,31058,31057,31211,31212,31200,31214,31213,31210,31196,31198,31197,31366,31369,31365,31371,31372,31370,31367,31448,31504,31492,31507,31493,31503,31496,31498,31502,31497,31506,31876,31889,31882,31884,31880,31885,31877,32030,32029,32017,32014,32024,32022,32019,32031,32018,32015,32012,32604,32609,32606,32608,32605,32603,32662,32658,32707,32706,32704,32790,32830,32825,33018,33010,33017,33013,33025,33019,33024,33281,33327,33317,33587,33581,33604,33561,33617,33573,33622,33599,33601,33574,33564,33570,33602,33614,33563,33578,33544,33596,33613,33558,33572,33568,33591,33583,33577,33607,33605,33612,33619,33566,33580,33611,33575,33608,34387,34386,34466,34472,34454,34445,34449,34462,34439,34455,34438,34443,34458,34437,34469,34457,34465,34471,34453,34456,34446,34461,34448,34452,34883,34884,34925,34933,34934,34930,34944,34929,34943,34927,34947,34942,34932,34940,35346,35911,35927,35963,36004,36003,36214,36216,36277,36279,36278,36561,36563,36862,36853,36866,36863,36859,36868,36860,36854,37078,37088,37081,37082,37091,37087,37093,37080,37083,37079,37084,37092,37200,37198,37199,37333,37346,37338,38492,38495,38588,39139,39647,39727,20095,20592,20586,20577,20574,20576,20563,20555,20573,20594,20552,20557,20545,20571,20554,20578,20501,20549,20575,20585,20587,20579,20580,20550,20544,20590,20595,20567,20561,20944,21099,21101,21100,21102,21206,21203,21293,21404,21877,21878,21820,21837,21840,21812,21802,21841,21858,21814,21813,21808,21842,21829,21772,21810,21861,21838,21817,21832,21805,21819,21824,21835,22282,22279,22523,22548,22498,22518,22492,22516,22528,22509,22525,22536,22520,22539,22515,22479,22535,22510,22499,22514,22501,22508,22497,22542,22524,22544,22503,22529,22540,22513,22505,22512,22541,22532,22876,23136,23128,23125,23143,23134,23096,23093,23149,23120,23135,23141,23148,23123,23140,23127,23107,23133,23122,23108,23131,23112,23182,23102,23117,23097,23116,23152,23145,23111,23121,23126,23106,23132,23410,23406,23489,23488,23641,23838,23819,23837,23834,23840,23820,23848,23821,23846,23845,23823,23856,23826,23843,23839,23854,24126,24116,24241,24244,24249,24242,24243,24374,24376,24475,24470,24479,24714,24720,24710,24766,24752,24762,24787,24788,24783,24804,24793,24797,24776,24753,24795,24759,24778,24767,24771,24781,24768,25394,25445,25482,25474,25469,25533,25502,25517,25501,25495,25515,25486,25455,25479,25488,25454,25519,25461,25500,25453,25518,25468,25508,25403,25503,25464,25477,25473,25489,25485,25456,25939,26061,26213,26209,26203,26201,26204,26210,26392,26745,26759,26768,26780,26733,26734,26798,26795,26966,26735,26787,26796,26793,26741,26740,26802,26767,26743,26770,26748,26731,26738,26794,26752,26737,26750,26779,26774,26763,26784,26761,26788,26744,26747,26769,26764,26762,26749,27446,27443,27447,27448,27537,27535,27533,27534,27532,27690,28096,28075,28084,28083,28276,28076,28137,28130,28087,28150,28116,28160,28104,28128,28127,28118,28094,28133,28124,28125,28123,28148,28106,28093,28141,28144,28090,28117,28098,28111,28105,28112,28146,28115,28157,28119,28109,28131,28091,28922,28941,28919,28951,28916,28940,28912,28932,28915,28944,28924,28927,28934,28947,28928,28920,28918,28939,28930,28942,29310,29307,29308,29311,29469,29463,29447,29457,29464,29450,29448,29439,29455,29470,29576,29686,29688,29685,29700,29697,29693,29703,29696,29690,29692,29695,29708,29707,29684,29704,30052,30051,30158,30162,30159,30155,30156,30161,30160,30351,30345,30419,30521,30511,30509,30513,30514,30516,30515,30525,30501,30523,30517,30792,30802,30793,30797,30794,30796,30758,30789,30800,31076,31079,31081,31082,31075,31083,31073,31163,31226,31224,31222,31223,31375,31380,31376,31541,31559,31540,31525,31536,31522,31524,31539,31512,31530,31517,31537,31531,31533,31535,31538,31544,31514,31523,31892,31896,31894,31907,32053,32061,32056,32054,32058,32069,32044,32041,32065,32071,32062,32063,32074,32059,32040,32611,32661,32668,32669,32667,32714,32715,32717,32720,32721,32711,32719,32713,32799,32798,32795,32839,32835,32840,33048,33061,33049,33051,33069,33055,33068,33054,33057,33045,33063,33053,33058,33297,33336,33331,33338,33332,33330,33396,33680,33699,33704,33677,33658,33651,33700,33652,33679,33665,33685,33689,33653,33684,33705,33661,33667,33676,33693,33691,33706,33675,33662,33701,33711,33672,33687,33712,33663,33702,33671,33710,33654,33690,34393,34390,34495,34487,34498,34497,34501,34490,34480,34504,34489,34483,34488,34508,34484,34491,34492,34499,34493,34494,34898,34953,34965,34984,34978,34986,34970,34961,34977,34975,34968,34983,34969,34971,34967,34980,34988,34956,34963,34958,35202,35286,35289,35285,35376,35367,35372,35358,35897,35899,35932,35933,35965,36005,36221,36219,36217,36284,36290,36281,36287,36289,36568,36574,36573,36572,36567,36576,36577,36900,36875,36881,36892,36876,36897,37103,37098,37104,37108,37106,37107,37076,37099,37100,37097,37206,37208,37210,37203,37205,37356,37364,37361,37363,37368,37348,37369,37354,37355,37367,37352,37358,38266,38278,38280,38524,38509,38507,38513,38511,38591,38762,38916,39141,39319,20635,20629,20628,20638,20619,20643,20611,20620,20622,20637,20584,20636,20626,20610,20615,20831,20948,21266,21265,21412,21415,21905,21928,21925,21933,21879,22085,21922,21907,21896,21903,21941,21889,21923,21906,21924,21885,21900,21926,21887,21909,21921,21902,22284,22569,22583,22553,22558,22567,22563,22568,22517,22600,22565,22556,22555,22579,22591,22582,22574,22585,22584,22573,22572,22587,22881,23215,23188,23199,23162,23202,23198,23160,23206,23164,23205,23212,23189,23214,23095,23172,23178,23191,23171,23179,23209,23163,23165,23180,23196,23183,23187,23197,23530,23501,23499,23508,23505,23498,23502,23564,23600,23863,23875,23915,23873,23883,23871,23861,23889,23886,23893,23859,23866,23890,23869,23857,23897,23874,23865,23881,23864,23868,23858,23862,23872,23877,24132,24129,24408,24486,24485,24491,24777,24761,24780,24802,24782,24772,24852,24818,24842,24854,24837,24821,24851,24824,24828,24830,24769,24835,24856,24861,24848,24831,24836,24843,25162,25492,25521,25520,25550,25573,25576,25583,25539,25757,25587,25546,25568,25590,25557,25586,25589,25697,25567,25534,25565,25564,25540,25560,25555,25538,25543,25548,25547,25544,25584,25559,25561,25906,25959,25962,25956,25948,25960,25957,25996,26013,26014,26030,26064,26066,26236,26220,26235,26240,26225,26233,26218,26226,26369,26892,26835,26884,26844,26922,26860,26858,26865,26895,26838,26871,26859,26852,26870,26899,26896,26867,26849,26887,26828,26888,26992,26804,26897,26863,26822,26900,26872,26832,26877,26876,26856,26891,26890,26903,26830,26824,26845,26846,26854,26868,26833,26886,26836,26857,26901,26917,26823,27449,27451,27455,27452,27540,27543,27545,27541,27581,27632,27634,27635,27696,28156,28230,28231,28191,28233,28296,28220,28221,28229,28258,28203,28223,28225,28253,28275,28188,28211,28235,28224,28241,28219,28163,28206,28254,28264,28252,28257,28209,28200,28256,28273,28267,28217,28194,28208,28243,28261,28199,28280,28260,28279,28245,28281,28242,28262,28213,28214,28250,28960,28958,28975,28923,28974,28977,28963,28965,28962,28978,28959,28968,28986,28955,29259,29274,29320,29321,29318,29317,29323,29458,29451,29488,29474,29489,29491,29479,29490,29485,29478,29475,29493,29452,29742,29740,29744,29739,29718,29722,29729,29741,29745,29732,29731,29725,29737,29728,29746,29947,29999,30063,30060,30183,30170,30177,30182,30173,30175,30180,30167,30357,30354,30426,30534,30535,30532,30541,30533,30538,30542,30539,30540,30686,30700,30816,30820,30821,30812,30829,30833,30826,30830,30832,30825,30824,30814,30818,31092,31091,31090,31088,31234,31242,31235,31244,31236,31385,31462,31460,31562,31547,31556,31560,31564,31566,31552,31576,31557,31906,31902,31912,31905,32088,32111,32099,32083,32086,32103,32106,32079,32109,32092,32107,32082,32084,32105,32081,32095,32078,32574,32575,32613,32614,32674,32672,32673,32727,32849,32847,32848,33022,32980,33091,33098,33106,33103,33095,33085,33101,33082,33254,33262,33271,33272,33273,33284,33340,33341,33343,33397,33595,33743,33785,33827,33728,33768,33810,33767,33764,33788,33782,33808,33734,33736,33771,33763,33727,33793,33757,33765,33752,33791,33761,33739,33742,33750,33781,33737,33801,33807,33758,33809,33798,33730,33779,33749,33786,33735,33745,33770,33811,33731,33772,33774,33732,33787,33751,33762,33819,33755,33790,34520,34530,34534,34515,34531,34522,34538,34525,34539,34524,34540,34537,34519,34536,34513,34888,34902,34901,35002,35031,35001,35000,35008,35006,34998,35004,34999,35005,34994,35073,35017,35221,35224,35223,35293,35290,35291,35406,35405,35385,35417,35392,35415,35416,35396,35397,35410,35400,35409,35402,35404,35407,35935,35969,35968,36026,36030,36016,36025,36021,36228,36224,36233,36312,36307,36301,36295,36310,36316,36303,36309,36313,36296,36311,36293,36591,36599,36602,36601,36582,36590,36581,36597,36583,36584,36598,36587,36593,36588,36596,36585,36909,36916,36911,37126,37164,37124,37119,37116,37128,37113,37115,37121,37120,37127,37125,37123,37217,37220,37215,37218,37216,37377,37386,37413,37379,37402,37414,37391,37388,37376,37394,37375,37373,37382,37380,37415,37378,37404,37412,37401,37399,37381,37398,38267,38285,38284,38288,38535,38526,38536,38537,38531,38528,38594,38600,38595,38641,38640,38764,38768,38766,38919,39081,39147,40166,40697,20099,20100,20150,20669,20671,20678,20654,20676,20682,20660,20680,20674,20656,20673,20666,20657,20683,20681,20662,20664,20951,21114,21112,21115,21116,21955,21979,21964,21968,21963,21962,21981,21952,21972,21956,21993,21951,21970,21901,21967,21973,21986,21974,21960,22002,21965,21977,21954,22292,22611,22632,22628,22607,22605,22601,22639,22613,22606,22621,22617,22629,22619,22589,22627,22641,22780,23239,23236,23243,23226,23224,23217,23221,23216,23231,23240,23227,23238,23223,23232,23242,23220,23222,23245,23225,23184,23510,23512,23513,23583,23603,23921,23907,23882,23909,23922,23916,23902,23912,23911,23906,24048,24143,24142,24138,24141,24139,24261,24268,24262,24267,24263,24384,24495,24493,24823,24905,24906,24875,24901,24886,24882,24878,24902,24879,24911,24873,24896,25120,37224,25123,25125,25124,25541,25585,25579,25616,25618,25609,25632,25636,25651,25667,25631,25621,25624,25657,25655,25634,25635,25612,25638,25648,25640,25665,25653,25647,25610,25626,25664,25637,25639,25611,25575,25627,25646,25633,25614,25967,26002,26067,26246,26252,26261,26256,26251,26250,26265,26260,26232,26400,26982,26975,26936,26958,26978,26993,26943,26949,26986,26937,26946,26967,26969,27002,26952,26953,26933,26988,26931,26941,26981,26864,27000,26932,26985,26944,26991,26948,26998,26968,26945,26996,26956,26939,26955,26935,26972,26959,26961,26930,26962,26927,27003,26940,27462,27461,27459,27458,27464,27457,27547,64013,27643,27644,27641,27639,27640,28315,28374,28360,28303,28352,28319,28307,28308,28320,28337,28345,28358,28370,28349,28353,28318,28361,28343,28336,28365,28326,28367,28338,28350,28355,28380,28376,28313,28306,28302,28301,28324,28321,28351,28339,28368,28362,28311,28334,28323,28999,29012,29010,29027,29024,28993,29021,29026,29042,29048,29034,29025,28994,29016,28995,29003,29040,29023,29008,29011,28996,29005,29018,29263,29325,29324,29329,29328,29326,29500,29506,29499,29498,29504,29514,29513,29764,29770,29771,29778,29777,29783,29760,29775,29776,29774,29762,29766,29773,29780,29921,29951,29950,29949,29981,30073,30071,27011,30191,30223,30211,30199,30206,30204,30201,30200,30224,30203,30198,30189,30197,30205,30361,30389,30429,30549,30559,30560,30546,30550,30554,30569,30567,30548,30553,30573,30688,30855,30874,30868,30863,30852,30869,30853,30854,30881,30851,30841,30873,30848,30870,30843,31100,31106,31101,31097,31249,31256,31257,31250,31255,31253,31266,31251,31259,31248,31395,31394,31390,31467,31590,31588,31597,31604,31593,31602,31589,31603,31601,31600,31585,31608,31606,31587,31922,31924,31919,32136,32134,32128,32141,32127,32133,32122,32142,32123,32131,32124,32140,32148,32132,32125,32146,32621,32619,32615,32616,32620,32678,32677,32679,32731,32732,32801,33124,33120,33143,33116,33129,33115,33122,33138,26401,33118,33142,33127,33135,33092,33121,33309,33353,33348,33344,33346,33349,34033,33855,33878,33910,33913,33935,33933,33893,33873,33856,33926,33895,33840,33869,33917,33882,33881,33908,33907,33885,34055,33886,33847,33850,33844,33914,33859,33912,33842,33861,33833,33753,33867,33839,33858,33837,33887,33904,33849,33870,33868,33874,33903,33989,33934,33851,33863,33846,33843,33896,33918,33860,33835,33888,33876,33902,33872,34571,34564,34551,34572,34554,34518,34549,34637,34552,34574,34569,34561,34550,34573,34565,35030,35019,35021,35022,35038,35035,35034,35020,35024,35205,35227,35295,35301,35300,35297,35296,35298,35292,35302,35446,35462,35455,35425,35391,35447,35458,35460,35445,35459,35457,35444,35450,35900,35915,35914,35941,35940,35942,35974,35972,35973,36044,36200,36201,36241,36236,36238,36239,36237,36243,36244,36240,36242,36336,36320,36332,36337,36334,36304,36329,36323,36322,36327,36338,36331,36340,36614,36607,36609,36608,36613,36615,36616,36610,36619,36946,36927,36932,36937,36925,37136,37133,37135,37137,37142,37140,37131,37134,37230,37231,37448,37458,37424,37434,37478,37427,37477,37470,37507,37422,37450,37446,37485,37484,37455,37472,37479,37487,37430,37473,37488,37425,37460,37475,37456,37490,37454,37459,37452,37462,37426,38303,38300,38302,38299,38546,38547,38545,38551,38606,38650,38653,38648,38645,38771,38775,38776,38770,38927,38925,38926,39084,39158,39161,39343,39346,39344,39349,39597,39595,39771,40170,40173,40167,40576,40701,20710,20692,20695,20712,20723,20699,20714,20701,20708,20691,20716,20720,20719,20707,20704,20952,21120,21121,21225,21227,21296,21420,22055,22037,22028,22034,22012,22031,22044,22017,22035,22018,22010,22045,22020,22015,22009,22665,22652,22672,22680,22662,22657,22655,22644,22667,22650,22663,22673,22670,22646,22658,22664,22651,22676,22671,22782,22891,23260,23278,23269,23253,23274,23258,23277,23275,23283,23266,23264,23259,23276,23262,23261,23257,23272,23263,23415,23520,23523,23651,23938,23936,23933,23942,23930,23937,23927,23946,23945,23944,23934,23932,23949,23929,23935,24152,24153,24147,24280,24273,24279,24270,24284,24277,24281,24274,24276,24388,24387,24431,24502,24876,24872,24897,24926,24945,24947,24914,24915,24946,24940,24960,24948,24916,24954,24923,24933,24891,24938,24929,24918,25129,25127,25131,25643,25677,25691,25693,25716,25718,25714,25715,25725,25717,25702,25766,25678,25730,25694,25692,25675,25683,25696,25680,25727,25663,25708,25707,25689,25701,25719,25971,26016,26273,26272,26271,26373,26372,26402,27057,27062,27081,27040,27086,27030,27056,27052,27068,27025,27033,27022,27047,27021,27049,27070,27055,27071,27076,27069,27044,27092,27065,27082,27034,27087,27059,27027,27050,27041,27038,27097,27031,27024,27074,27061,27045,27078,27466,27469,27467,27550,27551,27552,27587,27588,27646,28366,28405,28401,28419,28453,28408,28471,28411,28462,28425,28494,28441,28442,28455,28440,28475,28434,28397,28426,28470,28531,28409,28398,28461,28480,28464,28476,28469,28395,28423,28430,28483,28421,28413,28406,28473,28444,28412,28474,28447,28429,28446,28424,28449,29063,29072,29065,29056,29061,29058,29071,29051,29062,29057,29079,29252,29267,29335,29333,29331,29507,29517,29521,29516,29794,29811,29809,29813,29810,29799,29806,29952,29954,29955,30077,30096,30230,30216,30220,30229,30225,30218,30228,30392,30593,30588,30597,30594,30574,30592,30575,30590,30595,30898,30890,30900,30893,30888,30846,30891,30878,30885,30880,30892,30882,30884,31128,31114,31115,31126,31125,31124,31123,31127,31112,31122,31120,31275,31306,31280,31279,31272,31270,31400,31403,31404,31470,31624,31644,31626,31633,31632,31638,31629,31628,31643,31630,31621,31640,21124,31641,31652,31618,31931,31935,31932,31930,32167,32183,32194,32163,32170,32193,32192,32197,32157,32206,32196,32198,32203,32204,32175,32185,32150,32188,32159,32166,32174,32169,32161,32201,32627,32738,32739,32741,32734,32804,32861,32860,33161,33158,33155,33159,33165,33164,33163,33301,33943,33956,33953,33951,33978,33998,33986,33964,33966,33963,33977,33972,33985,33997,33962,33946,33969,34000,33949,33959,33979,33954,33940,33991,33996,33947,33961,33967,33960,34006,33944,33974,33999,33952,34007,34004,34002,34011,33968,33937,34401,34611,34595,34600,34667,34624,34606,34590,34593,34585,34587,34627,34604,34625,34622,34630,34592,34610,34602,34605,34620,34578,34618,34609,34613,34626,34598,34599,34616,34596,34586,34608,34577,35063,35047,35057,35058,35066,35070,35054,35068,35062,35067,35056,35052,35051,35229,35233,35231,35230,35305,35307,35304,35499,35481,35467,35474,35471,35478,35901,35944,35945,36053,36047,36055,36246,36361,36354,36351,36365,36349,36362,36355,36359,36358,36357,36350,36352,36356,36624,36625,36622,36621,37155,37148,37152,37154,37151,37149,37146,37156,37153,37147,37242,37234,37241,37235,37541,37540,37494,37531,37498,37536,37524,37546,37517,37542,37530,37547,37497,37527,37503,37539,37614,37518,37506,37525,37538,37501,37512,37537,37514,37510,37516,37529,37543,37502,37511,37545,37533,37515,37421,38558,38561,38655,38744,38781,38778,38782,38787,38784,38786,38779,38788,38785,38783,38862,38861,38934,39085,39086,39170,39168,39175,39325,39324,39363,39353,39355,39354,39362,39357,39367,39601,39651,39655,39742,39743,39776,39777,39775,40177,40178,40181,40615,20735,20739,20784,20728,20742,20743,20726,20734,20747,20748,20733,20746,21131,21132,21233,21231,22088,22082,22092,22069,22081,22090,22089,22086,22104,22106,22080,22067,22077,22060,22078,22072,22058,22074,22298,22699,22685,22705,22688,22691,22703,22700,22693,22689,22783,23295,23284,23293,23287,23286,23299,23288,23298,23289,23297,23303,23301,23311,23655,23961,23959,23967,23954,23970,23955,23957,23968,23964,23969,23962,23966,24169,24157,24160,24156,32243,24283,24286,24289,24393,24498,24971,24963,24953,25009,25008,24994,24969,24987,24979,25007,25005,24991,24978,25002,24993,24973,24934,25011,25133,25710,25712,25750,25760,25733,25751,25756,25743,25739,25738,25740,25763,25759,25704,25777,25752,25974,25978,25977,25979,26034,26035,26293,26288,26281,26290,26295,26282,26287,27136,27142,27159,27109,27128,27157,27121,27108,27168,27135,27116,27106,27163,27165,27134,27175,27122,27118,27156,27127,27111,27200,27144,27110,27131,27149,27132,27115,27145,27140,27160,27173,27151,27126,27174,27143,27124,27158,27473,27557,27555,27554,27558,27649,27648,27647,27650,28481,28454,28542,28551,28614,28562,28557,28553,28556,28514,28495,28549,28506,28566,28534,28524,28546,28501,28530,28498,28496,28503,28564,28563,28509,28416,28513,28523,28541,28519,28560,28499,28555,28521,28543,28565,28515,28535,28522,28539,29106,29103,29083,29104,29088,29082,29097,29109,29085,29093,29086,29092,29089,29098,29084,29095,29107,29336,29338,29528,29522,29534,29535,29536,29533,29531,29537,29530,29529,29538,29831,29833,29834,29830,29825,29821,29829,29832,29820,29817,29960,29959,30078,30245,30238,30233,30237,30236,30243,30234,30248,30235,30364,30365,30366,30363,30605,30607,30601,30600,30925,30907,30927,30924,30929,30926,30932,30920,30915,30916,30921,31130,31137,31136,31132,31138,31131,27510,31289,31410,31412,31411,31671,31691,31678,31660,31694,31663,31673,31690,31669,31941,31944,31948,31947,32247,32219,32234,32231,32215,32225,32259,32250,32230,32246,32241,32240,32238,32223,32630,32684,32688,32685,32749,32747,32746,32748,32742,32744,32868,32871,33187,33183,33182,33173,33186,33177,33175,33302,33359,33363,33362,33360,33358,33361,34084,34107,34063,34048,34089,34062,34057,34061,34079,34058,34087,34076,34043,34091,34042,34056,34060,34036,34090,34034,34069,34039,34027,34035,34044,34066,34026,34025,34070,34046,34088,34077,34094,34050,34045,34078,34038,34097,34086,34023,34024,34032,34031,34041,34072,34080,34096,34059,34073,34095,34402,34646,34659,34660,34679,34785,34675,34648,34644,34651,34642,34657,34650,34641,34654,34669,34666,34640,34638,34655,34653,34671,34668,34682,34670,34652,34661,34639,34683,34677,34658,34663,34665,34906,35077,35084,35092,35083,35095,35096,35097,35078,35094,35089,35086,35081,35234,35236,35235,35309,35312,35308,35535,35526,35512,35539,35537,35540,35541,35515,35543,35518,35520,35525,35544,35523,35514,35517,35545,35902,35917,35983,36069,36063,36057,36072,36058,36061,36071,36256,36252,36257,36251,36384,36387,36389,36388,36398,36373,36379,36374,36369,36377,36390,36391,36372,36370,36376,36371,36380,36375,36378,36652,36644,36632,36634,36640,36643,36630,36631,36979,36976,36975,36967,36971,37167,37163,37161,37162,37170,37158,37166,37253,37254,37258,37249,37250,37252,37248,37584,37571,37572,37568,37593,37558,37583,37617,37599,37592,37609,37591,37597,37580,37615,37570,37608,37578,37576,37582,37606,37581,37589,37577,37600,37598,37607,37585,37587,37557,37601,37574,37556,38268,38316,38315,38318,38320,38564,38562,38611,38661,38664,38658,38746,38794,38798,38792,38864,38863,38942,38941,38950,38953,38952,38944,38939,38951,39090,39176,39162,39185,39188,39190,39191,39189,39388,39373,39375,39379,39380,39374,39369,39382,39384,39371,39383,39372,39603,39660,39659,39667,39666,39665,39750,39747,39783,39796,39793,39782,39798,39797,39792,39784,39780,39788,40188,40186,40189,40191,40183,40199,40192,40185,40187,40200,40197,40196,40579,40659,40719,40720,20764,20755,20759,20762,20753,20958,21300,21473,22128,22112,22126,22131,22118,22115,22125,22130,22110,22135,22300,22299,22728,22717,22729,22719,22714,22722,22716,22726,23319,23321,23323,23329,23316,23315,23312,23318,23336,23322,23328,23326,23535,23980,23985,23977,23975,23989,23984,23982,23978,23976,23986,23981,23983,23988,24167,24168,24166,24175,24297,24295,24294,24296,24293,24395,24508,24989,25000,24982,25029,25012,25030,25025,25036,25018,25023,25016,24972,25815,25814,25808,25807,25801,25789,25737,25795,25819,25843,25817,25907,25983,25980,26018,26312,26302,26304,26314,26315,26319,26301,26299,26298,26316,26403,27188,27238,27209,27239,27186,27240,27198,27229,27245,27254,27227,27217,27176,27226,27195,27199,27201,27242,27236,27216,27215,27220,27247,27241,27232,27196,27230,27222,27221,27213,27214,27206,27477,27476,27478,27559,27562,27563,27592,27591,27652,27651,27654,28589,28619,28579,28615,28604,28622,28616,28510,28612,28605,28574,28618,28584,28676,28581,28590,28602,28588,28586,28623,28607,28600,28578,28617,28587,28621,28591,28594,28592,29125,29122,29119,29112,29142,29120,29121,29131,29140,29130,29127,29135,29117,29144,29116,29126,29146,29147,29341,29342,29545,29542,29543,29548,29541,29547,29546,29823,29850,29856,29844,29842,29845,29857,29963,30080,30255,30253,30257,30269,30259,30268,30261,30258,30256,30395,30438,30618,30621,30625,30620,30619,30626,30627,30613,30617,30615,30941,30953,30949,30954,30942,30947,30939,30945,30946,30957,30943,30944,31140,31300,31304,31303,31414,31416,31413,31409,31415,31710,31715,31719,31709,31701,31717,31706,31720,31737,31700,31722,31714,31708,31723,31704,31711,31954,31956,31959,31952,31953,32274,32289,32279,32268,32287,32288,32275,32270,32284,32277,32282,32290,32267,32271,32278,32269,32276,32293,32292,32579,32635,32636,32634,32689,32751,32810,32809,32876,33201,33190,33198,33209,33205,33195,33200,33196,33204,33202,33207,33191,33266,33365,33366,33367,34134,34117,34155,34125,34131,34145,34136,34112,34118,34148,34113,34146,34116,34129,34119,34147,34110,34139,34161,34126,34158,34165,34133,34151,34144,34188,34150,34141,34132,34149,34156,34403,34405,34404,34715,34703,34711,34707,34706,34696,34689,34710,34712,34681,34695,34723,34693,34704,34705,34717,34692,34708,34716,34714,34697,35102,35110,35120,35117,35118,35111,35121,35106,35113,35107,35119,35116,35103,35313,35552,35554,35570,35572,35573,35549,35604,35556,35551,35568,35528,35550,35553,35560,35583,35567,35579,35985,35986,35984,36085,36078,36081,36080,36083,36204,36206,36261,36263,36403,36414,36408,36416,36421,36406,36412,36413,36417,36400,36415,36541,36662,36654,36661,36658,36665,36663,36660,36982,36985,36987,36998,37114,37171,37173,37174,37267,37264,37265,37261,37263,37671,37662,37640,37663,37638,37647,37754,37688,37692,37659,37667,37650,37633,37702,37677,37646,37645,37579,37661,37626,37669,37651,37625,37623,37684,37634,37668,37631,37673,37689,37685,37674,37652,37644,37643,37630,37641,37632,37627,37654,38332,38349,38334,38329,38330,38326,38335,38325,38333,38569,38612,38667,38674,38672,38809,38807,38804,38896,38904,38965,38959,38962,39204,39199,39207,39209,39326,39406,39404,39397,39396,39408,39395,39402,39401,39399,39609,39615,39604,39611,39670,39674,39673,39671,39731,39808,39813,39815,39804,39806,39803,39810,39827,39826,39824,39802,39829,39805,39816,40229,40215,40224,40222,40212,40233,40221,40216,40226,40208,40217,40223,40584,40582,40583,40622,40621,40661,40662,40698,40722,40765,20774,20773,20770,20772,20768,20777,21236,22163,22156,22157,22150,22148,22147,22142,22146,22143,22145,22742,22740,22735,22738,23341,23333,23346,23331,23340,23335,23334,23343,23342,23419,23537,23538,23991,24172,24170,24510,24507,25027,25013,25020,25063,25056,25061,25060,25064,25054,25839,25833,25827,25835,25828,25832,25985,25984,26038,26074,26322,27277,27286,27265,27301,27273,27295,27291,27297,27294,27271,27283,27278,27285,27267,27304,27300,27281,27263,27302,27290,27269,27276,27282,27483,27565,27657,28620,28585,28660,28628,28643,28636,28653,28647,28646,28638,28658,28637,28642,28648,29153,29169,29160,29170,29156,29168,29154,29555,29550,29551,29847,29874,29867,29840,29866,29869,29873,29861,29871,29968,29969,29970,29967,30084,30275,30280,30281,30279,30372,30441,30645,30635,30642,30647,30646,30644,30641,30632,30704,30963,30973,30978,30971,30972,30962,30981,30969,30974,30980,31147,31144,31324,31323,31318,31320,31316,31322,31422,31424,31425,31749,31759,31730,31744,31743,31739,31758,31732,31755,31731,31746,31753,31747,31745,31736,31741,31750,31728,31729,31760,31754,31976,32301,32316,32322,32307,38984,32312,32298,32329,32320,32327,32297,32332,32304,32315,32310,32324,32314,32581,32639,32638,32637,32756,32754,32812,33211,33220,33228,33226,33221,33223,33212,33257,33371,33370,33372,34179,34176,34191,34215,34197,34208,34187,34211,34171,34212,34202,34206,34167,34172,34185,34209,34170,34168,34135,34190,34198,34182,34189,34201,34205,34177,34210,34178,34184,34181,34169,34166,34200,34192,34207,34408,34750,34730,34733,34757,34736,34732,34745,34741,34748,34734,34761,34755,34754,34764,34743,34735,34756,34762,34740,34742,34751,34744,34749,34782,34738,35125,35123,35132,35134,35137,35154,35127,35138,35245,35247,35246,35314,35315,35614,35608,35606,35601,35589,35595,35618,35599,35602,35605,35591,35597,35592,35590,35612,35603,35610,35919,35952,35954,35953,35951,35989,35988,36089,36207,36430,36429,36435,36432,36428,36423,36675,36672,36997,36990,37176,37274,37282,37275,37273,37279,37281,37277,37280,37793,37763,37807,37732,37718,37703,37756,37720,37724,37750,37705,37712,37713,37728,37741,37775,37708,37738,37753,37719,37717,37714,37711,37745,37751,37755,37729,37726,37731,37735,37760,37710,37721,38343,38336,38345,38339,38341,38327,38574,38576,38572,38688,38687,38680,38685,38681,38810,38817,38812,38814,38813,38869,38868,38897,38977,38980,38986,38985,38981,38979,39205,39211,39212,39210,39219,39218,39215,39213,39217,39216,39320,39331,39329,39426,39418,39412,39415,39417,39416,39414,39419,39421,39422,39420,39427,39614,39678,39677,39681,39676,39752,39834,39848,39838,39835,39846,39841,39845,39844,39814,39842,39840,39855,40243,40257,40295,40246,40238,40239,40241,40248,40240,40261,40258,40259,40254,40247,40256,40253,32757,40237,40586,40585,40589,40624,40648,40666,40699,40703,40740,40739,40738,40788,40864,20785,20781,20782,22168,22172,22167,22170,22173,22169,22896,23356,23657,23658,24000,24173,24174,25048,25055,25069,25070,25073,25066,25072,25067,25046,25065,25855,25860,25853,25848,25857,25859,25852,26004,26075,26330,26331,26328,27333,27321,27325,27361,27334,27322,27318,27319,27335,27316,27309,27486,27593,27659,28679,28684,28685,28673,28677,28692,28686,28671,28672,28667,28710,28668,28663,28682,29185,29183,29177,29187,29181,29558,29880,29888,29877,29889,29886,29878,29883,29890,29972,29971,30300,30308,30297,30288,30291,30295,30298,30374,30397,30444,30658,30650,30975,30988,30995,30996,30985,30992,30994,30993,31149,31148,31327,31772,31785,31769,31776,31775,31789,31773,31782,31784,31778,31781,31792,32348,32336,32342,32355,32344,32354,32351,32337,32352,32343,32339,32693,32691,32759,32760,32885,33233,33234,33232,33375,33374,34228,34246,34240,34243,34242,34227,34229,34237,34247,34244,34239,34251,34254,34248,34245,34225,34230,34258,34340,34232,34231,34238,34409,34791,34790,34786,34779,34795,34794,34789,34783,34803,34788,34772,34780,34771,34797,34776,34787,34724,34775,34777,34817,34804,34792,34781,35155,35147,35151,35148,35142,35152,35153,35145,35626,35623,35619,35635,35632,35637,35655,35631,35644,35646,35633,35621,35639,35622,35638,35630,35620,35643,35645,35642,35906,35957,35993,35992,35991,36094,36100,36098,36096,36444,36450,36448,36439,36438,36446,36453,36455,36443,36442,36449,36445,36457,36436,36678,36679,36680,36683,37160,37178,37179,37182,37288,37285,37287,37295,37290,37813,37772,37778,37815,37787,37789,37769,37799,37774,37802,37790,37798,37781,37768,37785,37791,37773,37809,37777,37810,37796,37800,37812,37795,37797,38354,38355,38353,38579,38615,38618,24002,38623,38616,38621,38691,38690,38693,38828,38830,38824,38827,38820,38826,38818,38821,38871,38873,38870,38872,38906,38992,38993,38994,39096,39233,39228,39226,39439,39435,39433,39437,39428,39441,39434,39429,39431,39430,39616,39644,39688,39684,39685,39721,39733,39754,39756,39755,39879,39878,39875,39871,39873,39861,39864,39891,39862,39876,39865,39869,40284,40275,40271,40266,40283,40267,40281,40278,40268,40279,40274,40276,40287,40280,40282,40590,40588,40671,40705,40704,40726,40741,40747,40746,40745,40744,40780,40789,20788,20789,21142,21239,21428,22187,22189,22182,22183,22186,22188,22746,22749,22747,22802,23357,23358,23359,24003,24176,24511,25083,25863,25872,25869,25865,25868,25870,25988,26078,26077,26334,27367,27360,27340,27345,27353,27339,27359,27356,27344,27371,27343,27341,27358,27488,27568,27660,28697,28711,28704,28694,28715,28705,28706,28707,28713,28695,28708,28700,28714,29196,29194,29191,29186,29189,29349,29350,29348,29347,29345,29899,29893,29879,29891,29974,30304,30665,30666,30660,30705,31005,31003,31009,31004,30999,31006,31152,31335,31336,31795,31804,31801,31788,31803,31980,31978,32374,32373,32376,32368,32375,32367,32378,32370,32372,32360,32587,32586,32643,32646,32695,32765,32766,32888,33239,33237,33380,33377,33379,34283,34289,34285,34265,34273,34280,34266,34263,34284,34290,34296,34264,34271,34275,34268,34257,34288,34278,34287,34270,34274,34816,34810,34819,34806,34807,34825,34828,34827,34822,34812,34824,34815,34826,34818,35170,35162,35163,35159,35169,35164,35160,35165,35161,35208,35255,35254,35318,35664,35656,35658,35648,35667,35670,35668,35659,35669,35665,35650,35666,35671,35907,35959,35958,35994,36102,36103,36105,36268,36266,36269,36267,36461,36472,36467,36458,36463,36475,36546,36690,36689,36687,36688,36691,36788,37184,37183,37296,37293,37854,37831,37839,37826,37850,37840,37881,37868,37836,37849,37801,37862,37834,37844,37870,37859,37845,37828,37838,37824,37842,37863,38269,38362,38363,38625,38697,38699,38700,38696,38694,38835,38839,38838,38877,38878,38879,39004,39001,39005,38999,39103,39101,39099,39102,39240,39239,39235,39334,39335,39450,39445,39461,39453,39460,39451,39458,39456,39463,39459,39454,39452,39444,39618,39691,39690,39694,39692,39735,39914,39915,39904,39902,39908,39910,39906,39920,39892,39895,39916,39900,39897,39909,39893,39905,39898,40311,40321,40330,40324,40328,40305,40320,40312,40326,40331,40332,40317,40299,40308,40309,40304,40297,40325,40307,40315,40322,40303,40313,40319,40327,40296,40596,40593,40640,40700,40749,40768,40769,40781,40790,40791,40792,21303,22194,22197,22195,22755,23365,24006,24007,24302,24303,24512,24513,25081,25879,25878,25877,25875,26079,26344,26339,26340,27379,27376,27370,27368,27385,27377,27374,27375,28732,28725,28719,28727,28724,28721,28738,28728,28735,28730,28729,28736,28731,28723,28737,29203,29204,29352,29565,29564,29882,30379,30378,30398,30445,30668,30670,30671,30669,30706,31013,31011,31015,31016,31012,31017,31154,31342,31340,31341,31479,31817,31816,31818,31815,31813,31982,32379,32382,32385,32384,32698,32767,32889,33243,33241,33291,33384,33385,34338,34303,34305,34302,34331,34304,34294,34308,34313,34309,34316,34301,34841,34832,34833,34839,34835,34838,35171,35174,35257,35319,35680,35690,35677,35688,35683,35685,35687,35693,36270,36486,36488,36484,36697,36694,36695,36693,36696,36698,37005,37187,37185,37303,37301,37298,37299,37899,37907,37883,37920,37903,37908,37886,37909,37904,37928,37913,37901,37877,37888,37879,37895,37902,37910,37906,37882,37897,37880,37898,37887,37884,37900,37878,37905,37894,38366,38368,38367,38702,38703,38841,38843,38909,38910,39008,39010,39011,39007,39105,39106,39248,39246,39257,39244,39243,39251,39474,39476,39473,39468,39466,39478,39465,39470,39480,39469,39623,39626,39622,39696,39698,39697,39947,39944,39927,39941,39954,39928,40000,39943,39950,39942,39959,39956,39945,40351,40345,40356,40349,40338,40344,40336,40347,40352,40340,40348,40362,40343,40353,40346,40354,40360,40350,40355,40383,40361,40342,40358,40359,40601,40603,40602,40677,40676,40679,40678,40752,40750,40795,40800,40798,40797,40793,40849,20794,20793,21144,21143,22211,22205,22206,23368,23367,24011,24015,24305,25085,25883,27394,27388,27395,27384,27392,28739,28740,28746,28744,28745,28741,28742,29213,29210,29209,29566,29975,30314,30672,31021,31025,31023,31828,31827,31986,32394,32391,32392,32395,32390,32397,32589,32699,32816,33245,34328,34346,34342,34335,34339,34332,34329,34343,34350,34337,34336,34345,34334,34341,34857,34845,34843,34848,34852,34844,34859,34890,35181,35177,35182,35179,35322,35705,35704,35653,35706,35707,36112,36116,36271,36494,36492,36702,36699,36701,37190,37188,37189,37305,37951,37947,37942,37929,37949,37948,37936,37945,37930,37943,37932,37952,37937,38373,38372,38371,38709,38714,38847,38881,39012,39113,39110,39104,39256,39254,39481,39485,39494,39492,39490,39489,39482,39487,39629,39701,39703,39704,39702,39738,39762,39979,39965,39964,39980,39971,39976,39977,39972,39969,40375,40374,40380,40385,40391,40394,40399,40382,40389,40387,40379,40373,40398,40377,40378,40364,40392,40369,40365,40396,40371,40397,40370,40570,40604,40683,40686,40685,40731,40728,40730,40753,40782,40805,40804,40850,20153,22214,22213,22219,22897,23371,23372,24021,24017,24306,25889,25888,25894,25890,27403,27400,27401,27661,28757,28758,28759,28754,29214,29215,29353,29567,29912,29909,29913,29911,30317,30381,31029,31156,31344,31345,31831,31836,31833,31835,31834,31988,31985,32401,32591,32647,33246,33387,34356,34357,34355,34348,34354,34358,34860,34856,34854,34858,34853,35185,35263,35262,35323,35710,35716,35714,35718,35717,35711,36117,36501,36500,36506,36498,36496,36502,36503,36704,36706,37191,37964,37968,37962,37963,37967,37959,37957,37960,37961,37958,38719,38883,39018,39017,39115,39252,39259,39502,39507,39508,39500,39503,39496,39498,39497,39506,39504,39632,39705,39723,39739,39766,39765,40006,40008,39999,40004,39993,39987,40001,39996,39991,39988,39986,39997,39990,40411,40402,40414,40410,40395,40400,40412,40401,40415,40425,40409,40408,40406,40437,40405,40413,40630,40688,40757,40755,40754,40770,40811,40853,40866,20797,21145,22760,22759,22898,23373,24024,34863,24399,25089,25091,25092,25897,25893,26006,26347,27409,27410,27407,27594,28763,28762,29218,29570,29569,29571,30320,30676,31847,31846,32405,33388,34362,34368,34361,34364,34353,34363,34366,34864,34866,34862,34867,35190,35188,35187,35326,35724,35726,35723,35720,35909,36121,36504,36708,36707,37308,37986,37973,37981,37975,37982,38852,38853,38912,39510,39513,39710,39711,39712,40018,40024,40016,40010,40013,40011,40021,40025,40012,40014,40443,40439,40431,40419,40427,40440,40420,40438,40417,40430,40422,40434,40432,40418,40428,40436,40435,40424,40429,40642,40656,40690,40691,40710,40732,40760,40759,40758,40771,40783,40817,40816,40814,40815,22227,22221,23374,23661,25901,26349,26350,27411,28767,28769,28765,28768,29219,29915,29925,30677,31032,31159,31158,31850,32407,32649,33389,34371,34872,34871,34869,34891,35732,35733,36510,36511,36512,36509,37310,37309,37314,37995,37992,37993,38629,38726,38723,38727,38855,38885,39518,39637,39769,40035,40039,40038,40034,40030,40032,40450,40446,40455,40451,40454,40453,40448,40449,40457,40447,40445,40452,40608,40734,40774,40820,40821,40822,22228,25902,26040,27416,27417,27415,27418,28770,29222,29354,30680,30681,31033,31849,31851,31990,32410,32408,32411,32409,33248,33249,34374,34375,34376,35193,35194,35196,35195,35327,35736,35737,36517,36516,36515,37998,37997,37999,38001,38003,38729,39026,39263,40040,40046,40045,40459,40461,40464,40463,40466,40465,40609,40693,40713,40775,40824,40827,40826,40825,22302,28774,31855,34876,36274,36518,37315,38004,38008,38006,38005,39520,40052,40051,40049,40053,40468,40467,40694,40714,40868,28776,28773,31991,34410,34878,34877,34879,35742,35996,36521,36553,38731,39027,39028,39116,39265,39339,39524,39526,39527,39716,40469,40471,40776,25095,27422,29223,34380,36520,38018,38016,38017,39529,39528,39726,40473,29225,34379,35743,38019,40057,40631,30325,39531,40058,40477,28777,28778,40612,40830,40777,40856,30849,37561,35023,22715,24658,31911,23290,9556,9574,9559,9568,9580,9571,9562,9577,9565,9554,9572,9557,9566,9578,9569,9560,9575,9563,9555,9573,9558,9567,9579,9570,9561,9576,9564,9553,9552,9581,9582,9584,9583,65517,132423,37595,132575,147397,34124,17077,29679,20917,13897,149826,166372,37700,137691,33518,146632,30780,26436,25311,149811,166314,131744,158643,135941,20395,140525,20488,159017,162436,144896,150193,140563,20521,131966,24484,131968,131911,28379,132127,20605,20737,13434,20750,39020,14147,33814,149924,132231,20832,144308,20842,134143,139516,131813,140592,132494,143923,137603,23426,34685,132531,146585,20914,20920,40244,20937,20943,20945,15580,20947,150182,20915,20962,21314,20973,33741,26942,145197,24443,21003,21030,21052,21173,21079,21140,21177,21189,31765,34114,21216,34317,158483,21253,166622,21833,28377,147328,133460,147436,21299,21316,134114,27851,136998,26651,29653,24650,16042,14540,136936,29149,17570,21357,21364,165547,21374,21375,136598,136723,30694,21395,166555,21408,21419,21422,29607,153458,16217,29596,21441,21445,27721,20041,22526,21465,15019,134031,21472,147435,142755,21494,134263,21523,28793,21803,26199,27995,21613,158547,134516,21853,21647,21668,18342,136973,134877,15796,134477,166332,140952,21831,19693,21551,29719,21894,21929,22021,137431,147514,17746,148533,26291,135348,22071,26317,144010,26276,26285,22093,22095,30961,22257,38791,21502,22272,22255,22253,166758,13859,135759,22342,147877,27758,28811,22338,14001,158846,22502,136214,22531,136276,148323,22566,150517,22620,22698,13665,22752,22748,135740,22779,23551,22339,172368,148088,37843,13729,22815,26790,14019,28249,136766,23076,21843,136850,34053,22985,134478,158849,159018,137180,23001,137211,137138,159142,28017,137256,136917,23033,159301,23211,23139,14054,149929,23159,14088,23190,29797,23251,159649,140628,15749,137489,14130,136888,24195,21200,23414,25992,23420,162318,16388,18525,131588,23509,24928,137780,154060,132517,23539,23453,19728,23557,138052,23571,29646,23572,138405,158504,23625,18653,23685,23785,23791,23947,138745,138807,23824,23832,23878,138916,23738,24023,33532,14381,149761,139337,139635,33415,14390,15298,24110,27274,24181,24186,148668,134355,21414,20151,24272,21416,137073,24073,24308,164994,24313,24315,14496,24316,26686,37915,24333,131521,194708,15070,18606,135994,24378,157832,140240,24408,140401,24419,38845,159342,24434,37696,166454,24487,23990,15711,152144,139114,159992,140904,37334,131742,166441,24625,26245,137335,14691,15815,13881,22416,141236,31089,15936,24734,24740,24755,149890,149903,162387,29860,20705,23200,24932,33828,24898,194726,159442,24961,20980,132694,24967,23466,147383,141407,25043,166813,170333,25040,14642,141696,141505,24611,24924,25886,25483,131352,25285,137072,25301,142861,25452,149983,14871,25656,25592,136078,137212,25744,28554,142902,38932,147596,153373,25825,25829,38011,14950,25658,14935,25933,28438,150056,150051,25989,25965,25951,143486,26037,149824,19255,26065,16600,137257,26080,26083,24543,144384,26136,143863,143864,26180,143780,143781,26187,134773,26215,152038,26227,26228,138813,143921,165364,143816,152339,30661,141559,39332,26370,148380,150049,15147,27130,145346,26462,26471,26466,147917,168173,26583,17641,26658,28240,37436,26625,144358,159136,26717,144495,27105,27147,166623,26995,26819,144845,26881,26880,15666,14849,144956,15232,26540,26977,166474,17148,26934,27032,15265,132041,33635,20624,27129,144985,139562,27205,145155,27293,15347,26545,27336,168348,15373,27421,133411,24798,27445,27508,141261,28341,146139,132021,137560,14144,21537,146266,27617,147196,27612,27703,140427,149745,158545,27738,33318,27769,146876,17605,146877,147876,149772,149760,146633,14053,15595,134450,39811,143865,140433,32655,26679,159013,159137,159211,28054,27996,28284,28420,149887,147589,159346,34099,159604,20935,27804,28189,33838,166689,28207,146991,29779,147330,31180,28239,23185,143435,28664,14093,28573,146992,28410,136343,147517,17749,37872,28484,28508,15694,28532,168304,15675,28575,147780,28627,147601,147797,147513,147440,147380,147775,20959,147798,147799,147776,156125,28747,28798,28839,28801,28876,28885,28886,28895,16644,15848,29108,29078,148087,28971,28997,23176,29002,29038,23708,148325,29007,37730,148161,28972,148570,150055,150050,29114,166888,28861,29198,37954,29205,22801,37955,29220,37697,153093,29230,29248,149876,26813,29269,29271,15957,143428,26637,28477,29314,29482,29483,149539,165931,18669,165892,29480,29486,29647,29610,134202,158254,29641,29769,147938,136935,150052,26147,14021,149943,149901,150011,29687,29717,26883,150054,29753,132547,16087,29788,141485,29792,167602,29767,29668,29814,33721,29804,14128,29812,37873,27180,29826,18771,150156,147807,150137,166799,23366,166915,137374,29896,137608,29966,29929,29982,167641,137803,23511,167596,37765,30029,30026,30055,30062,151426,16132,150803,30094,29789,30110,30132,30210,30252,30289,30287,30319,30326,156661,30352,33263,14328,157969,157966,30369,30373,30391,30412,159647,33890,151709,151933,138780,30494,30502,30528,25775,152096,30552,144044,30639,166244,166248,136897,30708,30729,136054,150034,26826,30895,30919,30931,38565,31022,153056,30935,31028,30897,161292,36792,34948,166699,155779,140828,31110,35072,26882,31104,153687,31133,162617,31036,31145,28202,160038,16040,31174,168205,31188],"euc-kr":[44034,44035,44037,44038,44043,44044,44045,44046,44047,44056,44062,44063,44065,44066,44067,44069,44070,44071,44072,44073,44074,44075,44078,44082,44083,44084,null,null,null,null,null,null,44085,44086,44087,44090,44091,44093,44094,44095,44097,44098,44099,44100,44101,44102,44103,44104,44105,44106,44108,44110,44111,44112,44113,44114,44115,44117,null,null,null,null,null,null,44118,44119,44121,44122,44123,44125,44126,44127,44128,44129,44130,44131,44132,44133,44134,44135,44136,44137,44138,44139,44140,44141,44142,44143,44146,44147,44149,44150,44153,44155,44156,44157,44158,44159,44162,44167,44168,44173,44174,44175,44177,44178,44179,44181,44182,44183,44184,44185,44186,44187,44190,44194,44195,44196,44197,44198,44199,44203,44205,44206,44209,44210,44211,44212,44213,44214,44215,44218,44222,44223,44224,44226,44227,44229,44230,44231,44233,44234,44235,44237,44238,44239,44240,44241,44242,44243,44244,44246,44248,44249,44250,44251,44252,44253,44254,44255,44258,44259,44261,44262,44265,44267,44269,44270,44274,44276,44279,44280,44281,44282,44283,44286,44287,44289,44290,44291,44293,44295,44296,44297,44298,44299,44302,44304,44306,44307,44308,44309,44310,44311,44313,44314,44315,44317,44318,44319,44321,44322,44323,44324,44325,44326,44327,44328,44330,44331,44334,44335,44336,44337,44338,44339,null,null,null,null,null,null,44342,44343,44345,44346,44347,44349,44350,44351,44352,44353,44354,44355,44358,44360,44362,44363,44364,44365,44366,44367,44369,44370,44371,44373,44374,44375,null,null,null,null,null,null,44377,44378,44379,44380,44381,44382,44383,44384,44386,44388,44389,44390,44391,44392,44393,44394,44395,44398,44399,44401,44402,44407,44408,44409,44410,44414,44416,44419,44420,44421,44422,44423,44426,44427,44429,44430,44431,44433,44434,44435,44436,44437,44438,44439,44440,44441,44442,44443,44446,44447,44448,44449,44450,44451,44453,44454,44455,44456,44457,44458,44459,44460,44461,44462,44463,44464,44465,44466,44467,44468,44469,44470,44472,44473,44474,44475,44476,44477,44478,44479,44482,44483,44485,44486,44487,44489,44490,44491,44492,44493,44494,44495,44498,44500,44501,44502,44503,44504,44505,44506,44507,44509,44510,44511,44513,44514,44515,44517,44518,44519,44520,44521,44522,44523,44524,44525,44526,44527,44528,44529,44530,44531,44532,44533,44534,44535,44538,44539,44541,44542,44546,44547,44548,44549,44550,44551,44554,44556,44558,44559,44560,44561,44562,44563,44565,44566,44567,44568,44569,44570,44571,44572,null,null,null,null,null,null,44573,44574,44575,44576,44577,44578,44579,44580,44581,44582,44583,44584,44585,44586,44587,44588,44589,44590,44591,44594,44595,44597,44598,44601,44603,44604,null,null,null,null,null,null,44605,44606,44607,44610,44612,44615,44616,44617,44619,44623,44625,44626,44627,44629,44631,44632,44633,44634,44635,44638,44642,44643,44644,44646,44647,44650,44651,44653,44654,44655,44657,44658,44659,44660,44661,44662,44663,44666,44670,44671,44672,44673,44674,44675,44678,44679,44680,44681,44682,44683,44685,44686,44687,44688,44689,44690,44691,44692,44693,44694,44695,44696,44697,44698,44699,44700,44701,44702,44703,44704,44705,44706,44707,44708,44709,44710,44711,44712,44713,44714,44715,44716,44717,44718,44719,44720,44721,44722,44723,44724,44725,44726,44727,44728,44729,44730,44731,44735,44737,44738,44739,44741,44742,44743,44744,44745,44746,44747,44750,44754,44755,44756,44757,44758,44759,44762,44763,44765,44766,44767,44768,44769,44770,44771,44772,44773,44774,44775,44777,44778,44780,44782,44783,44784,44785,44786,44787,44789,44790,44791,44793,44794,44795,44797,44798,44799,44800,44801,44802,44803,44804,44805,null,null,null,null,null,null,44806,44809,44810,44811,44812,44814,44815,44817,44818,44819,44820,44821,44822,44823,44824,44825,44826,44827,44828,44829,44830,44831,44832,44833,44834,44835,null,null,null,null,null,null,44836,44837,44838,44839,44840,44841,44842,44843,44846,44847,44849,44851,44853,44854,44855,44856,44857,44858,44859,44862,44864,44868,44869,44870,44871,44874,44875,44876,44877,44878,44879,44881,44882,44883,44884,44885,44886,44887,44888,44889,44890,44891,44894,44895,44896,44897,44898,44899,44902,44903,44904,44905,44906,44907,44908,44909,44910,44911,44912,44913,44914,44915,44916,44917,44918,44919,44920,44922,44923,44924,44925,44926,44927,44929,44930,44931,44933,44934,44935,44937,44938,44939,44940,44941,44942,44943,44946,44947,44948,44950,44951,44952,44953,44954,44955,44957,44958,44959,44960,44961,44962,44963,44964,44965,44966,44967,44968,44969,44970,44971,44972,44973,44974,44975,44976,44977,44978,44979,44980,44981,44982,44983,44986,44987,44989,44990,44991,44993,44994,44995,44996,44997,44998,45002,45004,45007,45008,45009,45010,45011,45013,45014,45015,45016,45017,45018,45019,45021,45022,45023,45024,45025,null,null,null,null,null,null,45026,45027,45028,45029,45030,45031,45034,45035,45036,45037,45038,45039,45042,45043,45045,45046,45047,45049,45050,45051,45052,45053,45054,45055,45058,45059,null,null,null,null,null,null,45061,45062,45063,45064,45065,45066,45067,45069,45070,45071,45073,45074,45075,45077,45078,45079,45080,45081,45082,45083,45086,45087,45088,45089,45090,45091,45092,45093,45094,45095,45097,45098,45099,45100,45101,45102,45103,45104,45105,45106,45107,45108,45109,45110,45111,45112,45113,45114,45115,45116,45117,45118,45119,45120,45121,45122,45123,45126,45127,45129,45131,45133,45135,45136,45137,45138,45142,45144,45146,45147,45148,45150,45151,45152,45153,45154,45155,45156,45157,45158,45159,45160,45161,45162,45163,45164,45165,45166,45167,45168,45169,45170,45171,45172,45173,45174,45175,45176,45177,45178,45179,45182,45183,45185,45186,45187,45189,45190,45191,45192,45193,45194,45195,45198,45200,45202,45203,45204,45205,45206,45207,45211,45213,45214,45219,45220,45221,45222,45223,45226,45232,45234,45238,45239,45241,45242,45243,45245,45246,45247,45248,45249,45250,45251,45254,45258,45259,45260,45261,45262,45263,45266,null,null,null,null,null,null,45267,45269,45270,45271,45273,45274,45275,45276,45277,45278,45279,45281,45282,45283,45284,45286,45287,45288,45289,45290,45291,45292,45293,45294,45295,45296,null,null,null,null,null,null,45297,45298,45299,45300,45301,45302,45303,45304,45305,45306,45307,45308,45309,45310,45311,45312,45313,45314,45315,45316,45317,45318,45319,45322,45325,45326,45327,45329,45332,45333,45334,45335,45338,45342,45343,45344,45345,45346,45350,45351,45353,45354,45355,45357,45358,45359,45360,45361,45362,45363,45366,45370,45371,45372,45373,45374,45375,45378,45379,45381,45382,45383,45385,45386,45387,45388,45389,45390,45391,45394,45395,45398,45399,45401,45402,45403,45405,45406,45407,45409,45410,45411,45412,45413,45414,45415,45416,45417,45418,45419,45420,45421,45422,45423,45424,45425,45426,45427,45428,45429,45430,45431,45434,45435,45437,45438,45439,45441,45443,45444,45445,45446,45447,45450,45452,45454,45455,45456,45457,45461,45462,45463,45465,45466,45467,45469,45470,45471,45472,45473,45474,45475,45476,45477,45478,45479,45481,45482,45483,45484,45485,45486,45487,45488,45489,45490,45491,45492,45493,45494,45495,45496,null,null,null,null,null,null,45497,45498,45499,45500,45501,45502,45503,45504,45505,45506,45507,45508,45509,45510,45511,45512,45513,45514,45515,45517,45518,45519,45521,45522,45523,45525,null,null,null,null,null,null,45526,45527,45528,45529,45530,45531,45534,45536,45537,45538,45539,45540,45541,45542,45543,45546,45547,45549,45550,45551,45553,45554,45555,45556,45557,45558,45559,45560,45562,45564,45566,45567,45568,45569,45570,45571,45574,45575,45577,45578,45581,45582,45583,45584,45585,45586,45587,45590,45592,45594,45595,45596,45597,45598,45599,45601,45602,45603,45604,45605,45606,45607,45608,45609,45610,45611,45612,45613,45614,45615,45616,45617,45618,45619,45621,45622,45623,45624,45625,45626,45627,45629,45630,45631,45632,45633,45634,45635,45636,45637,45638,45639,45640,45641,45642,45643,45644,45645,45646,45647,45648,45649,45650,45651,45652,45653,45654,45655,45657,45658,45659,45661,45662,45663,45665,45666,45667,45668,45669,45670,45671,45674,45675,45676,45677,45678,45679,45680,45681,45682,45683,45686,45687,45688,45689,45690,45691,45693,45694,45695,45696,45697,45698,45699,45702,45703,45704,45706,45707,45708,45709,45710,null,null,null,null,null,null,45711,45714,45715,45717,45718,45719,45723,45724,45725,45726,45727,45730,45732,45735,45736,45737,45739,45741,45742,45743,45745,45746,45747,45749,45750,45751,null,null,null,null,null,null,45752,45753,45754,45755,45756,45757,45758,45759,45760,45761,45762,45763,45764,45765,45766,45767,45770,45771,45773,45774,45775,45777,45779,45780,45781,45782,45783,45786,45788,45790,45791,45792,45793,45795,45799,45801,45802,45808,45809,45810,45814,45820,45821,45822,45826,45827,45829,45830,45831,45833,45834,45835,45836,45837,45838,45839,45842,45846,45847,45848,45849,45850,45851,45853,45854,45855,45856,45857,45858,45859,45860,45861,45862,45863,45864,45865,45866,45867,45868,45869,45870,45871,45872,45873,45874,45875,45876,45877,45878,45879,45880,45881,45882,45883,45884,45885,45886,45887,45888,45889,45890,45891,45892,45893,45894,45895,45896,45897,45898,45899,45900,45901,45902,45903,45904,45905,45906,45907,45911,45913,45914,45917,45920,45921,45922,45923,45926,45928,45930,45932,45933,45935,45938,45939,45941,45942,45943,45945,45946,45947,45948,45949,45950,45951,45954,45958,45959,45960,45961,45962,45963,45965,null,null,null,null,null,null,45966,45967,45969,45970,45971,45973,45974,45975,45976,45977,45978,45979,45980,45981,45982,45983,45986,45987,45988,45989,45990,45991,45993,45994,45995,45997,null,null,null,null,null,null,45998,45999,46000,46001,46002,46003,46004,46005,46006,46007,46008,46009,46010,46011,46012,46013,46014,46015,46016,46017,46018,46019,46022,46023,46025,46026,46029,46031,46033,46034,46035,46038,46040,46042,46044,46046,46047,46049,46050,46051,46053,46054,46055,46057,46058,46059,46060,46061,46062,46063,46064,46065,46066,46067,46068,46069,46070,46071,46072,46073,46074,46075,46077,46078,46079,46080,46081,46082,46083,46084,46085,46086,46087,46088,46089,46090,46091,46092,46093,46094,46095,46097,46098,46099,46100,46101,46102,46103,46105,46106,46107,46109,46110,46111,46113,46114,46115,46116,46117,46118,46119,46122,46124,46125,46126,46127,46128,46129,46130,46131,46133,46134,46135,46136,46137,46138,46139,46140,46141,46142,46143,46144,46145,46146,46147,46148,46149,46150,46151,46152,46153,46154,46155,46156,46157,46158,46159,46162,46163,46165,46166,46167,46169,46170,46171,46172,46173,46174,46175,46178,46180,46182,null,null,null,null,null,null,46183,46184,46185,46186,46187,46189,46190,46191,46192,46193,46194,46195,46196,46197,46198,46199,46200,46201,46202,46203,46204,46205,46206,46207,46209,46210,null,null,null,null,null,null,46211,46212,46213,46214,46215,46217,46218,46219,46220,46221,46222,46223,46224,46225,46226,46227,46228,46229,46230,46231,46232,46233,46234,46235,46236,46238,46239,46240,46241,46242,46243,46245,46246,46247,46249,46250,46251,46253,46254,46255,46256,46257,46258,46259,46260,46262,46264,46266,46267,46268,46269,46270,46271,46273,46274,46275,46277,46278,46279,46281,46282,46283,46284,46285,46286,46287,46289,46290,46291,46292,46294,46295,46296,46297,46298,46299,46302,46303,46305,46306,46309,46311,46312,46313,46314,46315,46318,46320,46322,46323,46324,46325,46326,46327,46329,46330,46331,46332,46333,46334,46335,46336,46337,46338,46339,46340,46341,46342,46343,46344,46345,46346,46347,46348,46349,46350,46351,46352,46353,46354,46355,46358,46359,46361,46362,46365,46366,46367,46368,46369,46370,46371,46374,46379,46380,46381,46382,46383,46386,46387,46389,46390,46391,46393,46394,46395,46396,46397,46398,46399,46402,46406,null,null,null,null,null,null,46407,46408,46409,46410,46414,46415,46417,46418,46419,46421,46422,46423,46424,46425,46426,46427,46430,46434,46435,46436,46437,46438,46439,46440,46441,46442,null,null,null,null,null,null,46443,46444,46445,46446,46447,46448,46449,46450,46451,46452,46453,46454,46455,46456,46457,46458,46459,46460,46461,46462,46463,46464,46465,46466,46467,46468,46469,46470,46471,46472,46473,46474,46475,46476,46477,46478,46479,46480,46481,46482,46483,46484,46485,46486,46487,46488,46489,46490,46491,46492,46493,46494,46495,46498,46499,46501,46502,46503,46505,46508,46509,46510,46511,46514,46518,46519,46520,46521,46522,46526,46527,46529,46530,46531,46533,46534,46535,46536,46537,46538,46539,46542,46546,46547,46548,46549,46550,46551,46553,46554,46555,46556,46557,46558,46559,46560,46561,46562,46563,46564,46565,46566,46567,46568,46569,46570,46571,46573,46574,46575,46576,46577,46578,46579,46580,46581,46582,46583,46584,46585,46586,46587,46588,46589,46590,46591,46592,46593,46594,46595,46596,46597,46598,46599,46600,46601,46602,46603,46604,46605,46606,46607,46610,46611,46613,46614,46615,46617,46618,46619,46620,46621,null,null,null,null,null,null,46622,46623,46624,46625,46626,46627,46628,46630,46631,46632,46633,46634,46635,46637,46638,46639,46640,46641,46642,46643,46645,46646,46647,46648,46649,46650,null,null,null,null,null,null,46651,46652,46653,46654,46655,46656,46657,46658,46659,46660,46661,46662,46663,46665,46666,46667,46668,46669,46670,46671,46672,46673,46674,46675,46676,46677,46678,46679,46680,46681,46682,46683,46684,46685,46686,46687,46688,46689,46690,46691,46693,46694,46695,46697,46698,46699,46700,46701,46702,46703,46704,46705,46706,46707,46708,46709,46710,46711,46712,46713,46714,46715,46716,46717,46718,46719,46720,46721,46722,46723,46724,46725,46726,46727,46728,46729,46730,46731,46732,46733,46734,46735,46736,46737,46738,46739,46740,46741,46742,46743,46744,46745,46746,46747,46750,46751,46753,46754,46755,46757,46758,46759,46760,46761,46762,46765,46766,46767,46768,46770,46771,46772,46773,46774,46775,46776,46777,46778,46779,46780,46781,46782,46783,46784,46785,46786,46787,46788,46789,46790,46791,46792,46793,46794,46795,46796,46797,46798,46799,46800,46801,46802,46803,46805,46806,46807,46808,46809,46810,46811,46812,46813,null,null,null,null,null,null,46814,46815,46816,46817,46818,46819,46820,46821,46822,46823,46824,46825,46826,46827,46828,46829,46830,46831,46833,46834,46835,46837,46838,46839,46841,46842,null,null,null,null,null,null,46843,46844,46845,46846,46847,46850,46851,46852,46854,46855,46856,46857,46858,46859,46860,46861,46862,46863,46864,46865,46866,46867,46868,46869,46870,46871,46872,46873,46874,46875,46876,46877,46878,46879,46880,46881,46882,46883,46884,46885,46886,46887,46890,46891,46893,46894,46897,46898,46899,46900,46901,46902,46903,46906,46908,46909,46910,46911,46912,46913,46914,46915,46917,46918,46919,46921,46922,46923,46925,46926,46927,46928,46929,46930,46931,46934,46935,46936,46937,46938,46939,46940,46941,46942,46943,46945,46946,46947,46949,46950,46951,46953,46954,46955,46956,46957,46958,46959,46962,46964,46966,46967,46968,46969,46970,46971,46974,46975,46977,46978,46979,46981,46982,46983,46984,46985,46986,46987,46990,46995,46996,46997,47002,47003,47005,47006,47007,47009,47010,47011,47012,47013,47014,47015,47018,47022,47023,47024,47025,47026,47027,47030,47031,47033,47034,47035,47036,47037,47038,47039,47040,47041,null,null,null,null,null,null,47042,47043,47044,47045,47046,47048,47050,47051,47052,47053,47054,47055,47056,47057,47058,47059,47060,47061,47062,47063,47064,47065,47066,47067,47068,47069,null,null,null,null,null,null,47070,47071,47072,47073,47074,47075,47076,47077,47078,47079,47080,47081,47082,47083,47086,47087,47089,47090,47091,47093,47094,47095,47096,47097,47098,47099,47102,47106,47107,47108,47109,47110,47114,47115,47117,47118,47119,47121,47122,47123,47124,47125,47126,47127,47130,47132,47134,47135,47136,47137,47138,47139,47142,47143,47145,47146,47147,47149,47150,47151,47152,47153,47154,47155,47158,47162,47163,47164,47165,47166,47167,47169,47170,47171,47173,47174,47175,47176,47177,47178,47179,47180,47181,47182,47183,47184,47186,47188,47189,47190,47191,47192,47193,47194,47195,47198,47199,47201,47202,47203,47205,47206,47207,47208,47209,47210,47211,47214,47216,47218,47219,47220,47221,47222,47223,47225,47226,47227,47229,47230,47231,47232,47233,47234,47235,47236,47237,47238,47239,47240,47241,47242,47243,47244,47246,47247,47248,47249,47250,47251,47252,47253,47254,47255,47256,47257,47258,47259,47260,47261,47262,47263,null,null,null,null,null,null,47264,47265,47266,47267,47268,47269,47270,47271,47273,47274,47275,47276,47277,47278,47279,47281,47282,47283,47285,47286,47287,47289,47290,47291,47292,47293,null,null,null,null,null,null,47294,47295,47298,47300,47302,47303,47304,47305,47306,47307,47309,47310,47311,47313,47314,47315,47317,47318,47319,47320,47321,47322,47323,47324,47326,47328,47330,47331,47332,47333,47334,47335,47338,47339,47341,47342,47343,47345,47346,47347,47348,47349,47350,47351,47354,47356,47358,47359,47360,47361,47362,47363,47365,47366,47367,47368,47369,47370,47371,47372,47373,47374,47375,47376,47377,47378,47379,47380,47381,47382,47383,47385,47386,47387,47388,47389,47390,47391,47393,47394,47395,47396,47397,47398,47399,47400,47401,47402,47403,47404,47405,47406,47407,47408,47409,47410,47411,47412,47413,47414,47415,47416,47417,47418,47419,47422,47423,47425,47426,47427,47429,47430,47431,47432,47433,47434,47435,47437,47438,47440,47442,47443,47444,47445,47446,47447,47450,47451,47453,47454,47455,47457,47458,47459,47460,47461,47462,47463,47466,47468,47470,47471,47472,47473,47474,47475,47478,47479,47481,47482,47483,47485,null,null,null,null,null,null,47486,47487,47488,47489,47490,47491,47494,47496,47499,47500,47503,47504,47505,47506,47507,47508,47509,47510,47511,47512,47513,47514,47515,47516,47517,47518,null,null,null,null,null,null,47519,47520,47521,47522,47523,47524,47525,47526,47527,47528,47529,47530,47531,47534,47535,47537,47538,47539,47541,47542,47543,47544,47545,47546,47547,47550,47552,47554,47555,47556,47557,47558,47559,47562,47563,47565,47571,47572,47573,47574,47575,47578,47580,47583,47584,47586,47590,47591,47593,47594,47595,47597,47598,47599,47600,47601,47602,47603,47606,47611,47612,47613,47614,47615,47618,47619,47620,47621,47622,47623,47625,47626,47627,47628,47629,47630,47631,47632,47633,47634,47635,47636,47638,47639,47640,47641,47642,47643,47644,47645,47646,47647,47648,47649,47650,47651,47652,47653,47654,47655,47656,47657,47658,47659,47660,47661,47662,47663,47664,47665,47666,47667,47668,47669,47670,47671,47674,47675,47677,47678,47679,47681,47683,47684,47685,47686,47687,47690,47692,47695,47696,47697,47698,47702,47703,47705,47706,47707,47709,47710,47711,47712,47713,47714,47715,47718,47722,47723,47724,47725,47726,47727,null,null,null,null,null,null,47730,47731,47733,47734,47735,47737,47738,47739,47740,47741,47742,47743,47744,47745,47746,47750,47752,47753,47754,47755,47757,47758,47759,47760,47761,47762,null,null,null,null,null,null,47763,47764,47765,47766,47767,47768,47769,47770,47771,47772,47773,47774,47775,47776,47777,47778,47779,47780,47781,47782,47783,47786,47789,47790,47791,47793,47795,47796,47797,47798,47799,47802,47804,47806,47807,47808,47809,47810,47811,47813,47814,47815,47817,47818,47819,47820,47821,47822,47823,47824,47825,47826,47827,47828,47829,47830,47831,47834,47835,47836,47837,47838,47839,47840,47841,47842,47843,47844,47845,47846,47847,47848,47849,47850,47851,47852,47853,47854,47855,47856,47857,47858,47859,47860,47861,47862,47863,47864,47865,47866,47867,47869,47870,47871,47873,47874,47875,47877,47878,47879,47880,47881,47882,47883,47884,47886,47888,47890,47891,47892,47893,47894,47895,47897,47898,47899,47901,47902,47903,47905,47906,47907,47908,47909,47910,47911,47912,47914,47916,47917,47918,47919,47920,47921,47922,47923,47927,47929,47930,47935,47936,47937,47938,47939,47942,47944,47946,47947,47948,47950,47953,47954,null,null,null,null,null,null,47955,47957,47958,47959,47961,47962,47963,47964,47965,47966,47967,47968,47970,47972,47973,47974,47975,47976,47977,47978,47979,47981,47982,47983,47984,47985,null,null,null,null,null,null,47986,47987,47988,47989,47990,47991,47992,47993,47994,47995,47996,47997,47998,47999,48000,48001,48002,48003,48004,48005,48006,48007,48009,48010,48011,48013,48014,48015,48017,48018,48019,48020,48021,48022,48023,48024,48025,48026,48027,48028,48029,48030,48031,48032,48033,48034,48035,48037,48038,48039,48041,48042,48043,48045,48046,48047,48048,48049,48050,48051,48053,48054,48056,48057,48058,48059,48060,48061,48062,48063,48065,48066,48067,48069,48070,48071,48073,48074,48075,48076,48077,48078,48079,48081,48082,48084,48085,48086,48087,48088,48089,48090,48091,48092,48093,48094,48095,48096,48097,48098,48099,48100,48101,48102,48103,48104,48105,48106,48107,48108,48109,48110,48111,48112,48113,48114,48115,48116,48117,48118,48119,48122,48123,48125,48126,48129,48131,48132,48133,48134,48135,48138,48142,48144,48146,48147,48153,48154,48160,48161,48162,48163,48166,48168,48170,48171,48172,48174,48175,48178,48179,48181,null,null,null,null,null,null,48182,48183,48185,48186,48187,48188,48189,48190,48191,48194,48198,48199,48200,48202,48203,48206,48207,48209,48210,48211,48212,48213,48214,48215,48216,48217,null,null,null,null,null,null,48218,48219,48220,48222,48223,48224,48225,48226,48227,48228,48229,48230,48231,48232,48233,48234,48235,48236,48237,48238,48239,48240,48241,48242,48243,48244,48245,48246,48247,48248,48249,48250,48251,48252,48253,48254,48255,48256,48257,48258,48259,48262,48263,48265,48266,48269,48271,48272,48273,48274,48275,48278,48280,48283,48284,48285,48286,48287,48290,48291,48293,48294,48297,48298,48299,48300,48301,48302,48303,48306,48310,48311,48312,48313,48314,48315,48318,48319,48321,48322,48323,48325,48326,48327,48328,48329,48330,48331,48332,48334,48338,48339,48340,48342,48343,48345,48346,48347,48349,48350,48351,48352,48353,48354,48355,48356,48357,48358,48359,48360,48361,48362,48363,48364,48365,48366,48367,48368,48369,48370,48371,48375,48377,48378,48379,48381,48382,48383,48384,48385,48386,48387,48390,48392,48394,48395,48396,48397,48398,48399,48401,48402,48403,48405,48406,48407,48408,48409,48410,48411,48412,48413,null,null,null,null,null,null,48414,48415,48416,48417,48418,48419,48421,48422,48423,48424,48425,48426,48427,48429,48430,48431,48432,48433,48434,48435,48436,48437,48438,48439,48440,48441,null,null,null,null,null,null,48442,48443,48444,48445,48446,48447,48449,48450,48451,48452,48453,48454,48455,48458,48459,48461,48462,48463,48465,48466,48467,48468,48469,48470,48471,48474,48475,48476,48477,48478,48479,48480,48481,48482,48483,48485,48486,48487,48489,48490,48491,48492,48493,48494,48495,48496,48497,48498,48499,48500,48501,48502,48503,48504,48505,48506,48507,48508,48509,48510,48511,48514,48515,48517,48518,48523,48524,48525,48526,48527,48530,48532,48534,48535,48536,48539,48541,48542,48543,48544,48545,48546,48547,48549,48550,48551,48552,48553,48554,48555,48556,48557,48558,48559,48561,48562,48563,48564,48565,48566,48567,48569,48570,48571,48572,48573,48574,48575,48576,48577,48578,48579,48580,48581,48582,48583,48584,48585,48586,48587,48588,48589,48590,48591,48592,48593,48594,48595,48598,48599,48601,48602,48603,48605,48606,48607,48608,48609,48610,48611,48612,48613,48614,48615,48616,48618,48619,48620,48621,48622,48623,48625,null,null,null,null,null,null,48626,48627,48629,48630,48631,48633,48634,48635,48636,48637,48638,48639,48641,48642,48644,48646,48647,48648,48649,48650,48651,48654,48655,48657,48658,48659,null,null,null,null,null,null,48661,48662,48663,48664,48665,48666,48667,48670,48672,48673,48674,48675,48676,48677,48678,48679,48680,48681,48682,48683,48684,48685,48686,48687,48688,48689,48690,48691,48692,48693,48694,48695,48696,48697,48698,48699,48700,48701,48702,48703,48704,48705,48706,48707,48710,48711,48713,48714,48715,48717,48719,48720,48721,48722,48723,48726,48728,48732,48733,48734,48735,48738,48739,48741,48742,48743,48745,48747,48748,48749,48750,48751,48754,48758,48759,48760,48761,48762,48766,48767,48769,48770,48771,48773,48774,48775,48776,48777,48778,48779,48782,48786,48787,48788,48789,48790,48791,48794,48795,48796,48797,48798,48799,48800,48801,48802,48803,48804,48805,48806,48807,48809,48810,48811,48812,48813,48814,48815,48816,48817,48818,48819,48820,48821,48822,48823,48824,48825,48826,48827,48828,48829,48830,48831,48832,48833,48834,48835,48836,48837,48838,48839,48840,48841,48842,48843,48844,48845,48846,48847,48850,48851,null,null,null,null,null,null,48853,48854,48857,48858,48859,48860,48861,48862,48863,48865,48866,48870,48871,48872,48873,48874,48875,48877,48878,48879,48880,48881,48882,48883,48884,48885,null,null,null,null,null,null,48886,48887,48888,48889,48890,48891,48892,48893,48894,48895,48896,48898,48899,48900,48901,48902,48903,48906,48907,48908,48909,48910,48911,48912,48913,48914,48915,48916,48917,48918,48919,48922,48926,48927,48928,48929,48930,48931,48932,48933,48934,48935,48936,48937,48938,48939,48940,48941,48942,48943,48944,48945,48946,48947,48948,48949,48950,48951,48952,48953,48954,48955,48956,48957,48958,48959,48962,48963,48965,48966,48967,48969,48970,48971,48972,48973,48974,48975,48978,48979,48980,48982,48983,48984,48985,48986,48987,48988,48989,48990,48991,48992,48993,48994,48995,48996,48997,48998,48999,49000,49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,49012,49013,49014,49015,49016,49017,49018,49019,49020,49021,49022,49023,49024,49025,49026,49027,49028,49029,49030,49031,49032,49033,49034,49035,49036,49037,49038,49039,49040,49041,49042,49043,49045,49046,49047,49048,49049,49050,49051,49052,49053,null,null,null,null,null,null,49054,49055,49056,49057,49058,49059,49060,49061,49062,49063,49064,49065,49066,49067,49068,49069,49070,49071,49073,49074,49075,49076,49077,49078,49079,49080,null,null,null,null,null,null,49081,49082,49083,49084,49085,49086,49087,49088,49089,49090,49091,49092,49094,49095,49096,49097,49098,49099,49102,49103,49105,49106,49107,49109,49110,49111,49112,49113,49114,49115,49117,49118,49120,49122,49123,49124,49125,49126,49127,49128,49129,49130,49131,49132,49133,49134,49135,49136,49137,49138,49139,49140,49141,49142,49143,49144,49145,49146,49147,49148,49149,49150,49151,49152,49153,49154,49155,49156,49157,49158,49159,49160,49161,49162,49163,49164,49165,49166,49167,49168,49169,49170,49171,49172,49173,49174,49175,49176,49177,49178,49179,49180,49181,49182,49183,49184,49185,49186,49187,49188,49189,49190,49191,49192,49193,49194,49195,49196,49197,49198,49199,49200,49201,49202,49203,49204,49205,49206,49207,49208,49209,49210,49211,49213,49214,49215,49216,49217,49218,49219,49220,49221,49222,49223,49224,49225,49226,49227,49228,49229,49230,49231,49232,49234,49235,49236,49237,49238,49239,49241,49242,49243,null,null,null,null,null,null,49245,49246,49247,49249,49250,49251,49252,49253,49254,49255,49258,49259,49260,49261,49262,49263,49264,49265,49266,49267,49268,49269,49270,49271,49272,49273,null,null,null,null,null,null,49274,49275,49276,49277,49278,49279,49280,49281,49282,49283,49284,49285,49286,49287,49288,49289,49290,49291,49292,49293,49294,49295,49298,49299,49301,49302,49303,49305,49306,49307,49308,49309,49310,49311,49314,49316,49318,49319,49320,49321,49322,49323,49326,49329,49330,49335,49336,49337,49338,49339,49342,49346,49347,49348,49350,49351,49354,49355,49357,49358,49359,49361,49362,49363,49364,49365,49366,49367,49370,49374,49375,49376,49377,49378,49379,49382,49383,49385,49386,49387,49389,49390,49391,49392,49393,49394,49395,49398,49400,49402,49403,49404,49405,49406,49407,49409,49410,49411,49413,49414,49415,49417,49418,49419,49420,49421,49422,49423,49425,49426,49427,49428,49430,49431,49432,49433,49434,49435,49441,49442,49445,49448,49449,49450,49451,49454,49458,49459,49460,49461,49463,49466,49467,49469,49470,49471,49473,49474,49475,49476,49477,49478,49479,49482,49486,49487,49488,49489,49490,49491,49494,49495,null,null,null,null,null,null,49497,49498,49499,49501,49502,49503,49504,49505,49506,49507,49510,49514,49515,49516,49517,49518,49519,49521,49522,49523,49525,49526,49527,49529,49530,49531,null,null,null,null,null,null,49532,49533,49534,49535,49536,49537,49538,49539,49540,49542,49543,49544,49545,49546,49547,49551,49553,49554,49555,49557,49559,49560,49561,49562,49563,49566,49568,49570,49571,49572,49574,49575,49578,49579,49581,49582,49583,49585,49586,49587,49588,49589,49590,49591,49592,49593,49594,49595,49596,49598,49599,49600,49601,49602,49603,49605,49606,49607,49609,49610,49611,49613,49614,49615,49616,49617,49618,49619,49621,49622,49625,49626,49627,49628,49629,49630,49631,49633,49634,49635,49637,49638,49639,49641,49642,49643,49644,49645,49646,49647,49650,49652,49653,49654,49655,49656,49657,49658,49659,49662,49663,49665,49666,49667,49669,49670,49671,49672,49673,49674,49675,49678,49680,49682,49683,49684,49685,49686,49687,49690,49691,49693,49694,49697,49698,49699,49700,49701,49702,49703,49706,49708,49710,49712,49715,49717,49718,49719,49720,49721,49722,49723,49724,49725,49726,49727,49728,49729,49730,49731,49732,49733,null,null,null,null,null,null,49734,49735,49737,49738,49739,49740,49741,49742,49743,49746,49747,49749,49750,49751,49753,49754,49755,49756,49757,49758,49759,49761,49762,49763,49764,49766,null,null,null,null,null,null,49767,49768,49769,49770,49771,49774,49775,49777,49778,49779,49781,49782,49783,49784,49785,49786,49787,49790,49792,49794,49795,49796,49797,49798,49799,49802,49803,49804,49805,49806,49807,49809,49810,49811,49812,49813,49814,49815,49817,49818,49820,49822,49823,49824,49825,49826,49827,49830,49831,49833,49834,49835,49838,49839,49840,49841,49842,49843,49846,49848,49850,49851,49852,49853,49854,49855,49856,49857,49858,49859,49860,49861,49862,49863,49864,49865,49866,49867,49868,49869,49870,49871,49872,49873,49874,49875,49876,49877,49878,49879,49880,49881,49882,49883,49886,49887,49889,49890,49893,49894,49895,49896,49897,49898,49902,49904,49906,49907,49908,49909,49911,49914,49917,49918,49919,49921,49922,49923,49924,49925,49926,49927,49930,49931,49934,49935,49936,49937,49938,49942,49943,49945,49946,49947,49949,49950,49951,49952,49953,49954,49955,49958,49959,49962,49963,49964,49965,49966,49967,49968,49969,49970,null,null,null,null,null,null,49971,49972,49973,49974,49975,49976,49977,49978,49979,49980,49981,49982,49983,49984,49985,49986,49987,49988,49990,49991,49992,49993,49994,49995,49996,49997,null,null,null,null,null,null,49998,49999,50000,50001,50002,50003,50004,50005,50006,50007,50008,50009,50010,50011,50012,50013,50014,50015,50016,50017,50018,50019,50020,50021,50022,50023,50026,50027,50029,50030,50031,50033,50035,50036,50037,50038,50039,50042,50043,50046,50047,50048,50049,50050,50051,50053,50054,50055,50057,50058,50059,50061,50062,50063,50064,50065,50066,50067,50068,50069,50070,50071,50072,50073,50074,50075,50076,50077,50078,50079,50080,50081,50082,50083,50084,50085,50086,50087,50088,50089,50090,50091,50092,50093,50094,50095,50096,50097,50098,50099,50100,50101,50102,50103,50104,50105,50106,50107,50108,50109,50110,50111,50113,50114,50115,50116,50117,50118,50119,50120,50121,50122,50123,50124,50125,50126,50127,50128,50129,50130,50131,50132,50133,50134,50135,50138,50139,50141,50142,50145,50147,50148,50149,50150,50151,50154,50155,50156,50158,50159,50160,50161,50162,50163,50166,50167,50169,50170,50171,50172,50173,50174,null,null,null,null,null,null,50175,50176,50177,50178,50179,50180,50181,50182,50183,50185,50186,50187,50188,50189,50190,50191,50193,50194,50195,50196,50197,50198,50199,50200,50201,50202,null,null,null,null,null,null,50203,50204,50205,50206,50207,50208,50209,50210,50211,50213,50214,50215,50216,50217,50218,50219,50221,50222,50223,50225,50226,50227,50229,50230,50231,50232,50233,50234,50235,50238,50239,50240,50241,50242,50243,50244,50245,50246,50247,50249,50250,50251,50252,50253,50254,50255,50256,50257,50258,50259,50260,50261,50262,50263,50264,50265,50266,50267,50268,50269,50270,50271,50272,50273,50274,50275,50278,50279,50281,50282,50283,50285,50286,50287,50288,50289,50290,50291,50294,50295,50296,50298,50299,50300,50301,50302,50303,50305,50306,50307,50308,50309,50310,50311,50312,50313,50314,50315,50316,50317,50318,50319,50320,50321,50322,50323,50325,50326,50327,50328,50329,50330,50331,50333,50334,50335,50336,50337,50338,50339,50340,50341,50342,50343,50344,50345,50346,50347,50348,50349,50350,50351,50352,50353,50354,50355,50356,50357,50358,50359,50361,50362,50363,50365,50366,50367,50368,50369,50370,50371,50372,50373,null,null,null,null,null,null,50374,50375,50376,50377,50378,50379,50380,50381,50382,50383,50384,50385,50386,50387,50388,50389,50390,50391,50392,50393,50394,50395,50396,50397,50398,50399,null,null,null,null,null,null,50400,50401,50402,50403,50404,50405,50406,50407,50408,50410,50411,50412,50413,50414,50415,50418,50419,50421,50422,50423,50425,50427,50428,50429,50430,50434,50435,50436,50437,50438,50439,50440,50441,50442,50443,50445,50446,50447,50449,50450,50451,50453,50454,50455,50456,50457,50458,50459,50461,50462,50463,50464,50465,50466,50467,50468,50469,50470,50471,50474,50475,50477,50478,50479,50481,50482,50483,50484,50485,50486,50487,50490,50492,50494,50495,50496,50497,50498,50499,50502,50503,50507,50511,50512,50513,50514,50518,50522,50523,50524,50527,50530,50531,50533,50534,50535,50537,50538,50539,50540,50541,50542,50543,50546,50550,50551,50552,50553,50554,50555,50558,50559,50561,50562,50563,50565,50566,50568,50569,50570,50571,50574,50576,50578,50579,50580,50582,50585,50586,50587,50589,50590,50591,50593,50594,50595,50596,50597,50598,50599,50600,50602,50603,50604,50605,50606,50607,50608,50609,50610,50611,50614,null,null,null,null,null,null,50615,50618,50623,50624,50625,50626,50627,50635,50637,50639,50642,50643,50645,50646,50647,50649,50650,50651,50652,50653,50654,50655,50658,50660,50662,50663,null,null,null,null,null,null,50664,50665,50666,50667,50671,50673,50674,50675,50677,50680,50681,50682,50683,50690,50691,50692,50697,50698,50699,50701,50702,50703,50705,50706,50707,50708,50709,50710,50711,50714,50717,50718,50719,50720,50721,50722,50723,50726,50727,50729,50730,50731,50735,50737,50738,50742,50744,50746,50748,50749,50750,50751,50754,50755,50757,50758,50759,50761,50762,50763,50764,50765,50766,50767,50770,50774,50775,50776,50777,50778,50779,50782,50783,50785,50786,50787,50788,50789,50790,50791,50792,50793,50794,50795,50797,50798,50800,50802,50803,50804,50805,50806,50807,50810,50811,50813,50814,50815,50817,50818,50819,50820,50821,50822,50823,50826,50828,50830,50831,50832,50833,50834,50835,50838,50839,50841,50842,50843,50845,50846,50847,50848,50849,50850,50851,50854,50856,50858,50859,50860,50861,50862,50863,50866,50867,50869,50870,50871,50875,50876,50877,50878,50879,50882,50884,50886,50887,50888,50889,50890,50891,50894,null,null,null,null,null,null,50895,50897,50898,50899,50901,50902,50903,50904,50905,50906,50907,50910,50911,50914,50915,50916,50917,50918,50919,50922,50923,50925,50926,50927,50929,50930,null,null,null,null,null,null,50931,50932,50933,50934,50935,50938,50939,50940,50942,50943,50944,50945,50946,50947,50950,50951,50953,50954,50955,50957,50958,50959,50960,50961,50962,50963,50966,50968,50970,50971,50972,50973,50974,50975,50978,50979,50981,50982,50983,50985,50986,50987,50988,50989,50990,50991,50994,50996,50998,51000,51001,51002,51003,51006,51007,51009,51010,51011,51013,51014,51015,51016,51017,51019,51022,51024,51033,51034,51035,51037,51038,51039,51041,51042,51043,51044,51045,51046,51047,51049,51050,51052,51053,51054,51055,51056,51057,51058,51059,51062,51063,51065,51066,51067,51071,51072,51073,51074,51078,51083,51084,51085,51087,51090,51091,51093,51097,51099,51100,51101,51102,51103,51106,51111,51112,51113,51114,51115,51118,51119,51121,51122,51123,51125,51126,51127,51128,51129,51130,51131,51134,51138,51139,51140,51141,51142,51143,51146,51147,51149,51151,51153,51154,51155,51156,51157,51158,51159,51161,51162,51163,51164,null,null,null,null,null,null,51166,51167,51168,51169,51170,51171,51173,51174,51175,51177,51178,51179,51181,51182,51183,51184,51185,51186,51187,51188,51189,51190,51191,51192,51193,51194,null,null,null,null,null,null,51195,51196,51197,51198,51199,51202,51203,51205,51206,51207,51209,51211,51212,51213,51214,51215,51218,51220,51223,51224,51225,51226,51227,51230,51231,51233,51234,51235,51237,51238,51239,51240,51241,51242,51243,51246,51248,51250,51251,51252,51253,51254,51255,51257,51258,51259,51261,51262,51263,51265,51266,51267,51268,51269,51270,51271,51274,51275,51278,51279,51280,51281,51282,51283,51285,51286,51287,51288,51289,51290,51291,51292,51293,51294,51295,51296,51297,51298,51299,51300,51301,51302,51303,51304,51305,51306,51307,51308,51309,51310,51311,51314,51315,51317,51318,51319,51321,51323,51324,51325,51326,51327,51330,51332,51336,51337,51338,51342,51343,51344,51345,51346,51347,51349,51350,51351,51352,51353,51354,51355,51356,51358,51360,51362,51363,51364,51365,51366,51367,51369,51370,51371,51372,51373,51374,51375,51376,51377,51378,51379,51380,51381,51382,51383,51384,51385,51386,51387,51390,51391,51392,51393,null,null,null,null,null,null,51394,51395,51397,51398,51399,51401,51402,51403,51405,51406,51407,51408,51409,51410,51411,51414,51416,51418,51419,51420,51421,51422,51423,51426,51427,51429,null,null,null,null,null,null,51430,51431,51432,51433,51434,51435,51436,51437,51438,51439,51440,51441,51442,51443,51444,51446,51447,51448,51449,51450,51451,51454,51455,51457,51458,51459,51463,51464,51465,51466,51467,51470,12288,12289,12290,183,8229,8230,168,12291,173,8213,8741,65340,8764,8216,8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,177,215,247,8800,8804,8805,8734,8756,176,8242,8243,8451,8491,65504,65505,65509,9794,9792,8736,8869,8978,8706,8711,8801,8786,167,8251,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8594,8592,8593,8595,8596,12307,8810,8811,8730,8765,8733,8757,8747,8748,8712,8715,8838,8839,8834,8835,8746,8745,8743,8744,65506,51472,51474,51475,51476,51477,51478,51479,51481,51482,51483,51484,51485,51486,51487,51488,51489,51490,51491,51492,51493,51494,51495,51496,51497,51498,51499,null,null,null,null,null,null,51501,51502,51503,51504,51505,51506,51507,51509,51510,51511,51512,51513,51514,51515,51516,51517,51518,51519,51520,51521,51522,51523,51524,51525,51526,51527,null,null,null,null,null,null,51528,51529,51530,51531,51532,51533,51534,51535,51538,51539,51541,51542,51543,51545,51546,51547,51548,51549,51550,51551,51554,51556,51557,51558,51559,51560,51561,51562,51563,51565,51566,51567,8658,8660,8704,8707,180,65374,711,728,733,730,729,184,731,161,191,720,8750,8721,8719,164,8457,8240,9665,9664,9655,9654,9828,9824,9825,9829,9831,9827,8857,9672,9635,9680,9681,9618,9636,9637,9640,9639,9638,9641,9832,9743,9742,9756,9758,182,8224,8225,8597,8599,8601,8598,8600,9837,9833,9834,9836,12927,12828,8470,13255,8482,13250,13272,8481,8364,174,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,51569,51570,51571,51573,51574,51575,51576,51577,51578,51579,51581,51582,51583,51584,51585,51586,51587,51588,51589,51590,51591,51594,51595,51597,51598,51599,null,null,null,null,null,null,51601,51602,51603,51604,51605,51606,51607,51610,51612,51614,51615,51616,51617,51618,51619,51620,51621,51622,51623,51624,51625,51626,51627,51628,51629,51630,null,null,null,null,null,null,51631,51632,51633,51634,51635,51636,51637,51638,51639,51640,51641,51642,51643,51644,51645,51646,51647,51650,51651,51653,51654,51657,51659,51660,51661,51662,51663,51666,51668,51671,51672,51675,65281,65282,65283,65284,65285,65286,65287,65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339,65510,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,65373,65507,51678,51679,51681,51683,51685,51686,51688,51689,51690,51691,51694,51698,51699,51700,51701,51702,51703,51706,51707,51709,51710,51711,51713,51714,51715,51716,null,null,null,null,null,null,51717,51718,51719,51722,51726,51727,51728,51729,51730,51731,51733,51734,51735,51737,51738,51739,51740,51741,51742,51743,51744,51745,51746,51747,51748,51749,null,null,null,null,null,null,51750,51751,51752,51754,51755,51756,51757,51758,51759,51760,51761,51762,51763,51764,51765,51766,51767,51768,51769,51770,51771,51772,51773,51774,51775,51776,51777,51778,51779,51780,51781,51782,12593,12594,12595,12596,12597,12598,12599,12600,12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615,12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631,12632,12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679,12680,12681,12682,12683,12684,12685,12686,51783,51784,51785,51786,51787,51790,51791,51793,51794,51795,51797,51798,51799,51800,51801,51802,51803,51806,51810,51811,51812,51813,51814,51815,51817,51818,null,null,null,null,null,null,51819,51820,51821,51822,51823,51824,51825,51826,51827,51828,51829,51830,51831,51832,51833,51834,51835,51836,51838,51839,51840,51841,51842,51843,51845,51846,null,null,null,null,null,null,51847,51848,51849,51850,51851,51852,51853,51854,51855,51856,51857,51858,51859,51860,51861,51862,51863,51865,51866,51867,51868,51869,51870,51871,51872,51873,51874,51875,51876,51877,51878,51879,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,null,null,null,null,null,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,null,null,null,null,null,null,null,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,null,null,null,null,null,null,null,null,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,null,null,null,null,null,null,51880,51881,51882,51883,51884,51885,51886,51887,51888,51889,51890,51891,51892,51893,51894,51895,51896,51897,51898,51899,51902,51903,51905,51906,51907,51909,null,null,null,null,null,null,51910,51911,51912,51913,51914,51915,51918,51920,51922,51924,51925,51926,51927,51930,51931,51932,51933,51934,51935,51937,51938,51939,51940,51941,51942,51943,null,null,null,null,null,null,51944,51945,51946,51947,51949,51950,51951,51952,51953,51954,51955,51957,51958,51959,51960,51961,51962,51963,51964,51965,51966,51967,51968,51969,51970,51971,51972,51973,51974,51975,51977,51978,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,9490,9489,9498,9497,9494,9493,9486,9485,9502,9503,9505,9506,9510,9511,9513,9514,9517,9518,9521,9522,9525,9526,9529,9530,9533,9534,9536,9537,9539,9540,9541,9542,9543,9544,9545,9546,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,51979,51980,51981,51982,51983,51985,51986,51987,51989,51990,51991,51993,51994,51995,51996,51997,51998,51999,52002,52003,52004,52005,52006,52007,52008,52009,null,null,null,null,null,null,52010,52011,52012,52013,52014,52015,52016,52017,52018,52019,52020,52021,52022,52023,52024,52025,52026,52027,52028,52029,52030,52031,52032,52034,52035,52036,null,null,null,null,null,null,52037,52038,52039,52042,52043,52045,52046,52047,52049,52050,52051,52052,52053,52054,52055,52058,52059,52060,52062,52063,52064,52065,52066,52067,52069,52070,52071,52072,52073,52074,52075,52076,13205,13206,13207,8467,13208,13252,13219,13220,13221,13222,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13258,13197,13198,13199,13263,13192,13193,13256,13223,13224,13232,13233,13234,13235,13236,13237,13238,13239,13240,13241,13184,13185,13186,13187,13188,13242,13243,13244,13245,13246,13247,13200,13201,13202,13203,13204,8486,13248,13249,13194,13195,13196,13270,13253,13229,13230,13231,13275,13225,13226,13227,13228,13277,13264,13267,13251,13257,13276,13254,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52077,52078,52079,52080,52081,52082,52083,52084,52085,52086,52087,52090,52091,52092,52093,52094,52095,52096,52097,52098,52099,52100,52101,52102,52103,52104,null,null,null,null,null,null,52105,52106,52107,52108,52109,52110,52111,52112,52113,52114,52115,52116,52117,52118,52119,52120,52121,52122,52123,52125,52126,52127,52128,52129,52130,52131,null,null,null,null,null,null,52132,52133,52134,52135,52136,52137,52138,52139,52140,52141,52142,52143,52144,52145,52146,52147,52148,52149,52150,52151,52153,52154,52155,52156,52157,52158,52159,52160,52161,52162,52163,52164,198,208,170,294,null,306,null,319,321,216,338,186,222,358,330,null,12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,9424,9425,9426,9427,9428,9429,9430,9431,9432,9433,9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446,9447,9448,9449,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,189,8531,8532,188,190,8539,8540,8541,8542,52165,52166,52167,52168,52169,52170,52171,52172,52173,52174,52175,52176,52177,52178,52179,52181,52182,52183,52184,52185,52186,52187,52188,52189,52190,52191,null,null,null,null,null,null,52192,52193,52194,52195,52197,52198,52200,52202,52203,52204,52205,52206,52207,52208,52209,52210,52211,52212,52213,52214,52215,52216,52217,52218,52219,52220,null,null,null,null,null,null,52221,52222,52223,52224,52225,52226,52227,52228,52229,52230,52231,52232,52233,52234,52235,52238,52239,52241,52242,52243,52245,52246,52247,52248,52249,52250,52251,52254,52255,52256,52259,52260,230,273,240,295,305,307,312,320,322,248,339,223,254,359,331,329,12800,12801,12802,12803,12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,12818,12819,12820,12821,12822,12823,12824,12825,12826,12827,9372,9373,9374,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,9396,9397,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,185,178,179,8308,8319,8321,8322,8323,8324,52261,52262,52266,52267,52269,52271,52273,52274,52275,52276,52277,52278,52279,52282,52287,52288,52289,52290,52291,52294,52295,52297,52298,52299,52301,52302,null,null,null,null,null,null,52303,52304,52305,52306,52307,52310,52314,52315,52316,52317,52318,52319,52321,52322,52323,52325,52327,52329,52330,52331,52332,52333,52334,52335,52337,52338,null,null,null,null,null,null,52339,52340,52342,52343,52344,52345,52346,52347,52348,52349,52350,52351,52352,52353,52354,52355,52356,52357,52358,52359,52360,52361,52362,52363,52364,52365,52366,52367,52368,52369,52370,52371,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,null,null,null,null,null,null,null,null,null,null,null,52372,52373,52374,52375,52378,52379,52381,52382,52383,52385,52386,52387,52388,52389,52390,52391,52394,52398,52399,52400,52401,52402,52403,52406,52407,52409,null,null,null,null,null,null,52410,52411,52413,52414,52415,52416,52417,52418,52419,52422,52424,52426,52427,52428,52429,52430,52431,52433,52434,52435,52437,52438,52439,52440,52441,52442,null,null,null,null,null,null,52443,52444,52445,52446,52447,52448,52449,52450,52451,52453,52454,52455,52456,52457,52458,52459,52461,52462,52463,52465,52466,52467,52468,52469,52470,52471,52472,52473,52474,52475,52476,52477,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,null,null,null,null,null,null,null,null,52478,52479,52480,52482,52483,52484,52485,52486,52487,52490,52491,52493,52494,52495,52497,52498,52499,52500,52501,52502,52503,52506,52508,52510,52511,52512,null,null,null,null,null,null,52513,52514,52515,52517,52518,52519,52521,52522,52523,52525,52526,52527,52528,52529,52530,52531,52532,52533,52534,52535,52536,52538,52539,52540,52541,52542,null,null,null,null,null,null,52543,52544,52545,52546,52547,52548,52549,52550,52551,52552,52553,52554,52555,52556,52557,52558,52559,52560,52561,52562,52563,52564,52565,52566,52567,52568,52569,52570,52571,52573,52574,52575,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,null,null,null,null,null,null,null,null,null,null,null,null,null,52577,52578,52579,52581,52582,52583,52584,52585,52586,52587,52590,52592,52594,52595,52596,52597,52598,52599,52601,52602,52603,52604,52605,52606,52607,52608,null,null,null,null,null,null,52609,52610,52611,52612,52613,52614,52615,52617,52618,52619,52620,52621,52622,52623,52624,52625,52626,52627,52630,52631,52633,52634,52635,52637,52638,52639,null,null,null,null,null,null,52640,52641,52642,52643,52646,52648,52650,52651,52652,52653,52654,52655,52657,52658,52659,52660,52661,52662,52663,52664,52665,52666,52667,52668,52669,52670,52671,52672,52673,52674,52675,52677,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52678,52679,52680,52681,52682,52683,52685,52686,52687,52689,52690,52691,52692,52693,52694,52695,52696,52697,52698,52699,52700,52701,52702,52703,52704,52705,null,null,null,null,null,null,52706,52707,52708,52709,52710,52711,52713,52714,52715,52717,52718,52719,52721,52722,52723,52724,52725,52726,52727,52730,52732,52734,52735,52736,52737,52738,null,null,null,null,null,null,52739,52741,52742,52743,52745,52746,52747,52749,52750,52751,52752,52753,52754,52755,52757,52758,52759,52760,52762,52763,52764,52765,52766,52767,52770,52771,52773,52774,52775,52777,52778,52779,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52780,52781,52782,52783,52786,52788,52790,52791,52792,52793,52794,52795,52796,52797,52798,52799,52800,52801,52802,52803,52804,52805,52806,52807,52808,52809,null,null,null,null,null,null,52810,52811,52812,52813,52814,52815,52816,52817,52818,52819,52820,52821,52822,52823,52826,52827,52829,52830,52834,52835,52836,52837,52838,52839,52842,52844,null,null,null,null,null,null,52846,52847,52848,52849,52850,52851,52854,52855,52857,52858,52859,52861,52862,52863,52864,52865,52866,52867,52870,52872,52874,52875,52876,52877,52878,52879,52882,52883,52885,52886,52887,52889,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52890,52891,52892,52893,52894,52895,52898,52902,52903,52904,52905,52906,52907,52910,52911,52912,52913,52914,52915,52916,52917,52918,52919,52920,52921,52922,null,null,null,null,null,null,52923,52924,52925,52926,52927,52928,52930,52931,52932,52933,52934,52935,52936,52937,52938,52939,52940,52941,52942,52943,52944,52945,52946,52947,52948,52949,null,null,null,null,null,null,52950,52951,52952,52953,52954,52955,52956,52957,52958,52959,52960,52961,52962,52963,52966,52967,52969,52970,52973,52974,52975,52976,52977,52978,52979,52982,52986,52987,52988,52989,52990,52991,44032,44033,44036,44039,44040,44041,44042,44048,44049,44050,44051,44052,44053,44054,44055,44057,44058,44059,44060,44061,44064,44068,44076,44077,44079,44080,44081,44088,44089,44092,44096,44107,44109,44116,44120,44124,44144,44145,44148,44151,44152,44154,44160,44161,44163,44164,44165,44166,44169,44170,44171,44172,44176,44180,44188,44189,44191,44192,44193,44200,44201,44202,44204,44207,44208,44216,44217,44219,44220,44221,44225,44228,44232,44236,44245,44247,44256,44257,44260,44263,44264,44266,44268,44271,44272,44273,44275,44277,44278,44284,44285,44288,44292,44294,52994,52995,52997,52998,52999,53001,53002,53003,53004,53005,53006,53007,53010,53012,53014,53015,53016,53017,53018,53019,53021,53022,53023,53025,53026,53027,null,null,null,null,null,null,53029,53030,53031,53032,53033,53034,53035,53038,53042,53043,53044,53045,53046,53047,53049,53050,53051,53052,53053,53054,53055,53056,53057,53058,53059,53060,null,null,null,null,null,null,53061,53062,53063,53064,53065,53066,53067,53068,53069,53070,53071,53072,53073,53074,53075,53078,53079,53081,53082,53083,53085,53086,53087,53088,53089,53090,53091,53094,53096,53098,53099,53100,44300,44301,44303,44305,44312,44316,44320,44329,44332,44333,44340,44341,44344,44348,44356,44357,44359,44361,44368,44372,44376,44385,44387,44396,44397,44400,44403,44404,44405,44406,44411,44412,44413,44415,44417,44418,44424,44425,44428,44432,44444,44445,44452,44471,44480,44481,44484,44488,44496,44497,44499,44508,44512,44516,44536,44537,44540,44543,44544,44545,44552,44553,44555,44557,44564,44592,44593,44596,44599,44600,44602,44608,44609,44611,44613,44614,44618,44620,44621,44622,44624,44628,44630,44636,44637,44639,44640,44641,44645,44648,44649,44652,44656,44664,53101,53102,53103,53106,53107,53109,53110,53111,53113,53114,53115,53116,53117,53118,53119,53121,53122,53123,53124,53126,53127,53128,53129,53130,53131,53133,null,null,null,null,null,null,53134,53135,53136,53137,53138,53139,53140,53141,53142,53143,53144,53145,53146,53147,53148,53149,53150,53151,53152,53154,53155,53156,53157,53158,53159,53161,null,null,null,null,null,null,53162,53163,53164,53165,53166,53167,53169,53170,53171,53172,53173,53174,53175,53176,53177,53178,53179,53180,53181,53182,53183,53184,53185,53186,53187,53189,53190,53191,53192,53193,53194,53195,44665,44667,44668,44669,44676,44677,44684,44732,44733,44734,44736,44740,44748,44749,44751,44752,44753,44760,44761,44764,44776,44779,44781,44788,44792,44796,44807,44808,44813,44816,44844,44845,44848,44850,44852,44860,44861,44863,44865,44866,44867,44872,44873,44880,44892,44893,44900,44901,44921,44928,44932,44936,44944,44945,44949,44956,44984,44985,44988,44992,44999,45000,45001,45003,45005,45006,45012,45020,45032,45033,45040,45041,45044,45048,45056,45057,45060,45068,45072,45076,45084,45085,45096,45124,45125,45128,45130,45132,45134,45139,45140,45141,45143,45145,53196,53197,53198,53199,53200,53201,53202,53203,53204,53205,53206,53207,53208,53209,53210,53211,53212,53213,53214,53215,53218,53219,53221,53222,53223,53225,null,null,null,null,null,null,53226,53227,53228,53229,53230,53231,53234,53236,53238,53239,53240,53241,53242,53243,53245,53246,53247,53249,53250,53251,53253,53254,53255,53256,53257,53258,null,null,null,null,null,null,53259,53260,53261,53262,53263,53264,53266,53267,53268,53269,53270,53271,53273,53274,53275,53276,53277,53278,53279,53280,53281,53282,53283,53284,53285,53286,53287,53288,53289,53290,53291,53292,45149,45180,45181,45184,45188,45196,45197,45199,45201,45208,45209,45210,45212,45215,45216,45217,45218,45224,45225,45227,45228,45229,45230,45231,45233,45235,45236,45237,45240,45244,45252,45253,45255,45256,45257,45264,45265,45268,45272,45280,45285,45320,45321,45323,45324,45328,45330,45331,45336,45337,45339,45340,45341,45347,45348,45349,45352,45356,45364,45365,45367,45368,45369,45376,45377,45380,45384,45392,45393,45396,45397,45400,45404,45408,45432,45433,45436,45440,45442,45448,45449,45451,45453,45458,45459,45460,45464,45468,45480,45516,45520,45524,45532,45533,53294,53295,53296,53297,53298,53299,53302,53303,53305,53306,53307,53309,53310,53311,53312,53313,53314,53315,53318,53320,53322,53323,53324,53325,53326,53327,null,null,null,null,null,null,53329,53330,53331,53333,53334,53335,53337,53338,53339,53340,53341,53342,53343,53345,53346,53347,53348,53349,53350,53351,53352,53353,53354,53355,53358,53359,null,null,null,null,null,null,53361,53362,53363,53365,53366,53367,53368,53369,53370,53371,53374,53375,53376,53378,53379,53380,53381,53382,53383,53384,53385,53386,53387,53388,53389,53390,53391,53392,53393,53394,53395,53396,45535,45544,45545,45548,45552,45561,45563,45565,45572,45573,45576,45579,45580,45588,45589,45591,45593,45600,45620,45628,45656,45660,45664,45672,45673,45684,45685,45692,45700,45701,45705,45712,45713,45716,45720,45721,45722,45728,45729,45731,45733,45734,45738,45740,45744,45748,45768,45769,45772,45776,45778,45784,45785,45787,45789,45794,45796,45797,45798,45800,45803,45804,45805,45806,45807,45811,45812,45813,45815,45816,45817,45818,45819,45823,45824,45825,45828,45832,45840,45841,45843,45844,45845,45852,45908,45909,45910,45912,45915,45916,45918,45919,45924,45925,53397,53398,53399,53400,53401,53402,53403,53404,53405,53406,53407,53408,53409,53410,53411,53414,53415,53417,53418,53419,53421,53422,53423,53424,53425,53426,null,null,null,null,null,null,53427,53430,53432,53434,53435,53436,53437,53438,53439,53442,53443,53445,53446,53447,53450,53451,53452,53453,53454,53455,53458,53462,53463,53464,53465,53466,null,null,null,null,null,null,53467,53470,53471,53473,53474,53475,53477,53478,53479,53480,53481,53482,53483,53486,53490,53491,53492,53493,53494,53495,53497,53498,53499,53500,53501,53502,53503,53504,53505,53506,53507,53508,45927,45929,45931,45934,45936,45937,45940,45944,45952,45953,45955,45956,45957,45964,45968,45972,45984,45985,45992,45996,46020,46021,46024,46027,46028,46030,46032,46036,46037,46039,46041,46043,46045,46048,46052,46056,46076,46096,46104,46108,46112,46120,46121,46123,46132,46160,46161,46164,46168,46176,46177,46179,46181,46188,46208,46216,46237,46244,46248,46252,46261,46263,46265,46272,46276,46280,46288,46293,46300,46301,46304,46307,46308,46310,46316,46317,46319,46321,46328,46356,46357,46360,46363,46364,46372,46373,46375,46376,46377,46378,46384,46385,46388,46392,53509,53510,53511,53512,53513,53514,53515,53516,53518,53519,53520,53521,53522,53523,53524,53525,53526,53527,53528,53529,53530,53531,53532,53533,53534,53535,null,null,null,null,null,null,53536,53537,53538,53539,53540,53541,53542,53543,53544,53545,53546,53547,53548,53549,53550,53551,53554,53555,53557,53558,53559,53561,53563,53564,53565,53566,null,null,null,null,null,null,53567,53570,53574,53575,53576,53577,53578,53579,53582,53583,53585,53586,53587,53589,53590,53591,53592,53593,53594,53595,53598,53600,53602,53603,53604,53605,53606,53607,53609,53610,53611,53613,46400,46401,46403,46404,46405,46411,46412,46413,46416,46420,46428,46429,46431,46432,46433,46496,46497,46500,46504,46506,46507,46512,46513,46515,46516,46517,46523,46524,46525,46528,46532,46540,46541,46543,46544,46545,46552,46572,46608,46609,46612,46616,46629,46636,46644,46664,46692,46696,46748,46749,46752,46756,46763,46764,46769,46804,46832,46836,46840,46848,46849,46853,46888,46889,46892,46895,46896,46904,46905,46907,46916,46920,46924,46932,46933,46944,46948,46952,46960,46961,46963,46965,46972,46973,46976,46980,46988,46989,46991,46992,46993,46994,46998,46999,53614,53615,53616,53617,53618,53619,53620,53621,53622,53623,53624,53625,53626,53627,53629,53630,53631,53632,53633,53634,53635,53637,53638,53639,53641,53642,null,null,null,null,null,null,53643,53644,53645,53646,53647,53648,53649,53650,53651,53652,53653,53654,53655,53656,53657,53658,53659,53660,53661,53662,53663,53666,53667,53669,53670,53671,null,null,null,null,null,null,53673,53674,53675,53676,53677,53678,53679,53682,53684,53686,53687,53688,53689,53691,53693,53694,53695,53697,53698,53699,53700,53701,53702,53703,53704,53705,53706,53707,53708,53709,53710,53711,47000,47001,47004,47008,47016,47017,47019,47020,47021,47028,47029,47032,47047,47049,47084,47085,47088,47092,47100,47101,47103,47104,47105,47111,47112,47113,47116,47120,47128,47129,47131,47133,47140,47141,47144,47148,47156,47157,47159,47160,47161,47168,47172,47185,47187,47196,47197,47200,47204,47212,47213,47215,47217,47224,47228,47245,47272,47280,47284,47288,47296,47297,47299,47301,47308,47312,47316,47325,47327,47329,47336,47337,47340,47344,47352,47353,47355,47357,47364,47384,47392,47420,47421,47424,47428,47436,47439,47441,47448,47449,47452,47456,47464,47465,53712,53713,53714,53715,53716,53717,53718,53719,53721,53722,53723,53724,53725,53726,53727,53728,53729,53730,53731,53732,53733,53734,53735,53736,53737,53738,null,null,null,null,null,null,53739,53740,53741,53742,53743,53744,53745,53746,53747,53749,53750,53751,53753,53754,53755,53756,53757,53758,53759,53760,53761,53762,53763,53764,53765,53766,null,null,null,null,null,null,53768,53770,53771,53772,53773,53774,53775,53777,53778,53779,53780,53781,53782,53783,53784,53785,53786,53787,53788,53789,53790,53791,53792,53793,53794,53795,53796,53797,53798,53799,53800,53801,47467,47469,47476,47477,47480,47484,47492,47493,47495,47497,47498,47501,47502,47532,47533,47536,47540,47548,47549,47551,47553,47560,47561,47564,47566,47567,47568,47569,47570,47576,47577,47579,47581,47582,47585,47587,47588,47589,47592,47596,47604,47605,47607,47608,47609,47610,47616,47617,47624,47637,47672,47673,47676,47680,47682,47688,47689,47691,47693,47694,47699,47700,47701,47704,47708,47716,47717,47719,47720,47721,47728,47729,47732,47736,47747,47748,47749,47751,47756,47784,47785,47787,47788,47792,47794,47800,47801,47803,47805,47812,47816,47832,47833,47868,53802,53803,53806,53807,53809,53810,53811,53813,53814,53815,53816,53817,53818,53819,53822,53824,53826,53827,53828,53829,53830,53831,53833,53834,53835,53836,null,null,null,null,null,null,53837,53838,53839,53840,53841,53842,53843,53844,53845,53846,53847,53848,53849,53850,53851,53853,53854,53855,53856,53857,53858,53859,53861,53862,53863,53864,null,null,null,null,null,null,53865,53866,53867,53868,53869,53870,53871,53872,53873,53874,53875,53876,53877,53878,53879,53880,53881,53882,53883,53884,53885,53886,53887,53890,53891,53893,53894,53895,53897,53898,53899,53900,47872,47876,47885,47887,47889,47896,47900,47904,47913,47915,47924,47925,47926,47928,47931,47932,47933,47934,47940,47941,47943,47945,47949,47951,47952,47956,47960,47969,47971,47980,48008,48012,48016,48036,48040,48044,48052,48055,48064,48068,48072,48080,48083,48120,48121,48124,48127,48128,48130,48136,48137,48139,48140,48141,48143,48145,48148,48149,48150,48151,48152,48155,48156,48157,48158,48159,48164,48165,48167,48169,48173,48176,48177,48180,48184,48192,48193,48195,48196,48197,48201,48204,48205,48208,48221,48260,48261,48264,48267,48268,48270,48276,48277,48279,53901,53902,53903,53906,53907,53908,53910,53911,53912,53913,53914,53915,53917,53918,53919,53921,53922,53923,53925,53926,53927,53928,53929,53930,53931,53933,null,null,null,null,null,null,53934,53935,53936,53938,53939,53940,53941,53942,53943,53946,53947,53949,53950,53953,53955,53956,53957,53958,53959,53962,53964,53965,53966,53967,53968,53969,null,null,null,null,null,null,53970,53971,53973,53974,53975,53977,53978,53979,53981,53982,53983,53984,53985,53986,53987,53990,53991,53992,53993,53994,53995,53996,53997,53998,53999,54002,54003,54005,54006,54007,54009,54010,48281,48282,48288,48289,48292,48295,48296,48304,48305,48307,48308,48309,48316,48317,48320,48324,48333,48335,48336,48337,48341,48344,48348,48372,48373,48374,48376,48380,48388,48389,48391,48393,48400,48404,48420,48428,48448,48456,48457,48460,48464,48472,48473,48484,48488,48512,48513,48516,48519,48520,48521,48522,48528,48529,48531,48533,48537,48538,48540,48548,48560,48568,48596,48597,48600,48604,48617,48624,48628,48632,48640,48643,48645,48652,48653,48656,48660,48668,48669,48671,48708,48709,48712,48716,48718,48724,48725,48727,48729,48730,48731,48736,48737,48740,54011,54012,54013,54014,54015,54018,54020,54022,54023,54024,54025,54026,54027,54031,54033,54034,54035,54037,54039,54040,54041,54042,54043,54046,54050,54051,null,null,null,null,null,null,54052,54054,54055,54058,54059,54061,54062,54063,54065,54066,54067,54068,54069,54070,54071,54074,54078,54079,54080,54081,54082,54083,54086,54087,54088,54089,null,null,null,null,null,null,54090,54091,54092,54093,54094,54095,54096,54097,54098,54099,54100,54101,54102,54103,54104,54105,54106,54107,54108,54109,54110,54111,54112,54113,54114,54115,54116,54117,54118,54119,54120,54121,48744,48746,48752,48753,48755,48756,48757,48763,48764,48765,48768,48772,48780,48781,48783,48784,48785,48792,48793,48808,48848,48849,48852,48855,48856,48864,48867,48868,48869,48876,48897,48904,48905,48920,48921,48923,48924,48925,48960,48961,48964,48968,48976,48977,48981,49044,49072,49093,49100,49101,49104,49108,49116,49119,49121,49212,49233,49240,49244,49248,49256,49257,49296,49297,49300,49304,49312,49313,49315,49317,49324,49325,49327,49328,49331,49332,49333,49334,49340,49341,49343,49344,49345,49349,49352,49353,49356,49360,49368,49369,49371,49372,49373,49380,54122,54123,54124,54125,54126,54127,54128,54129,54130,54131,54132,54133,54134,54135,54136,54137,54138,54139,54142,54143,54145,54146,54147,54149,54150,54151,null,null,null,null,null,null,54152,54153,54154,54155,54158,54162,54163,54164,54165,54166,54167,54170,54171,54173,54174,54175,54177,54178,54179,54180,54181,54182,54183,54186,54188,54190,null,null,null,null,null,null,54191,54192,54193,54194,54195,54197,54198,54199,54201,54202,54203,54205,54206,54207,54208,54209,54210,54211,54214,54215,54218,54219,54220,54221,54222,54223,54225,54226,54227,54228,54229,54230,49381,49384,49388,49396,49397,49399,49401,49408,49412,49416,49424,49429,49436,49437,49438,49439,49440,49443,49444,49446,49447,49452,49453,49455,49456,49457,49462,49464,49465,49468,49472,49480,49481,49483,49484,49485,49492,49493,49496,49500,49508,49509,49511,49512,49513,49520,49524,49528,49541,49548,49549,49550,49552,49556,49558,49564,49565,49567,49569,49573,49576,49577,49580,49584,49597,49604,49608,49612,49620,49623,49624,49632,49636,49640,49648,49649,49651,49660,49661,49664,49668,49676,49677,49679,49681,49688,49689,49692,49695,49696,49704,49705,49707,49709,54231,54233,54234,54235,54236,54237,54238,54239,54240,54242,54244,54245,54246,54247,54248,54249,54250,54251,54254,54255,54257,54258,54259,54261,54262,54263,null,null,null,null,null,null,54264,54265,54266,54267,54270,54272,54274,54275,54276,54277,54278,54279,54281,54282,54283,54284,54285,54286,54287,54288,54289,54290,54291,54292,54293,54294,null,null,null,null,null,null,54295,54296,54297,54298,54299,54300,54302,54303,54304,54305,54306,54307,54308,54309,54310,54311,54312,54313,54314,54315,54316,54317,54318,54319,54320,54321,54322,54323,54324,54325,54326,54327,49711,49713,49714,49716,49736,49744,49745,49748,49752,49760,49765,49772,49773,49776,49780,49788,49789,49791,49793,49800,49801,49808,49816,49819,49821,49828,49829,49832,49836,49837,49844,49845,49847,49849,49884,49885,49888,49891,49892,49899,49900,49901,49903,49905,49910,49912,49913,49915,49916,49920,49928,49929,49932,49933,49939,49940,49941,49944,49948,49956,49957,49960,49961,49989,50024,50025,50028,50032,50034,50040,50041,50044,50045,50052,50056,50060,50112,50136,50137,50140,50143,50144,50146,50152,50153,50157,50164,50165,50168,50184,50192,50212,50220,50224,54328,54329,54330,54331,54332,54333,54334,54335,54337,54338,54339,54341,54342,54343,54344,54345,54346,54347,54348,54349,54350,54351,54352,54353,54354,54355,null,null,null,null,null,null,54356,54357,54358,54359,54360,54361,54362,54363,54365,54366,54367,54369,54370,54371,54373,54374,54375,54376,54377,54378,54379,54380,54382,54384,54385,54386,null,null,null,null,null,null,54387,54388,54389,54390,54391,54394,54395,54397,54398,54401,54403,54404,54405,54406,54407,54410,54412,54414,54415,54416,54417,54418,54419,54421,54422,54423,54424,54425,54426,54427,54428,54429,50228,50236,50237,50248,50276,50277,50280,50284,50292,50293,50297,50304,50324,50332,50360,50364,50409,50416,50417,50420,50424,50426,50431,50432,50433,50444,50448,50452,50460,50472,50473,50476,50480,50488,50489,50491,50493,50500,50501,50504,50505,50506,50508,50509,50510,50515,50516,50517,50519,50520,50521,50525,50526,50528,50529,50532,50536,50544,50545,50547,50548,50549,50556,50557,50560,50564,50567,50572,50573,50575,50577,50581,50583,50584,50588,50592,50601,50612,50613,50616,50617,50619,50620,50621,50622,50628,50629,50630,50631,50632,50633,50634,50636,50638,54430,54431,54432,54433,54434,54435,54436,54437,54438,54439,54440,54442,54443,54444,54445,54446,54447,54448,54449,54450,54451,54452,54453,54454,54455,54456,null,null,null,null,null,null,54457,54458,54459,54460,54461,54462,54463,54464,54465,54466,54467,54468,54469,54470,54471,54472,54473,54474,54475,54477,54478,54479,54481,54482,54483,54485,null,null,null,null,null,null,54486,54487,54488,54489,54490,54491,54493,54494,54496,54497,54498,54499,54500,54501,54502,54503,54505,54506,54507,54509,54510,54511,54513,54514,54515,54516,54517,54518,54519,54521,54522,54524,50640,50641,50644,50648,50656,50657,50659,50661,50668,50669,50670,50672,50676,50678,50679,50684,50685,50686,50687,50688,50689,50693,50694,50695,50696,50700,50704,50712,50713,50715,50716,50724,50725,50728,50732,50733,50734,50736,50739,50740,50741,50743,50745,50747,50752,50753,50756,50760,50768,50769,50771,50772,50773,50780,50781,50784,50796,50799,50801,50808,50809,50812,50816,50824,50825,50827,50829,50836,50837,50840,50844,50852,50853,50855,50857,50864,50865,50868,50872,50873,50874,50880,50881,50883,50885,50892,50893,50896,50900,50908,50909,50912,50913,50920,54526,54527,54528,54529,54530,54531,54533,54534,54535,54537,54538,54539,54541,54542,54543,54544,54545,54546,54547,54550,54552,54553,54554,54555,54556,54557,null,null,null,null,null,null,54558,54559,54560,54561,54562,54563,54564,54565,54566,54567,54568,54569,54570,54571,54572,54573,54574,54575,54576,54577,54578,54579,54580,54581,54582,54583,null,null,null,null,null,null,54584,54585,54586,54587,54590,54591,54593,54594,54595,54597,54598,54599,54600,54601,54602,54603,54606,54608,54610,54611,54612,54613,54614,54615,54618,54619,54621,54622,54623,54625,54626,54627,50921,50924,50928,50936,50937,50941,50948,50949,50952,50956,50964,50965,50967,50969,50976,50977,50980,50984,50992,50993,50995,50997,50999,51004,51005,51008,51012,51018,51020,51021,51023,51025,51026,51027,51028,51029,51030,51031,51032,51036,51040,51048,51051,51060,51061,51064,51068,51069,51070,51075,51076,51077,51079,51080,51081,51082,51086,51088,51089,51092,51094,51095,51096,51098,51104,51105,51107,51108,51109,51110,51116,51117,51120,51124,51132,51133,51135,51136,51137,51144,51145,51148,51150,51152,51160,51165,51172,51176,51180,51200,51201,51204,51208,51210,54628,54630,54631,54634,54636,54638,54639,54640,54641,54642,54643,54646,54647,54649,54650,54651,54653,54654,54655,54656,54657,54658,54659,54662,54666,54667,null,null,null,null,null,null,54668,54669,54670,54671,54673,54674,54675,54676,54677,54678,54679,54680,54681,54682,54683,54684,54685,54686,54687,54688,54689,54690,54691,54692,54694,54695,null,null,null,null,null,null,54696,54697,54698,54699,54700,54701,54702,54703,54704,54705,54706,54707,54708,54709,54710,54711,54712,54713,54714,54715,54716,54717,54718,54719,54720,54721,54722,54723,54724,54725,54726,54727,51216,51217,51219,51221,51222,51228,51229,51232,51236,51244,51245,51247,51249,51256,51260,51264,51272,51273,51276,51277,51284,51312,51313,51316,51320,51322,51328,51329,51331,51333,51334,51335,51339,51340,51341,51348,51357,51359,51361,51368,51388,51389,51396,51400,51404,51412,51413,51415,51417,51424,51425,51428,51445,51452,51453,51456,51460,51461,51462,51468,51469,51471,51473,51480,51500,51508,51536,51537,51540,51544,51552,51553,51555,51564,51568,51572,51580,51592,51593,51596,51600,51608,51609,51611,51613,51648,51649,51652,51655,51656,51658,51664,51665,51667,54730,54731,54733,54734,54735,54737,54739,54740,54741,54742,54743,54746,54748,54750,54751,54752,54753,54754,54755,54758,54759,54761,54762,54763,54765,54766,null,null,null,null,null,null,54767,54768,54769,54770,54771,54774,54776,54778,54779,54780,54781,54782,54783,54786,54787,54789,54790,54791,54793,54794,54795,54796,54797,54798,54799,54802,null,null,null,null,null,null,54806,54807,54808,54809,54810,54811,54813,54814,54815,54817,54818,54819,54821,54822,54823,54824,54825,54826,54827,54828,54830,54831,54832,54833,54834,54835,54836,54837,54838,54839,54842,54843,51669,51670,51673,51674,51676,51677,51680,51682,51684,51687,51692,51693,51695,51696,51697,51704,51705,51708,51712,51720,51721,51723,51724,51725,51732,51736,51753,51788,51789,51792,51796,51804,51805,51807,51808,51809,51816,51837,51844,51864,51900,51901,51904,51908,51916,51917,51919,51921,51923,51928,51929,51936,51948,51956,51976,51984,51988,51992,52000,52001,52033,52040,52041,52044,52048,52056,52057,52061,52068,52088,52089,52124,52152,52180,52196,52199,52201,52236,52237,52240,52244,52252,52253,52257,52258,52263,52264,52265,52268,52270,52272,52280,52281,52283,54845,54846,54847,54849,54850,54851,54852,54854,54855,54858,54860,54862,54863,54864,54866,54867,54870,54871,54873,54874,54875,54877,54878,54879,54880,54881,null,null,null,null,null,null,54882,54883,54884,54885,54886,54888,54890,54891,54892,54893,54894,54895,54898,54899,54901,54902,54903,54904,54905,54906,54907,54908,54909,54910,54911,54912,null,null,null,null,null,null,54913,54914,54916,54918,54919,54920,54921,54922,54923,54926,54927,54929,54930,54931,54933,54934,54935,54936,54937,54938,54939,54940,54942,54944,54946,54947,54948,54949,54950,54951,54953,54954,52284,52285,52286,52292,52293,52296,52300,52308,52309,52311,52312,52313,52320,52324,52326,52328,52336,52341,52376,52377,52380,52384,52392,52393,52395,52396,52397,52404,52405,52408,52412,52420,52421,52423,52425,52432,52436,52452,52460,52464,52481,52488,52489,52492,52496,52504,52505,52507,52509,52516,52520,52524,52537,52572,52576,52580,52588,52589,52591,52593,52600,52616,52628,52629,52632,52636,52644,52645,52647,52649,52656,52676,52684,52688,52712,52716,52720,52728,52729,52731,52733,52740,52744,52748,52756,52761,52768,52769,52772,52776,52784,52785,52787,52789,54955,54957,54958,54959,54961,54962,54963,54964,54965,54966,54967,54968,54970,54972,54973,54974,54975,54976,54977,54978,54979,54982,54983,54985,54986,54987,null,null,null,null,null,null,54989,54990,54991,54992,54994,54995,54997,54998,55000,55002,55003,55004,55005,55006,55007,55009,55010,55011,55013,55014,55015,55017,55018,55019,55020,55021,null,null,null,null,null,null,55022,55023,55025,55026,55027,55028,55030,55031,55032,55033,55034,55035,55038,55039,55041,55042,55043,55045,55046,55047,55048,55049,55050,55051,55052,55053,55054,55055,55056,55058,55059,55060,52824,52825,52828,52831,52832,52833,52840,52841,52843,52845,52852,52853,52856,52860,52868,52869,52871,52873,52880,52881,52884,52888,52896,52897,52899,52900,52901,52908,52909,52929,52964,52965,52968,52971,52972,52980,52981,52983,52984,52985,52992,52993,52996,53000,53008,53009,53011,53013,53020,53024,53028,53036,53037,53039,53040,53041,53048,53076,53077,53080,53084,53092,53093,53095,53097,53104,53105,53108,53112,53120,53125,53132,53153,53160,53168,53188,53216,53217,53220,53224,53232,53233,53235,53237,53244,53248,53252,53265,53272,53293,53300,53301,53304,53308,55061,55062,55063,55066,55067,55069,55070,55071,55073,55074,55075,55076,55077,55078,55079,55082,55084,55086,55087,55088,55089,55090,55091,55094,55095,55097,null,null,null,null,null,null,55098,55099,55101,55102,55103,55104,55105,55106,55107,55109,55110,55112,55114,55115,55116,55117,55118,55119,55122,55123,55125,55130,55131,55132,55133,55134,null,null,null,null,null,null,55135,55138,55140,55142,55143,55144,55146,55147,55149,55150,55151,55153,55154,55155,55157,55158,55159,55160,55161,55162,55163,55166,55167,55168,55170,55171,55172,55173,55174,55175,55178,55179,53316,53317,53319,53321,53328,53332,53336,53344,53356,53357,53360,53364,53372,53373,53377,53412,53413,53416,53420,53428,53429,53431,53433,53440,53441,53444,53448,53449,53456,53457,53459,53460,53461,53468,53469,53472,53476,53484,53485,53487,53488,53489,53496,53517,53552,53553,53556,53560,53562,53568,53569,53571,53572,53573,53580,53581,53584,53588,53596,53597,53599,53601,53608,53612,53628,53636,53640,53664,53665,53668,53672,53680,53681,53683,53685,53690,53692,53696,53720,53748,53752,53767,53769,53776,53804,53805,53808,53812,53820,53821,53823,53825,53832,53852,55181,55182,55183,55185,55186,55187,55188,55189,55190,55191,55194,55196,55198,55199,55200,55201,55202,55203,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,53860,53888,53889,53892,53896,53904,53905,53909,53916,53920,53924,53932,53937,53944,53945,53948,53951,53952,53954,53960,53961,53963,53972,53976,53980,53988,53989,54000,54001,54004,54008,54016,54017,54019,54021,54028,54029,54030,54032,54036,54038,54044,54045,54047,54048,54049,54053,54056,54057,54060,54064,54072,54073,54075,54076,54077,54084,54085,54140,54141,54144,54148,54156,54157,54159,54160,54161,54168,54169,54172,54176,54184,54185,54187,54189,54196,54200,54204,54212,54213,54216,54217,54224,54232,54241,54243,54252,54253,54256,54260,54268,54269,54271,54273,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,54280,54301,54336,54340,54364,54368,54372,54381,54383,54392,54393,54396,54399,54400,54402,54408,54409,54411,54413,54420,54441,54476,54480,54484,54492,54495,54504,54508,54512,54520,54523,54525,54532,54536,54540,54548,54549,54551,54588,54589,54592,54596,54604,54605,54607,54609,54616,54617,54620,54624,54629,54632,54633,54635,54637,54644,54645,54648,54652,54660,54661,54663,54664,54665,54672,54693,54728,54729,54732,54736,54738,54744,54745,54747,54749,54756,54757,54760,54764,54772,54773,54775,54777,54784,54785,54788,54792,54800,54801,54803,54804,54805,54812,54816,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,54820,54829,54840,54841,54844,54848,54853,54856,54857,54859,54861,54865,54868,54869,54872,54876,54887,54889,54896,54897,54900,54915,54917,54924,54925,54928,54932,54941,54943,54945,54952,54956,54960,54969,54971,54980,54981,54984,54988,54993,54996,54999,55001,55008,55012,55016,55024,55029,55036,55037,55040,55044,55057,55064,55065,55068,55072,55080,55081,55083,55085,55092,55093,55096,55100,55108,55111,55113,55120,55121,55124,55126,55127,55128,55129,55136,55137,55139,55141,55145,55148,55152,55156,55164,55165,55169,55176,55177,55180,55184,55192,55193,55195,55197,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20285,20339,20551,20729,21152,21487,21621,21733,22025,23233,23478,26247,26550,26551,26607,27468,29634,30146,31292,33499,33540,34903,34952,35382,36040,36303,36603,36838,39381,21051,21364,21508,24682,24932,27580,29647,33050,35258,35282,38307,20355,21002,22718,22904,23014,24178,24185,25031,25536,26438,26604,26751,28567,30286,30475,30965,31240,31487,31777,32925,33390,33393,35563,38291,20075,21917,26359,28212,30883,31469,33883,35088,34638,38824,21208,22350,22570,23884,24863,25022,25121,25954,26577,27204,28187,29976,30131,30435,30640,32058,37039,37969,37970,40853,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21283,23724,30002,32987,37440,38296,21083,22536,23004,23713,23831,24247,24378,24394,24951,27743,30074,30086,31968,32115,32177,32652,33108,33313,34193,35137,35611,37628,38477,40007,20171,20215,20491,20977,22607,24887,24894,24936,25913,27114,28433,30117,30342,30422,31623,33445,33995,63744,37799,38283,21888,23458,22353,63745,31923,32697,37301,20520,21435,23621,24040,25298,25454,25818,25831,28192,28844,31067,36317,36382,63746,36989,37445,37624,20094,20214,20581,24062,24314,24838,26967,33137,34388,36423,37749,39467,20062,20625,26480,26688,20745,21133,21138,27298,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30652,37392,40660,21163,24623,36850,20552,25001,25581,25802,26684,27268,28608,33160,35233,38548,22533,29309,29356,29956,32121,32365,32937,35211,35700,36963,40273,25225,27770,28500,32080,32570,35363,20860,24906,31645,35609,37463,37772,20140,20435,20510,20670,20742,21185,21197,21375,22384,22659,24218,24465,24950,25004,25806,25964,26223,26299,26356,26775,28039,28805,28913,29855,29861,29898,30169,30828,30956,31455,31478,32069,32147,32789,32831,33051,33686,35686,36629,36885,37857,38915,38968,39514,39912,20418,21843,22586,22865,23395,23622,24760,25106,26690,26800,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26856,28330,30028,30328,30926,31293,31995,32363,32380,35336,35489,35903,38542,40388,21476,21481,21578,21617,22266,22993,23396,23611,24235,25335,25911,25925,25970,26272,26543,27073,27837,30204,30352,30590,31295,32660,32771,32929,33167,33510,33533,33776,34241,34865,34996,35493,63747,36764,37678,38599,39015,39640,40723,21741,26011,26354,26767,31296,35895,40288,22256,22372,23825,26118,26801,26829,28414,29736,34974,39908,27752,63748,39592,20379,20844,20849,21151,23380,24037,24656,24685,25329,25511,25915,29657,31354,34467,36002,38799,20018,23521,25096,26524,29916,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31185,33747,35463,35506,36328,36942,37707,38982,24275,27112,34303,37101,63749,20896,23448,23532,24931,26874,27454,28748,29743,29912,31649,32592,33733,35264,36011,38364,39208,21038,24669,25324,36866,20362,20809,21281,22745,24291,26336,27960,28826,29378,29654,31568,33009,37979,21350,25499,32619,20054,20608,22602,22750,24618,24871,25296,27088,39745,23439,32024,32945,36703,20132,20689,21676,21932,23308,23968,24039,25898,25934,26657,27211,29409,30350,30703,32094,32761,33184,34126,34527,36611,36686,37066,39171,39509,39851,19992,20037,20061,20167,20465,20855,21246,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21312,21475,21477,21646,22036,22389,22434,23495,23943,24272,25084,25304,25937,26552,26601,27083,27472,27590,27628,27714,28317,28792,29399,29590,29699,30655,30697,31350,32127,32777,33276,33285,33290,33503,34914,35635,36092,36544,36881,37041,37476,37558,39378,39493,40169,40407,40860,22283,23616,33738,38816,38827,40628,21531,31384,32676,35033,36557,37089,22528,23624,25496,31391,23470,24339,31353,31406,33422,36524,20518,21048,21240,21367,22280,25331,25458,27402,28099,30519,21413,29527,34152,36470,38357,26426,27331,28528,35437,36556,39243,63750,26231,27512,36020,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,39740,63751,21483,22317,22862,25542,27131,29674,30789,31418,31429,31998,33909,35215,36211,36917,38312,21243,22343,30023,31584,33740,37406,63752,27224,20811,21067,21127,25119,26840,26997,38553,20677,21156,21220,25027,26020,26681,27135,29822,31563,33465,33771,35250,35641,36817,39241,63753,20170,22935,25810,26129,27278,29748,31105,31165,33449,34942,34943,35167,63754,37670,20235,21450,24613,25201,27762,32026,32102,20120,20834,30684,32943,20225,20238,20854,20864,21980,22120,22331,22522,22524,22804,22855,22931,23492,23696,23822,24049,24190,24524,25216,26071,26083,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26398,26399,26462,26827,26820,27231,27450,27683,27773,27778,28103,29592,29734,29738,29826,29859,30072,30079,30849,30959,31041,31047,31048,31098,31637,32000,32186,32648,32774,32813,32908,35352,35663,35912,36215,37665,37668,39138,39249,39438,39439,39525,40594,32202,20342,21513,25326,26708,37329,21931,20794,63755,63756,23068,25062,63757,25295,25343,63758,63759,63760,63761,63762,63763,37027,63764,63765,63766,63767,63768,35582,63769,63770,63771,63772,26262,63773,29014,63774,63775,38627,63776,25423,25466,21335,63777,26511,26976,28275,63778,30007,63779,63780,63781,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32013,63782,63783,34930,22218,23064,63784,63785,63786,63787,63788,20035,63789,20839,22856,26608,32784,63790,22899,24180,25754,31178,24565,24684,25288,25467,23527,23511,21162,63791,22900,24361,24594,63792,63793,63794,29785,63795,63796,63797,63798,63799,63800,39377,63801,63802,63803,63804,63805,63806,63807,63808,63809,63810,63811,28611,63812,63813,33215,36786,24817,63814,63815,33126,63816,63817,23615,63818,63819,63820,63821,63822,63823,63824,63825,23273,35365,26491,32016,63826,63827,63828,63829,63830,63831,33021,63832,63833,23612,27877,21311,28346,22810,33590,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20025,20150,20294,21934,22296,22727,24406,26039,26086,27264,27573,28237,30701,31471,31774,32222,34507,34962,37170,37723,25787,28606,29562,30136,36948,21846,22349,25018,25812,26311,28129,28251,28525,28601,30192,32835,33213,34113,35203,35527,35674,37663,27795,30035,31572,36367,36957,21776,22530,22616,24162,25095,25758,26848,30070,31958,34739,40680,20195,22408,22382,22823,23565,23729,24118,24453,25140,25825,29619,33274,34955,36024,38538,40667,23429,24503,24755,20498,20992,21040,22294,22581,22615,23566,23648,23798,23947,24230,24466,24764,25361,25481,25623,26691,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26873,27330,28120,28193,28372,28644,29182,30428,30585,31153,31291,33796,35241,36077,36339,36424,36867,36884,36947,37117,37709,38518,38876,27602,28678,29272,29346,29544,30563,31167,31716,32411,35712,22697,24775,25958,26109,26302,27788,28958,29129,35930,38931,20077,31361,20189,20908,20941,21205,21516,24999,26481,26704,26847,27934,28540,30140,30643,31461,33012,33891,37509,20828,26007,26460,26515,30168,31431,33651,63834,35910,36887,38957,23663,33216,33434,36929,36975,37389,24471,23965,27225,29128,30331,31561,34276,35588,37159,39472,21895,25078,63835,30313,32645,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,34367,34746,35064,37007,63836,27931,28889,29662,32097,33853,63837,37226,39409,63838,20098,21365,27396,27410,28734,29211,34349,40478,21068,36771,23888,25829,25900,27414,28651,31811,32412,34253,35172,35261,25289,33240,34847,24266,26391,28010,29436,29701,29807,34690,37086,20358,23821,24480,33802,20919,25504,30053,20142,20486,20841,20937,26753,27153,31918,31921,31975,33391,35538,36635,37327,20406,20791,21237,21570,24300,24942,25150,26053,27354,28670,31018,34268,34851,38317,39522,39530,40599,40654,21147,26310,27511,28701,31019,36706,38722,24976,25088,25891,28451,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29001,29833,32244,32879,34030,36646,36899,37706,20925,21015,21155,27916,28872,35010,24265,25986,27566,28610,31806,29557,20196,20278,22265,63839,23738,23994,24604,29618,31533,32666,32718,32838,36894,37428,38646,38728,38936,40801,20363,28583,31150,37300,38583,21214,63840,25736,25796,27347,28510,28696,29200,30439,32769,34310,34396,36335,36613,38706,39791,40442,40565,30860,31103,32160,33737,37636,40575,40595,35542,22751,24324,26407,28711,29903,31840,32894,20769,28712,29282,30922,36034,36058,36084,38647,20102,20698,23534,24278,26009,29134,30274,30637,32842,34044,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36988,39719,40845,22744,23105,23650,27155,28122,28431,30267,32047,32311,34078,35128,37860,38475,21129,26066,26611,27060,27969,28316,28687,29705,29792,30041,30244,30827,35628,39006,20845,25134,38520,20374,20523,23833,28138,32184,36650,24459,24900,26647,63841,38534,21202,32907,20956,20940,26974,31260,32190,33777,38517,20442,21033,21400,21519,21774,23653,24743,26446,26792,28012,29313,29432,29702,29827,63842,30178,31852,32633,32696,33673,35023,35041,37324,37328,38626,39881,21533,28542,29136,29848,34298,36522,38563,40023,40607,26519,28107,29747,33256,38678,30764,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31435,31520,31890,25705,29802,30194,30908,30952,39340,39764,40635,23518,24149,28448,33180,33707,37000,19975,21325,23081,24018,24398,24930,25405,26217,26364,28415,28459,28771,30622,33836,34067,34875,36627,39237,39995,21788,25273,26411,27819,33545,35178,38778,20129,22916,24536,24537,26395,32178,32596,33426,33579,33725,36638,37017,22475,22969,23186,23504,26151,26522,26757,27599,29028,32629,36023,36067,36993,39749,33032,35978,38476,39488,40613,23391,27667,29467,30450,30431,33804,20906,35219,20813,20885,21193,26825,27796,30468,30496,32191,32236,38754,40629,28357,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,34065,20901,21517,21629,26126,26269,26919,28319,30399,30609,33559,33986,34719,37225,37528,40180,34946,20398,20882,21215,22982,24125,24917,25720,25721,26286,26576,27169,27597,27611,29279,29281,29761,30520,30683,32791,33468,33541,35584,35624,35980,26408,27792,29287,30446,30566,31302,40361,27519,27794,22818,26406,33945,21359,22675,22937,24287,25551,26164,26483,28218,29483,31447,33495,37672,21209,24043,25006,25035,25098,25287,25771,26080,26969,27494,27595,28961,29687,30045,32326,33310,33538,34154,35491,36031,38695,40289,22696,40664,20497,21006,21563,21839,25991,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,27766,32010,32011,32862,34442,38272,38639,21247,27797,29289,21619,23194,23614,23883,24396,24494,26410,26806,26979,28220,28228,30473,31859,32654,34183,35598,36855,38753,40692,23735,24758,24845,25003,25935,26107,26108,27665,27887,29599,29641,32225,38292,23494,34588,35600,21085,21338,25293,25615,25778,26420,27192,27850,29632,29854,31636,31893,32283,33162,33334,34180,36843,38649,39361,20276,21322,21453,21467,25292,25644,25856,26001,27075,27886,28504,29677,30036,30242,30436,30460,30928,30971,31020,32070,33324,34784,36820,38930,39151,21187,25300,25765,28196,28497,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30332,36299,37297,37474,39662,39747,20515,20621,22346,22952,23592,24135,24439,25151,25918,26041,26049,26121,26507,27036,28354,30917,32033,32938,33152,33323,33459,33953,34444,35370,35607,37030,38450,40848,20493,20467,63843,22521,24472,25308,25490,26479,28227,28953,30403,32972,32986,35060,35061,35097,36064,36649,37197,38506,20271,20336,24091,26575,26658,30333,30334,39748,24161,27146,29033,29140,30058,63844,32321,34115,34281,39132,20240,31567,32624,38309,20961,24070,26805,27710,27726,27867,29359,31684,33539,27861,29754,20731,21128,22721,25816,27287,29863,30294,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30887,34327,38370,38713,63845,21342,24321,35722,36776,36783,37002,21029,30629,40009,40712,19993,20482,20853,23643,24183,26142,26170,26564,26821,28851,29953,30149,31177,31453,36647,39200,39432,20445,22561,22577,23542,26222,27493,27921,28282,28541,29668,29995,33769,35036,35091,35676,36628,20239,20693,21264,21340,23443,24489,26381,31119,33145,33583,34068,35079,35206,36665,36667,39333,39954,26412,20086,20472,22857,23553,23791,23792,25447,26834,28925,29090,29739,32299,34028,34562,36898,37586,40179,19981,20184,20463,20613,21078,21103,21542,21648,22496,22827,23142,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,23386,23413,23500,24220,63846,25206,25975,26023,28014,28325,29238,31526,31807,32566,33104,33105,33178,33344,33433,33705,35331,36000,36070,36091,36212,36282,37096,37340,38428,38468,39385,40167,21271,20998,21545,22132,22707,22868,22894,24575,24996,25198,26128,27774,28954,30406,31881,31966,32027,33452,36033,38640,63847,20315,24343,24447,25282,23849,26379,26842,30844,32323,40300,19989,20633,21269,21290,21329,22915,23138,24199,24754,24970,25161,25209,26000,26503,27047,27604,27606,27607,27608,27832,63848,29749,30202,30738,30865,31189,31192,31875,32203,32737,32933,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,33086,33218,33778,34586,35048,35513,35692,36027,37145,38750,39131,40763,22188,23338,24428,25996,27315,27567,27996,28657,28693,29277,29613,36007,36051,38971,24977,27703,32856,39425,20045,20107,20123,20181,20282,20284,20351,20447,20735,21490,21496,21766,21987,22235,22763,22882,23057,23531,23546,23556,24051,24107,24473,24605,25448,26012,26031,26614,26619,26797,27515,27801,27863,28195,28681,29509,30722,31038,31040,31072,31169,31721,32023,32114,32902,33293,33678,34001,34503,35039,35408,35422,35613,36060,36198,36781,37034,39164,39391,40605,21066,63849,26388,63850,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20632,21034,23665,25955,27733,29642,29987,30109,31639,33948,37240,38704,20087,25746,27578,29022,34217,19977,63851,26441,26862,28183,33439,34072,34923,25591,28545,37394,39087,19978,20663,20687,20767,21830,21930,22039,23360,23577,23776,24120,24202,24224,24258,24819,26705,27233,28248,29245,29248,29376,30456,31077,31665,32724,35059,35316,35443,35937,36062,38684,22622,29885,36093,21959,63852,31329,32034,33394,29298,29983,29989,63853,31513,22661,22779,23996,24207,24246,24464,24661,25234,25471,25933,26257,26329,26360,26646,26866,29312,29790,31598,32110,32214,32626,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32997,33298,34223,35199,35475,36893,37604,40653,40736,22805,22893,24109,24796,26132,26227,26512,27728,28101,28511,30707,30889,33990,37323,37675,20185,20682,20808,21892,23307,23459,25159,25982,26059,28210,29053,29697,29764,29831,29887,30316,31146,32218,32341,32680,33146,33203,33337,34330,34796,35445,36323,36984,37521,37925,39245,39854,21352,23633,26964,27844,27945,28203,33292,34203,35131,35373,35498,38634,40807,21089,26297,27570,32406,34814,36109,38275,38493,25885,28041,29166,63854,22478,22995,23468,24615,24826,25104,26143,26207,29481,29689,30427,30465,31596,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32854,32882,33125,35488,37266,19990,21218,27506,27927,31237,31545,32048,63855,36016,21484,22063,22609,23477,23567,23569,24034,25152,25475,25620,26157,26803,27836,28040,28335,28703,28836,29138,29990,30095,30094,30233,31505,31712,31787,32032,32057,34092,34157,34311,35380,36877,36961,37045,37559,38902,39479,20439,23660,26463,28049,31903,32396,35606,36118,36895,23403,24061,25613,33984,36956,39137,29575,23435,24730,26494,28126,35359,35494,36865,38924,21047,63856,28753,30862,37782,34928,37335,20462,21463,22013,22234,22402,22781,23234,23432,23723,23744,24101,24833,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,25101,25163,25480,25628,25910,25976,27193,27530,27700,27929,28465,29159,29417,29560,29703,29874,30246,30561,31168,31319,31466,31929,32143,32172,32353,32670,33065,33585,33936,34010,34282,34966,35504,35728,36664,36930,36995,37228,37526,37561,38539,38567,38568,38614,38656,38920,39318,39635,39706,21460,22654,22809,23408,23487,28113,28506,29087,29729,29881,32901,33789,24033,24455,24490,24642,26092,26642,26991,27219,27529,27957,28147,29667,30462,30636,31565,32020,33059,33308,33600,34036,34147,35426,35524,37255,37662,38918,39348,25100,34899,36848,37477,23815,23847,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,23913,29791,33181,34664,28629,25342,32722,35126,35186,19998,20056,20711,21213,21319,25215,26119,32361,34821,38494,20365,21273,22070,22987,23204,23608,23630,23629,24066,24337,24643,26045,26159,26178,26558,26612,29468,30690,31034,32709,33940,33997,35222,35430,35433,35553,35925,35962,22516,23508,24335,24687,25325,26893,27542,28252,29060,31698,34645,35672,36606,39135,39166,20280,20353,20449,21627,23072,23480,24892,26032,26216,29180,30003,31070,32051,33102,33251,33688,34218,34254,34563,35338,36523,36763,63857,36805,22833,23460,23526,24713,23529,23563,24515,27777,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63858,28145,28683,29978,33455,35574,20160,21313,63859,38617,27663,20126,20420,20818,21854,23077,23784,25105,29273,33469,33706,34558,34905,35357,38463,38597,39187,40201,40285,22538,23731,23997,24132,24801,24853,25569,27138,28197,37122,37716,38990,39952,40823,23433,23736,25353,26191,26696,30524,38593,38797,38996,39839,26017,35585,36555,38332,21813,23721,24022,24245,26263,30284,33780,38343,22739,25276,29390,40232,20208,22830,24591,26171,27523,31207,40230,21395,21696,22467,23830,24859,26326,28079,30861,33406,38552,38724,21380,25212,25494,28082,32266,33099,38989,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,27387,32588,40367,40474,20063,20539,20918,22812,24825,25590,26928,29242,32822,63860,37326,24369,63861,63862,32004,33509,33903,33979,34277,36493,63863,20335,63864,63865,22756,23363,24665,25562,25880,25965,26264,63866,26954,27171,27915,28673,29036,30162,30221,31155,31344,63867,32650,63868,35140,63869,35731,37312,38525,63870,39178,22276,24481,26044,28417,30208,31142,35486,39341,39770,40812,20740,25014,25233,27277,33222,20547,22576,24422,28937,35328,35578,23420,34326,20474,20796,22196,22852,25513,28153,23978,26989,20870,20104,20313,63871,63872,63873,22914,63874,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63875,27487,27741,63876,29877,30998,63877,33287,33349,33593,36671,36701,63878,39192,63879,63880,63881,20134,63882,22495,24441,26131,63883,63884,30123,32377,35695,63885,36870,39515,22181,22567,23032,23071,23476,63886,24310,63887,63888,25424,25403,63889,26941,27783,27839,28046,28051,28149,28436,63890,28895,28982,29017,63891,29123,29141,63892,30799,30831,63893,31605,32227,63894,32303,63895,34893,36575,63896,63897,63898,37467,63899,40182,63900,63901,63902,24709,28037,63903,29105,63904,63905,38321,21421,63906,63907,63908,26579,63909,28814,28976,29744,33398,33490,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63910,38331,39653,40573,26308,63911,29121,33865,63912,63913,22603,63914,63915,23992,24433,63916,26144,26254,27001,27054,27704,27891,28214,28481,28634,28699,28719,29008,29151,29552,63917,29787,63918,29908,30408,31310,32403,63919,63920,33521,35424,36814,63921,37704,63922,38681,63923,63924,20034,20522,63925,21000,21473,26355,27757,28618,29450,30591,31330,33454,34269,34306,63926,35028,35427,35709,35947,63927,37555,63928,38675,38928,20116,20237,20425,20658,21320,21566,21555,21978,22626,22714,22887,23067,23524,24735,63929,25034,25942,26111,26212,26791,27738,28595,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,28879,29100,29522,31613,34568,35492,39986,40711,23627,27779,29508,29577,37434,28331,29797,30239,31337,32277,34314,20800,22725,25793,29934,29973,30320,32705,37013,38605,39252,28198,29926,31401,31402,33253,34521,34680,35355,23113,23436,23451,26785,26880,28003,29609,29715,29740,30871,32233,32747,33048,33109,33694,35916,38446,38929,26352,24448,26106,26505,27754,29579,20525,23043,27498,30702,22806,23916,24013,29477,30031,63930,63931,20709,20985,22575,22829,22934,23002,23525,63932,63933,23970,25303,25622,25747,25854,63934,26332,63935,27208,63936,29183,29796,63937,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31368,31407,32327,32350,32768,33136,63938,34799,35201,35616,36953,63939,36992,39250,24958,27442,28020,32287,35109,36785,20433,20653,20887,21191,22471,22665,23481,24248,24898,27029,28044,28263,28342,29076,29794,29992,29996,32883,33592,33993,36362,37780,37854,63940,20110,20305,20598,20778,21448,21451,21491,23431,23507,23588,24858,24962,26100,29275,29591,29760,30402,31056,31121,31161,32006,32701,33419,34261,34398,36802,36935,37109,37354,38533,38632,38633,21206,24423,26093,26161,26671,29020,31286,37057,38922,20113,63941,27218,27550,28560,29065,32792,33464,34131,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36939,38549,38642,38907,34074,39729,20112,29066,38596,20803,21407,21729,22291,22290,22435,23195,23236,23491,24616,24895,25588,27781,27961,28274,28304,29232,29503,29783,33489,34945,36677,36960,63942,38498,39000,40219,26376,36234,37470,20301,20553,20702,21361,22285,22996,23041,23561,24944,26256,28205,29234,29771,32239,32963,33806,33894,34111,34655,34907,35096,35586,36949,38859,39759,20083,20369,20754,20842,63943,21807,21929,23418,23461,24188,24189,24254,24736,24799,24840,24841,25540,25912,26377,63944,26580,26586,63945,26977,26978,27833,27943,63946,28216,63947,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,28641,29494,29495,63948,29788,30001,63949,30290,63950,63951,32173,33278,33848,35029,35480,35547,35565,36400,36418,36938,36926,36986,37193,37321,37742,63952,63953,22537,63954,27603,32905,32946,63955,63956,20801,22891,23609,63957,63958,28516,29607,32996,36103,63959,37399,38287,63960,63961,63962,63963,32895,25102,28700,32104,34701,63964,22432,24681,24903,27575,35518,37504,38577,20057,21535,28139,34093,38512,38899,39150,25558,27875,37009,20957,25033,33210,40441,20381,20506,20736,23452,24847,25087,25836,26885,27589,30097,30691,32681,33380,34191,34811,34915,35516,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,35696,37291,20108,20197,20234,63965,63966,22839,23016,63967,24050,24347,24411,24609,63968,63969,63970,63971,29246,29669,63972,30064,30157,63973,31227,63974,32780,32819,32900,33505,33617,63975,63976,36029,36019,36999,63977,63978,39156,39180,63979,63980,28727,30410,32714,32716,32764,35610,20154,20161,20995,21360,63981,21693,22240,23035,23493,24341,24525,28270,63982,63983,32106,33589,63984,34451,35469,63985,38765,38775,63986,63987,19968,20314,20350,22777,26085,28322,36920,37808,39353,20219,22764,22922,23001,24641,63988,63989,31252,63990,33615,36035,20837,21316,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63991,63992,63993,20173,21097,23381,33471,20180,21050,21672,22985,23039,23376,23383,23388,24675,24904,28363,28825,29038,29574,29943,30133,30913,32043,32773,33258,33576,34071,34249,35566,36039,38604,20316,21242,22204,26027,26152,28796,28856,29237,32189,33421,37196,38592,40306,23409,26855,27544,28538,30430,23697,26283,28507,31668,31786,34870,38620,19976,20183,21280,22580,22715,22767,22892,23559,24115,24196,24373,25484,26290,26454,27167,27299,27404,28479,29254,63994,29520,29835,31456,31911,33144,33247,33255,33674,33900,34083,34196,34255,35037,36115,37292,38263,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38556,20877,21705,22312,23472,25165,26448,26685,26771,28221,28371,28797,32289,35009,36001,36617,40779,40782,29229,31631,35533,37658,20295,20302,20786,21632,22992,24213,25269,26485,26990,27159,27822,28186,29401,29482,30141,31672,32053,33511,33785,33879,34295,35419,36015,36487,36889,37048,38606,40799,21219,21514,23265,23490,25688,25973,28404,29380,63995,30340,31309,31515,31821,32318,32735,33659,35627,36042,36196,36321,36447,36842,36857,36969,37841,20291,20346,20659,20840,20856,21069,21098,22625,22652,22880,23560,23637,24283,24731,25136,26643,27583,27656,28593,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29006,29728,30000,30008,30033,30322,31564,31627,31661,31686,32399,35438,36670,36681,37439,37523,37666,37931,38651,39002,39019,39198,20999,25130,25240,27993,30308,31434,31680,32118,21344,23742,24215,28472,28857,31896,38673,39822,40670,25509,25722,34678,19969,20117,20141,20572,20597,21576,22979,23450,24128,24237,24311,24449,24773,25402,25919,25972,26060,26230,26232,26622,26984,27273,27491,27712,28096,28136,28191,28254,28702,28833,29582,29693,30010,30555,30855,31118,31243,31357,31934,32142,33351,35330,35562,35998,37165,37194,37336,37478,37580,37664,38662,38742,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38748,38914,40718,21046,21137,21884,22564,24093,24351,24716,25552,26799,28639,31085,31532,33229,34234,35069,35576,36420,37261,38500,38555,38717,38988,40778,20430,20806,20939,21161,22066,24340,24427,25514,25805,26089,26177,26362,26361,26397,26781,26839,27133,28437,28526,29031,29157,29226,29866,30522,31062,31066,31199,31264,31381,31895,31967,32068,32368,32903,34299,34468,35412,35519,36249,36481,36896,36973,37347,38459,38613,40165,26063,31751,36275,37827,23384,23562,21330,25305,29469,20519,23447,24478,24752,24939,26837,28121,29742,31278,32066,32156,32305,33131,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36394,36405,37758,37912,20304,22352,24038,24231,25387,32618,20027,20303,20367,20570,23005,32964,21610,21608,22014,22863,23449,24030,24282,26205,26417,26609,26666,27880,27954,28234,28557,28855,29664,30087,31820,32002,32044,32162,33311,34523,35387,35461,36208,36490,36659,36913,37198,37202,37956,39376,31481,31909,20426,20737,20934,22472,23535,23803,26201,27197,27994,28310,28652,28940,30063,31459,34850,36897,36981,38603,39423,33537,20013,20210,34886,37325,21373,27355,26987,27713,33914,22686,24974,26366,25327,28893,29969,30151,32338,33976,35657,36104,20043,21482,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21675,22320,22336,24535,25345,25351,25711,25903,26088,26234,26525,26547,27490,27744,27802,28460,30693,30757,31049,31063,32025,32930,33026,33267,33437,33463,34584,35468,63996,36100,36286,36978,30452,31257,31287,32340,32887,21767,21972,22645,25391,25634,26185,26187,26733,27035,27524,27941,28337,29645,29800,29857,30043,30137,30433,30494,30603,31206,32265,32285,33275,34095,34967,35386,36049,36587,36784,36914,37805,38499,38515,38663,20356,21489,23018,23241,24089,26702,29894,30142,31209,31378,33187,34541,36074,36300,36845,26015,26389,63997,22519,28503,32221,36655,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,37878,38598,24501,25074,28548,19988,20376,20511,21449,21983,23919,24046,27425,27492,30923,31642,63998,36425,36554,36974,25417,25662,30528,31364,37679,38015,40810,25776,28591,29158,29864,29914,31428,31762,32386,31922,32408,35738,36106,38013,39184,39244,21049,23519,25830,26413,32046,20717,21443,22649,24920,24921,25082,26028,31449,35730,35734,20489,20513,21109,21809,23100,24288,24432,24884,25950,26124,26166,26274,27085,28356,28466,29462,30241,31379,33081,33369,33750,33980,20661,22512,23488,23528,24425,25505,30758,32181,33756,34081,37319,37365,20874,26613,31574,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36012,20932,22971,24765,34389,20508,63999,21076,23610,24957,25114,25299,25842,26021,28364,30240,33034,36448,38495,38587,20191,21315,21912,22825,24029,25797,27849,28154,29588,31359,33307,34214,36068,36368,36983,37351,38369,38433,38854,20984,21746,21894,24505,25764,28552,32180,36639,36685,37941,20681,23574,27838,28155,29979,30651,31805,31844,35449,35522,22558,22974,24086,25463,29266,30090,30571,35548,36028,36626,24307,26228,28152,32893,33729,35531,38737,39894,64000,21059,26367,28053,28399,32224,35558,36910,36958,39636,21021,21119,21736,24980,25220,25307,26786,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26898,26970,27189,28818,28966,30813,30977,30990,31186,31245,32918,33400,33493,33609,34121,35970,36229,37218,37259,37294,20419,22225,29165,30679,34560,35320,23544,24534,26449,37032,21474,22618,23541,24740,24961,25696,32317,32880,34085,37507,25774,20652,23828,26368,22684,25277,25512,26894,27000,27166,28267,30394,31179,33467,33833,35535,36264,36861,37138,37195,37276,37648,37656,37786,38619,39478,39949,19985,30044,31069,31482,31569,31689,32302,33988,36441,36468,36600,36880,26149,26943,29763,20986,26414,40668,20805,24544,27798,34802,34909,34935,24756,33205,33795,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36101,21462,21561,22068,23094,23601,28810,32736,32858,33030,33261,36259,37257,39519,40434,20596,20164,21408,24827,28204,23652,20360,20516,21988,23769,24159,24677,26772,27835,28100,29118,30164,30196,30305,31258,31305,32199,32251,32622,33268,34473,36636,38601,39347,40786,21063,21189,39149,35242,19971,26578,28422,20405,23522,26517,27784,28024,29723,30759,37341,37756,34756,31204,31281,24555,20182,21668,21822,22702,22949,24816,25171,25302,26422,26965,33333,38464,39345,39389,20524,21331,21828,22396,64001,25176,64002,25826,26219,26589,28609,28655,29730,29752,35351,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,37944,21585,22022,22374,24392,24986,27470,28760,28845,32187,35477,22890,33067,25506,30472,32829,36010,22612,25645,27067,23445,24081,28271,64003,34153,20812,21488,22826,24608,24907,27526,27760,27888,31518,32974,33492,36294,37040,39089,64004,25799,28580,25745,25860,20814,21520,22303,35342,24927,26742,64005,30171,31570,32113,36890,22534,27084,33151,35114,36864,38969,20600,22871,22956,25237,36879,39722,24925,29305,38358,22369,23110,24052,25226,25773,25850,26487,27874,27966,29228,29750,30772,32631,33453,36315,38935,21028,22338,26495,29256,29923,36009,36774,37393,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38442,20843,21485,25420,20329,21764,24726,25943,27803,28031,29260,29437,31255,35207,35997,24429,28558,28921,33192,24846,20415,20559,25153,29255,31687,32232,32745,36941,38829,39449,36022,22378,24179,26544,33805,35413,21536,23318,24163,24290,24330,25987,32954,34109,38281,38491,20296,21253,21261,21263,21638,21754,22275,24067,24598,25243,25265,25429,64006,27873,28006,30129,30770,32990,33071,33502,33889,33970,34957,35090,36875,37610,39165,39825,24133,26292,26333,28689,29190,64007,20469,21117,24426,24915,26451,27161,28418,29922,31080,34920,35961,39111,39108,39491,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21697,31263,26963,35575,35914,39080,39342,24444,25259,30130,30382,34987,36991,38466,21305,24380,24517,27852,29644,30050,30091,31558,33534,39325,20047,36924,19979,20309,21414,22799,24264,26160,27827,29781,33655,34662,36032,36944,38686,39957,22737,23416,34384,35604,40372,23506,24680,24717,26097,27735,28450,28579,28698,32597,32752,38289,38290,38480,38867,21106,36676,20989,21547,21688,21859,21898,27323,28085,32216,33382,37532,38519,40569,21512,21704,30418,34532,38308,38356,38492,20130,20233,23022,23270,24055,24658,25239,26477,26689,27782,28207,32568,32923,33322,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,64008,64009,38917,20133,20565,21683,22419,22874,23401,23475,25032,26999,28023,28707,34809,35299,35442,35559,36994,39405,39608,21182,26680,20502,24184,26447,33607,34892,20139,21521,22190,29670,37141,38911,39177,39255,39321,22099,22687,34395,35377,25010,27382,29563,36562,27463,38570,39511,22869,29184,36203,38761,20436,23796,24358,25080,26203,27883,28843,29572,29625,29694,30505,30541,32067,32098,32291,33335,34898,64010,36066,37449,39023,23377,31348,34880,38913,23244,20448,21332,22846,23805,25406,28025,29433,33029,33031,33698,37583,38960,20136,20804,21009,22411,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,24418,27842,28366,28677,28752,28847,29074,29673,29801,33610,34722,34913,36872,37026,37795,39336,20846,24407,24800,24935,26291,34137,36426,37295,38795,20046,20114,21628,22741,22778,22909,23733,24359,25142,25160,26122,26215,27627,28009,28111,28246,28408,28564,28640,28649,28765,29392,29733,29786,29920,30355,31068,31946,32286,32993,33446,33899,33983,34382,34399,34676,35703,35946,37804,38912,39013,24785,25110,37239,23130,26127,28151,28222,29759,39746,24573,24794,31503,21700,24344,27742,27859,27946,28888,32005,34425,35340,40251,21270,21644,23301,27194,28779,30069,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31117,31166,33457,33775,35441,35649,36008,38772,64011,25844,25899,30906,30907,31339,20024,21914,22864,23462,24187,24739,25563,27489,26213,26707,28185,29029,29872,32008,36996,39529,39973,27963,28369,29502,35905,38346,20976,24140,24488,24653,24822,24880,24908,26179,26180,27045,27841,28255,28361,28514,29004,29852,30343,31681,31783,33618,34647,36945,38541,40643,21295,22238,24315,24458,24674,24724,25079,26214,26371,27292,28142,28590,28784,29546,32362,33214,33588,34516,35496,36036,21123,29554,23446,27243,37892,21742,22150,23389,25928,25989,26313,26783,28045,28102,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29243,32948,37237,39501,20399,20505,21402,21518,21564,21897,21957,24127,24460,26429,29030,29661,36869,21211,21235,22628,22734,28932,29071,29179,34224,35347,26248,34216,21927,26244,29002,33841,21321,21913,27585,24409,24509,25582,26249,28999,35569,36637,40638,20241,25658,28875,30054,34407,24676,35662,40440,20807,20982,21256,27958,33016,40657,26133,27427,28824,30165,21507,23673,32007,35350,27424,27453,27462,21560,24688,27965,32725,33288,20694,20958,21916,22123,22221,23020,23305,24076,24985,24984,25137,26206,26342,29081,29113,29114,29351,31143,31232,32690,35440,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],gb18030:[19970,19972,19973,19974,19983,19986,19991,19999,20000,20001,20003,20006,20009,20014,20015,20017,20019,20021,20023,20028,20032,20033,20034,20036,20038,20042,20049,20053,20055,20058,20059,20066,20067,20068,20069,20071,20072,20074,20075,20076,20077,20078,20079,20082,20084,20085,20086,20087,20088,20089,20090,20091,20092,20093,20095,20096,20097,20098,20099,20100,20101,20103,20106,20112,20118,20119,20121,20124,20125,20126,20131,20138,20143,20144,20145,20148,20150,20151,20152,20153,20156,20157,20158,20168,20172,20175,20176,20178,20186,20187,20188,20192,20194,20198,20199,20201,20205,20206,20207,20209,20212,20216,20217,20218,20220,20222,20224,20226,20227,20228,20229,20230,20231,20232,20235,20236,20242,20243,20244,20245,20246,20252,20253,20257,20259,20264,20265,20268,20269,20270,20273,20275,20277,20279,20281,20283,20286,20287,20288,20289,20290,20292,20293,20295,20296,20297,20298,20299,20300,20306,20308,20310,20321,20322,20326,20328,20330,20331,20333,20334,20337,20338,20341,20343,20344,20345,20346,20349,20352,20353,20354,20357,20358,20359,20362,20364,20366,20368,20370,20371,20373,20374,20376,20377,20378,20380,20382,20383,20385,20386,20388,20395,20397,20400,20401,20402,20403,20404,20406,20407,20408,20409,20410,20411,20412,20413,20414,20416,20417,20418,20422,20423,20424,20425,20427,20428,20429,20434,20435,20436,20437,20438,20441,20443,20448,20450,20452,20453,20455,20459,20460,20464,20466,20468,20469,20470,20471,20473,20475,20476,20477,20479,20480,20481,20482,20483,20484,20485,20486,20487,20488,20489,20490,20491,20494,20496,20497,20499,20501,20502,20503,20507,20509,20510,20512,20514,20515,20516,20519,20523,20527,20528,20529,20530,20531,20532,20533,20534,20535,20536,20537,20539,20541,20543,20544,20545,20546,20548,20549,20550,20553,20554,20555,20557,20560,20561,20562,20563,20564,20566,20567,20568,20569,20571,20573,20574,20575,20576,20577,20578,20579,20580,20582,20583,20584,20585,20586,20587,20589,20590,20591,20592,20593,20594,20595,20596,20597,20600,20601,20602,20604,20605,20609,20610,20611,20612,20614,20615,20617,20618,20619,20620,20622,20623,20624,20625,20626,20627,20628,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641,20642,20644,20646,20650,20651,20653,20654,20655,20656,20657,20659,20660,20661,20662,20663,20664,20665,20668,20669,20670,20671,20672,20673,20674,20675,20676,20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,20688,20689,20690,20691,20692,20693,20695,20696,20697,20699,20700,20701,20702,20703,20704,20705,20706,20707,20708,20709,20712,20713,20714,20715,20719,20720,20721,20722,20724,20726,20727,20728,20729,20730,20732,20733,20734,20735,20736,20737,20738,20739,20740,20741,20744,20745,20746,20748,20749,20750,20751,20752,20753,20755,20756,20757,20758,20759,20760,20761,20762,20763,20764,20765,20766,20767,20768,20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,20795,20796,20797,20798,20802,20807,20810,20812,20814,20815,20816,20818,20819,20823,20824,20825,20827,20829,20830,20831,20832,20833,20835,20836,20838,20839,20841,20842,20847,20850,20858,20862,20863,20867,20868,20870,20871,20874,20875,20878,20879,20880,20881,20883,20884,20888,20890,20893,20894,20895,20897,20899,20902,20903,20904,20905,20906,20909,20910,20916,20920,20921,20922,20926,20927,20929,20930,20931,20933,20936,20938,20941,20942,20944,20946,20947,20948,20949,20950,20951,20952,20953,20954,20956,20958,20959,20962,20963,20965,20966,20967,20968,20969,20970,20972,20974,20977,20978,20980,20983,20990,20996,20997,21001,21003,21004,21007,21008,21011,21012,21013,21020,21022,21023,21025,21026,21027,21029,21030,21031,21034,21036,21039,21041,21042,21044,21045,21052,21054,21060,21061,21062,21063,21064,21065,21067,21070,21071,21074,21075,21077,21079,21080,21081,21082,21083,21085,21087,21088,21090,21091,21092,21094,21096,21099,21100,21101,21102,21104,21105,21107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21118,21120,21123,21124,21125,21126,21127,21129,21130,21131,21132,21133,21134,21135,21137,21138,21140,21141,21142,21143,21144,21145,21146,21148,21156,21157,21158,21159,21166,21167,21168,21172,21173,21174,21175,21176,21177,21178,21179,21180,21181,21184,21185,21186,21188,21189,21190,21192,21194,21196,21197,21198,21199,21201,21203,21204,21205,21207,21209,21210,21211,21212,21213,21214,21216,21217,21218,21219,21221,21222,21223,21224,21225,21226,21227,21228,21229,21230,21231,21233,21234,21235,21236,21237,21238,21239,21240,21243,21244,21245,21249,21250,21251,21252,21255,21257,21258,21259,21260,21262,21265,21266,21267,21268,21272,21275,21276,21278,21279,21282,21284,21285,21287,21288,21289,21291,21292,21293,21295,21296,21297,21298,21299,21300,21301,21302,21303,21304,21308,21309,21312,21314,21316,21318,21323,21324,21325,21328,21332,21336,21337,21339,21341,21349,21352,21354,21356,21357,21362,21366,21369,21371,21372,21373,21374,21376,21377,21379,21383,21384,21386,21390,21391,21392,21393,21394,21395,21396,21398,21399,21401,21403,21404,21406,21408,21409,21412,21415,21418,21419,21420,21421,21423,21424,21425,21426,21427,21428,21429,21431,21432,21433,21434,21436,21437,21438,21440,21443,21444,21445,21446,21447,21454,21455,21456,21458,21459,21461,21466,21468,21469,21470,21473,21474,21479,21492,21498,21502,21503,21504,21506,21509,21511,21515,21524,21528,21529,21530,21532,21538,21540,21541,21546,21552,21555,21558,21559,21562,21565,21567,21569,21570,21572,21573,21575,21577,21580,21581,21582,21583,21585,21594,21597,21598,21599,21600,21601,21603,21605,21607,21609,21610,21611,21612,21613,21614,21615,21616,21620,21625,21626,21630,21631,21633,21635,21637,21639,21640,21641,21642,21645,21649,21651,21655,21656,21660,21662,21663,21664,21665,21666,21669,21678,21680,21682,21685,21686,21687,21689,21690,21692,21694,21699,21701,21706,21707,21718,21720,21723,21728,21729,21730,21731,21732,21739,21740,21743,21744,21745,21748,21749,21750,21751,21752,21753,21755,21758,21760,21762,21763,21764,21765,21768,21770,21771,21772,21773,21774,21778,21779,21781,21782,21783,21784,21785,21786,21788,21789,21790,21791,21793,21797,21798,21800,21801,21803,21805,21810,21812,21813,21814,21816,21817,21818,21819,21821,21824,21826,21829,21831,21832,21835,21836,21837,21838,21839,21841,21842,21843,21844,21847,21848,21849,21850,21851,21853,21854,21855,21856,21858,21859,21864,21865,21867,21871,21872,21873,21874,21875,21876,21881,21882,21885,21887,21893,21894,21900,21901,21902,21904,21906,21907,21909,21910,21911,21914,21915,21918,21920,21921,21922,21923,21924,21925,21926,21928,21929,21930,21931,21932,21933,21934,21935,21936,21938,21940,21942,21944,21946,21948,21951,21952,21953,21954,21955,21958,21959,21960,21962,21963,21966,21967,21968,21973,21975,21976,21977,21978,21979,21982,21984,21986,21991,21993,21997,21998,22000,22001,22004,22006,22008,22009,22010,22011,22012,22015,22018,22019,22020,22021,22022,22023,22026,22027,22029,22032,22033,22034,22035,22036,22037,22038,22039,22041,22042,22044,22045,22048,22049,22050,22053,22054,22056,22057,22058,22059,22062,22063,22064,22067,22069,22071,22072,22074,22076,22077,22078,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22095,22096,22097,22098,22099,22101,22102,22106,22107,22109,22110,22111,22112,22113,22115,22117,22118,22119,22125,22126,22127,22128,22130,22131,22132,22133,22135,22136,22137,22138,22141,22142,22143,22144,22145,22146,22147,22148,22151,22152,22153,22154,22155,22156,22157,22160,22161,22162,22164,22165,22166,22167,22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,22178,22180,22181,22182,22183,22184,22185,22186,22187,22188,22189,22190,22192,22193,22194,22195,22196,22197,22198,22200,22201,22202,22203,22205,22206,22207,22208,22209,22210,22211,22212,22213,22214,22215,22216,22217,22219,22220,22221,22222,22223,22224,22225,22226,22227,22229,22230,22232,22233,22236,22243,22245,22246,22247,22248,22249,22250,22252,22254,22255,22258,22259,22262,22263,22264,22267,22268,22272,22273,22274,22277,22279,22283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,22298,22299,22301,22302,22304,22305,22306,22308,22309,22310,22311,22315,22321,22322,22324,22325,22326,22327,22328,22332,22333,22335,22337,22339,22340,22341,22342,22344,22345,22347,22354,22355,22356,22357,22358,22360,22361,22370,22371,22373,22375,22380,22382,22384,22385,22386,22388,22389,22392,22393,22394,22397,22398,22399,22400,22401,22407,22408,22409,22410,22413,22414,22415,22416,22417,22420,22421,22422,22423,22424,22425,22426,22428,22429,22430,22431,22437,22440,22442,22444,22447,22448,22449,22451,22453,22454,22455,22457,22458,22459,22460,22461,22462,22463,22464,22465,22468,22469,22470,22471,22472,22473,22474,22476,22477,22480,22481,22483,22486,22487,22491,22492,22494,22497,22498,22499,22501,22502,22503,22504,22505,22506,22507,22508,22510,22512,22513,22514,22515,22517,22518,22519,22523,22524,22526,22527,22529,22531,22532,22533,22536,22537,22538,22540,22542,22543,22544,22546,22547,22548,22550,22551,22552,22554,22555,22556,22557,22559,22562,22563,22565,22566,22567,22568,22569,22571,22572,22573,22574,22575,22577,22578,22579,22580,22582,22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,22595,22597,22598,22599,22600,22601,22602,22603,22606,22607,22608,22610,22611,22613,22614,22615,22617,22618,22619,22620,22621,22623,22624,22625,22626,22627,22628,22630,22631,22632,22633,22634,22637,22638,22639,22640,22641,22642,22643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22655,22658,22660,22662,22663,22664,22666,22667,22668,22669,22670,22671,22672,22673,22676,22677,22678,22679,22680,22683,22684,22685,22688,22689,22690,22691,22692,22693,22694,22695,22698,22699,22700,22701,22702,22703,22704,22705,22706,22707,22708,22709,22710,22711,22712,22713,22714,22715,22717,22718,22719,22720,22722,22723,22724,22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22738,22739,22740,22742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753,22754,22755,22757,22758,22759,22760,22761,22762,22765,22767,22769,22770,22772,22773,22775,22776,22778,22779,22780,22781,22782,22783,22784,22785,22787,22789,22790,22792,22793,22794,22795,22796,22798,22800,22801,22802,22803,22807,22808,22811,22813,22814,22816,22817,22818,22819,22822,22824,22828,22832,22834,22835,22837,22838,22843,22845,22846,22847,22848,22851,22853,22854,22858,22860,22861,22864,22866,22867,22873,22875,22876,22877,22878,22879,22881,22883,22884,22886,22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,22898,22901,22903,22906,22907,22908,22910,22911,22912,22917,22921,22923,22924,22926,22927,22928,22929,22932,22933,22936,22938,22939,22940,22941,22943,22944,22945,22946,22950,22951,22956,22957,22960,22961,22963,22964,22965,22966,22967,22968,22970,22972,22973,22975,22976,22977,22978,22979,22980,22981,22983,22984,22985,22988,22989,22990,22991,22997,22998,23001,23003,23006,23007,23008,23009,23010,23012,23014,23015,23017,23018,23019,23021,23022,23023,23024,23025,23026,23027,23028,23029,23030,23031,23032,23034,23036,23037,23038,23040,23042,23050,23051,23053,23054,23055,23056,23058,23060,23061,23062,23063,23065,23066,23067,23069,23070,23073,23074,23076,23078,23079,23080,23082,23083,23084,23085,23086,23087,23088,23091,23093,23095,23096,23097,23098,23099,23101,23102,23103,23105,23106,23107,23108,23109,23111,23112,23115,23116,23117,23118,23119,23120,23121,23122,23123,23124,23126,23127,23128,23129,23131,23132,23133,23134,23135,23136,23137,23139,23140,23141,23142,23144,23145,23147,23148,23149,23150,23151,23152,23153,23154,23155,23160,23161,23163,23164,23165,23166,23168,23169,23170,23171,23172,23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,23187,23188,23189,23190,23191,23192,23193,23196,23197,23198,23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,23209,23211,23212,23213,23214,23215,23216,23217,23220,23222,23223,23225,23226,23227,23228,23229,23231,23232,23235,23236,23237,23238,23239,23240,23242,23243,23245,23246,23247,23248,23249,23251,23253,23255,23257,23258,23259,23261,23262,23263,23266,23268,23269,23271,23272,23274,23276,23277,23278,23279,23280,23282,23283,23284,23285,23286,23287,23288,23289,23290,23291,23292,23293,23294,23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,23306,23307,23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329,23330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,23342,23343,23344,23345,23347,23349,23350,23352,23353,23354,23355,23356,23357,23358,23359,23361,23362,23363,23364,23365,23366,23367,23368,23369,23370,23371,23372,23373,23374,23375,23378,23382,23390,23392,23393,23399,23400,23403,23405,23406,23407,23410,23412,23414,23415,23416,23417,23419,23420,23422,23423,23426,23430,23434,23437,23438,23440,23441,23442,23444,23446,23455,23463,23464,23465,23468,23469,23470,23471,23473,23474,23479,23482,23483,23484,23488,23489,23491,23496,23497,23498,23499,23501,23502,23503,23505,23508,23509,23510,23511,23512,23513,23514,23515,23516,23520,23522,23523,23526,23527,23529,23530,23531,23532,23533,23535,23537,23538,23539,23540,23541,23542,23543,23549,23550,23552,23554,23555,23557,23559,23560,23563,23564,23565,23566,23568,23570,23571,23575,23577,23579,23582,23583,23584,23585,23587,23590,23592,23593,23594,23595,23597,23598,23599,23600,23602,23603,23605,23606,23607,23619,23620,23622,23623,23628,23629,23634,23635,23636,23638,23639,23640,23642,23643,23644,23645,23647,23650,23652,23655,23656,23657,23658,23659,23660,23661,23664,23666,23667,23668,23669,23670,23671,23672,23675,23676,23677,23678,23680,23683,23684,23685,23686,23687,23689,23690,23691,23694,23695,23698,23699,23701,23709,23710,23711,23712,23713,23716,23717,23718,23719,23720,23722,23726,23727,23728,23730,23732,23734,23737,23738,23739,23740,23742,23744,23746,23747,23749,23750,23751,23752,23753,23754,23756,23757,23758,23759,23760,23761,23763,23764,23765,23766,23767,23768,23770,23771,23772,23773,23774,23775,23776,23778,23779,23783,23785,23787,23788,23790,23791,23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,23804,23805,23806,23807,23808,23809,23812,23813,23816,23817,23818,23819,23820,23821,23823,23824,23825,23826,23827,23829,23831,23832,23833,23834,23836,23837,23839,23840,23841,23842,23843,23845,23848,23850,23851,23852,23855,23856,23857,23858,23859,23861,23862,23863,23864,23865,23866,23867,23868,23871,23872,23873,23874,23875,23876,23877,23878,23880,23881,23885,23886,23887,23888,23889,23890,23891,23892,23893,23894,23895,23897,23898,23900,23902,23903,23904,23905,23906,23907,23908,23909,23910,23911,23912,23914,23917,23918,23920,23921,23922,23923,23925,23926,23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23939,23940,23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953,23954,23955,23956,23957,23958,23959,23960,23962,23963,23964,23966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,23978,23979,23980,23981,23982,23983,23984,23985,23986,23987,23988,23989,23990,23992,23993,23994,23995,23996,23997,23998,23999,24000,24001,24002,24003,24004,24006,24007,24008,24009,24010,24011,24012,24014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,24026,24028,24031,24032,24035,24036,24042,24044,24045,24048,24053,24054,24056,24057,24058,24059,24060,24063,24064,24068,24071,24073,24074,24075,24077,24078,24082,24083,24087,24094,24095,24096,24097,24098,24099,24100,24101,24104,24105,24106,24107,24108,24111,24112,24114,24115,24116,24117,24118,24121,24122,24126,24127,24128,24129,24131,24134,24135,24136,24137,24138,24139,24141,24142,24143,24144,24145,24146,24147,24150,24151,24152,24153,24154,24156,24157,24159,24160,24163,24164,24165,24166,24167,24168,24169,24170,24171,24172,24173,24174,24175,24176,24177,24181,24183,24185,24190,24193,24194,24195,24197,24200,24201,24204,24205,24206,24210,24216,24219,24221,24225,24226,24227,24228,24232,24233,24234,24235,24236,24238,24239,24240,24241,24242,24244,24250,24251,24252,24253,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24267,24268,24269,24270,24271,24272,24276,24277,24279,24280,24281,24282,24284,24285,24286,24287,24288,24289,24290,24291,24292,24293,24294,24295,24297,24299,24300,24301,24302,24303,24304,24305,24306,24307,24309,24312,24313,24315,24316,24317,24325,24326,24327,24329,24332,24333,24334,24336,24338,24340,24342,24345,24346,24348,24349,24350,24353,24354,24355,24356,24360,24363,24364,24366,24368,24370,24371,24372,24373,24374,24375,24376,24379,24381,24382,24383,24385,24386,24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,24398,24399,24401,24404,24409,24410,24411,24412,24414,24415,24416,24419,24421,24423,24424,24427,24430,24431,24434,24436,24437,24438,24440,24442,24445,24446,24447,24451,24454,24461,24462,24463,24465,24467,24468,24470,24474,24475,24477,24478,24479,24480,24482,24483,24484,24485,24486,24487,24489,24491,24492,24495,24496,24497,24498,24499,24500,24502,24504,24505,24506,24507,24510,24511,24512,24513,24514,24519,24520,24522,24523,24526,24531,24532,24533,24538,24539,24540,24542,24543,24546,24547,24549,24550,24552,24553,24556,24559,24560,24562,24563,24564,24566,24567,24569,24570,24572,24583,24584,24585,24587,24588,24592,24593,24595,24599,24600,24602,24606,24607,24610,24611,24612,24620,24621,24622,24624,24625,24626,24627,24628,24630,24631,24632,24633,24634,24637,24638,24640,24644,24645,24646,24647,24648,24649,24650,24652,24654,24655,24657,24659,24660,24662,24663,24664,24667,24668,24670,24671,24672,24673,24677,24678,24686,24689,24690,24692,24693,24695,24702,24704,24705,24706,24709,24710,24711,24712,24714,24715,24718,24719,24720,24721,24723,24725,24727,24728,24729,24732,24734,24737,24738,24740,24741,24743,24745,24746,24750,24752,24755,24757,24758,24759,24761,24762,24765,24766,24767,24768,24769,24770,24771,24772,24775,24776,24777,24780,24781,24782,24783,24784,24786,24787,24788,24790,24791,24793,24795,24798,24801,24802,24803,24804,24805,24810,24817,24818,24821,24823,24824,24827,24828,24829,24830,24831,24834,24835,24836,24837,24839,24842,24843,24844,24848,24849,24850,24851,24852,24854,24855,24856,24857,24859,24860,24861,24862,24865,24866,24869,24872,24873,24874,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,24887,24888,24889,24890,24891,24892,24893,24894,24896,24897,24898,24899,24900,24901,24902,24903,24905,24907,24909,24911,24912,24914,24915,24916,24918,24919,24920,24921,24922,24923,24924,24926,24927,24928,24929,24931,24932,24933,24934,24937,24938,24939,24940,24941,24942,24943,24945,24946,24947,24948,24950,24952,24953,24954,24955,24956,24957,24958,24959,24960,24961,24962,24963,24964,24965,24966,24967,24968,24969,24970,24972,24973,24975,24976,24977,24978,24979,24981,24982,24983,24984,24985,24986,24987,24988,24990,24991,24992,24993,24994,24995,24996,24997,24998,25002,25003,25005,25006,25007,25008,25009,25010,25011,25012,25013,25014,25016,25017,25018,25019,25020,25021,25023,25024,25025,25027,25028,25029,25030,25031,25033,25036,25037,25038,25039,25040,25043,25045,25046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,25058,25059,25060,25061,25063,25064,25065,25066,25067,25068,25069,25070,25071,25072,25073,25074,25075,25076,25078,25079,25080,25081,25082,25083,25084,25085,25086,25088,25089,25090,25091,25092,25093,25095,25097,25107,25108,25113,25116,25117,25118,25120,25123,25126,25127,25128,25129,25131,25133,25135,25136,25137,25138,25141,25142,25144,25145,25146,25147,25148,25154,25156,25157,25158,25162,25167,25168,25173,25174,25175,25177,25178,25180,25181,25182,25183,25184,25185,25186,25188,25189,25192,25201,25202,25204,25205,25207,25208,25210,25211,25213,25217,25218,25219,25221,25222,25223,25224,25227,25228,25229,25230,25231,25232,25236,25241,25244,25245,25246,25251,25254,25255,25257,25258,25261,25262,25263,25264,25266,25267,25268,25270,25271,25272,25274,25278,25280,25281,25283,25291,25295,25297,25301,25309,25310,25312,25313,25316,25322,25323,25328,25330,25333,25336,25337,25338,25339,25344,25347,25348,25349,25350,25354,25355,25356,25357,25359,25360,25362,25363,25364,25365,25367,25368,25369,25372,25382,25383,25385,25388,25389,25390,25392,25393,25395,25396,25397,25398,25399,25400,25403,25404,25406,25407,25408,25409,25412,25415,25416,25418,25425,25426,25427,25428,25430,25431,25432,25433,25434,25435,25436,25437,25440,25444,25445,25446,25448,25450,25451,25452,25455,25456,25458,25459,25460,25461,25464,25465,25468,25469,25470,25471,25473,25475,25476,25477,25478,25483,25485,25489,25491,25492,25493,25495,25497,25498,25499,25500,25501,25502,25503,25505,25508,25510,25515,25519,25521,25522,25525,25526,25529,25531,25533,25535,25536,25537,25538,25539,25541,25543,25544,25546,25547,25548,25553,25555,25556,25557,25559,25560,25561,25562,25563,25564,25565,25567,25570,25572,25573,25574,25575,25576,25579,25580,25582,25583,25584,25585,25587,25589,25591,25593,25594,25595,25596,25598,25603,25604,25606,25607,25608,25609,25610,25613,25614,25617,25618,25621,25622,25623,25624,25625,25626,25629,25631,25634,25635,25636,25637,25639,25640,25641,25643,25646,25647,25648,25649,25650,25651,25653,25654,25655,25656,25657,25659,25660,25662,25664,25666,25667,25673,25675,25676,25677,25678,25679,25680,25681,25683,25685,25686,25687,25689,25690,25691,25692,25693,25695,25696,25697,25698,25699,25700,25701,25702,25704,25706,25707,25708,25710,25711,25712,25713,25714,25715,25716,25717,25718,25719,25723,25724,25725,25726,25727,25728,25729,25731,25734,25736,25737,25738,25739,25740,25741,25742,25743,25744,25747,25748,25751,25752,25754,25755,25756,25757,25759,25760,25761,25762,25763,25765,25766,25767,25768,25770,25771,25775,25777,25778,25779,25780,25782,25785,25787,25789,25790,25791,25793,25795,25796,25798,25799,25800,25801,25802,25803,25804,25807,25809,25811,25812,25813,25814,25817,25818,25819,25820,25821,25823,25824,25825,25827,25829,25831,25832,25833,25834,25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846,25847,25848,25849,25850,25851,25852,25853,25854,25855,25857,25858,25859,25860,25861,25862,25863,25864,25866,25867,25868,25869,25870,25871,25872,25873,25875,25876,25877,25878,25879,25881,25882,25883,25884,25885,25886,25887,25888,25889,25890,25891,25892,25894,25895,25896,25897,25898,25900,25901,25904,25905,25906,25907,25911,25914,25916,25917,25920,25921,25922,25923,25924,25926,25927,25930,25931,25933,25934,25936,25938,25939,25940,25943,25944,25946,25948,25951,25952,25953,25956,25957,25959,25960,25961,25962,25965,25966,25967,25969,25971,25973,25974,25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,25986,25987,25988,25989,25990,25992,25993,25994,25997,25998,25999,26002,26004,26005,26006,26008,26010,26013,26014,26016,26018,26019,26022,26024,26026,26028,26030,26033,26034,26035,26036,26037,26038,26039,26040,26042,26043,26046,26047,26048,26050,26055,26056,26057,26058,26061,26064,26065,26067,26068,26069,26072,26073,26074,26075,26076,26077,26078,26079,26081,26083,26084,26090,26091,26098,26099,26100,26101,26104,26105,26107,26108,26109,26110,26111,26113,26116,26117,26119,26120,26121,26123,26125,26128,26129,26130,26134,26135,26136,26138,26139,26140,26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26162,26163,26167,26168,26169,26170,26171,26173,26175,26176,26178,26180,26181,26182,26183,26184,26185,26186,26189,26190,26192,26193,26200,26201,26203,26204,26205,26206,26208,26210,26211,26213,26215,26217,26218,26219,26220,26221,26225,26226,26227,26229,26232,26233,26235,26236,26237,26239,26240,26241,26243,26245,26246,26248,26249,26250,26251,26253,26254,26255,26256,26258,26259,26260,26261,26264,26265,26266,26267,26268,26270,26271,26272,26273,26274,26275,26276,26277,26278,26281,26282,26283,26284,26285,26287,26288,26289,26290,26291,26293,26294,26295,26296,26298,26299,26300,26301,26303,26304,26305,26306,26307,26308,26309,26310,26311,26312,26313,26314,26315,26316,26317,26318,26319,26320,26321,26322,26323,26324,26325,26326,26327,26328,26330,26334,26335,26336,26337,26338,26339,26340,26341,26343,26344,26346,26347,26348,26349,26350,26351,26353,26357,26358,26360,26362,26363,26365,26369,26370,26371,26372,26373,26374,26375,26380,26382,26383,26385,26386,26387,26390,26392,26393,26394,26396,26398,26400,26401,26402,26403,26404,26405,26407,26409,26414,26416,26418,26419,26422,26423,26424,26425,26427,26428,26430,26431,26433,26436,26437,26439,26442,26443,26445,26450,26452,26453,26455,26456,26457,26458,26459,26461,26466,26467,26468,26470,26471,26475,26476,26478,26481,26484,26486,26488,26489,26490,26491,26493,26496,26498,26499,26501,26502,26504,26506,26508,26509,26510,26511,26513,26514,26515,26516,26518,26521,26523,26527,26528,26529,26532,26534,26537,26540,26542,26545,26546,26548,26553,26554,26555,26556,26557,26558,26559,26560,26562,26565,26566,26567,26568,26569,26570,26571,26572,26573,26574,26581,26582,26583,26587,26591,26593,26595,26596,26598,26599,26600,26602,26603,26605,26606,26610,26613,26614,26615,26616,26617,26618,26619,26620,26622,26625,26626,26627,26628,26630,26637,26640,26642,26644,26645,26648,26649,26650,26651,26652,26654,26655,26656,26658,26659,26660,26661,26662,26663,26664,26667,26668,26669,26670,26671,26672,26673,26676,26677,26678,26682,26683,26687,26695,26699,26701,26703,26706,26710,26711,26712,26713,26714,26715,26716,26717,26718,26719,26730,26732,26733,26734,26735,26736,26737,26738,26739,26741,26744,26745,26746,26747,26748,26749,26750,26751,26752,26754,26756,26759,26760,26761,26762,26763,26764,26765,26766,26768,26769,26770,26772,26773,26774,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785,26787,26788,26789,26793,26794,26795,26796,26798,26801,26802,26804,26806,26807,26808,26809,26810,26811,26812,26813,26814,26815,26817,26819,26820,26821,26822,26823,26824,26826,26828,26830,26831,26832,26833,26835,26836,26838,26839,26841,26843,26844,26845,26846,26847,26849,26850,26852,26853,26854,26855,26856,26857,26858,26859,26860,26861,26863,26866,26867,26868,26870,26871,26872,26875,26877,26878,26879,26880,26882,26883,26884,26886,26887,26888,26889,26890,26892,26895,26897,26899,26900,26901,26902,26903,26904,26905,26906,26907,26908,26909,26910,26913,26914,26915,26917,26918,26919,26920,26921,26922,26923,26924,26926,26927,26929,26930,26931,26933,26934,26935,26936,26938,26939,26940,26942,26944,26945,26947,26948,26949,26950,26951,26952,26953,26954,26955,26956,26957,26958,26959,26960,26961,26962,26963,26965,26966,26968,26969,26971,26972,26975,26977,26978,26980,26981,26983,26984,26985,26986,26988,26989,26991,26992,26994,26995,26996,26997,26998,27002,27003,27005,27006,27007,27009,27011,27013,27018,27019,27020,27022,27023,27024,27025,27026,27027,27030,27031,27033,27034,27037,27038,27039,27040,27041,27042,27043,27044,27045,27046,27049,27050,27052,27054,27055,27056,27058,27059,27061,27062,27064,27065,27066,27068,27069,27070,27071,27072,27074,27075,27076,27077,27078,27079,27080,27081,27083,27085,27087,27089,27090,27091,27093,27094,27095,27096,27097,27098,27100,27101,27102,27105,27106,27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27118,27119,27120,27121,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27134,27136,27137,27138,27139,27140,27141,27142,27143,27144,27145,27147,27148,27149,27150,27151,27152,27153,27154,27155,27156,27157,27158,27161,27162,27163,27164,27165,27166,27168,27170,27171,27172,27173,27174,27175,27177,27179,27180,27181,27182,27184,27186,27187,27188,27190,27191,27192,27193,27194,27195,27196,27199,27200,27201,27202,27203,27205,27206,27208,27209,27210,27211,27212,27213,27214,27215,27217,27218,27219,27220,27221,27222,27223,27226,27228,27229,27230,27231,27232,27234,27235,27236,27238,27239,27240,27241,27242,27243,27244,27245,27246,27247,27248,27250,27251,27252,27253,27254,27255,27256,27258,27259,27261,27262,27263,27265,27266,27267,27269,27270,27271,27272,27273,27274,27275,27276,27277,27279,27282,27283,27284,27285,27286,27288,27289,27290,27291,27292,27293,27294,27295,27297,27298,27299,27300,27301,27302,27303,27304,27306,27309,27310,27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337,27338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,27362,27363,27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,27374,27375,27376,27377,27378,27379,27380,27381,27382,27383,27384,27385,27386,27387,27388,27389,27390,27391,27392,27393,27394,27395,27396,27397,27398,27399,27400,27401,27402,27403,27404,27405,27406,27407,27408,27409,27410,27411,27412,27413,27414,27415,27416,27417,27418,27419,27420,27421,27422,27423,27429,27430,27432,27433,27434,27435,27436,27437,27438,27439,27440,27441,27443,27444,27445,27446,27448,27451,27452,27453,27455,27456,27457,27458,27460,27461,27464,27466,27467,27469,27470,27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27482,27483,27484,27485,27486,27487,27488,27489,27496,27497,27499,27500,27501,27502,27503,27504,27505,27506,27507,27508,27509,27510,27511,27512,27514,27517,27518,27519,27520,27525,27528,27532,27534,27535,27536,27537,27540,27541,27543,27544,27545,27548,27549,27550,27551,27552,27554,27555,27556,27557,27558,27559,27560,27561,27563,27564,27565,27566,27567,27568,27569,27570,27574,27576,27577,27578,27579,27580,27581,27582,27584,27587,27588,27590,27591,27592,27593,27594,27596,27598,27600,27601,27608,27610,27612,27613,27614,27615,27616,27618,27619,27620,27621,27622,27623,27624,27625,27628,27629,27630,27632,27633,27634,27636,27638,27639,27640,27642,27643,27644,27646,27647,27648,27649,27650,27651,27652,27656,27657,27658,27659,27660,27662,27666,27671,27676,27677,27678,27680,27683,27685,27691,27692,27693,27697,27699,27702,27703,27705,27706,27707,27708,27710,27711,27715,27716,27717,27720,27723,27724,27725,27726,27727,27729,27730,27731,27734,27736,27737,27738,27746,27747,27749,27750,27751,27755,27756,27757,27758,27759,27761,27763,27765,27767,27768,27770,27771,27772,27775,27776,27780,27783,27786,27787,27789,27790,27793,27794,27797,27798,27799,27800,27802,27804,27805,27806,27808,27810,27816,27820,27823,27824,27828,27829,27830,27831,27834,27840,27841,27842,27843,27846,27847,27848,27851,27853,27854,27855,27857,27858,27864,27865,27866,27868,27869,27871,27876,27878,27879,27881,27884,27885,27890,27892,27897,27903,27904,27906,27907,27909,27910,27912,27913,27914,27917,27919,27920,27921,27923,27924,27925,27926,27928,27932,27933,27935,27936,27937,27938,27939,27940,27942,27944,27945,27948,27949,27951,27952,27956,27958,27959,27960,27962,27967,27968,27970,27972,27977,27980,27984,27989,27990,27991,27992,27995,27997,27999,28001,28002,28004,28005,28007,28008,28011,28012,28013,28016,28017,28018,28019,28021,28022,28025,28026,28027,28029,28030,28031,28032,28033,28035,28036,28038,28039,28042,28043,28045,28047,28048,28050,28054,28055,28056,28057,28058,28060,28066,28069,28076,28077,28080,28081,28083,28084,28086,28087,28089,28090,28091,28092,28093,28094,28097,28098,28099,28104,28105,28106,28109,28110,28111,28112,28114,28115,28116,28117,28119,28122,28123,28124,28127,28130,28131,28133,28135,28136,28137,28138,28141,28143,28144,28146,28148,28149,28150,28152,28154,28157,28158,28159,28160,28161,28162,28163,28164,28166,28167,28168,28169,28171,28175,28178,28179,28181,28184,28185,28187,28188,28190,28191,28194,28198,28199,28200,28202,28204,28206,28208,28209,28211,28213,28214,28215,28217,28219,28220,28221,28222,28223,28224,28225,28226,28229,28230,28231,28232,28233,28234,28235,28236,28239,28240,28241,28242,28245,28247,28249,28250,28252,28253,28254,28256,28257,28258,28259,28260,28261,28262,28263,28264,28265,28266,28268,28269,28271,28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,28288,28289,28290,28292,28295,28296,28298,28299,28300,28301,28302,28305,28306,28307,28308,28309,28310,28311,28313,28314,28315,28317,28318,28320,28321,28323,28324,28326,28328,28329,28331,28332,28333,28334,28336,28339,28341,28344,28345,28348,28350,28351,28352,28355,28356,28357,28358,28360,28361,28362,28364,28365,28366,28368,28370,28374,28376,28377,28379,28380,28381,28387,28391,28394,28395,28396,28397,28398,28399,28400,28401,28402,28403,28405,28406,28407,28408,28410,28411,28412,28413,28414,28415,28416,28417,28419,28420,28421,28423,28424,28426,28427,28428,28429,28430,28432,28433,28434,28438,28439,28440,28441,28442,28443,28444,28445,28446,28447,28449,28450,28451,28453,28454,28455,28456,28460,28462,28464,28466,28468,28469,28471,28472,28473,28474,28475,28476,28477,28479,28480,28481,28482,28483,28484,28485,28488,28489,28490,28492,28494,28495,28496,28497,28498,28499,28500,28501,28502,28503,28505,28506,28507,28509,28511,28512,28513,28515,28516,28517,28519,28520,28521,28522,28523,28524,28527,28528,28529,28531,28533,28534,28535,28537,28539,28541,28542,28543,28544,28545,28546,28547,28549,28550,28551,28554,28555,28559,28560,28561,28562,28563,28564,28565,28566,28567,28568,28569,28570,28571,28573,28574,28575,28576,28578,28579,28580,28581,28582,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594,28596,28597,28599,28600,28602,28603,28604,28605,28606,28607,28609,28611,28612,28613,28614,28615,28616,28618,28619,28620,28621,28622,28623,28624,28627,28628,28629,28630,28631,28632,28633,28634,28635,28636,28637,28639,28642,28643,28644,28645,28646,28647,28648,28649,28650,28651,28652,28653,28656,28657,28658,28659,28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,28670,28671,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28690,28691,28692,28693,28694,28695,28696,28697,28700,28701,28702,28703,28704,28705,28706,28708,28709,28710,28711,28712,28713,28714,28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28726,28727,28728,28730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,28742,28743,28744,28745,28746,28747,28749,28750,28752,28753,28754,28755,28756,28757,28758,28759,28760,28761,28762,28763,28764,28765,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,28778,28782,28785,28786,28787,28788,28791,28793,28794,28795,28797,28801,28802,28803,28804,28806,28807,28808,28811,28812,28813,28815,28816,28817,28819,28823,28824,28826,28827,28830,28831,28832,28833,28834,28835,28836,28837,28838,28839,28840,28841,28842,28848,28850,28852,28853,28854,28858,28862,28863,28868,28869,28870,28871,28873,28875,28876,28877,28878,28879,28880,28881,28882,28883,28884,28885,28886,28887,28890,28892,28893,28894,28896,28897,28898,28899,28901,28906,28910,28912,28913,28914,28915,28916,28917,28918,28920,28922,28923,28924,28926,28927,28928,28929,28930,28931,28932,28933,28934,28935,28936,28939,28940,28941,28942,28943,28945,28946,28948,28951,28955,28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28967,28968,28969,28970,28971,28972,28973,28974,28978,28979,28980,28981,28983,28984,28985,28986,28987,28988,28989,28990,28991,28992,28993,28994,28995,28996,28998,28999,29000,29001,29003,29005,29007,29008,29009,29010,29011,29012,29013,29014,29015,29016,29017,29018,29019,29021,29023,29024,29025,29026,29027,29029,29033,29034,29035,29036,29037,29039,29040,29041,29044,29045,29046,29047,29049,29051,29052,29054,29055,29056,29057,29058,29059,29061,29062,29063,29064,29065,29067,29068,29069,29070,29072,29073,29074,29075,29077,29078,29079,29082,29083,29084,29085,29086,29089,29090,29091,29092,29093,29094,29095,29097,29098,29099,29101,29102,29103,29104,29105,29106,29108,29110,29111,29112,29114,29115,29116,29117,29118,29119,29120,29121,29122,29124,29125,29126,29127,29128,29129,29130,29131,29132,29133,29135,29136,29137,29138,29139,29142,29143,29144,29145,29146,29147,29148,29149,29150,29151,29153,29154,29155,29156,29158,29160,29161,29162,29163,29164,29165,29167,29168,29169,29170,29171,29172,29173,29174,29175,29176,29178,29179,29180,29181,29182,29183,29184,29185,29186,29187,29188,29189,29191,29192,29193,29194,29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206,29207,29208,29209,29210,29211,29212,29214,29215,29216,29217,29218,29219,29220,29221,29222,29223,29225,29227,29229,29230,29231,29234,29235,29236,29242,29244,29246,29248,29249,29250,29251,29252,29253,29254,29257,29258,29259,29262,29263,29264,29265,29267,29268,29269,29271,29272,29274,29276,29278,29280,29283,29284,29285,29288,29290,29291,29292,29293,29296,29297,29299,29300,29302,29303,29304,29307,29308,29309,29314,29315,29317,29318,29319,29320,29321,29324,29326,29328,29329,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,29342,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,29354,29355,29358,29361,29362,29363,29365,29370,29371,29372,29373,29374,29375,29376,29381,29382,29383,29385,29386,29387,29388,29391,29393,29395,29396,29397,29398,29400,29402,29403,58566,58567,58568,58569,58570,58571,58572,58573,58574,58575,58576,58577,58578,58579,58580,58581,58582,58583,58584,58585,58586,58587,58588,58589,58590,58591,58592,58593,58594,58595,58596,58597,58598,58599,58600,58601,58602,58603,58604,58605,58606,58607,58608,58609,58610,58611,58612,58613,58614,58615,58616,58617,58618,58619,58620,58621,58622,58623,58624,58625,58626,58627,58628,58629,58630,58631,58632,58633,58634,58635,58636,58637,58638,58639,58640,58641,58642,58643,58644,58645,58646,58647,58648,58649,58650,58651,58652,58653,58654,58655,58656,58657,58658,58659,58660,58661,12288,12289,12290,183,713,711,168,12291,12293,8212,65374,8214,8230,8216,8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12310,12311,12304,12305,177,215,247,8758,8743,8744,8721,8719,8746,8745,8712,8759,8730,8869,8741,8736,8978,8857,8747,8750,8801,8780,8776,8765,8733,8800,8814,8815,8804,8805,8734,8757,8756,9794,9792,176,8242,8243,8451,65284,164,65504,65505,8240,167,8470,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,8251,8594,8592,8593,8595,12307,58662,58663,58664,58665,58666,58667,58668,58669,58670,58671,58672,58673,58674,58675,58676,58677,58678,58679,58680,58681,58682,58683,58684,58685,58686,58687,58688,58689,58690,58691,58692,58693,58694,58695,58696,58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707,58708,58709,58710,58711,58712,58713,58714,58715,58716,58717,58718,58719,58720,58721,58722,58723,58724,58725,58726,58727,58728,58729,58730,58731,58732,58733,58734,58735,58736,58737,58738,58739,58740,58741,58742,58743,58744,58745,58746,58747,58748,58749,58750,58751,58752,58753,58754,58755,58756,58757,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,59238,59239,59240,59241,59242,59243,9352,9353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,8364,59245,12832,12833,12834,12835,12836,12837,12838,12839,12840,12841,59246,59247,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,59248,59249,58758,58759,58760,58761,58762,58763,58764,58765,58766,58767,58768,58769,58770,58771,58772,58773,58774,58775,58776,58777,58778,58779,58780,58781,58782,58783,58784,58785,58786,58787,58788,58789,58790,58791,58792,58793,58794,58795,58796,58797,58798,58799,58800,58801,58802,58803,58804,58805,58806,58807,58808,58809,58810,58811,58812,58813,58814,58815,58816,58817,58818,58819,58820,58821,58822,58823,58824,58825,58826,58827,58828,58829,58830,58831,58832,58833,58834,58835,58836,58837,58838,58839,58840,58841,58842,58843,58844,58845,58846,58847,58848,58849,58850,58851,58852,12288,65281,65282,65283,65509,65285,65286,65287,65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339,65340,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,65373,65507,58854,58855,58856,58857,58858,58859,58860,58861,58862,58863,58864,58865,58866,58867,58868,58869,58870,58871,58872,58873,58874,58875,58876,58877,58878,58879,58880,58881,58882,58883,58884,58885,58886,58887,58888,58889,58890,58891,58892,58893,58894,58895,58896,58897,58898,58899,58900,58901,58902,58903,58904,58905,58906,58907,58908,58909,58910,58911,58912,58913,58914,58915,58916,58917,58918,58919,58920,58921,58922,58923,58924,58925,58926,58927,58928,58929,58930,58931,58932,58933,58934,58935,58936,58937,58938,58939,58940,58941,58942,58943,58944,58945,58946,58947,58948,58949,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,59250,59251,59252,59253,59254,59255,59256,59257,59258,59259,59260,58950,58951,58952,58953,58954,58955,58956,58957,58958,58959,58960,58961,58962,58963,58964,58965,58966,58967,58968,58969,58970,58971,58972,58973,58974,58975,58976,58977,58978,58979,58980,58981,58982,58983,58984,58985,58986,58987,58988,58989,58990,58991,58992,58993,58994,58995,58996,58997,58998,58999,59000,59001,59002,59003,59004,59005,59006,59007,59008,59009,59010,59011,59012,59013,59014,59015,59016,59017,59018,59019,59020,59021,59022,59023,59024,59025,59026,59027,59028,59029,59030,59031,59032,59033,59034,59035,59036,59037,59038,59039,59040,59041,59042,59043,59044,59045,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,59261,59262,59263,59264,59265,59266,59267,59268,59046,59047,59048,59049,59050,59051,59052,59053,59054,59055,59056,59057,59058,59059,59060,59061,59062,59063,59064,59065,59066,59067,59068,59069,59070,59071,59072,59073,59074,59075,59076,59077,59078,59079,59080,59081,59082,59083,59084,59085,59086,59087,59088,59089,59090,59091,59092,59093,59094,59095,59096,59097,59098,59099,59100,59101,59102,59103,59104,59105,59106,59107,59108,59109,59110,59111,59112,59113,59114,59115,59116,59117,59118,59119,59120,59121,59122,59123,59124,59125,59126,59127,59128,59129,59130,59131,59132,59133,59134,59135,59136,59137,59138,59139,59140,59141,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,59269,59270,59271,59272,59273,59274,59275,59276,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,59277,59278,59279,59280,59281,59282,59283,65077,65078,65081,65082,65087,65088,65085,65086,65089,65090,65091,65092,59284,59285,65083,65084,65079,65080,65073,59286,65075,65076,59287,59288,59289,59290,59291,59292,59293,59294,59295,59142,59143,59144,59145,59146,59147,59148,59149,59150,59151,59152,59153,59154,59155,59156,59157,59158,59159,59160,59161,59162,59163,59164,59165,59166,59167,59168,59169,59170,59171,59172,59173,59174,59175,59176,59177,59178,59179,59180,59181,59182,59183,59184,59185,59186,59187,59188,59189,59190,59191,59192,59193,59194,59195,59196,59197,59198,59199,59200,59201,59202,59203,59204,59205,59206,59207,59208,59209,59210,59211,59212,59213,59214,59215,59216,59217,59218,59219,59220,59221,59222,59223,59224,59225,59226,59227,59228,59229,59230,59231,59232,59233,59234,59235,59236,59237,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,59296,59297,59298,59299,59300,59301,59302,59303,59304,59305,59306,59307,59308,59309,59310,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,59311,59312,59313,59314,59315,59316,59317,59318,59319,59320,59321,59322,59323,714,715,729,8211,8213,8229,8245,8453,8457,8598,8599,8600,8601,8725,8735,8739,8786,8806,8807,8895,9552,9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9601,9602,9603,9604,9605,9606,9607,9608,9609,9610,9611,9612,9613,9614,9615,9619,9620,9621,9660,9661,9698,9699,9700,9701,9737,8853,12306,12317,12318,59324,59325,59326,59327,59328,59329,59330,59331,59332,59333,59334,257,225,462,224,275,233,283,232,299,237,464,236,333,243,466,242,363,250,468,249,470,472,474,476,252,234,593,7743,324,328,505,609,59337,59338,59339,59340,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,59341,59342,59343,59344,59345,59346,59347,59348,59349,59350,59351,59352,59353,59354,59355,59356,59357,59358,59359,59360,59361,12321,12322,12323,12324,12325,12326,12327,12328,12329,12963,13198,13199,13212,13213,13214,13217,13252,13262,13265,13266,13269,65072,65506,65508,59362,8481,12849,59363,8208,59364,59365,59366,12540,12443,12444,12541,12542,12294,12445,12446,65097,65098,65099,65100,65101,65102,65103,65104,65105,65106,65108,65109,65110,65111,65113,65114,65115,65116,65117,65118,65119,65120,65121,65122,65123,65124,65125,65126,65128,65129,65130,65131,12350,12272,12273,12274,12275,12276,12277,12278,12279,12280,12281,12282,12283,12295,59380,59381,59382,59383,59384,59385,59386,59387,59388,59389,59390,59391,59392,9472,9473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,59393,59394,59395,59396,59397,59398,59399,59400,59401,59402,59403,59404,59405,59406,59407,29404,29405,29407,29410,29411,29412,29413,29414,29415,29418,29419,29429,29430,29433,29437,29438,29439,29440,29442,29444,29445,29446,29447,29448,29449,29451,29452,29453,29455,29456,29457,29458,29460,29464,29465,29466,29471,29472,29475,29476,29478,29479,29480,29485,29487,29488,29490,29491,29493,29494,29498,29499,29500,29501,29504,29505,29506,29507,29508,29509,29510,29511,29512,29513,29514,29515,29516,29518,29519,29521,29523,29524,29525,29526,29528,29529,29530,29531,29532,29533,29534,29535,29537,29538,29539,29540,29541,29542,29543,29544,29545,29546,29547,29550,29552,29553,57344,57345,57346,57347,57348,57349,57350,57351,57352,57353,57354,57355,57356,57357,57358,57359,57360,57361,57362,57363,57364,57365,57366,57367,57368,57369,57370,57371,57372,57373,57374,57375,57376,57377,57378,57379,57380,57381,57382,57383,57384,57385,57386,57387,57388,57389,57390,57391,57392,57393,57394,57395,57396,57397,57398,57399,57400,57401,57402,57403,57404,57405,57406,57407,57408,57409,57410,57411,57412,57413,57414,57415,57416,57417,57418,57419,57420,57421,57422,57423,57424,57425,57426,57427,57428,57429,57430,57431,57432,57433,57434,57435,57436,57437,29554,29555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29567,29568,29569,29570,29571,29573,29574,29576,29578,29580,29581,29583,29584,29586,29587,29588,29589,29591,29592,29593,29594,29596,29597,29598,29600,29601,29603,29604,29605,29606,29607,29608,29610,29612,29613,29617,29620,29621,29622,29624,29625,29628,29629,29630,29631,29633,29635,29636,29637,29638,29639,29643,29644,29646,29650,29651,29652,29653,29654,29655,29656,29658,29659,29660,29661,29663,29665,29666,29667,29668,29670,29672,29674,29675,29676,29678,29679,29680,29681,29683,29684,29685,29686,29687,57438,57439,57440,57441,57442,57443,57444,57445,57446,57447,57448,57449,57450,57451,57452,57453,57454,57455,57456,57457,57458,57459,57460,57461,57462,57463,57464,57465,57466,57467,57468,57469,57470,57471,57472,57473,57474,57475,57476,57477,57478,57479,57480,57481,57482,57483,57484,57485,57486,57487,57488,57489,57490,57491,57492,57493,57494,57495,57496,57497,57498,57499,57500,57501,57502,57503,57504,57505,57506,57507,57508,57509,57510,57511,57512,57513,57514,57515,57516,57517,57518,57519,57520,57521,57522,57523,57524,57525,57526,57527,57528,57529,57530,57531,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697,29698,29700,29703,29704,29707,29708,29709,29710,29713,29714,29715,29716,29717,29718,29719,29720,29721,29724,29725,29726,29727,29728,29729,29731,29732,29735,29737,29739,29741,29743,29745,29746,29751,29752,29753,29754,29755,29757,29758,29759,29760,29762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772,29773,29774,29775,29776,29777,29778,29779,29780,29782,29784,29789,29792,29793,29794,29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29806,29807,29809,29810,29811,29812,29813,29816,29817,29818,57532,57533,57534,57535,57536,57537,57538,57539,57540,57541,57542,57543,57544,57545,57546,57547,57548,57549,57550,57551,57552,57553,57554,57555,57556,57557,57558,57559,57560,57561,57562,57563,57564,57565,57566,57567,57568,57569,57570,57571,57572,57573,57574,57575,57576,57577,57578,57579,57580,57581,57582,57583,57584,57585,57586,57587,57588,57589,57590,57591,57592,57593,57594,57595,57596,57597,57598,57599,57600,57601,57602,57603,57604,57605,57606,57607,57608,57609,57610,57611,57612,57613,57614,57615,57616,57617,57618,57619,57620,57621,57622,57623,57624,57625,29819,29820,29821,29823,29826,29828,29829,29830,29832,29833,29834,29836,29837,29839,29841,29842,29843,29844,29845,29846,29847,29848,29849,29850,29851,29853,29855,29856,29857,29858,29859,29860,29861,29862,29866,29867,29868,29869,29870,29871,29872,29873,29874,29875,29876,29877,29878,29879,29880,29881,29883,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,29894,29895,29896,29897,29898,29899,29900,29901,29902,29903,29904,29905,29907,29908,29909,29910,29911,29912,29913,29914,29915,29917,29919,29921,29925,29927,29928,29929,29930,29931,29932,29933,29936,29937,29938,57626,57627,57628,57629,57630,57631,57632,57633,57634,57635,57636,57637,57638,57639,57640,57641,57642,57643,57644,57645,57646,57647,57648,57649,57650,57651,57652,57653,57654,57655,57656,57657,57658,57659,57660,57661,57662,57663,57664,57665,57666,57667,57668,57669,57670,57671,57672,57673,57674,57675,57676,57677,57678,57679,57680,57681,57682,57683,57684,57685,57686,57687,57688,57689,57690,57691,57692,57693,57694,57695,57696,57697,57698,57699,57700,57701,57702,57703,57704,57705,57706,57707,57708,57709,57710,57711,57712,57713,57714,57715,57716,57717,57718,57719,29939,29941,29944,29945,29946,29947,29948,29949,29950,29952,29953,29954,29955,29957,29958,29959,29960,29961,29962,29963,29964,29966,29968,29970,29972,29973,29974,29975,29979,29981,29982,29984,29985,29986,29987,29988,29990,29991,29994,29998,30004,30006,30009,30012,30013,30015,30017,30018,30019,30020,30022,30023,30025,30026,30029,30032,30033,30034,30035,30037,30038,30039,30040,30045,30046,30047,30048,30049,30050,30051,30052,30055,30056,30057,30059,30060,30061,30062,30063,30064,30065,30067,30069,30070,30071,30074,30075,30076,30077,30078,30080,30081,30082,30084,30085,30087,57720,57721,57722,57723,57724,57725,57726,57727,57728,57729,57730,57731,57732,57733,57734,57735,57736,57737,57738,57739,57740,57741,57742,57743,57744,57745,57746,57747,57748,57749,57750,57751,57752,57753,57754,57755,57756,57757,57758,57759,57760,57761,57762,57763,57764,57765,57766,57767,57768,57769,57770,57771,57772,57773,57774,57775,57776,57777,57778,57779,57780,57781,57782,57783,57784,57785,57786,57787,57788,57789,57790,57791,57792,57793,57794,57795,57796,57797,57798,57799,57800,57801,57802,57803,57804,57805,57806,57807,57808,57809,57810,57811,57812,57813,30088,30089,30090,30092,30093,30094,30096,30099,30101,30104,30107,30108,30110,30114,30118,30119,30120,30121,30122,30125,30134,30135,30138,30139,30143,30144,30145,30150,30155,30156,30158,30159,30160,30161,30163,30167,30169,30170,30172,30173,30175,30176,30177,30181,30185,30188,30189,30190,30191,30194,30195,30197,30198,30199,30200,30202,30203,30205,30206,30210,30212,30214,30215,30216,30217,30219,30221,30222,30223,30225,30226,30227,30228,30230,30234,30236,30237,30238,30241,30243,30247,30248,30252,30254,30255,30257,30258,30262,30263,30265,30266,30267,30269,30273,30274,30276,57814,57815,57816,57817,57818,57819,57820,57821,57822,57823,57824,57825,57826,57827,57828,57829,57830,57831,57832,57833,57834,57835,57836,57837,57838,57839,57840,57841,57842,57843,57844,57845,57846,57847,57848,57849,57850,57851,57852,57853,57854,57855,57856,57857,57858,57859,57860,57861,57862,57863,57864,57865,57866,57867,57868,57869,57870,57871,57872,57873,57874,57875,57876,57877,57878,57879,57880,57881,57882,57883,57884,57885,57886,57887,57888,57889,57890,57891,57892,57893,57894,57895,57896,57897,57898,57899,57900,57901,57902,57903,57904,57905,57906,57907,30277,30278,30279,30280,30281,30282,30283,30286,30287,30288,30289,30290,30291,30293,30295,30296,30297,30298,30299,30301,30303,30304,30305,30306,30308,30309,30310,30311,30312,30313,30314,30316,30317,30318,30320,30321,30322,30323,30324,30325,30326,30327,30329,30330,30332,30335,30336,30337,30339,30341,30345,30346,30348,30349,30351,30352,30354,30356,30357,30359,30360,30362,30363,30364,30365,30366,30367,30368,30369,30370,30371,30373,30374,30375,30376,30377,30378,30379,30380,30381,30383,30384,30387,30389,30390,30391,30392,30393,30394,30395,30396,30397,30398,30400,30401,30403,21834,38463,22467,25384,21710,21769,21696,30353,30284,34108,30702,33406,30861,29233,38552,38797,27688,23433,20474,25353,26263,23736,33018,26696,32942,26114,30414,20985,25942,29100,32753,34948,20658,22885,25034,28595,33453,25420,25170,21485,21543,31494,20843,30116,24052,25300,36299,38774,25226,32793,22365,38712,32610,29240,30333,26575,30334,25670,20336,36133,25308,31255,26001,29677,25644,25203,33324,39041,26495,29256,25198,25292,20276,29923,21322,21150,32458,37030,24110,26758,27036,33152,32465,26834,30917,34444,38225,20621,35876,33502,32990,21253,35090,21093,30404,30407,30409,30411,30412,30419,30421,30425,30426,30428,30429,30430,30432,30433,30434,30435,30436,30438,30439,30440,30441,30442,30443,30444,30445,30448,30451,30453,30454,30455,30458,30459,30461,30463,30464,30466,30467,30469,30470,30474,30476,30478,30479,30480,30481,30482,30483,30484,30485,30486,30487,30488,30491,30492,30493,30494,30497,30499,30500,30501,30503,30506,30507,30508,30510,30512,30513,30514,30515,30516,30521,30523,30525,30526,30527,30530,30532,30533,30534,30536,30537,30538,30539,30540,30541,30542,30543,30546,30547,30548,30549,30550,30551,30552,30553,30556,34180,38649,20445,22561,39281,23453,25265,25253,26292,35961,40077,29190,26479,30865,24754,21329,21271,36744,32972,36125,38049,20493,29384,22791,24811,28953,34987,22868,33519,26412,31528,23849,32503,29997,27893,36454,36856,36924,40763,27604,37145,31508,24444,30887,34006,34109,27605,27609,27606,24065,24199,30201,38381,25949,24330,24517,36767,22721,33218,36991,38491,38829,36793,32534,36140,25153,20415,21464,21342,36776,36777,36779,36941,26631,24426,33176,34920,40150,24971,21035,30250,24428,25996,28626,28392,23486,25672,20853,20912,26564,19993,31177,39292,28851,30557,30558,30559,30560,30564,30567,30569,30570,30573,30574,30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30586,30587,30588,30593,30594,30595,30598,30599,30600,30601,30602,30603,30607,30608,30611,30612,30613,30614,30615,30616,30617,30618,30619,30620,30621,30622,30625,30627,30628,30630,30632,30635,30637,30638,30639,30641,30642,30644,30646,30647,30648,30649,30650,30652,30654,30656,30657,30658,30659,30660,30661,30662,30663,30664,30665,30666,30667,30668,30670,30671,30672,30673,30674,30675,30676,30677,30678,30680,30681,30682,30685,30686,30687,30688,30689,30692,30149,24182,29627,33760,25773,25320,38069,27874,21338,21187,25615,38082,31636,20271,24091,33334,33046,33162,28196,27850,39539,25429,21340,21754,34917,22496,19981,24067,27493,31807,37096,24598,25830,29468,35009,26448,25165,36130,30572,36393,37319,24425,33756,34081,39184,21442,34453,27531,24813,24808,28799,33485,33329,20179,27815,34255,25805,31961,27133,26361,33609,21397,31574,20391,20876,27979,23618,36461,25554,21449,33580,33590,26597,30900,25661,23519,23700,24046,35815,25286,26612,35962,25600,25530,34633,39307,35863,32544,38130,20135,38416,39076,26124,29462,30694,30696,30698,30703,30704,30705,30706,30708,30709,30711,30713,30714,30715,30716,30723,30724,30725,30726,30727,30728,30730,30731,30734,30735,30736,30739,30741,30745,30747,30750,30752,30753,30754,30756,30760,30762,30763,30766,30767,30769,30770,30771,30773,30774,30781,30783,30785,30786,30787,30788,30790,30792,30793,30794,30795,30797,30799,30801,30803,30804,30808,30809,30810,30811,30812,30814,30815,30816,30817,30818,30819,30820,30821,30822,30823,30824,30825,30831,30832,30833,30834,30835,30836,30837,30838,30840,30841,30842,30843,30845,30846,30847,30848,30849,30850,30851,22330,23581,24120,38271,20607,32928,21378,25950,30021,21809,20513,36229,25220,38046,26397,22066,28526,24034,21557,28818,36710,25199,25764,25507,24443,28552,37108,33251,36784,23576,26216,24561,27785,38472,36225,34924,25745,31216,22478,27225,25104,21576,20056,31243,24809,28548,35802,25215,36894,39563,31204,21507,30196,25345,21273,27744,36831,24347,39536,32827,40831,20360,23610,36196,32709,26021,28861,20805,20914,34411,23815,23456,25277,37228,30068,36364,31264,24833,31609,20167,32504,30597,19985,33261,21021,20986,27249,21416,36487,38148,38607,28353,38500,26970,30852,30853,30854,30856,30858,30859,30863,30864,30866,30868,30869,30870,30873,30877,30878,30880,30882,30884,30886,30888,30889,30890,30891,30892,30893,30894,30895,30901,30902,30903,30904,30906,30907,30908,30909,30911,30912,30914,30915,30916,30918,30919,30920,30924,30925,30926,30927,30929,30930,30931,30934,30935,30936,30938,30939,30940,30941,30942,30943,30944,30945,30946,30947,30948,30949,30950,30951,30953,30954,30955,30957,30958,30959,30960,30961,30963,30965,30966,30968,30969,30971,30972,30973,30974,30975,30976,30978,30979,30980,30982,30983,30984,30985,30986,30987,30988,30784,20648,30679,25616,35302,22788,25571,24029,31359,26941,20256,33337,21912,20018,30126,31383,24162,24202,38383,21019,21561,28810,25462,38180,22402,26149,26943,37255,21767,28147,32431,34850,25139,32496,30133,33576,30913,38604,36766,24904,29943,35789,27492,21050,36176,27425,32874,33905,22257,21254,20174,19995,20945,31895,37259,31751,20419,36479,31713,31388,25703,23828,20652,33030,30209,31929,28140,32736,26449,23384,23544,30923,25774,25619,25514,25387,38169,25645,36798,31572,30249,25171,22823,21574,27513,20643,25140,24102,27526,20195,36151,34955,24453,36910,30989,30990,30991,30992,30993,30994,30996,30997,30998,30999,31000,31001,31002,31003,31004,31005,31007,31008,31009,31010,31011,31013,31014,31015,31016,31017,31018,31019,31020,31021,31022,31023,31024,31025,31026,31027,31029,31030,31031,31032,31033,31037,31039,31042,31043,31044,31045,31047,31050,31051,31052,31053,31054,31055,31056,31057,31058,31060,31061,31064,31065,31073,31075,31076,31078,31081,31082,31083,31084,31086,31088,31089,31090,31091,31092,31093,31094,31097,31099,31100,31101,31102,31103,31106,31107,31110,31111,31112,31113,31115,31116,31117,31118,31120,31121,31122,24608,32829,25285,20025,21333,37112,25528,32966,26086,27694,20294,24814,28129,35806,24377,34507,24403,25377,20826,33633,26723,20992,25443,36424,20498,23707,31095,23548,21040,31291,24764,36947,30423,24503,24471,30340,36460,28783,30331,31561,30634,20979,37011,22564,20302,28404,36842,25932,31515,29380,28068,32735,23265,25269,24213,22320,33922,31532,24093,24351,36882,32532,39072,25474,28359,30872,28857,20856,38747,22443,30005,20291,30008,24215,24806,22880,28096,27583,30857,21500,38613,20939,20993,25481,21514,38035,35843,36300,29241,30879,34678,36845,35853,21472,31123,31124,31125,31126,31127,31128,31129,31131,31132,31133,31134,31135,31136,31137,31138,31139,31140,31141,31142,31144,31145,31146,31147,31148,31149,31150,31151,31152,31153,31154,31156,31157,31158,31159,31160,31164,31167,31170,31172,31173,31175,31176,31178,31180,31182,31183,31184,31187,31188,31190,31191,31193,31194,31195,31196,31197,31198,31200,31201,31202,31205,31208,31210,31212,31214,31217,31218,31219,31220,31221,31222,31223,31225,31226,31228,31230,31231,31233,31236,31237,31239,31240,31241,31242,31244,31247,31248,31249,31250,31251,31253,31254,31256,31257,31259,31260,19969,30447,21486,38025,39030,40718,38189,23450,35746,20002,19996,20908,33891,25026,21160,26635,20375,24683,20923,27934,20828,25238,26007,38497,35910,36887,30168,37117,30563,27602,29322,29420,35835,22581,30585,36172,26460,38208,32922,24230,28193,22930,31471,30701,38203,27573,26029,32526,22534,20817,38431,23545,22697,21544,36466,25958,39039,22244,38045,30462,36929,25479,21702,22810,22842,22427,36530,26421,36346,33333,21057,24816,22549,34558,23784,40517,20420,39069,35769,23077,24694,21380,25212,36943,37122,39295,24681,32780,20799,32819,23572,39285,27953,20108,31261,31263,31265,31266,31268,31269,31270,31271,31272,31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,31284,31285,31286,31288,31290,31294,31296,31297,31298,31299,31300,31301,31303,31304,31305,31306,31307,31308,31309,31310,31311,31312,31314,31315,31316,31317,31318,31320,31321,31322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31345,31346,31347,31349,31355,31356,31357,31358,31362,31365,31367,31369,31370,31371,31372,31374,31375,31376,31379,31380,31385,31386,31387,31390,31393,31394,36144,21457,32602,31567,20240,20047,38400,27861,29648,34281,24070,30058,32763,27146,30718,38034,32321,20961,28902,21453,36820,33539,36137,29359,39277,27867,22346,33459,26041,32938,25151,38450,22952,20223,35775,32442,25918,33778,38750,21857,39134,32933,21290,35837,21536,32954,24223,27832,36153,33452,37210,21545,27675,20998,32439,22367,28954,27774,31881,22859,20221,24575,24868,31914,20016,23553,26539,34562,23792,38155,39118,30127,28925,36898,20911,32541,35773,22857,20964,20315,21542,22827,25975,32932,23413,25206,25282,36752,24133,27679,31526,20239,20440,26381,31395,31396,31399,31401,31402,31403,31406,31407,31408,31409,31410,31412,31413,31414,31415,31416,31417,31418,31419,31420,31421,31422,31424,31425,31426,31427,31428,31429,31430,31431,31432,31433,31434,31436,31437,31438,31439,31440,31441,31442,31443,31444,31445,31447,31448,31450,31451,31452,31453,31457,31458,31460,31463,31464,31465,31466,31467,31468,31470,31472,31473,31474,31475,31476,31477,31478,31479,31480,31483,31484,31486,31488,31489,31490,31493,31495,31497,31500,31501,31502,31504,31506,31507,31510,31511,31512,31514,31516,31517,31519,31521,31522,31523,31527,31529,31533,28014,28074,31119,34993,24343,29995,25242,36741,20463,37340,26023,33071,33105,24220,33104,36212,21103,35206,36171,22797,20613,20184,38428,29238,33145,36127,23500,35747,38468,22919,32538,21648,22134,22030,35813,25913,27010,38041,30422,28297,24178,29976,26438,26577,31487,32925,36214,24863,31174,25954,36195,20872,21018,38050,32568,32923,32434,23703,28207,26464,31705,30347,39640,33167,32660,31957,25630,38224,31295,21578,21733,27468,25601,25096,40509,33011,30105,21106,38761,33883,26684,34532,38401,38548,38124,20010,21508,32473,26681,36319,32789,26356,24218,32697,31535,31536,31538,31540,31541,31542,31543,31545,31547,31549,31551,31552,31553,31554,31555,31556,31558,31560,31562,31565,31566,31571,31573,31575,31577,31580,31582,31583,31585,31587,31588,31589,31590,31591,31592,31593,31594,31595,31596,31597,31599,31600,31603,31604,31606,31608,31610,31612,31613,31615,31617,31618,31619,31620,31622,31623,31624,31625,31626,31627,31628,31630,31631,31633,31634,31635,31638,31640,31641,31642,31643,31646,31647,31648,31651,31652,31653,31662,31663,31664,31666,31667,31669,31670,31671,31673,31674,31675,31676,31677,31678,31679,31680,31682,31683,31684,22466,32831,26775,24037,25915,21151,24685,40858,20379,36524,20844,23467,24339,24041,27742,25329,36129,20849,38057,21246,27807,33503,29399,22434,26500,36141,22815,36764,33735,21653,31629,20272,27837,23396,22993,40723,21476,34506,39592,35895,32929,25925,39038,22266,38599,21038,29916,21072,23521,25346,35074,20054,25296,24618,26874,20851,23448,20896,35266,31649,39302,32592,24815,28748,36143,20809,24191,36891,29808,35268,22317,30789,24402,40863,38394,36712,39740,35809,30328,26690,26588,36330,36149,21053,36746,28378,26829,38149,37101,22269,26524,35065,36807,21704,31685,31688,31689,31690,31691,31693,31694,31695,31696,31698,31700,31701,31702,31703,31704,31707,31708,31710,31711,31712,31714,31715,31716,31719,31720,31721,31723,31724,31725,31727,31728,31730,31731,31732,31733,31734,31736,31737,31738,31739,31741,31743,31744,31745,31746,31747,31748,31749,31750,31752,31753,31754,31757,31758,31760,31761,31762,31763,31764,31765,31767,31768,31769,31770,31771,31772,31773,31774,31776,31777,31778,31779,31780,31781,31784,31785,31787,31788,31789,31790,31791,31792,31793,31794,31795,31796,31797,31798,31799,31801,31802,31803,31804,31805,31806,31810,39608,23401,28023,27686,20133,23475,39559,37219,25000,37039,38889,21547,28085,23506,20989,21898,32597,32752,25788,25421,26097,25022,24717,28938,27735,27721,22831,26477,33322,22741,22158,35946,27627,37085,22909,32791,21495,28009,21621,21917,33655,33743,26680,31166,21644,20309,21512,30418,35977,38402,27827,28088,36203,35088,40548,36154,22079,40657,30165,24456,29408,24680,21756,20136,27178,34913,24658,36720,21700,28888,34425,40511,27946,23439,24344,32418,21897,20399,29492,21564,21402,20505,21518,21628,20046,24573,29786,22774,33899,32993,34676,29392,31946,28246,31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31822,31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848,31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,31861,31862,31863,31864,31865,31866,31870,31871,31872,31873,31874,31875,31876,31877,31878,31879,31880,31882,31883,31884,31885,31886,31887,31888,31891,31892,31894,31897,31898,31899,31904,31905,31907,31910,31911,31912,31913,31915,31916,31917,31919,31920,31924,31925,31926,31927,31928,31930,31931,24359,34382,21804,25252,20114,27818,25143,33457,21719,21326,29502,28369,30011,21010,21270,35805,27088,24458,24576,28142,22351,27426,29615,26707,36824,32531,25442,24739,21796,30186,35938,28949,28067,23462,24187,33618,24908,40644,30970,34647,31783,30343,20976,24822,29004,26179,24140,24653,35854,28784,25381,36745,24509,24674,34516,22238,27585,24724,24935,21321,24800,26214,36159,31229,20250,28905,27719,35763,35826,32472,33636,26127,23130,39746,27985,28151,35905,27963,20249,28779,33719,25110,24785,38669,36135,31096,20987,22334,22522,26426,30072,31293,31215,31637,31935,31936,31938,31939,31940,31942,31945,31947,31950,31951,31952,31953,31954,31955,31956,31960,31962,31963,31965,31966,31969,31970,31971,31972,31973,31974,31975,31977,31978,31979,31980,31981,31982,31984,31985,31986,31987,31988,31989,31990,31991,31993,31994,31996,31997,31998,31999,32000,32001,32002,32003,32004,32005,32006,32007,32008,32009,32011,32012,32013,32014,32015,32016,32017,32018,32019,32020,32021,32022,32023,32024,32025,32026,32027,32028,32029,32030,32031,32033,32035,32036,32037,32038,32040,32041,32042,32044,32045,32046,32048,32049,32050,32051,32052,32053,32054,32908,39269,36857,28608,35749,40481,23020,32489,32521,21513,26497,26840,36753,31821,38598,21450,24613,30142,27762,21363,23241,32423,25380,20960,33034,24049,34015,25216,20864,23395,20238,31085,21058,24760,27982,23492,23490,35745,35760,26082,24524,38469,22931,32487,32426,22025,26551,22841,20339,23478,21152,33626,39050,36158,30002,38078,20551,31292,20215,26550,39550,23233,27516,30417,22362,23574,31546,38388,29006,20860,32937,33392,22904,32516,33575,26816,26604,30897,30839,25315,25441,31616,20461,21098,20943,33616,27099,37492,36341,36145,35265,38190,31661,20214,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,32066,32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,32078,32079,32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,32090,32091,32092,32093,32094,32095,32096,32097,32098,32099,32100,32101,32102,32103,32104,32105,32106,32107,32108,32109,32111,32112,32113,32114,32115,32116,32117,32118,32120,32121,32122,32123,32124,32125,32126,32127,32128,32129,32130,32131,32132,32133,32134,32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145,32146,32147,32148,32149,32150,32151,32152,20581,33328,21073,39279,28176,28293,28071,24314,20725,23004,23558,27974,27743,30086,33931,26728,22870,35762,21280,37233,38477,34121,26898,30977,28966,33014,20132,37066,27975,39556,23047,22204,25605,38128,30699,20389,33050,29409,35282,39290,32564,32478,21119,25945,37237,36735,36739,21483,31382,25581,25509,30342,31224,34903,38454,25130,21163,33410,26708,26480,25463,30571,31469,27905,32467,35299,22992,25106,34249,33445,30028,20511,20171,30117,35819,23626,24062,31563,26020,37329,20170,27941,35167,32039,38182,20165,35880,36827,38771,26187,31105,36817,28908,28024,32153,32154,32155,32156,32157,32158,32159,32160,32161,32162,32163,32164,32165,32167,32168,32169,32170,32171,32172,32173,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,32186,32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,32222,32223,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,32234,32235,32236,32237,32238,32239,32240,32241,32242,32243,32244,32245,32246,32247,32248,32249,32250,23613,21170,33606,20834,33550,30555,26230,40120,20140,24778,31934,31923,32463,20117,35686,26223,39048,38745,22659,25964,38236,24452,30153,38742,31455,31454,20928,28847,31384,25578,31350,32416,29590,38893,20037,28792,20061,37202,21417,25937,26087,33276,33285,21646,23601,30106,38816,25304,29401,30141,23621,39545,33738,23616,21632,30697,20030,27822,32858,25298,25454,24040,20855,36317,36382,38191,20465,21477,24807,28844,21095,25424,40515,23071,20518,30519,21367,32482,25733,25899,25225,25496,20500,29237,35273,20915,35776,32477,22343,33740,38055,20891,21531,23803,32251,32252,32253,32254,32255,32256,32257,32258,32259,32260,32261,32262,32263,32264,32265,32266,32267,32268,32269,32270,32271,32272,32273,32274,32275,32276,32277,32278,32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289,32290,32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302,32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,32314,32316,32317,32318,32319,32320,32322,32323,32324,32325,32326,32328,32329,32330,32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,32342,32343,32344,32345,32346,32347,32348,32349,20426,31459,27994,37089,39567,21888,21654,21345,21679,24320,25577,26999,20975,24936,21002,22570,21208,22350,30733,30475,24247,24951,31968,25179,25239,20130,28821,32771,25335,28900,38752,22391,33499,26607,26869,30933,39063,31185,22771,21683,21487,28212,20811,21051,23458,35838,32943,21827,22438,24691,22353,21549,31354,24656,23380,25511,25248,21475,25187,23495,26543,21741,31391,33510,37239,24211,35044,22840,22446,25358,36328,33007,22359,31607,20393,24555,23485,27454,21281,31568,29378,26694,30719,30518,26103,20917,20111,30420,23743,31397,33909,22862,39745,20608,32350,32351,32352,32353,32354,32355,32356,32357,32358,32359,32360,32361,32362,32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382,32383,32384,32385,32387,32388,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409,32410,32412,32413,32414,32430,32436,32443,32444,32470,32484,32492,32505,32522,32528,32542,32567,32569,32571,32572,32573,32574,32575,32576,32577,32579,32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32594,32595,39304,24871,28291,22372,26118,25414,22256,25324,25193,24275,38420,22403,25289,21895,34593,33098,36771,21862,33713,26469,36182,34013,23146,26639,25318,31726,38417,20848,28572,35888,25597,35272,25042,32518,28866,28389,29701,27028,29436,24266,37070,26391,28010,25438,21171,29282,32769,20332,23013,37226,28889,28061,21202,20048,38647,38253,34174,30922,32047,20769,22418,25794,32907,31867,27882,26865,26974,20919,21400,26792,29313,40654,31729,29432,31163,28435,29702,26446,37324,40100,31036,33673,33620,21519,26647,20029,21385,21169,30782,21382,21033,20616,20363,20432,32598,32601,32603,32604,32605,32606,32608,32611,32612,32613,32614,32615,32619,32620,32621,32623,32624,32627,32629,32630,32631,32632,32634,32635,32636,32637,32639,32640,32642,32643,32644,32645,32646,32647,32648,32649,32651,32653,32655,32656,32657,32658,32659,32661,32662,32663,32664,32665,32667,32668,32672,32674,32675,32677,32678,32680,32681,32682,32683,32684,32685,32686,32689,32691,32692,32693,32694,32695,32698,32699,32702,32704,32706,32707,32708,32710,32711,32712,32713,32715,32717,32719,32720,32721,32722,32723,32726,32727,32729,32730,32731,32732,32733,32734,32738,32739,30178,31435,31890,27813,38582,21147,29827,21737,20457,32852,33714,36830,38256,24265,24604,28063,24088,25947,33080,38142,24651,28860,32451,31918,20937,26753,31921,33391,20004,36742,37327,26238,20142,35845,25769,32842,20698,30103,29134,23525,36797,28518,20102,25730,38243,24278,26009,21015,35010,28872,21155,29454,29747,26519,30967,38678,20020,37051,40158,28107,20955,36161,21533,25294,29618,33777,38646,40836,38083,20278,32666,20940,28789,38517,23725,39046,21478,20196,28316,29705,27060,30827,39311,30041,21016,30244,27969,26611,20845,40857,32843,21657,31548,31423,32740,32743,32744,32746,32747,32748,32749,32751,32754,32756,32757,32758,32759,32760,32761,32762,32765,32766,32767,32770,32775,32776,32777,32778,32782,32783,32785,32787,32794,32795,32797,32798,32799,32801,32803,32804,32811,32812,32813,32814,32815,32816,32818,32820,32825,32826,32828,32830,32832,32833,32836,32837,32839,32840,32841,32846,32847,32848,32849,32851,32853,32854,32855,32857,32859,32860,32861,32862,32863,32864,32865,32866,32867,32868,32869,32870,32871,32872,32875,32876,32877,32878,32879,32880,32882,32883,32884,32885,32886,32887,32888,32889,32890,32891,32892,32893,38534,22404,25314,38471,27004,23044,25602,31699,28431,38475,33446,21346,39045,24208,28809,25523,21348,34383,40065,40595,30860,38706,36335,36162,40575,28510,31108,24405,38470,25134,39540,21525,38109,20387,26053,23653,23649,32533,34385,27695,24459,29575,28388,32511,23782,25371,23402,28390,21365,20081,25504,30053,25249,36718,20262,20177,27814,32438,35770,33821,34746,32599,36923,38179,31657,39585,35064,33853,27931,39558,32476,22920,40635,29595,30721,34434,39532,39554,22043,21527,22475,20080,40614,21334,36808,33033,30610,39314,34542,28385,34067,26364,24930,28459,32894,32897,32898,32901,32904,32906,32909,32910,32911,32912,32913,32914,32916,32917,32919,32921,32926,32931,32934,32935,32936,32940,32944,32947,32949,32950,32952,32953,32955,32965,32967,32968,32969,32970,32971,32975,32976,32977,32978,32979,32980,32981,32984,32991,32992,32994,32995,32998,33006,33013,33015,33017,33019,33022,33023,33024,33025,33027,33028,33029,33031,33032,33035,33036,33045,33047,33049,33051,33052,33053,33055,33056,33057,33058,33059,33060,33061,33062,33063,33064,33065,33066,33067,33069,33070,33072,33075,33076,33077,33079,33081,33082,33083,33084,33085,33087,35881,33426,33579,30450,27667,24537,33725,29483,33541,38170,27611,30683,38086,21359,33538,20882,24125,35980,36152,20040,29611,26522,26757,37238,38665,29028,27809,30473,23186,38209,27599,32654,26151,23504,22969,23194,38376,38391,20204,33804,33945,27308,30431,38192,29467,26790,23391,30511,37274,38753,31964,36855,35868,24357,31859,31192,35269,27852,34588,23494,24130,26825,30496,32501,20885,20813,21193,23081,32517,38754,33495,25551,30596,34256,31186,28218,24217,22937,34065,28781,27665,25279,30399,25935,24751,38397,26126,34719,40483,38125,21517,21629,35884,25720,33088,33089,33090,33091,33092,33093,33095,33097,33101,33102,33103,33106,33110,33111,33112,33115,33116,33117,33118,33119,33121,33122,33123,33124,33126,33128,33130,33131,33132,33135,33138,33139,33141,33142,33143,33144,33153,33155,33156,33157,33158,33159,33161,33163,33164,33165,33166,33168,33170,33171,33172,33173,33174,33175,33177,33178,33182,33183,33184,33185,33186,33188,33189,33191,33193,33195,33196,33197,33198,33199,33200,33201,33202,33204,33205,33206,33207,33208,33209,33212,33213,33214,33215,33220,33221,33223,33224,33225,33227,33229,33230,33231,33232,33233,33234,33235,25721,34321,27169,33180,30952,25705,39764,25273,26411,33707,22696,40664,27819,28448,23518,38476,35851,29279,26576,25287,29281,20137,22982,27597,22675,26286,24149,21215,24917,26408,30446,30566,29287,31302,25343,21738,21584,38048,37027,23068,32435,27670,20035,22902,32784,22856,21335,30007,38590,22218,25376,33041,24700,38393,28118,21602,39297,20869,23273,33021,22958,38675,20522,27877,23612,25311,20320,21311,33147,36870,28346,34091,25288,24180,30910,25781,25467,24565,23064,37247,40479,23615,25423,32834,23421,21870,38218,38221,28037,24744,26592,29406,20957,23425,33236,33237,33238,33239,33240,33241,33242,33243,33244,33245,33246,33247,33248,33249,33250,33252,33253,33254,33256,33257,33259,33262,33263,33264,33265,33266,33269,33270,33271,33272,33273,33274,33277,33279,33283,33287,33288,33289,33290,33291,33294,33295,33297,33299,33301,33302,33303,33304,33305,33306,33309,33312,33316,33317,33318,33319,33321,33326,33330,33338,33340,33341,33343,33344,33345,33346,33347,33349,33350,33352,33354,33356,33357,33358,33360,33361,33362,33363,33364,33365,33366,33367,33369,33371,33372,33373,33374,33376,33377,33378,33379,33380,33381,33382,33383,33385,25319,27870,29275,25197,38062,32445,33043,27987,20892,24324,22900,21162,24594,22899,26262,34384,30111,25386,25062,31983,35834,21734,27431,40485,27572,34261,21589,20598,27812,21866,36276,29228,24085,24597,29750,25293,25490,29260,24472,28227,27966,25856,28504,30424,30928,30460,30036,21028,21467,20051,24222,26049,32810,32982,25243,21638,21032,28846,34957,36305,27873,21624,32986,22521,35060,36180,38506,37197,20329,27803,21943,30406,30768,25256,28921,28558,24429,34028,26842,30844,31735,33192,26379,40527,25447,30896,22383,30738,38713,25209,25259,21128,29749,27607,33386,33387,33388,33389,33393,33397,33398,33399,33400,33403,33404,33408,33409,33411,33413,33414,33415,33417,33420,33424,33427,33428,33429,33430,33434,33435,33438,33440,33442,33443,33447,33458,33461,33462,33466,33467,33468,33471,33472,33474,33475,33477,33478,33481,33488,33494,33497,33498,33501,33506,33511,33512,33513,33514,33516,33517,33518,33520,33522,33523,33525,33526,33528,33530,33532,33533,33534,33535,33536,33546,33547,33549,33552,33554,33555,33558,33560,33561,33565,33566,33567,33568,33569,33570,33571,33572,33573,33574,33577,33578,33582,33584,33586,33591,33595,33597,21860,33086,30130,30382,21305,30174,20731,23617,35692,31687,20559,29255,39575,39128,28418,29922,31080,25735,30629,25340,39057,36139,21697,32856,20050,22378,33529,33805,24179,20973,29942,35780,23631,22369,27900,39047,23110,30772,39748,36843,31893,21078,25169,38138,20166,33670,33889,33769,33970,22484,26420,22275,26222,28006,35889,26333,28689,26399,27450,26646,25114,22971,19971,20932,28422,26578,27791,20854,26827,22855,27495,30054,23822,33040,40784,26071,31048,31041,39569,36215,23682,20062,20225,21551,22865,30732,22120,27668,36804,24323,27773,27875,35755,25488,33598,33599,33601,33602,33604,33605,33608,33610,33611,33612,33613,33614,33619,33621,33622,33623,33624,33625,33629,33634,33648,33649,33650,33651,33652,33653,33654,33657,33658,33662,33663,33664,33665,33666,33667,33668,33671,33672,33674,33675,33676,33677,33679,33680,33681,33684,33685,33686,33687,33689,33690,33693,33695,33697,33698,33699,33700,33701,33702,33703,33708,33709,33710,33711,33717,33723,33726,33727,33730,33731,33732,33734,33736,33737,33739,33741,33742,33744,33745,33746,33747,33749,33751,33753,33754,33755,33758,33762,33763,33764,33766,33767,33768,33771,33772,33773,24688,27965,29301,25190,38030,38085,21315,36801,31614,20191,35878,20094,40660,38065,38067,21069,28508,36963,27973,35892,22545,23884,27424,27465,26538,21595,33108,32652,22681,34103,24378,25250,27207,38201,25970,24708,26725,30631,20052,20392,24039,38808,25772,32728,23789,20431,31373,20999,33540,19988,24623,31363,38054,20405,20146,31206,29748,21220,33465,25810,31165,23517,27777,38738,36731,27682,20542,21375,28165,25806,26228,27696,24773,39031,35831,24198,29756,31351,31179,19992,37041,29699,27714,22234,37195,27845,36235,21306,34502,26354,36527,23624,39537,28192,33774,33775,33779,33780,33781,33782,33783,33786,33787,33788,33790,33791,33792,33794,33797,33799,33800,33801,33802,33808,33810,33811,33812,33813,33814,33815,33817,33818,33819,33822,33823,33824,33825,33826,33827,33833,33834,33835,33836,33837,33838,33839,33840,33842,33843,33844,33845,33846,33847,33849,33850,33851,33854,33855,33856,33857,33858,33859,33860,33861,33863,33864,33865,33866,33867,33868,33869,33870,33871,33872,33874,33875,33876,33877,33878,33880,33885,33886,33887,33888,33890,33892,33893,33894,33895,33896,33898,33902,33903,33904,33906,33908,33911,33913,33915,33916,21462,23094,40843,36259,21435,22280,39079,26435,37275,27849,20840,30154,25331,29356,21048,21149,32570,28820,30264,21364,40522,27063,30830,38592,35033,32676,28982,29123,20873,26579,29924,22756,25880,22199,35753,39286,25200,32469,24825,28909,22764,20161,20154,24525,38887,20219,35748,20995,22922,32427,25172,20173,26085,25102,33592,33993,33635,34701,29076,28342,23481,32466,20887,25545,26580,32905,33593,34837,20754,23418,22914,36785,20083,27741,20837,35109,36719,38446,34122,29790,38160,38384,28070,33509,24369,25746,27922,33832,33134,40131,22622,36187,19977,21441,33917,33918,33919,33920,33921,33923,33924,33925,33926,33930,33933,33935,33936,33937,33938,33939,33940,33941,33942,33944,33946,33947,33949,33950,33951,33952,33954,33955,33956,33957,33958,33959,33960,33961,33962,33963,33964,33965,33966,33968,33969,33971,33973,33974,33975,33979,33980,33982,33984,33986,33987,33989,33990,33991,33992,33995,33996,33998,33999,34002,34004,34005,34007,34008,34009,34010,34011,34012,34014,34017,34018,34020,34023,34024,34025,34026,34027,34029,34030,34031,34033,34034,34035,34036,34037,34038,34039,34040,34041,34042,34043,34045,34046,34048,34049,34050,20254,25955,26705,21971,20007,25620,39578,25195,23234,29791,33394,28073,26862,20711,33678,30722,26432,21049,27801,32433,20667,21861,29022,31579,26194,29642,33515,26441,23665,21024,29053,34923,38378,38485,25797,36193,33203,21892,27733,25159,32558,22674,20260,21830,36175,26188,19978,23578,35059,26786,25422,31245,28903,33421,21242,38902,23569,21736,37045,32461,22882,36170,34503,33292,33293,36198,25668,23556,24913,28041,31038,35774,30775,30003,21627,20280,36523,28145,23072,32453,31070,27784,23457,23158,29978,32958,24910,28183,22768,29983,29989,29298,21319,32499,34051,34052,34053,34054,34055,34056,34057,34058,34059,34061,34062,34063,34064,34066,34068,34069,34070,34072,34073,34075,34076,34077,34078,34080,34082,34083,34084,34085,34086,34087,34088,34089,34090,34093,34094,34095,34096,34097,34098,34099,34100,34101,34102,34110,34111,34112,34113,34114,34116,34117,34118,34119,34123,34124,34125,34126,34127,34128,34129,34130,34131,34132,34133,34135,34136,34138,34139,34140,34141,34143,34144,34145,34146,34147,34149,34150,34151,34153,34154,34155,34156,34157,34158,34159,34160,34161,34163,34165,34166,34167,34168,34172,34173,34175,34176,34177,30465,30427,21097,32988,22307,24072,22833,29422,26045,28287,35799,23608,34417,21313,30707,25342,26102,20160,39135,34432,23454,35782,21490,30690,20351,23630,39542,22987,24335,31034,22763,19990,26623,20107,25325,35475,36893,21183,26159,21980,22124,36866,20181,20365,37322,39280,27663,24066,24643,23460,35270,35797,25910,25163,39318,23432,23551,25480,21806,21463,30246,20861,34092,26530,26803,27530,25234,36755,21460,33298,28113,30095,20070,36174,23408,29087,34223,26257,26329,32626,34560,40653,40736,23646,26415,36848,26641,26463,25101,31446,22661,24246,25968,28465,34178,34179,34182,34184,34185,34186,34187,34188,34189,34190,34192,34193,34194,34195,34196,34197,34198,34199,34200,34201,34202,34205,34206,34207,34208,34209,34210,34211,34213,34214,34215,34217,34219,34220,34221,34225,34226,34227,34228,34229,34230,34232,34234,34235,34236,34237,34238,34239,34240,34242,34243,34244,34245,34246,34247,34248,34250,34251,34252,34253,34254,34257,34258,34260,34262,34263,34264,34265,34266,34267,34269,34270,34271,34272,34273,34274,34275,34277,34278,34279,34280,34282,34283,34284,34285,34286,34287,34288,34289,34290,34291,34292,34293,34294,34295,34296,24661,21047,32781,25684,34928,29993,24069,26643,25332,38684,21452,29245,35841,27700,30561,31246,21550,30636,39034,33308,35828,30805,26388,28865,26031,25749,22070,24605,31169,21496,19997,27515,32902,23546,21987,22235,20282,20284,39282,24051,26494,32824,24578,39042,36865,23435,35772,35829,25628,33368,25822,22013,33487,37221,20439,32032,36895,31903,20723,22609,28335,23487,35785,32899,37240,33948,31639,34429,38539,38543,32485,39635,30862,23681,31319,36930,38567,31071,23385,25439,31499,34001,26797,21766,32553,29712,32034,38145,25152,22604,20182,23427,22905,22612,34297,34298,34300,34301,34302,34304,34305,34306,34307,34308,34310,34311,34312,34313,34314,34315,34316,34317,34318,34319,34320,34322,34323,34324,34325,34327,34328,34329,34330,34331,34332,34333,34334,34335,34336,34337,34338,34339,34340,34341,34342,34344,34346,34347,34348,34349,34350,34351,34352,34353,34354,34355,34356,34357,34358,34359,34361,34362,34363,34365,34366,34367,34368,34369,34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34386,34387,34389,34390,34391,34392,34393,34395,34396,34397,34399,34400,34401,34403,34404,34405,34406,34407,34408,34409,34410,29549,25374,36427,36367,32974,33492,25260,21488,27888,37214,22826,24577,27760,22349,25674,36138,30251,28393,22363,27264,30192,28525,35885,35848,22374,27631,34962,30899,25506,21497,28845,27748,22616,25642,22530,26848,33179,21776,31958,20504,36538,28108,36255,28907,25487,28059,28372,32486,33796,26691,36867,28120,38518,35752,22871,29305,34276,33150,30140,35466,26799,21076,36386,38161,25552,39064,36420,21884,20307,26367,22159,24789,28053,21059,23625,22825,28155,22635,30000,29980,24684,33300,33094,25361,26465,36834,30522,36339,36148,38081,24086,21381,21548,28867,34413,34415,34416,34418,34419,34420,34421,34422,34423,34424,34435,34436,34437,34438,34439,34440,34441,34446,34447,34448,34449,34450,34452,34454,34455,34456,34457,34458,34459,34462,34463,34464,34465,34466,34469,34470,34475,34477,34478,34482,34483,34487,34488,34489,34491,34492,34493,34494,34495,34497,34498,34499,34501,34504,34508,34509,34514,34515,34517,34518,34519,34522,34524,34525,34528,34529,34530,34531,34533,34534,34535,34536,34538,34539,34540,34543,34549,34550,34551,34554,34555,34556,34557,34559,34561,34564,34565,34566,34571,34572,34574,34575,34576,34577,34580,34582,27712,24311,20572,20141,24237,25402,33351,36890,26704,37230,30643,21516,38108,24420,31461,26742,25413,31570,32479,30171,20599,25237,22836,36879,20984,31171,31361,22270,24466,36884,28034,23648,22303,21520,20820,28237,22242,25512,39059,33151,34581,35114,36864,21534,23663,33216,25302,25176,33073,40501,38464,39534,39548,26925,22949,25299,21822,25366,21703,34521,27964,23043,29926,34972,27498,22806,35916,24367,28286,29609,39037,20024,28919,23436,30871,25405,26202,30358,24779,23451,23113,19975,33109,27754,29579,20129,26505,32593,24448,26106,26395,24536,22916,23041,34585,34587,34589,34591,34592,34596,34598,34599,34600,34602,34603,34604,34605,34607,34608,34610,34611,34613,34614,34616,34617,34618,34620,34621,34624,34625,34626,34627,34628,34629,34630,34634,34635,34637,34639,34640,34641,34642,34644,34645,34646,34648,34650,34651,34652,34653,34654,34655,34657,34658,34662,34663,34664,34665,34666,34667,34668,34669,34671,34673,34674,34675,34677,34679,34680,34681,34682,34687,34688,34689,34692,34694,34695,34697,34698,34700,34702,34703,34704,34705,34706,34708,34709,34710,34712,34713,34714,34715,34716,34717,34718,34720,34721,34722,34723,34724,24013,24494,21361,38886,36829,26693,22260,21807,24799,20026,28493,32500,33479,33806,22996,20255,20266,23614,32428,26410,34074,21619,30031,32963,21890,39759,20301,28205,35859,23561,24944,21355,30239,28201,34442,25991,38395,32441,21563,31283,32010,38382,21985,32705,29934,25373,34583,28065,31389,25105,26017,21351,25569,27779,24043,21596,38056,20044,27745,35820,23627,26080,33436,26791,21566,21556,27595,27494,20116,25410,21320,33310,20237,20398,22366,25098,38654,26212,29289,21247,21153,24735,35823,26132,29081,26512,35199,30802,30717,26224,22075,21560,38177,29306,34725,34726,34727,34729,34730,34734,34736,34737,34738,34740,34742,34743,34744,34745,34747,34748,34750,34751,34753,34754,34755,34756,34757,34759,34760,34761,34764,34765,34766,34767,34768,34772,34773,34774,34775,34776,34777,34778,34780,34781,34782,34783,34785,34786,34787,34788,34790,34791,34792,34793,34795,34796,34797,34799,34800,34801,34802,34803,34804,34805,34806,34807,34808,34810,34811,34812,34813,34815,34816,34817,34818,34820,34821,34822,34823,34824,34825,34827,34828,34829,34830,34831,34832,34833,34834,34836,34839,34840,34841,34842,34844,34845,34846,34847,34848,34851,31232,24687,24076,24713,33181,22805,24796,29060,28911,28330,27728,29312,27268,34989,24109,20064,23219,21916,38115,27927,31995,38553,25103,32454,30606,34430,21283,38686,36758,26247,23777,20384,29421,19979,21414,22799,21523,25472,38184,20808,20185,40092,32420,21688,36132,34900,33335,38386,28046,24358,23244,26174,38505,29616,29486,21439,33146,39301,32673,23466,38519,38480,32447,30456,21410,38262,39321,31665,35140,28248,20065,32724,31077,35814,24819,21709,20139,39033,24055,27233,20687,21521,35937,33831,30813,38660,21066,21742,22179,38144,28040,23477,28102,26195,34852,34853,34854,34855,34856,34857,34858,34859,34860,34861,34862,34863,34864,34865,34867,34868,34869,34870,34871,34872,34874,34875,34877,34878,34879,34881,34882,34883,34886,34887,34888,34889,34890,34891,34894,34895,34896,34897,34898,34899,34901,34902,34904,34906,34907,34908,34909,34910,34911,34912,34918,34919,34922,34925,34927,34929,34931,34932,34933,34934,34936,34937,34938,34939,34940,34944,34947,34950,34951,34953,34954,34956,34958,34959,34960,34961,34963,34964,34965,34967,34968,34969,34970,34971,34973,34974,34975,34976,34977,34979,34981,34982,34983,34984,34985,34986,23567,23389,26657,32918,21880,31505,25928,26964,20123,27463,34638,38795,21327,25375,25658,37034,26012,32961,35856,20889,26800,21368,34809,25032,27844,27899,35874,23633,34218,33455,38156,27427,36763,26032,24571,24515,20449,34885,26143,33125,29481,24826,20852,21009,22411,24418,37026,34892,37266,24184,26447,24615,22995,20804,20982,33016,21256,27769,38596,29066,20241,20462,32670,26429,21957,38152,31168,34966,32483,22687,25100,38656,34394,22040,39035,24464,35768,33988,37207,21465,26093,24207,30044,24676,32110,23167,32490,32493,36713,21927,23459,24748,26059,29572,34988,34990,34991,34992,34994,34995,34996,34997,34998,35000,35001,35002,35003,35005,35006,35007,35008,35011,35012,35015,35016,35018,35019,35020,35021,35023,35024,35025,35027,35030,35031,35034,35035,35036,35037,35038,35040,35041,35046,35047,35049,35050,35051,35052,35053,35054,35055,35058,35061,35062,35063,35066,35067,35069,35071,35072,35073,35075,35076,35077,35078,35079,35080,35081,35083,35084,35085,35086,35087,35089,35092,35093,35094,35095,35096,35100,35101,35102,35103,35104,35106,35107,35108,35110,35111,35112,35113,35116,35117,35118,35119,35121,35122,35123,35125,35127,36873,30307,30505,32474,38772,34203,23398,31348,38634,34880,21195,29071,24490,26092,35810,23547,39535,24033,27529,27739,35757,35759,36874,36805,21387,25276,40486,40493,21568,20011,33469,29273,34460,23830,34905,28079,38597,21713,20122,35766,28937,21693,38409,28895,28153,30416,20005,30740,34578,23721,24310,35328,39068,38414,28814,27839,22852,25513,30524,34893,28436,33395,22576,29141,21388,30746,38593,21761,24422,28976,23476,35866,39564,27523,22830,40495,31207,26472,25196,20335,30113,32650,27915,38451,27687,20208,30162,20859,26679,28478,36992,33136,22934,29814,35128,35129,35130,35131,35132,35133,35134,35135,35136,35138,35139,35141,35142,35143,35144,35145,35146,35147,35148,35149,35150,35151,35152,35153,35154,35155,35156,35157,35158,35159,35160,35161,35162,35163,35164,35165,35168,35169,35170,35171,35172,35173,35175,35176,35177,35178,35179,35180,35181,35182,35183,35184,35185,35186,35187,35188,35189,35190,35191,35192,35193,35194,35196,35197,35198,35200,35202,35204,35205,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217,35218,35219,35220,35221,35222,35223,35224,35225,35226,35227,35228,35229,35230,35231,35232,35233,25671,23591,36965,31377,35875,23002,21676,33280,33647,35201,32768,26928,22094,32822,29239,37326,20918,20063,39029,25494,19994,21494,26355,33099,22812,28082,19968,22777,21307,25558,38129,20381,20234,34915,39056,22839,36951,31227,20202,33008,30097,27778,23452,23016,24413,26885,34433,20506,24050,20057,30691,20197,33402,25233,26131,37009,23673,20159,24441,33222,36920,32900,30123,20134,35028,24847,27589,24518,20041,30410,28322,35811,35758,35850,35793,24322,32764,32716,32462,33589,33643,22240,27575,38899,38452,23035,21535,38134,28139,23493,39278,23609,24341,38544,35234,35235,35236,35237,35238,35239,35240,35241,35242,35243,35244,35245,35246,35247,35248,35249,35250,35251,35252,35253,35254,35255,35256,35257,35258,35259,35260,35261,35262,35263,35264,35267,35277,35283,35284,35285,35287,35288,35289,35291,35293,35295,35296,35297,35298,35300,35303,35304,35305,35306,35308,35309,35310,35312,35313,35314,35316,35317,35318,35319,35320,35321,35322,35323,35324,35325,35326,35327,35329,35330,35331,35332,35333,35334,35336,35337,35338,35339,35340,35341,35342,35343,35344,35345,35346,35347,35348,35349,35350,35351,35352,35353,35354,35355,35356,35357,21360,33521,27185,23156,40560,24212,32552,33721,33828,33829,33639,34631,36814,36194,30408,24433,39062,30828,26144,21727,25317,20323,33219,30152,24248,38605,36362,34553,21647,27891,28044,27704,24703,21191,29992,24189,20248,24736,24551,23588,30001,37038,38080,29369,27833,28216,37193,26377,21451,21491,20305,37321,35825,21448,24188,36802,28132,20110,30402,27014,34398,24858,33286,20313,20446,36926,40060,24841,28189,28180,38533,20104,23089,38632,19982,23679,31161,23431,35821,32701,29577,22495,33419,37057,21505,36935,21947,23786,24481,24840,27442,29425,32946,35465,35358,35359,35360,35361,35362,35363,35364,35365,35366,35367,35368,35369,35370,35371,35372,35373,35374,35375,35376,35377,35378,35379,35380,35381,35382,35383,35384,35385,35386,35387,35388,35389,35391,35392,35393,35394,35395,35396,35397,35398,35399,35401,35402,35403,35404,35405,35406,35407,35408,35409,35410,35411,35412,35413,35414,35415,35416,35417,35418,35419,35420,35421,35422,35423,35424,35425,35426,35427,35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,35450,35451,35452,35453,35454,35455,35456,28020,23507,35029,39044,35947,39533,40499,28170,20900,20803,22435,34945,21407,25588,36757,22253,21592,22278,29503,28304,32536,36828,33489,24895,24616,38498,26352,32422,36234,36291,38053,23731,31908,26376,24742,38405,32792,20113,37095,21248,38504,20801,36816,34164,37213,26197,38901,23381,21277,30776,26434,26685,21705,28798,23472,36733,20877,22312,21681,25874,26242,36190,36163,33039,33900,36973,31967,20991,34299,26531,26089,28577,34468,36481,22122,36896,30338,28790,29157,36131,25321,21017,27901,36156,24590,22686,24974,26366,36192,25166,21939,28195,26413,36711,35457,35458,35459,35460,35461,35462,35463,35464,35467,35468,35469,35470,35471,35472,35473,35474,35476,35477,35478,35479,35480,35481,35482,35483,35484,35485,35486,35487,35488,35489,35490,35491,35492,35493,35494,35495,35496,35497,35498,35499,35500,35501,35502,35503,35504,35505,35506,35507,35508,35509,35510,35511,35512,35513,35514,35515,35516,35517,35518,35519,35520,35521,35522,35523,35524,35525,35526,35527,35528,35529,35530,35531,35532,35533,35534,35535,35536,35537,35538,35539,35540,35541,35542,35543,35544,35545,35546,35547,35548,35549,35550,35551,35552,35553,35554,35555,38113,38392,30504,26629,27048,21643,20045,28856,35784,25688,25995,23429,31364,20538,23528,30651,27617,35449,31896,27838,30415,26025,36759,23853,23637,34360,26632,21344,25112,31449,28251,32509,27167,31456,24432,28467,24352,25484,28072,26454,19976,24080,36134,20183,32960,30260,38556,25307,26157,25214,27836,36213,29031,32617,20806,32903,21484,36974,25240,21746,34544,36761,32773,38167,34071,36825,27993,29645,26015,30495,29956,30759,33275,36126,38024,20390,26517,30137,35786,38663,25391,38215,38453,33976,25379,30529,24449,29424,20105,24596,25972,25327,27491,25919,35556,35557,35558,35559,35560,35561,35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573,35574,35575,35576,35577,35578,35579,35580,35581,35582,35583,35584,35585,35586,35587,35588,35589,35590,35592,35593,35594,35595,35596,35597,35598,35599,35600,35601,35602,35603,35604,35605,35606,35607,35608,35609,35610,35611,35612,35613,35614,35615,35616,35617,35618,35619,35620,35621,35623,35624,35625,35626,35627,35628,35629,35630,35631,35632,35633,35634,35635,35636,35637,35638,35639,35640,35641,35642,35643,35644,35645,35646,35647,35648,35649,35650,35651,35652,35653,24103,30151,37073,35777,33437,26525,25903,21553,34584,30693,32930,33026,27713,20043,32455,32844,30452,26893,27542,25191,20540,20356,22336,25351,27490,36286,21482,26088,32440,24535,25370,25527,33267,33268,32622,24092,23769,21046,26234,31209,31258,36136,28825,30164,28382,27835,31378,20013,30405,24544,38047,34935,32456,31181,32959,37325,20210,20247,33311,21608,24030,27954,35788,31909,36724,32920,24090,21650,30385,23449,26172,39588,29664,26666,34523,26417,29482,35832,35803,36880,31481,28891,29038,25284,30633,22065,20027,33879,26609,21161,34496,36142,38136,31569,35654,35655,35656,35657,35658,35659,35660,35661,35662,35663,35664,35665,35666,35667,35668,35669,35670,35671,35672,35673,35674,35675,35676,35677,35678,35679,35680,35681,35682,35683,35684,35685,35687,35688,35689,35690,35691,35693,35694,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706,35707,35708,35709,35710,35711,35712,35713,35714,35715,35716,35717,35718,35719,35720,35721,35722,35723,35724,35725,35726,35727,35728,35729,35730,35731,35732,35733,35734,35735,35736,35737,35738,35739,35740,35741,35742,35743,35756,35761,35771,35783,35792,35818,35849,35870,20303,27880,31069,39547,25235,29226,25341,19987,30742,36716,25776,36186,31686,26729,24196,35013,22918,25758,22766,29366,26894,38181,36861,36184,22368,32512,35846,20934,25417,25305,21331,26700,29730,33537,37196,21828,30528,28796,27978,20857,21672,36164,23039,28363,28100,23388,32043,20180,31869,28371,23376,33258,28173,23383,39683,26837,36394,23447,32508,24635,32437,37049,36208,22863,25549,31199,36275,21330,26063,31062,35781,38459,32452,38075,32386,22068,37257,26368,32618,23562,36981,26152,24038,20304,26590,20570,20316,22352,24231,59408,59409,59410,59411,59412,35896,35897,35898,35899,35900,35901,35902,35903,35904,35906,35907,35908,35909,35912,35914,35915,35917,35918,35919,35920,35921,35922,35923,35924,35926,35927,35928,35929,35931,35932,35933,35934,35935,35936,35939,35940,35941,35942,35943,35944,35945,35948,35949,35950,35951,35952,35953,35954,35956,35957,35958,35959,35963,35964,35965,35966,35967,35968,35969,35971,35972,35974,35975,35976,35979,35981,35982,35983,35984,35985,35986,35987,35989,35990,35991,35993,35994,35995,35996,35997,35998,35999,36000,36001,36002,36003,36004,36005,36006,36007,36008,36009,36010,36011,36012,36013,20109,19980,20800,19984,24319,21317,19989,20120,19998,39730,23404,22121,20008,31162,20031,21269,20039,22829,29243,21358,27664,22239,32996,39319,27603,30590,40727,20022,20127,40720,20060,20073,20115,33416,23387,21868,22031,20164,21389,21405,21411,21413,21422,38757,36189,21274,21493,21286,21294,21310,36188,21350,21347,20994,21000,21006,21037,21043,21055,21056,21068,21086,21089,21084,33967,21117,21122,21121,21136,21139,20866,32596,20155,20163,20169,20162,20200,20193,20203,20190,20251,20211,20258,20324,20213,20261,20263,20233,20267,20318,20327,25912,20314,20317,36014,36015,36016,36017,36018,36019,36020,36021,36022,36023,36024,36025,36026,36027,36028,36029,36030,36031,36032,36033,36034,36035,36036,36037,36038,36039,36040,36041,36042,36043,36044,36045,36046,36047,36048,36049,36050,36051,36052,36053,36054,36055,36056,36057,36058,36059,36060,36061,36062,36063,36064,36065,36066,36067,36068,36069,36070,36071,36072,36073,36074,36075,36076,36077,36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089,36090,36091,36092,36093,36094,36095,36096,36097,36098,36099,36100,36101,36102,36103,36104,36105,36106,36107,36108,36109,20319,20311,20274,20285,20342,20340,20369,20361,20355,20367,20350,20347,20394,20348,20396,20372,20454,20456,20458,20421,20442,20451,20444,20433,20447,20472,20521,20556,20467,20524,20495,20526,20525,20478,20508,20492,20517,20520,20606,20547,20565,20552,20558,20588,20603,20645,20647,20649,20666,20694,20742,20717,20716,20710,20718,20743,20747,20189,27709,20312,20325,20430,40864,27718,31860,20846,24061,40649,39320,20865,22804,21241,21261,35335,21264,20971,22809,20821,20128,20822,20147,34926,34980,20149,33044,35026,31104,23348,34819,32696,20907,20913,20925,20924,36110,36111,36112,36113,36114,36115,36116,36117,36118,36119,36120,36121,36122,36123,36124,36128,36177,36178,36183,36191,36197,36200,36201,36202,36204,36206,36207,36209,36210,36216,36217,36218,36219,36220,36221,36222,36223,36224,36226,36227,36230,36231,36232,36233,36236,36237,36238,36239,36240,36242,36243,36245,36246,36247,36248,36249,36250,36251,36252,36253,36254,36256,36257,36258,36260,36261,36262,36263,36264,36265,36266,36267,36268,36269,36270,36271,36272,36274,36278,36279,36281,36283,36285,36288,36289,36290,36293,36295,36296,36297,36298,36301,36304,36306,36307,36308,20935,20886,20898,20901,35744,35750,35751,35754,35764,35765,35767,35778,35779,35787,35791,35790,35794,35795,35796,35798,35800,35801,35804,35807,35808,35812,35816,35817,35822,35824,35827,35830,35833,35836,35839,35840,35842,35844,35847,35852,35855,35857,35858,35860,35861,35862,35865,35867,35864,35869,35871,35872,35873,35877,35879,35882,35883,35886,35887,35890,35891,35893,35894,21353,21370,38429,38434,38433,38449,38442,38461,38460,38466,38473,38484,38495,38503,38508,38514,38516,38536,38541,38551,38576,37015,37019,37021,37017,37036,37025,37044,37043,37046,37050,36309,36312,36313,36316,36320,36321,36322,36325,36326,36327,36329,36333,36334,36336,36337,36338,36340,36342,36348,36350,36351,36352,36353,36354,36355,36356,36358,36359,36360,36363,36365,36366,36368,36369,36370,36371,36373,36374,36375,36376,36377,36378,36379,36380,36384,36385,36388,36389,36390,36391,36392,36395,36397,36400,36402,36403,36404,36406,36407,36408,36411,36412,36414,36415,36419,36421,36422,36428,36429,36430,36431,36432,36435,36436,36437,36438,36439,36440,36442,36443,36444,36445,36446,36447,36448,36449,36450,36451,36452,36453,36455,36456,36458,36459,36462,36465,37048,37040,37071,37061,37054,37072,37060,37063,37075,37094,37090,37084,37079,37083,37099,37103,37118,37124,37154,37150,37155,37169,37167,37177,37187,37190,21005,22850,21154,21164,21165,21182,21759,21200,21206,21232,21471,29166,30669,24308,20981,20988,39727,21430,24321,30042,24047,22348,22441,22433,22654,22716,22725,22737,22313,22316,22314,22323,22329,22318,22319,22364,22331,22338,22377,22405,22379,22406,22396,22395,22376,22381,22390,22387,22445,22436,22412,22450,22479,22439,22452,22419,22432,22485,22488,22490,22489,22482,22456,22516,22511,22520,22500,22493,36467,36469,36471,36472,36473,36474,36475,36477,36478,36480,36482,36483,36484,36486,36488,36489,36490,36491,36492,36493,36494,36497,36498,36499,36501,36502,36503,36504,36505,36506,36507,36509,36511,36512,36513,36514,36515,36516,36517,36518,36519,36520,36521,36522,36525,36526,36528,36529,36531,36532,36533,36534,36535,36536,36537,36539,36540,36541,36542,36543,36544,36545,36546,36547,36548,36549,36550,36551,36552,36553,36554,36555,36556,36557,36559,36560,36561,36562,36563,36564,36565,36566,36567,36568,36569,36570,36571,36572,36573,36574,36575,36576,36577,36578,36579,36580,22539,22541,22525,22509,22528,22558,22553,22596,22560,22629,22636,22657,22665,22682,22656,39336,40729,25087,33401,33405,33407,33423,33418,33448,33412,33422,33425,33431,33433,33451,33464,33470,33456,33480,33482,33507,33432,33463,33454,33483,33484,33473,33449,33460,33441,33450,33439,33476,33486,33444,33505,33545,33527,33508,33551,33543,33500,33524,33490,33496,33548,33531,33491,33553,33562,33542,33556,33557,33504,33493,33564,33617,33627,33628,33544,33682,33596,33588,33585,33691,33630,33583,33615,33607,33603,33631,33600,33559,33632,33581,33594,33587,33638,33637,36581,36582,36583,36584,36585,36586,36587,36588,36589,36590,36591,36592,36593,36594,36595,36596,36597,36598,36599,36600,36601,36602,36603,36604,36605,36606,36607,36608,36609,36610,36611,36612,36613,36614,36615,36616,36617,36618,36619,36620,36621,36622,36623,36624,36625,36626,36627,36628,36629,36630,36631,36632,36633,36634,36635,36636,36637,36638,36639,36640,36641,36642,36643,36644,36645,36646,36647,36648,36649,36650,36651,36652,36653,36654,36655,36656,36657,36658,36659,36660,36661,36662,36663,36664,36665,36666,36667,36668,36669,36670,36671,36672,36673,36674,36675,36676,33640,33563,33641,33644,33642,33645,33646,33712,33656,33715,33716,33696,33706,33683,33692,33669,33660,33718,33705,33661,33720,33659,33688,33694,33704,33722,33724,33729,33793,33765,33752,22535,33816,33803,33757,33789,33750,33820,33848,33809,33798,33748,33759,33807,33795,33784,33785,33770,33733,33728,33830,33776,33761,33884,33873,33882,33881,33907,33927,33928,33914,33929,33912,33852,33862,33897,33910,33932,33934,33841,33901,33985,33997,34000,34022,33981,34003,33994,33983,33978,34016,33953,33977,33972,33943,34021,34019,34060,29965,34104,34032,34105,34079,34106,36677,36678,36679,36680,36681,36682,36683,36684,36685,36686,36687,36688,36689,36690,36691,36692,36693,36694,36695,36696,36697,36698,36699,36700,36701,36702,36703,36704,36705,36706,36707,36708,36709,36714,36736,36748,36754,36765,36768,36769,36770,36772,36773,36774,36775,36778,36780,36781,36782,36783,36786,36787,36788,36789,36791,36792,36794,36795,36796,36799,36800,36803,36806,36809,36810,36811,36812,36813,36815,36818,36822,36823,36826,36832,36833,36835,36839,36844,36847,36849,36850,36852,36853,36854,36858,36859,36860,36862,36863,36871,36872,36876,36878,36883,36885,36888,34134,34107,34047,34044,34137,34120,34152,34148,34142,34170,30626,34115,34162,34171,34212,34216,34183,34191,34169,34222,34204,34181,34233,34231,34224,34259,34241,34268,34303,34343,34309,34345,34326,34364,24318,24328,22844,22849,32823,22869,22874,22872,21263,23586,23589,23596,23604,25164,25194,25247,25275,25290,25306,25303,25326,25378,25334,25401,25419,25411,25517,25590,25457,25466,25486,25524,25453,25516,25482,25449,25518,25532,25586,25592,25568,25599,25540,25566,25550,25682,25542,25534,25669,25665,25611,25627,25632,25612,25638,25633,25694,25732,25709,25750,36889,36892,36899,36900,36901,36903,36904,36905,36906,36907,36908,36912,36913,36914,36915,36916,36919,36921,36922,36925,36927,36928,36931,36933,36934,36936,36937,36938,36939,36940,36942,36948,36949,36950,36953,36954,36956,36957,36958,36959,36960,36961,36964,36966,36967,36969,36970,36971,36972,36975,36976,36977,36978,36979,36982,36983,36984,36985,36986,36987,36988,36990,36993,36996,36997,36998,36999,37001,37002,37004,37005,37006,37007,37008,37010,37012,37014,37016,37018,37020,37022,37023,37024,37028,37029,37031,37032,37033,37035,37037,37042,37047,37052,37053,37055,37056,25722,25783,25784,25753,25786,25792,25808,25815,25828,25826,25865,25893,25902,24331,24530,29977,24337,21343,21489,21501,21481,21480,21499,21522,21526,21510,21579,21586,21587,21588,21590,21571,21537,21591,21593,21539,21554,21634,21652,21623,21617,21604,21658,21659,21636,21622,21606,21661,21712,21677,21698,21684,21714,21671,21670,21715,21716,21618,21667,21717,21691,21695,21708,21721,21722,21724,21673,21674,21668,21725,21711,21726,21787,21735,21792,21757,21780,21747,21794,21795,21775,21777,21799,21802,21863,21903,21941,21833,21869,21825,21845,21823,21840,21820,37058,37059,37062,37064,37065,37067,37068,37069,37074,37076,37077,37078,37080,37081,37082,37086,37087,37088,37091,37092,37093,37097,37098,37100,37102,37104,37105,37106,37107,37109,37110,37111,37113,37114,37115,37116,37119,37120,37121,37123,37125,37126,37127,37128,37129,37130,37131,37132,37133,37134,37135,37136,37137,37138,37139,37140,37141,37142,37143,37144,37146,37147,37148,37149,37151,37152,37153,37156,37157,37158,37159,37160,37161,37162,37163,37164,37165,37166,37168,37170,37171,37172,37173,37174,37175,37176,37178,37179,37180,37181,37182,37183,37184,37185,37186,37188,21815,21846,21877,21878,21879,21811,21808,21852,21899,21970,21891,21937,21945,21896,21889,21919,21886,21974,21905,21883,21983,21949,21950,21908,21913,21994,22007,21961,22047,21969,21995,21996,21972,21990,21981,21956,21999,21989,22002,22003,21964,21965,21992,22005,21988,36756,22046,22024,22028,22017,22052,22051,22014,22016,22055,22061,22104,22073,22103,22060,22093,22114,22105,22108,22092,22100,22150,22116,22129,22123,22139,22140,22149,22163,22191,22228,22231,22237,22241,22261,22251,22265,22271,22276,22282,22281,22300,24079,24089,24084,24081,24113,24123,24124,37189,37191,37192,37201,37203,37204,37205,37206,37208,37209,37211,37212,37215,37216,37222,37223,37224,37227,37229,37235,37242,37243,37244,37248,37249,37250,37251,37252,37254,37256,37258,37262,37263,37267,37268,37269,37270,37271,37272,37273,37276,37277,37278,37279,37280,37281,37284,37285,37286,37287,37288,37289,37291,37292,37296,37297,37298,37299,37302,37303,37304,37305,37307,37308,37309,37310,37311,37312,37313,37314,37315,37316,37317,37318,37320,37323,37328,37330,37331,37332,37333,37334,37335,37336,37337,37338,37339,37341,37342,37343,37344,37345,37346,37347,37348,37349,24119,24132,24148,24155,24158,24161,23692,23674,23693,23696,23702,23688,23704,23705,23697,23706,23708,23733,23714,23741,23724,23723,23729,23715,23745,23735,23748,23762,23780,23755,23781,23810,23811,23847,23846,23854,23844,23838,23814,23835,23896,23870,23860,23869,23916,23899,23919,23901,23915,23883,23882,23913,23924,23938,23961,23965,35955,23991,24005,24435,24439,24450,24455,24457,24460,24469,24473,24476,24488,24493,24501,24508,34914,24417,29357,29360,29364,29367,29368,29379,29377,29390,29389,29394,29416,29423,29417,29426,29428,29431,29441,29427,29443,29434,37350,37351,37352,37353,37354,37355,37356,37357,37358,37359,37360,37361,37362,37363,37364,37365,37366,37367,37368,37369,37370,37371,37372,37373,37374,37375,37376,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37387,37388,37389,37390,37391,37392,37393,37394,37395,37396,37397,37398,37399,37400,37401,37402,37403,37404,37405,37406,37407,37408,37409,37410,37411,37412,37413,37414,37415,37416,37417,37418,37419,37420,37421,37422,37423,37424,37425,37426,37427,37428,37429,37430,37431,37432,37433,37434,37435,37436,37437,37438,37439,37440,37441,37442,37443,37444,37445,29435,29463,29459,29473,29450,29470,29469,29461,29474,29497,29477,29484,29496,29489,29520,29517,29527,29536,29548,29551,29566,33307,22821,39143,22820,22786,39267,39271,39272,39273,39274,39275,39276,39284,39287,39293,39296,39300,39303,39306,39309,39312,39313,39315,39316,39317,24192,24209,24203,24214,24229,24224,24249,24245,24254,24243,36179,24274,24273,24283,24296,24298,33210,24516,24521,24534,24527,24579,24558,24580,24545,24548,24574,24581,24582,24554,24557,24568,24601,24629,24614,24603,24591,24589,24617,24619,24586,24639,24609,24696,24697,24699,24698,24642,37446,37447,37448,37449,37450,37451,37452,37453,37454,37455,37456,37457,37458,37459,37460,37461,37462,37463,37464,37465,37466,37467,37468,37469,37470,37471,37472,37473,37474,37475,37476,37477,37478,37479,37480,37481,37482,37483,37484,37485,37486,37487,37488,37489,37490,37491,37493,37494,37495,37496,37497,37498,37499,37500,37501,37502,37503,37504,37505,37506,37507,37508,37509,37510,37511,37512,37513,37514,37515,37516,37517,37519,37520,37521,37522,37523,37524,37525,37526,37527,37528,37529,37530,37531,37532,37533,37534,37535,37536,37537,37538,37539,37540,37541,37542,37543,24682,24701,24726,24730,24749,24733,24707,24722,24716,24731,24812,24763,24753,24797,24792,24774,24794,24756,24864,24870,24853,24867,24820,24832,24846,24875,24906,24949,25004,24980,24999,25015,25044,25077,24541,38579,38377,38379,38385,38387,38389,38390,38396,38398,38403,38404,38406,38408,38410,38411,38412,38413,38415,38418,38421,38422,38423,38425,38426,20012,29247,25109,27701,27732,27740,27722,27811,27781,27792,27796,27788,27752,27753,27764,27766,27782,27817,27856,27860,27821,27895,27896,27889,27863,27826,27872,27862,27898,27883,27886,27825,27859,27887,27902,37544,37545,37546,37547,37548,37549,37551,37552,37553,37554,37555,37556,37557,37558,37559,37560,37561,37562,37563,37564,37565,37566,37567,37568,37569,37570,37571,37572,37573,37574,37575,37577,37578,37579,37580,37581,37582,37583,37584,37585,37586,37587,37588,37589,37590,37591,37592,37593,37594,37595,37596,37597,37598,37599,37600,37601,37602,37603,37604,37605,37606,37607,37608,37609,37610,37611,37612,37613,37614,37615,37616,37617,37618,37619,37620,37621,37622,37623,37624,37625,37626,37627,37628,37629,37630,37631,37632,37633,37634,37635,37636,37637,37638,37639,37640,37641,27961,27943,27916,27971,27976,27911,27908,27929,27918,27947,27981,27950,27957,27930,27983,27986,27988,27955,28049,28015,28062,28064,27998,28051,28052,27996,28000,28028,28003,28186,28103,28101,28126,28174,28095,28128,28177,28134,28125,28121,28182,28075,28172,28078,28203,28270,28238,28267,28338,28255,28294,28243,28244,28210,28197,28228,28383,28337,28312,28384,28461,28386,28325,28327,28349,28347,28343,28375,28340,28367,28303,28354,28319,28514,28486,28487,28452,28437,28409,28463,28470,28491,28532,28458,28425,28457,28553,28557,28556,28536,28530,28540,28538,28625,37642,37643,37644,37645,37646,37647,37648,37649,37650,37651,37652,37653,37654,37655,37656,37657,37658,37659,37660,37661,37662,37663,37664,37665,37666,37667,37668,37669,37670,37671,37672,37673,37674,37675,37676,37677,37678,37679,37680,37681,37682,37683,37684,37685,37686,37687,37688,37689,37690,37691,37692,37693,37695,37696,37697,37698,37699,37700,37701,37702,37703,37704,37705,37706,37707,37708,37709,37710,37711,37712,37713,37714,37715,37716,37717,37718,37719,37720,37721,37722,37723,37724,37725,37726,37727,37728,37729,37730,37731,37732,37733,37734,37735,37736,37737,37739,28617,28583,28601,28598,28610,28641,28654,28638,28640,28655,28698,28707,28699,28729,28725,28751,28766,23424,23428,23445,23443,23461,23480,29999,39582,25652,23524,23534,35120,23536,36423,35591,36790,36819,36821,36837,36846,36836,36841,36838,36851,36840,36869,36868,36875,36902,36881,36877,36886,36897,36917,36918,36909,36911,36932,36945,36946,36944,36968,36952,36962,36955,26297,36980,36989,36994,37000,36995,37003,24400,24407,24406,24408,23611,21675,23632,23641,23409,23651,23654,32700,24362,24361,24365,33396,24380,39739,23662,22913,22915,22925,22953,22954,22947,37740,37741,37742,37743,37744,37745,37746,37747,37748,37749,37750,37751,37752,37753,37754,37755,37756,37757,37758,37759,37760,37761,37762,37763,37764,37765,37766,37767,37768,37769,37770,37771,37772,37773,37774,37776,37777,37778,37779,37780,37781,37782,37783,37784,37785,37786,37787,37788,37789,37790,37791,37792,37793,37794,37795,37796,37797,37798,37799,37800,37801,37802,37803,37804,37805,37806,37807,37808,37809,37810,37811,37812,37813,37814,37815,37816,37817,37818,37819,37820,37821,37822,37823,37824,37825,37826,37827,37828,37829,37830,37831,37832,37833,37835,37836,37837,22935,22986,22955,22942,22948,22994,22962,22959,22999,22974,23045,23046,23005,23048,23011,23000,23033,23052,23049,23090,23092,23057,23075,23059,23104,23143,23114,23125,23100,23138,23157,33004,23210,23195,23159,23162,23230,23275,23218,23250,23252,23224,23264,23267,23281,23254,23270,23256,23260,23305,23319,23318,23346,23351,23360,23573,23580,23386,23397,23411,23377,23379,23394,39541,39543,39544,39546,39551,39549,39552,39553,39557,39560,39562,39568,39570,39571,39574,39576,39579,39580,39581,39583,39584,39586,39587,39589,39591,32415,32417,32419,32421,32424,32425,37838,37839,37840,37841,37842,37843,37844,37845,37847,37848,37849,37850,37851,37852,37853,37854,37855,37856,37857,37858,37859,37860,37861,37862,37863,37864,37865,37866,37867,37868,37869,37870,37871,37872,37873,37874,37875,37876,37877,37878,37879,37880,37881,37882,37883,37884,37885,37886,37887,37888,37889,37890,37891,37892,37893,37894,37895,37896,37897,37898,37899,37900,37901,37902,37903,37904,37905,37906,37907,37908,37909,37910,37911,37912,37913,37914,37915,37916,37917,37918,37919,37920,37921,37922,37923,37924,37925,37926,37927,37928,37929,37930,37931,37932,37933,37934,32429,32432,32446,32448,32449,32450,32457,32459,32460,32464,32468,32471,32475,32480,32481,32488,32491,32494,32495,32497,32498,32525,32502,32506,32507,32510,32513,32514,32515,32519,32520,32523,32524,32527,32529,32530,32535,32537,32540,32539,32543,32545,32546,32547,32548,32549,32550,32551,32554,32555,32556,32557,32559,32560,32561,32562,32563,32565,24186,30079,24027,30014,37013,29582,29585,29614,29602,29599,29647,29634,29649,29623,29619,29632,29641,29640,29669,29657,39036,29706,29673,29671,29662,29626,29682,29711,29738,29787,29734,29733,29736,29744,29742,29740,37935,37936,37937,37938,37939,37940,37941,37942,37943,37944,37945,37946,37947,37948,37949,37951,37952,37953,37954,37955,37956,37957,37958,37959,37960,37961,37962,37963,37964,37965,37966,37967,37968,37969,37970,37971,37972,37973,37974,37975,37976,37977,37978,37979,37980,37981,37982,37983,37984,37985,37986,37987,37988,37989,37990,37991,37992,37993,37994,37996,37997,37998,37999,38000,38001,38002,38003,38004,38005,38006,38007,38008,38009,38010,38011,38012,38013,38014,38015,38016,38017,38018,38019,38020,38033,38038,38040,38087,38095,38099,38100,38106,38118,38139,38172,38176,29723,29722,29761,29788,29783,29781,29785,29815,29805,29822,29852,29838,29824,29825,29831,29835,29854,29864,29865,29840,29863,29906,29882,38890,38891,38892,26444,26451,26462,26440,26473,26533,26503,26474,26483,26520,26535,26485,26536,26526,26541,26507,26487,26492,26608,26633,26584,26634,26601,26544,26636,26585,26549,26586,26547,26589,26624,26563,26552,26594,26638,26561,26621,26674,26675,26720,26721,26702,26722,26692,26724,26755,26653,26709,26726,26689,26727,26688,26686,26698,26697,26665,26805,26767,26740,26743,26771,26731,26818,26990,26876,26911,26912,26873,38183,38195,38205,38211,38216,38219,38229,38234,38240,38254,38260,38261,38263,38264,38265,38266,38267,38268,38269,38270,38272,38273,38274,38275,38276,38277,38278,38279,38280,38281,38282,38283,38284,38285,38286,38287,38288,38289,38290,38291,38292,38293,38294,38295,38296,38297,38298,38299,38300,38301,38302,38303,38304,38305,38306,38307,38308,38309,38310,38311,38312,38313,38314,38315,38316,38317,38318,38319,38320,38321,38322,38323,38324,38325,38326,38327,38328,38329,38330,38331,38332,38333,38334,38335,38336,38337,38338,38339,38340,38341,38342,38343,38344,38345,38346,38347,26916,26864,26891,26881,26967,26851,26896,26993,26937,26976,26946,26973,27012,26987,27008,27032,27000,26932,27084,27015,27016,27086,27017,26982,26979,27001,27035,27047,27067,27051,27053,27092,27057,27073,27082,27103,27029,27104,27021,27135,27183,27117,27159,27160,27237,27122,27204,27198,27296,27216,27227,27189,27278,27257,27197,27176,27224,27260,27281,27280,27305,27287,27307,29495,29522,27521,27522,27527,27524,27538,27539,27533,27546,27547,27553,27562,36715,36717,36721,36722,36723,36725,36726,36728,36727,36729,36730,36732,36734,36737,36738,36740,36743,36747,38348,38349,38350,38351,38352,38353,38354,38355,38356,38357,38358,38359,38360,38361,38362,38363,38364,38365,38366,38367,38368,38369,38370,38371,38372,38373,38374,38375,38380,38399,38407,38419,38424,38427,38430,38432,38435,38436,38437,38438,38439,38440,38441,38443,38444,38445,38447,38448,38455,38456,38457,38458,38462,38465,38467,38474,38478,38479,38481,38482,38483,38486,38487,38488,38489,38490,38492,38493,38494,38496,38499,38501,38502,38507,38509,38510,38511,38512,38513,38515,38520,38521,38522,38523,38524,38525,38526,38527,38528,38529,38530,38531,38532,38535,38537,38538,36749,36750,36751,36760,36762,36558,25099,25111,25115,25119,25122,25121,25125,25124,25132,33255,29935,29940,29951,29967,29969,29971,25908,26094,26095,26096,26122,26137,26482,26115,26133,26112,28805,26359,26141,26164,26161,26166,26165,32774,26207,26196,26177,26191,26198,26209,26199,26231,26244,26252,26279,26269,26302,26331,26332,26342,26345,36146,36147,36150,36155,36157,36160,36165,36166,36168,36169,36167,36173,36181,36185,35271,35274,35275,35276,35278,35279,35280,35281,29294,29343,29277,29286,29295,29310,29311,29316,29323,29325,29327,29330,25352,25394,25520,38540,38542,38545,38546,38547,38549,38550,38554,38555,38557,38558,38559,38560,38561,38562,38563,38564,38565,38566,38568,38569,38570,38571,38572,38573,38574,38575,38577,38578,38580,38581,38583,38584,38586,38587,38591,38594,38595,38600,38602,38603,38608,38609,38611,38612,38614,38615,38616,38617,38618,38619,38620,38621,38622,38623,38625,38626,38627,38628,38629,38630,38631,38635,38636,38637,38638,38640,38641,38642,38644,38645,38648,38650,38651,38652,38653,38655,38658,38659,38661,38666,38667,38668,38672,38673,38674,38676,38677,38679,38680,38681,38682,38683,38685,38687,38688,25663,25816,32772,27626,27635,27645,27637,27641,27653,27655,27654,27661,27669,27672,27673,27674,27681,27689,27684,27690,27698,25909,25941,25963,29261,29266,29270,29232,34402,21014,32927,32924,32915,32956,26378,32957,32945,32939,32941,32948,32951,32999,33000,33001,33002,32987,32962,32964,32985,32973,32983,26384,32989,33003,33009,33012,33005,33037,33038,33010,33020,26389,33042,35930,33078,33054,33068,33048,33074,33096,33100,33107,33140,33113,33114,33137,33120,33129,33148,33149,33133,33127,22605,23221,33160,33154,33169,28373,33187,33194,33228,26406,33226,33211,38689,38690,38691,38692,38693,38694,38695,38696,38697,38699,38700,38702,38703,38705,38707,38708,38709,38710,38711,38714,38715,38716,38717,38719,38720,38721,38722,38723,38724,38725,38726,38727,38728,38729,38730,38731,38732,38733,38734,38735,38736,38737,38740,38741,38743,38744,38746,38748,38749,38751,38755,38756,38758,38759,38760,38762,38763,38764,38765,38766,38767,38768,38769,38770,38773,38775,38776,38777,38778,38779,38781,38782,38783,38784,38785,38786,38787,38788,38790,38791,38792,38793,38794,38796,38798,38799,38800,38803,38805,38806,38807,38809,38810,38811,38812,38813,33217,33190,27428,27447,27449,27459,27462,27481,39121,39122,39123,39125,39129,39130,27571,24384,27586,35315,26000,40785,26003,26044,26054,26052,26051,26060,26062,26066,26070,28800,28828,28822,28829,28859,28864,28855,28843,28849,28904,28874,28944,28947,28950,28975,28977,29043,29020,29032,28997,29042,29002,29048,29050,29080,29107,29109,29096,29088,29152,29140,29159,29177,29213,29224,28780,28952,29030,29113,25150,25149,25155,25160,25161,31035,31040,31046,31049,31067,31068,31059,31066,31074,31063,31072,31087,31079,31098,31109,31114,31130,31143,31155,24529,24528,38814,38815,38817,38818,38820,38821,38822,38823,38824,38825,38826,38828,38830,38832,38833,38835,38837,38838,38839,38840,38841,38842,38843,38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856,38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869,38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882,38883,38884,38885,38888,38894,38895,38896,38897,38898,38900,38903,38904,38905,38906,38907,38908,38909,38910,38911,38912,38913,38914,38915,38916,38917,38918,38919,38920,38921,38922,38923,38924,38925,38926,24636,24669,24666,24679,24641,24665,24675,24747,24838,24845,24925,25001,24989,25035,25041,25094,32896,32895,27795,27894,28156,30710,30712,30720,30729,30743,30744,30737,26027,30765,30748,30749,30777,30778,30779,30751,30780,30757,30764,30755,30761,30798,30829,30806,30807,30758,30800,30791,30796,30826,30875,30867,30874,30855,30876,30881,30883,30898,30905,30885,30932,30937,30921,30956,30962,30981,30964,30995,31012,31006,31028,40859,40697,40699,40700,30449,30468,30477,30457,30471,30472,30490,30498,30489,30509,30502,30517,30520,30544,30545,30535,30531,30554,30568,38927,38928,38929,38930,38931,38932,38933,38934,38935,38936,38937,38938,38939,38940,38941,38942,38943,38944,38945,38946,38947,38948,38949,38950,38951,38952,38953,38954,38955,38956,38957,38958,38959,38960,38961,38962,38963,38964,38965,38966,38967,38968,38969,38970,38971,38972,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982,38983,38984,38985,38986,38987,38988,38989,38990,38991,38992,38993,38994,38995,38996,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39007,39008,39009,39010,39011,39012,39013,39014,39015,39016,39017,39018,39019,39020,39021,39022,30562,30565,30591,30605,30589,30592,30604,30609,30623,30624,30640,30645,30653,30010,30016,30030,30027,30024,30043,30066,30073,30083,32600,32609,32607,35400,32616,32628,32625,32633,32641,32638,30413,30437,34866,38021,38022,38023,38027,38026,38028,38029,38031,38032,38036,38039,38037,38042,38043,38044,38051,38052,38059,38058,38061,38060,38063,38064,38066,38068,38070,38071,38072,38073,38074,38076,38077,38079,38084,38088,38089,38090,38091,38092,38093,38094,38096,38097,38098,38101,38102,38103,38105,38104,38107,38110,38111,38112,38114,38116,38117,38119,38120,38122,39023,39024,39025,39026,39027,39028,39051,39054,39058,39061,39065,39075,39080,39081,39082,39083,39084,39085,39086,39087,39088,39089,39090,39091,39092,39093,39094,39095,39096,39097,39098,39099,39100,39101,39102,39103,39104,39105,39106,39107,39108,39109,39110,39111,39112,39113,39114,39115,39116,39117,39119,39120,39124,39126,39127,39131,39132,39133,39136,39137,39138,39139,39140,39141,39142,39145,39146,39147,39148,39149,39150,39151,39152,39153,39154,39155,39156,39157,39158,39159,39160,39161,39162,39163,39164,39165,39166,39167,39168,39169,39170,39171,39172,39173,39174,39175,38121,38123,38126,38127,38131,38132,38133,38135,38137,38140,38141,38143,38147,38146,38150,38151,38153,38154,38157,38158,38159,38162,38163,38164,38165,38166,38168,38171,38173,38174,38175,38178,38186,38187,38185,38188,38193,38194,38196,38198,38199,38200,38204,38206,38207,38210,38197,38212,38213,38214,38217,38220,38222,38223,38226,38227,38228,38230,38231,38232,38233,38235,38238,38239,38237,38241,38242,38244,38245,38246,38247,38248,38249,38250,38251,38252,38255,38257,38258,38259,38202,30695,30700,38601,31189,31213,31203,31211,31238,23879,31235,31234,31262,31252,39176,39177,39178,39179,39180,39182,39183,39185,39186,39187,39188,39189,39190,39191,39192,39193,39194,39195,39196,39197,39198,39199,39200,39201,39202,39203,39204,39205,39206,39207,39208,39209,39210,39211,39212,39213,39215,39216,39217,39218,39219,39220,39221,39222,39223,39224,39225,39226,39227,39228,39229,39230,39231,39232,39233,39234,39235,39236,39237,39238,39239,39240,39241,39242,39243,39244,39245,39246,39247,39248,39249,39250,39251,39254,39255,39256,39257,39258,39259,39260,39261,39262,39263,39264,39265,39266,39268,39270,39283,39288,39289,39291,39294,39298,39299,39305,31289,31287,31313,40655,39333,31344,30344,30350,30355,30361,30372,29918,29920,29996,40480,40482,40488,40489,40490,40491,40492,40498,40497,40502,40504,40503,40505,40506,40510,40513,40514,40516,40518,40519,40520,40521,40523,40524,40526,40529,40533,40535,40538,40539,40540,40542,40547,40550,40551,40552,40553,40554,40555,40556,40561,40557,40563,30098,30100,30102,30112,30109,30124,30115,30131,30132,30136,30148,30129,30128,30147,30146,30166,30157,30179,30184,30182,30180,30187,30183,30211,30193,30204,30207,30224,30208,30213,30220,30231,30218,30245,30232,30229,30233,39308,39310,39322,39323,39324,39325,39326,39327,39328,39329,39330,39331,39332,39334,39335,39337,39338,39339,39340,39341,39342,39343,39344,39345,39346,39347,39348,39349,39350,39351,39352,39353,39354,39355,39356,39357,39358,39359,39360,39361,39362,39363,39364,39365,39366,39367,39368,39369,39370,39371,39372,39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383,39384,39385,39386,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396,39397,39398,39399,39400,39401,39402,39403,39404,39405,39406,39407,39408,39409,39410,39411,39412,39413,39414,39415,39416,39417,30235,30268,30242,30240,30272,30253,30256,30271,30261,30275,30270,30259,30285,30302,30292,30300,30294,30315,30319,32714,31462,31352,31353,31360,31366,31368,31381,31398,31392,31404,31400,31405,31411,34916,34921,34930,34941,34943,34946,34978,35014,34999,35004,35017,35042,35022,35043,35045,35057,35098,35068,35048,35070,35056,35105,35097,35091,35099,35082,35124,35115,35126,35137,35174,35195,30091,32997,30386,30388,30684,32786,32788,32790,32796,32800,32802,32805,32806,32807,32809,32808,32817,32779,32821,32835,32838,32845,32850,32873,32881,35203,39032,39040,39043,39418,39419,39420,39421,39422,39423,39424,39425,39426,39427,39428,39429,39430,39431,39432,39433,39434,39435,39436,39437,39438,39439,39440,39441,39442,39443,39444,39445,39446,39447,39448,39449,39450,39451,39452,39453,39454,39455,39456,39457,39458,39459,39460,39461,39462,39463,39464,39465,39466,39467,39468,39469,39470,39471,39472,39473,39474,39475,39476,39477,39478,39479,39480,39481,39482,39483,39484,39485,39486,39487,39488,39489,39490,39491,39492,39493,39494,39495,39496,39497,39498,39499,39500,39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39511,39512,39513,39049,39052,39053,39055,39060,39066,39067,39070,39071,39073,39074,39077,39078,34381,34388,34412,34414,34431,34426,34428,34427,34472,34445,34443,34476,34461,34471,34467,34474,34451,34473,34486,34500,34485,34510,34480,34490,34481,34479,34505,34511,34484,34537,34545,34546,34541,34547,34512,34579,34526,34548,34527,34520,34513,34563,34567,34552,34568,34570,34573,34569,34595,34619,34590,34597,34606,34586,34622,34632,34612,34609,34601,34615,34623,34690,34594,34685,34686,34683,34656,34672,34636,34670,34699,34643,34659,34684,34660,34649,34661,34707,34735,34728,34770,39514,39515,39516,39517,39518,39519,39520,39521,39522,39523,39524,39525,39526,39527,39528,39529,39530,39531,39538,39555,39561,39565,39566,39572,39573,39577,39590,39593,39594,39595,39596,39597,39598,39599,39602,39603,39604,39605,39609,39611,39613,39614,39615,39619,39620,39622,39623,39624,39625,39626,39629,39630,39631,39632,39634,39636,39637,39638,39639,39641,39642,39643,39644,39645,39646,39648,39650,39651,39652,39653,39655,39656,39657,39658,39660,39662,39664,39665,39666,39667,39668,39669,39670,39671,39672,39674,39676,39677,39678,39679,39680,39681,39682,39684,39685,39686,34758,34696,34693,34733,34711,34691,34731,34789,34732,34741,34739,34763,34771,34749,34769,34752,34762,34779,34794,34784,34798,34838,34835,34814,34826,34843,34849,34873,34876,32566,32578,32580,32581,33296,31482,31485,31496,31491,31492,31509,31498,31531,31503,31559,31544,31530,31513,31534,31537,31520,31525,31524,31539,31550,31518,31576,31578,31557,31605,31564,31581,31584,31598,31611,31586,31602,31601,31632,31654,31655,31672,31660,31645,31656,31621,31658,31644,31650,31659,31668,31697,31681,31692,31709,31706,31717,31718,31722,31756,31742,31740,31759,31766,31755,39687,39689,39690,39691,39692,39693,39694,39696,39697,39698,39700,39701,39702,39703,39704,39705,39706,39707,39708,39709,39710,39712,39713,39714,39716,39717,39718,39719,39720,39721,39722,39723,39724,39725,39726,39728,39729,39731,39732,39733,39734,39735,39736,39737,39738,39741,39742,39743,39744,39750,39754,39755,39756,39758,39760,39762,39763,39765,39766,39767,39768,39769,39770,39771,39772,39773,39774,39775,39776,39777,39778,39779,39780,39781,39782,39783,39784,39785,39786,39787,39788,39789,39790,39791,39792,39793,39794,39795,39796,39797,39798,39799,39800,39801,39802,39803,31775,31786,31782,31800,31809,31808,33278,33281,33282,33284,33260,34884,33313,33314,33315,33325,33327,33320,33323,33336,33339,33331,33332,33342,33348,33353,33355,33359,33370,33375,33384,34942,34949,34952,35032,35039,35166,32669,32671,32679,32687,32688,32690,31868,25929,31889,31901,31900,31902,31906,31922,31932,31933,31937,31943,31948,31949,31944,31941,31959,31976,33390,26280,32703,32718,32725,32741,32737,32742,32745,32750,32755,31992,32119,32166,32174,32327,32411,40632,40628,36211,36228,36244,36241,36273,36199,36205,35911,35913,37194,37200,37198,37199,37220,39804,39805,39806,39807,39808,39809,39810,39811,39812,39813,39814,39815,39816,39817,39818,39819,39820,39821,39822,39823,39824,39825,39826,39827,39828,39829,39830,39831,39832,39833,39834,39835,39836,39837,39838,39839,39840,39841,39842,39843,39844,39845,39846,39847,39848,39849,39850,39851,39852,39853,39854,39855,39856,39857,39858,39859,39860,39861,39862,39863,39864,39865,39866,39867,39868,39869,39870,39871,39872,39873,39874,39875,39876,39877,39878,39879,39880,39881,39882,39883,39884,39885,39886,39887,39888,39889,39890,39891,39892,39893,39894,39895,39896,39897,39898,39899,37218,37217,37232,37225,37231,37245,37246,37234,37236,37241,37260,37253,37264,37261,37265,37282,37283,37290,37293,37294,37295,37301,37300,37306,35925,40574,36280,36331,36357,36441,36457,36277,36287,36284,36282,36292,36310,36311,36314,36318,36302,36303,36315,36294,36332,36343,36344,36323,36345,36347,36324,36361,36349,36372,36381,36383,36396,36398,36387,36399,36410,36416,36409,36405,36413,36401,36425,36417,36418,36433,36434,36426,36464,36470,36476,36463,36468,36485,36495,36500,36496,36508,36510,35960,35970,35978,35973,35992,35988,26011,35286,35294,35290,35292,39900,39901,39902,39903,39904,39905,39906,39907,39908,39909,39910,39911,39912,39913,39914,39915,39916,39917,39918,39919,39920,39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933,39934,39935,39936,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946,39947,39948,39949,39950,39951,39952,39953,39954,39955,39956,39957,39958,39959,39960,39961,39962,39963,39964,39965,39966,39967,39968,39969,39970,39971,39972,39973,39974,39975,39976,39977,39978,39979,39980,39981,39982,39983,39984,39985,39986,39987,39988,39989,39990,39991,39992,39993,39994,39995,35301,35307,35311,35390,35622,38739,38633,38643,38639,38662,38657,38664,38671,38670,38698,38701,38704,38718,40832,40835,40837,40838,40839,40840,40841,40842,40844,40702,40715,40717,38585,38588,38589,38606,38610,30655,38624,37518,37550,37576,37694,37738,37834,37775,37950,37995,40063,40066,40069,40070,40071,40072,31267,40075,40078,40080,40081,40082,40084,40085,40090,40091,40094,40095,40096,40097,40098,40099,40101,40102,40103,40104,40105,40107,40109,40110,40112,40113,40114,40115,40116,40117,40118,40119,40122,40123,40124,40125,40132,40133,40134,40135,40138,40139,39996,39997,39998,39999,40000,40001,40002,40003,40004,40005,40006,40007,40008,40009,40010,40011,40012,40013,40014,40015,40016,40017,40018,40019,40020,40021,40022,40023,40024,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,40035,40036,40037,40038,40039,40040,40041,40042,40043,40044,40045,40046,40047,40048,40049,40050,40051,40052,40053,40054,40055,40056,40057,40058,40059,40061,40062,40064,40067,40068,40073,40074,40076,40079,40083,40086,40087,40088,40089,40093,40106,40108,40111,40121,40126,40127,40128,40129,40130,40136,40137,40145,40146,40154,40155,40160,40161,40140,40141,40142,40143,40144,40147,40148,40149,40151,40152,40153,40156,40157,40159,40162,38780,38789,38801,38802,38804,38831,38827,38819,38834,38836,39601,39600,39607,40536,39606,39610,39612,39617,39616,39621,39618,39627,39628,39633,39749,39747,39751,39753,39752,39757,39761,39144,39181,39214,39253,39252,39647,39649,39654,39663,39659,39675,39661,39673,39688,39695,39699,39711,39715,40637,40638,32315,40578,40583,40584,40587,40594,37846,40605,40607,40667,40668,40669,40672,40671,40674,40681,40679,40677,40682,40687,40738,40748,40751,40761,40759,40765,40766,40772,40163,40164,40165,40166,40167,40168,40169,40170,40171,40172,40173,40174,40175,40176,40177,40178,40179,40180,40181,40182,40183,40184,40185,40186,40187,40188,40189,40190,40191,40192,40193,40194,40195,40196,40197,40198,40199,40200,40201,40202,40203,40204,40205,40206,40207,40208,40209,40210,40211,40212,40213,40214,40215,40216,40217,40218,40219,40220,40221,40222,40223,40224,40225,40226,40227,40228,40229,40230,40231,40232,40233,40234,40235,40236,40237,40238,40239,40240,40241,40242,40243,40244,40245,40246,40247,40248,40249,40250,40251,40252,40253,40254,40255,40256,40257,40258,57908,57909,57910,57911,57912,57913,57914,57915,57916,57917,57918,57919,57920,57921,57922,57923,57924,57925,57926,57927,57928,57929,57930,57931,57932,57933,57934,57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946,57947,57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959,57960,57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972,57973,57974,57975,57976,57977,57978,57979,57980,57981,57982,57983,57984,57985,57986,57987,57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998,57999,58000,58001,40259,40260,40261,40262,40263,40264,40265,40266,40267,40268,40269,40270,40271,40272,40273,40274,40275,40276,40277,40278,40279,40280,40281,40282,40283,40284,40285,40286,40287,40288,40289,40290,40291,40292,40293,40294,40295,40296,40297,40298,40299,40300,40301,40302,40303,40304,40305,40306,40307,40308,40309,40310,40311,40312,40313,40314,40315,40316,40317,40318,40319,40320,40321,40322,40323,40324,40325,40326,40327,40328,40329,40330,40331,40332,40333,40334,40335,40336,40337,40338,40339,40340,40341,40342,40343,40344,40345,40346,40347,40348,40349,40350,40351,40352,40353,40354,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011,58012,58013,58014,58015,58016,58017,58018,58019,58020,58021,58022,58023,58024,58025,58026,58027,58028,58029,58030,58031,58032,58033,58034,58035,58036,58037,58038,58039,58040,58041,58042,58043,58044,58045,58046,58047,58048,58049,58050,58051,58052,58053,58054,58055,58056,58057,58058,58059,58060,58061,58062,58063,58064,58065,58066,58067,58068,58069,58070,58071,58072,58073,58074,58075,58076,58077,58078,58079,58080,58081,58082,58083,58084,58085,58086,58087,58088,58089,58090,58091,58092,58093,58094,58095,40355,40356,40357,40358,40359,40360,40361,40362,40363,40364,40365,40366,40367,40368,40369,40370,40371,40372,40373,40374,40375,40376,40377,40378,40379,40380,40381,40382,40383,40384,40385,40386,40387,40388,40389,40390,40391,40392,40393,40394,40395,40396,40397,40398,40399,40400,40401,40402,40403,40404,40405,40406,40407,40408,40409,40410,40411,40412,40413,40414,40415,40416,40417,40418,40419,40420,40421,40422,40423,40424,40425,40426,40427,40428,40429,40430,40431,40432,40433,40434,40435,40436,40437,40438,40439,40440,40441,40442,40443,40444,40445,40446,40447,40448,40449,40450,58096,58097,58098,58099,58100,58101,58102,58103,58104,58105,58106,58107,58108,58109,58110,58111,58112,58113,58114,58115,58116,58117,58118,58119,58120,58121,58122,58123,58124,58125,58126,58127,58128,58129,58130,58131,58132,58133,58134,58135,58136,58137,58138,58139,58140,58141,58142,58143,58144,58145,58146,58147,58148,58149,58150,58151,58152,58153,58154,58155,58156,58157,58158,58159,58160,58161,58162,58163,58164,58165,58166,58167,58168,58169,58170,58171,58172,58173,58174,58175,58176,58177,58178,58179,58180,58181,58182,58183,58184,58185,58186,58187,58188,58189,40451,40452,40453,40454,40455,40456,40457,40458,40459,40460,40461,40462,40463,40464,40465,40466,40467,40468,40469,40470,40471,40472,40473,40474,40475,40476,40477,40478,40484,40487,40494,40496,40500,40507,40508,40512,40525,40528,40530,40531,40532,40534,40537,40541,40543,40544,40545,40546,40549,40558,40559,40562,40564,40565,40566,40567,40568,40569,40570,40571,40572,40573,40576,40577,40579,40580,40581,40582,40585,40586,40588,40589,40590,40591,40592,40593,40596,40597,40598,40599,40600,40601,40602,40603,40604,40606,40608,40609,40610,40611,40612,40613,40615,40616,40617,40618,58190,58191,58192,58193,58194,58195,58196,58197,58198,58199,58200,58201,58202,58203,58204,58205,58206,58207,58208,58209,58210,58211,58212,58213,58214,58215,58216,58217,58218,58219,58220,58221,58222,58223,58224,58225,58226,58227,58228,58229,58230,58231,58232,58233,58234,58235,58236,58237,58238,58239,58240,58241,58242,58243,58244,58245,58246,58247,58248,58249,58250,58251,58252,58253,58254,58255,58256,58257,58258,58259,58260,58261,58262,58263,58264,58265,58266,58267,58268,58269,58270,58271,58272,58273,58274,58275,58276,58277,58278,58279,58280,58281,58282,58283,40619,40620,40621,40622,40623,40624,40625,40626,40627,40629,40630,40631,40633,40634,40636,40639,40640,40641,40642,40643,40645,40646,40647,40648,40650,40651,40652,40656,40658,40659,40661,40662,40663,40665,40666,40670,40673,40675,40676,40678,40680,40683,40684,40685,40686,40688,40689,40690,40691,40692,40693,40694,40695,40696,40698,40701,40703,40704,40705,40706,40707,40708,40709,40710,40711,40712,40713,40714,40716,40719,40721,40722,40724,40725,40726,40728,40730,40731,40732,40733,40734,40735,40737,40739,40740,40741,40742,40743,40744,40745,40746,40747,40749,40750,40752,40753,58284,58285,58286,58287,58288,58289,58290,58291,58292,58293,58294,58295,58296,58297,58298,58299,58300,58301,58302,58303,58304,58305,58306,58307,58308,58309,58310,58311,58312,58313,58314,58315,58316,58317,58318,58319,58320,58321,58322,58323,58324,58325,58326,58327,58328,58329,58330,58331,58332,58333,58334,58335,58336,58337,58338,58339,58340,58341,58342,58343,58344,58345,58346,58347,58348,58349,58350,58351,58352,58353,58354,58355,58356,58357,58358,58359,58360,58361,58362,58363,58364,58365,58366,58367,58368,58369,58370,58371,58372,58373,58374,58375,58376,58377,40754,40755,40756,40757,40758,40760,40762,40764,40767,40768,40769,40770,40771,40773,40774,40775,40776,40777,40778,40779,40780,40781,40782,40783,40786,40787,40788,40789,40790,40791,40792,40793,40794,40795,40796,40797,40798,40799,40800,40801,40802,40803,40804,40805,40806,40807,40808,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818,40819,40820,40821,40822,40823,40824,40825,40826,40827,40828,40829,40830,40833,40834,40845,40846,40847,40848,40849,40850,40851,40852,40853,40854,40855,40856,40860,40861,40862,40865,40866,40867,40868,40869,63788,63865,63893,63975,63985,58378,58379,58380,58381,58382,58383,58384,58385,58386,58387,58388,58389,58390,58391,58392,58393,58394,58395,58396,58397,58398,58399,58400,58401,58402,58403,58404,58405,58406,58407,58408,58409,58410,58411,58412,58413,58414,58415,58416,58417,58418,58419,58420,58421,58422,58423,58424,58425,58426,58427,58428,58429,58430,58431,58432,58433,58434,58435,58436,58437,58438,58439,58440,58441,58442,58443,58444,58445,58446,58447,58448,58449,58450,58451,58452,58453,58454,58455,58456,58457,58458,58459,58460,58461,58462,58463,58464,58465,58466,58467,58468,58469,58470,58471,64012,64013,64014,64015,64017,64019,64020,64024,64031,64032,64033,64035,64036,64039,64040,64041,11905,59414,59415,59416,11908,13427,13383,11912,11915,59422,13726,13850,13838,11916,11927,14702,14616,59430,14799,14815,14963,14800,59435,59436,15182,15470,15584,11943,59441,59442,11946,16470,16735,11950,17207,11955,11958,11959,59451,17329,17324,11963,17373,17622,18017,17996,59459,18211,18217,18300,18317,11978,18759,18810,18813,18818,18819,18821,18822,18847,18843,18871,18870,59476,59477,19619,19615,19616,19617,19575,19618,19731,19732,19733,19734,19735,19736,19737,19886,59492,58472,58473,58474,58475,58476,58477,58478,58479,58480,58481,58482,58483,58484,58485,58486,58487,58488,58489,58490,58491,58492,58493,58494,58495,58496,58497,58498,58499,58500,58501,58502,58503,58504,58505,58506,58507,58508,58509,58510,58511,58512,58513,58514,58515,58516,58517,58518,58519,58520,58521,58522,58523,58524,58525,58526,58527,58528,58529,58530,58531,58532,58533,58534,58535,58536,58537,58538,58539,58540,58541,58542,58543,58544,58545,58546,58547,58548,58549,58550,58551,58552,58553,58554,58555,58556,58557,58558,58559,58560,58561,58562,58563,58564,58565],"gb18030-ranges":[[0,128],[36,165],[38,169],[45,178],[50,184],[81,216],[89,226],[95,235],[96,238],[100,244],[103,248],[104,251],[105,253],[109,258],[126,276],[133,284],[148,300],[172,325],[175,329],[179,334],[208,364],[306,463],[307,465],[308,467],[309,469],[310,471],[311,473],[312,475],[313,477],[341,506],[428,594],[443,610],[544,712],[545,716],[558,730],[741,930],[742,938],[749,962],[750,970],[805,1026],[819,1104],[820,1106],[7922,8209],[7924,8215],[7925,8218],[7927,8222],[7934,8231],[7943,8241],[7944,8244],[7945,8246],[7950,8252],[8062,8365],[8148,8452],[8149,8454],[8152,8458],[8164,8471],[8174,8482],[8236,8556],[8240,8570],[8262,8596],[8264,8602],[8374,8713],[8380,8720],[8381,8722],[8384,8726],[8388,8731],[8390,8737],[8392,8740],[8393,8742],[8394,8748],[8396,8751],[8401,8760],[8406,8766],[8416,8777],[8419,8781],[8424,8787],[8437,8802],[8439,8808],[8445,8816],[8482,8854],[8485,8858],[8496,8870],[8521,8896],[8603,8979],[8936,9322],[8946,9372],[9046,9548],[9050,9588],[9063,9616],[9066,9622],[9076,9634],[9092,9652],[9100,9662],[9108,9672],[9111,9676],[9113,9680],[9131,9702],[9162,9735],[9164,9738],[9218,9793],[9219,9795],[11329,11906],[11331,11909],[11334,11913],[11336,11917],[11346,11928],[11361,11944],[11363,11947],[11366,11951],[11370,11956],[11372,11960],[11375,11964],[11389,11979],[11682,12284],[11686,12292],[11687,12312],[11692,12319],[11694,12330],[11714,12351],[11716,12436],[11723,12447],[11725,12535],[11730,12543],[11736,12586],[11982,12842],[11989,12850],[12102,12964],[12336,13200],[12348,13215],[12350,13218],[12384,13253],[12393,13263],[12395,13267],[12397,13270],[12510,13384],[12553,13428],[12851,13727],[12962,13839],[12973,13851],[13738,14617],[13823,14703],[13919,14801],[13933,14816],[14080,14964],[14298,15183],[14585,15471],[14698,15585],[15583,16471],[15847,16736],[16318,17208],[16434,17325],[16438,17330],[16481,17374],[16729,17623],[17102,17997],[17122,18018],[17315,18212],[17320,18218],[17402,18301],[17418,18318],[17859,18760],[17909,18811],[17911,18814],[17915,18820],[17916,18823],[17936,18844],[17939,18848],[17961,18872],[18664,19576],[18703,19620],[18814,19738],[18962,19887],[19043,40870],[33469,59244],[33470,59336],[33471,59367],[33484,59413],[33485,59417],[33490,59423],[33497,59431],[33501,59437],[33505,59443],[33513,59452],[33520,59460],[33536,59478],[33550,59493],[37845,63789],[37921,63866],[37948,63894],[38029,63976],[38038,63986],[38064,64016],[38065,64018],[38066,64021],[38069,64025],[38075,64034],[38076,64037],[38078,64042],[39108,65074],[39109,65093],[39113,65107],[39114,65112],[39115,65127],[39116,65132],[39265,65375],[39394,65510],[189000,65536]],jis0208:[12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,12293,12294,12295,12540,8213,8208,65295,65340,65374,8741,65372,8230,8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371,65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291,65293,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756,9794,9792,176,8242,8243,8451,65509,65284,65504,65505,65285,65283,65286,65290,65312,167,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593,8595,12307,null,null,null,null,null,null,null,null,null,null,null,8712,8715,8838,8839,8834,8835,8746,8745,null,null,null,null,null,null,null,null,8743,8744,65506,8658,8660,8704,8707,null,null,null,null,null,null,null,null,null,null,null,8736,8869,8978,8706,8711,8801,8786,8810,8811,8730,8765,8733,8757,8747,8748,null,null,null,null,null,null,null,8491,8240,9839,9837,9834,8224,8225,182,null,null,null,null,9711,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,null,null,null,null,null,null,null,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,null,null,null,null,null,null,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,null,null,null,null,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,null,null,null,null,null,null,null,null,null,null,null,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,null,null,null,null,null,null,null,null,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,null,null,null,null,null,null,null,null,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,null,null,null,null,null,null,null,null,null,null,null,null,null,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,null,13129,13076,13090,13133,13080,13095,13059,13110,13137,13143,13069,13094,13091,13099,13130,13115,13212,13213,13214,13198,13199,13252,13217,null,null,null,null,null,null,null,null,13179,12317,12319,8470,13261,8481,12964,12965,12966,12967,12968,12849,12850,12857,13182,13181,13180,8786,8801,8747,8750,8721,8730,8869,8736,8735,8895,8757,8745,8746,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312,24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451,22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353,26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801,21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359,40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013,21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942,23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964,33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322,27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839,28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713,27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681,28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487,22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779,29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662,35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011,33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602,22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123,22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226,35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990,25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963,28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666,20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059,21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022,25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929,38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696,24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215,35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931,23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696,25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653,21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470,24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932,22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378,29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208,20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220,22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465,33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306,29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936,31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418,20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950,24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076,32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335,33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770,28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048,21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609,36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015,40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791,27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399,20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184,24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179,26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343,30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108,33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681,26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038,24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661,20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507,28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617,38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948,21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613,31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638,39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158,29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531,20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985,23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045,26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930,33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164,27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012,29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610,26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462,23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754,21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722,33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598,37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294,37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576,21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477,23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484,25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169,28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505,31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443,35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055,20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611,20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187,26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455,34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645,22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920,37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883,32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968,26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738,38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707,31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509,25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808,21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849,27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549,37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950,22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105,30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299,35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204,36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384,23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549,22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550,32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151,33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432,40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129,28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243,22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347,24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044,31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449,24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159,28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530,38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515,27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131,20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340,32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576,22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799,27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969,37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594,20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947,24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783,29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957,39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461,33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563,31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182,33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905,29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492,22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226,25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467,24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493,22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687,31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893,33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843,37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138,22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495,27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318,29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329,21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130,30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131,27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051,38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220,24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676,36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096,23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998,21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991,32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281,38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857,23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370,35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952,24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192,35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778,26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412,32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598,21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001,31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695,40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180,23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538,22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446,26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249,20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220,35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188,22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076,29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178,24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469,33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651,34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053,21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942,26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618,31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155,28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105,24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894,34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498,36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880,28286,30871,33109,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098,20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147,20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233,20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329,20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725,20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795,20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866,22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905,20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960,34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034,21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097,21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149,21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269,21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325,20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413,21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485,21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582,21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636,21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988,21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068,22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176,22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216,22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350,22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451,22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539,22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442,22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001,23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094,23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273,23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363,23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416,25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524,23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939,23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802,23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842,23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940,23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019,24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118,24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181,24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417,24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473,24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755,24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614,24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643,24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756,24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820,24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032,25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087,25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179,25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236,25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282,25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424,25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481,25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825,25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884,25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942,25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015,26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081,26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180,26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248,26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438,26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507,26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590,26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688,26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797,26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765,26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863,26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163,27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146,27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225,27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306,27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447,30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489,27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562,27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929,27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053,28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126,28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270,28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227,28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371,28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433,28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525,28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601,28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683,28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720,28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846,28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030,29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113,29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477,29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562,29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733,29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795,29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955,29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029,30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070,30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278,30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361,30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433,30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501,30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590,30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653,30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014,30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072,31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146,31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245,31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305,31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382,31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439,31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503,31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718,31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783,31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832,31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915,31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960,31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115,32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125,32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377,32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396,32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616,32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669,32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714,32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786,32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858,32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155,33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200,33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240,33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287,33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373,33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406,33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523,33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660,33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795,33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848,34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922,33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009,33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071,34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196,34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516,34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555,34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586,34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768,38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829,34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870,34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942,34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219,35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290,35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365,35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458,35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546,35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596,35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646,35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737,35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960,35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013,36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093,36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045,36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303,36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361,36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639,36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678,36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791,36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885,36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975,36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039,37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194,37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523,37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718,37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853,37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941,37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000,38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292,38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346,28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577,38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620,38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681,38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748,38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778,38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854,38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968,38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319,39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406,39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493,39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524,39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646,39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722,39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827,39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054,40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367,40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314,40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386,40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569,40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632,40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672,40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,22575,27079,36953,29796,20956,29081,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32394,35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013,21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864,33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,null,null,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,65506,65508,65287,65282,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,65506,65508,65287,65282,12849,8470,8481,8757,32394,35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013,21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864,33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],jis0212:[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,728,711,184,729,733,175,731,730,65374,900,901,null,null,null,null,null,null,null,null,161,166,191,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,186,170,169,174,8482,164,8470,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,902,904,905,906,938,null,908,null,910,939,null,911,null,null,null,null,940,941,942,943,970,912,972,962,973,971,944,974,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1038,1039,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1118,1119,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,198,272,null,294,null,306,null,321,319,null,330,216,338,null,358,222,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,230,273,240,295,305,307,312,322,320,329,331,248,339,223,359,254,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,193,192,196,194,258,461,256,260,197,195,262,264,268,199,266,270,201,200,203,202,282,278,274,280,null,284,286,290,288,292,205,204,207,206,463,304,298,302,296,308,310,313,317,315,323,327,325,209,211,210,214,212,465,336,332,213,340,344,342,346,348,352,350,356,354,218,217,220,219,364,467,368,362,370,366,360,471,475,473,469,372,221,376,374,377,381,379,null,null,null,null,null,null,null,225,224,228,226,259,462,257,261,229,227,263,265,269,231,267,271,233,232,235,234,283,279,275,281,501,285,287,null,289,293,237,236,239,238,464,null,299,303,297,309,311,314,318,316,324,328,326,241,243,242,246,244,466,337,333,245,341,345,343,347,349,353,351,357,355,250,249,252,251,365,468,369,363,371,367,361,472,476,474,470,373,253,255,375,378,382,380,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,19970,19972,19973,19980,19986,19999,20003,20004,20008,20011,20014,20015,20016,20021,20032,20033,20036,20039,20049,20058,20060,20067,20072,20073,20084,20085,20089,20095,20109,20118,20119,20125,20143,20153,20163,20176,20186,20187,20192,20193,20194,20200,20207,20209,20211,20213,20221,20222,20223,20224,20226,20227,20232,20235,20236,20242,20245,20246,20247,20249,20270,20273,20320,20275,20277,20279,20281,20283,20286,20288,20290,20296,20297,20299,20300,20306,20308,20310,20312,20319,20323,20330,20332,20334,20337,20343,20344,20345,20346,20349,20350,20353,20354,20356,20357,20361,20362,20364,20366,20368,20370,20371,20372,20375,20377,20378,20382,20383,20402,20407,20409,20411,20412,20413,20414,20416,20417,20421,20422,20424,20425,20427,20428,20429,20431,20434,20444,20448,20450,20464,20466,20476,20477,20479,20480,20481,20484,20487,20490,20492,20494,20496,20499,20503,20504,20507,20508,20509,20510,20514,20519,20526,20528,20530,20531,20533,20544,20545,20546,20549,20550,20554,20556,20558,20561,20562,20563,20567,20569,20575,20576,20578,20579,20582,20583,20586,20589,20592,20593,20539,20609,20611,20612,20614,20618,20622,20623,20624,20626,20627,20628,20630,20635,20636,20638,20639,20640,20641,20642,20650,20655,20656,20665,20666,20669,20672,20675,20676,20679,20684,20686,20688,20691,20692,20696,20700,20701,20703,20706,20708,20710,20712,20713,20719,20721,20726,20730,20734,20739,20742,20743,20744,20747,20748,20749,20750,20722,20752,20759,20761,20763,20764,20765,20766,20771,20775,20776,20780,20781,20783,20785,20787,20788,20789,20792,20793,20802,20810,20815,20819,20821,20823,20824,20831,20836,20838,20862,20867,20868,20875,20878,20888,20893,20897,20899,20909,20920,20922,20924,20926,20927,20930,20936,20943,20945,20946,20947,20949,20952,20958,20962,20965,20974,20978,20979,20980,20983,20993,20994,20997,21010,21011,21013,21014,21016,21026,21032,21041,21042,21045,21052,21061,21065,21077,21079,21080,21082,21084,21087,21088,21089,21094,21102,21111,21112,21113,21120,21122,21125,21130,21132,21139,21141,21142,21143,21144,21146,21148,21156,21157,21158,21159,21167,21168,21174,21175,21176,21178,21179,21181,21184,21188,21190,21192,21196,21199,21201,21204,21206,21211,21212,21217,21221,21224,21225,21226,21228,21232,21233,21236,21238,21239,21248,21251,21258,21259,21260,21265,21267,21272,21275,21276,21278,21279,21285,21287,21288,21289,21291,21292,21293,21296,21298,21301,21308,21309,21310,21314,21324,21323,21337,21339,21345,21347,21349,21356,21357,21362,21369,21374,21379,21383,21384,21390,21395,21396,21401,21405,21409,21412,21418,21419,21423,21426,21428,21429,21431,21432,21434,21437,21440,21445,21455,21458,21459,21461,21466,21469,21470,21472,21478,21479,21493,21506,21523,21530,21537,21543,21544,21546,21551,21553,21556,21557,21571,21572,21575,21581,21583,21598,21602,21604,21606,21607,21609,21611,21613,21614,21620,21631,21633,21635,21637,21640,21641,21645,21649,21653,21654,21660,21663,21665,21670,21671,21673,21674,21677,21678,21681,21687,21689,21690,21691,21695,21702,21706,21709,21710,21728,21738,21740,21743,21750,21756,21758,21759,21760,21761,21765,21768,21769,21772,21773,21774,21781,21802,21803,21810,21813,21814,21819,21820,21821,21825,21831,21833,21834,21837,21840,21841,21848,21850,21851,21854,21856,21857,21860,21862,21887,21889,21890,21894,21896,21902,21903,21905,21906,21907,21908,21911,21923,21924,21933,21938,21951,21953,21955,21958,21961,21963,21964,21966,21969,21970,21971,21975,21976,21979,21982,21986,21993,22006,22015,22021,22024,22026,22029,22030,22031,22032,22033,22034,22041,22060,22064,22067,22069,22071,22073,22075,22076,22077,22079,22080,22081,22083,22084,22086,22089,22091,22093,22095,22100,22110,22112,22113,22114,22115,22118,22121,22125,22127,22129,22130,22133,22148,22149,22152,22155,22156,22165,22169,22170,22173,22174,22175,22182,22183,22184,22185,22187,22188,22189,22193,22195,22199,22206,22213,22217,22218,22219,22223,22224,22220,22221,22233,22236,22237,22239,22241,22244,22245,22246,22247,22248,22257,22251,22253,22262,22263,22273,22274,22279,22282,22284,22289,22293,22298,22299,22301,22304,22306,22307,22308,22309,22313,22314,22316,22318,22319,22323,22324,22333,22334,22335,22341,22342,22348,22349,22354,22370,22373,22375,22376,22379,22381,22382,22383,22384,22385,22387,22388,22389,22391,22393,22394,22395,22396,22398,22401,22403,22412,22420,22423,22425,22426,22428,22429,22430,22431,22433,22421,22439,22440,22441,22444,22456,22461,22471,22472,22476,22479,22485,22493,22494,22500,22502,22503,22505,22509,22512,22517,22518,22520,22525,22526,22527,22531,22532,22536,22537,22497,22540,22541,22555,22558,22559,22560,22566,22567,22573,22578,22585,22591,22601,22604,22605,22607,22608,22613,22623,22625,22628,22631,22632,22648,22652,22655,22656,22657,22663,22664,22665,22666,22668,22669,22671,22672,22676,22678,22685,22688,22689,22690,22694,22697,22705,22706,22724,22716,22722,22728,22733,22734,22736,22738,22740,22742,22746,22749,22753,22754,22761,22771,22789,22790,22795,22796,22802,22803,22804,34369,22813,22817,22819,22820,22824,22831,22832,22835,22837,22838,22847,22851,22854,22866,22867,22873,22875,22877,22878,22879,22881,22883,22891,22893,22895,22898,22901,22902,22905,22907,22908,22923,22924,22926,22930,22933,22935,22943,22948,22951,22957,22958,22959,22960,22963,22967,22970,22972,22977,22979,22980,22984,22986,22989,22994,23005,23006,23007,23011,23012,23015,23022,23023,23025,23026,23028,23031,23040,23044,23052,23053,23054,23058,23059,23070,23075,23076,23079,23080,23082,23085,23088,23108,23109,23111,23112,23116,23120,23125,23134,23139,23141,23143,23149,23159,23162,23163,23166,23179,23184,23187,23190,23193,23196,23198,23199,23200,23202,23207,23212,23217,23218,23219,23221,23224,23226,23227,23231,23236,23238,23240,23247,23258,23260,23264,23269,23274,23278,23285,23286,23293,23296,23297,23304,23319,23348,23321,23323,23325,23329,23333,23341,23352,23361,23371,23372,23378,23382,23390,23400,23406,23407,23420,23421,23422,23423,23425,23428,23430,23434,23438,23440,23441,23443,23444,23446,23464,23465,23468,23469,23471,23473,23474,23479,23482,23484,23488,23489,23501,23503,23510,23511,23512,23513,23514,23520,23535,23537,23540,23549,23564,23575,23582,23583,23587,23590,23593,23595,23596,23598,23600,23602,23605,23606,23641,23642,23644,23650,23651,23655,23656,23657,23661,23664,23668,23669,23674,23675,23676,23677,23687,23688,23690,23695,23698,23709,23711,23712,23714,23715,23718,23722,23730,23732,23733,23738,23753,23755,23762,23773,23767,23790,23793,23794,23796,23809,23814,23821,23826,23851,23843,23844,23846,23847,23857,23860,23865,23869,23871,23874,23875,23878,23880,23893,23889,23897,23882,23903,23904,23905,23906,23908,23914,23917,23920,23929,23930,23934,23935,23937,23939,23944,23946,23954,23955,23956,23957,23961,23963,23967,23968,23975,23979,23984,23988,23992,23993,24003,24007,24011,24016,24014,24024,24025,24032,24036,24041,24056,24057,24064,24071,24077,24082,24084,24085,24088,24095,24096,24110,24104,24114,24117,24126,24139,24144,24137,24145,24150,24152,24155,24156,24158,24168,24170,24171,24172,24173,24174,24176,24192,24203,24206,24226,24228,24229,24232,24234,24236,24241,24243,24253,24254,24255,24262,24268,24267,24270,24273,24274,24276,24277,24284,24286,24293,24299,24322,24326,24327,24328,24334,24345,24348,24349,24353,24354,24355,24356,24360,24363,24364,24366,24368,24372,24374,24379,24381,24383,24384,24388,24389,24391,24397,24400,24404,24408,24411,24416,24419,24420,24423,24431,24434,24436,24437,24440,24442,24445,24446,24457,24461,24463,24470,24476,24477,24482,24487,24491,24484,24492,24495,24496,24497,24504,24516,24519,24520,24521,24523,24528,24529,24530,24531,24532,24542,24545,24546,24552,24553,24554,24556,24557,24558,24559,24562,24563,24566,24570,24572,24583,24586,24589,24595,24596,24599,24600,24602,24607,24612,24621,24627,24629,24640,24647,24648,24649,24652,24657,24660,24662,24663,24669,24673,24679,24689,24702,24703,24706,24710,24712,24714,24718,24721,24723,24725,24728,24733,24734,24738,24740,24741,24744,24752,24753,24759,24763,24766,24770,24772,24776,24777,24778,24779,24782,24783,24788,24789,24793,24795,24797,24798,24802,24805,24818,24821,24824,24828,24829,24834,24839,24842,24844,24848,24849,24850,24851,24852,24854,24855,24857,24860,24862,24866,24874,24875,24880,24881,24885,24886,24887,24889,24897,24901,24902,24905,24926,24928,24940,24946,24952,24955,24956,24959,24960,24961,24963,24964,24971,24973,24978,24979,24983,24984,24988,24989,24991,24992,24997,25000,25002,25005,25016,25017,25020,25024,25025,25026,25038,25039,25045,25052,25053,25054,25055,25057,25058,25063,25065,25061,25068,25069,25071,25089,25091,25092,25095,25107,25109,25116,25120,25122,25123,25127,25129,25131,25145,25149,25154,25155,25156,25158,25164,25168,25169,25170,25172,25174,25178,25180,25188,25197,25199,25203,25210,25213,25229,25230,25231,25232,25254,25256,25267,25270,25271,25274,25278,25279,25284,25294,25301,25302,25306,25322,25330,25332,25340,25341,25347,25348,25354,25355,25357,25360,25363,25366,25368,25385,25386,25389,25397,25398,25401,25404,25409,25410,25411,25412,25414,25418,25419,25422,25426,25427,25428,25432,25435,25445,25446,25452,25453,25457,25460,25461,25464,25468,25469,25471,25474,25476,25479,25482,25488,25492,25493,25497,25498,25502,25508,25510,25517,25518,25519,25533,25537,25541,25544,25550,25553,25555,25556,25557,25564,25568,25573,25578,25580,25586,25587,25589,25592,25593,25609,25610,25616,25618,25620,25624,25630,25632,25634,25636,25637,25641,25642,25647,25648,25653,25661,25663,25675,25679,25681,25682,25683,25684,25690,25691,25692,25693,25695,25696,25697,25699,25709,25715,25716,25723,25725,25733,25735,25743,25744,25745,25752,25753,25755,25757,25759,25761,25763,25766,25768,25772,25779,25789,25790,25791,25796,25801,25802,25803,25804,25806,25808,25809,25813,25815,25828,25829,25833,25834,25837,25840,25845,25847,25851,25855,25857,25860,25864,25865,25866,25871,25875,25876,25878,25881,25883,25886,25887,25890,25894,25897,25902,25905,25914,25916,25917,25923,25927,25929,25936,25938,25940,25951,25952,25959,25963,25978,25981,25985,25989,25994,26002,26005,26008,26013,26016,26019,26022,26030,26034,26035,26036,26047,26050,26056,26057,26062,26064,26068,26070,26072,26079,26096,26098,26100,26101,26105,26110,26111,26112,26116,26120,26121,26125,26129,26130,26133,26134,26141,26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26161,26163,26169,26167,26176,26181,26182,26186,26188,26193,26190,26199,26200,26201,26203,26204,26208,26209,26363,26218,26219,26220,26238,26227,26229,26239,26231,26232,26233,26235,26240,26236,26251,26252,26253,26256,26258,26265,26266,26267,26268,26271,26272,26276,26285,26289,26290,26293,26299,26303,26304,26306,26307,26312,26316,26318,26319,26324,26331,26335,26344,26347,26348,26350,26362,26373,26375,26382,26387,26393,26396,26400,26402,26419,26430,26437,26439,26440,26444,26452,26453,26461,26470,26476,26478,26484,26486,26491,26497,26500,26510,26511,26513,26515,26518,26520,26521,26523,26544,26545,26546,26549,26555,26556,26557,26617,26560,26562,26563,26565,26568,26569,26578,26583,26585,26588,26593,26598,26608,26610,26614,26615,26706,26644,26649,26653,26655,26664,26663,26668,26669,26671,26672,26673,26675,26683,26687,26692,26693,26698,26700,26709,26711,26712,26715,26731,26734,26735,26736,26737,26738,26741,26745,26746,26747,26748,26754,26756,26758,26760,26774,26776,26778,26780,26785,26787,26789,26793,26794,26798,26802,26811,26821,26824,26828,26831,26832,26833,26835,26838,26841,26844,26845,26853,26856,26858,26859,26860,26861,26864,26865,26869,26870,26875,26876,26877,26886,26889,26890,26896,26897,26899,26902,26903,26929,26931,26933,26936,26939,26946,26949,26953,26958,26967,26971,26979,26980,26981,26982,26984,26985,26988,26992,26993,26994,27002,27003,27007,27008,27021,27026,27030,27032,27041,27045,27046,27048,27051,27053,27055,27063,27064,27066,27068,27077,27080,27089,27094,27095,27106,27109,27118,27119,27121,27123,27125,27134,27136,27137,27139,27151,27153,27157,27162,27165,27168,27172,27176,27184,27186,27188,27191,27195,27198,27199,27205,27206,27209,27210,27214,27216,27217,27218,27221,27222,27227,27236,27239,27242,27249,27251,27262,27265,27267,27270,27271,27273,27275,27281,27291,27293,27294,27295,27301,27307,27311,27312,27313,27316,27325,27326,27327,27334,27337,27336,27340,27344,27348,27349,27350,27356,27357,27364,27367,27372,27376,27377,27378,27388,27389,27394,27395,27398,27399,27401,27407,27408,27409,27415,27419,27422,27428,27432,27435,27436,27439,27445,27446,27451,27455,27462,27466,27469,27474,27478,27480,27485,27488,27495,27499,27502,27504,27509,27517,27518,27522,27525,27543,27547,27551,27552,27554,27555,27560,27561,27564,27565,27566,27568,27576,27577,27581,27582,27587,27588,27593,27596,27606,27610,27617,27619,27622,27623,27630,27633,27639,27641,27647,27650,27652,27653,27657,27661,27662,27664,27666,27673,27679,27686,27687,27688,27692,27694,27699,27701,27702,27706,27707,27711,27722,27723,27725,27727,27730,27732,27737,27739,27740,27755,27757,27759,27764,27766,27768,27769,27771,27781,27782,27783,27785,27796,27797,27799,27800,27804,27807,27824,27826,27828,27842,27846,27853,27855,27856,27857,27858,27860,27862,27866,27868,27872,27879,27881,27883,27884,27886,27890,27892,27908,27911,27914,27918,27919,27921,27923,27930,27942,27943,27944,27751,27950,27951,27953,27961,27964,27967,27991,27998,27999,28001,28005,28007,28015,28016,28028,28034,28039,28049,28050,28052,28054,28055,28056,28074,28076,28084,28087,28089,28093,28095,28100,28104,28106,28110,28111,28118,28123,28125,28127,28128,28130,28133,28137,28143,28144,28148,28150,28156,28160,28164,28190,28194,28199,28210,28214,28217,28219,28220,28228,28229,28232,28233,28235,28239,28241,28242,28243,28244,28247,28252,28253,28254,28258,28259,28264,28275,28283,28285,28301,28307,28313,28320,28327,28333,28334,28337,28339,28347,28351,28352,28353,28355,28359,28360,28362,28365,28366,28367,28395,28397,28398,28409,28411,28413,28420,28424,28426,28428,28429,28438,28440,28442,28443,28454,28457,28458,28463,28464,28467,28470,28475,28476,28461,28495,28497,28498,28499,28503,28505,28506,28509,28510,28513,28514,28520,28524,28541,28542,28547,28551,28552,28555,28556,28557,28560,28562,28563,28564,28566,28570,28575,28576,28581,28582,28583,28584,28590,28591,28592,28597,28598,28604,28613,28615,28616,28618,28634,28638,28648,28649,28656,28661,28665,28668,28669,28672,28677,28678,28679,28685,28695,28704,28707,28719,28724,28727,28729,28732,28739,28740,28744,28745,28746,28747,28756,28757,28765,28766,28750,28772,28773,28780,28782,28789,28790,28798,28801,28805,28806,28820,28821,28822,28823,28824,28827,28836,28843,28848,28849,28852,28855,28874,28881,28883,28884,28885,28886,28888,28892,28900,28922,28931,28932,28933,28934,28935,28939,28940,28943,28958,28960,28971,28973,28975,28976,28977,28984,28993,28997,28998,28999,29002,29003,29008,29010,29015,29018,29020,29022,29024,29032,29049,29056,29061,29063,29068,29074,29082,29083,29088,29090,29103,29104,29106,29107,29114,29119,29120,29121,29124,29131,29132,29139,29142,29145,29146,29148,29176,29182,29184,29191,29192,29193,29203,29207,29210,29213,29215,29220,29227,29231,29236,29240,29241,29249,29250,29251,29253,29262,29263,29264,29267,29269,29270,29274,29276,29278,29280,29283,29288,29291,29294,29295,29297,29303,29304,29307,29308,29311,29316,29321,29325,29326,29331,29339,29352,29357,29358,29361,29364,29374,29377,29383,29385,29388,29397,29398,29400,29407,29413,29427,29428,29434,29435,29438,29442,29444,29445,29447,29451,29453,29458,29459,29464,29465,29470,29474,29476,29479,29480,29484,29489,29490,29493,29498,29499,29501,29507,29517,29520,29522,29526,29528,29533,29534,29535,29536,29542,29543,29545,29547,29548,29550,29551,29553,29559,29561,29564,29568,29569,29571,29573,29574,29582,29584,29587,29589,29591,29592,29596,29598,29599,29600,29602,29605,29606,29610,29611,29613,29621,29623,29625,29628,29629,29631,29637,29638,29641,29643,29644,29647,29650,29651,29654,29657,29661,29665,29667,29670,29671,29673,29684,29685,29687,29689,29690,29691,29693,29695,29696,29697,29700,29703,29706,29713,29722,29723,29732,29734,29736,29737,29738,29739,29740,29741,29742,29743,29744,29745,29753,29760,29763,29764,29766,29767,29771,29773,29777,29778,29783,29789,29794,29798,29799,29800,29803,29805,29806,29809,29810,29824,29825,29829,29830,29831,29833,29839,29840,29841,29842,29848,29849,29850,29852,29855,29856,29857,29859,29862,29864,29865,29866,29867,29870,29871,29873,29874,29877,29881,29883,29887,29896,29897,29900,29904,29907,29912,29914,29915,29918,29919,29924,29928,29930,29931,29935,29940,29946,29947,29948,29951,29958,29970,29974,29975,29984,29985,29988,29991,29993,29994,29999,30006,30009,30013,30014,30015,30016,30019,30023,30024,30030,30032,30034,30039,30046,30047,30049,30063,30065,30073,30074,30075,30076,30077,30078,30081,30085,30096,30098,30099,30101,30105,30108,30114,30116,30132,30138,30143,30144,30145,30148,30150,30156,30158,30159,30167,30172,30175,30176,30177,30180,30183,30188,30190,30191,30193,30201,30208,30210,30211,30212,30215,30216,30218,30220,30223,30226,30227,30229,30230,30233,30235,30236,30237,30238,30243,30245,30246,30249,30253,30258,30259,30261,30264,30265,30266,30268,30282,30272,30273,30275,30276,30277,30281,30283,30293,30297,30303,30308,30309,30317,30318,30319,30321,30324,30337,30341,30348,30349,30357,30363,30364,30365,30367,30368,30370,30371,30372,30373,30374,30375,30376,30378,30381,30397,30401,30405,30409,30411,30412,30414,30420,30425,30432,30438,30440,30444,30448,30449,30454,30457,30460,30464,30470,30474,30478,30482,30484,30485,30487,30489,30490,30492,30498,30504,30509,30510,30511,30516,30517,30518,30521,30525,30526,30530,30533,30534,30538,30541,30542,30543,30546,30550,30551,30556,30558,30559,30560,30562,30564,30567,30570,30572,30576,30578,30579,30580,30586,30589,30592,30596,30604,30605,30612,30613,30614,30618,30623,30626,30631,30634,30638,30639,30641,30645,30654,30659,30665,30673,30674,30677,30681,30686,30687,30688,30692,30694,30698,30700,30704,30705,30708,30712,30715,30725,30726,30729,30733,30734,30737,30749,30753,30754,30755,30765,30766,30768,30773,30775,30787,30788,30791,30792,30796,30798,30802,30812,30814,30816,30817,30819,30820,30824,30826,30830,30842,30846,30858,30863,30868,30872,30881,30877,30878,30879,30884,30888,30892,30893,30896,30897,30898,30899,30907,30909,30911,30919,30920,30921,30924,30926,30930,30931,30933,30934,30948,30939,30943,30944,30945,30950,30954,30962,30963,30976,30966,30967,30970,30971,30975,30982,30988,30992,31002,31004,31006,31007,31008,31013,31015,31017,31021,31025,31028,31029,31035,31037,31039,31044,31045,31046,31050,31051,31055,31057,31060,31064,31067,31068,31079,31081,31083,31090,31097,31099,31100,31102,31115,31116,31121,31123,31124,31125,31126,31128,31131,31132,31137,31144,31145,31147,31151,31153,31156,31160,31163,31170,31172,31175,31176,31178,31183,31188,31190,31194,31197,31198,31200,31202,31205,31210,31211,31213,31217,31224,31228,31234,31235,31239,31241,31242,31244,31249,31253,31259,31262,31265,31271,31275,31277,31279,31280,31284,31285,31288,31289,31290,31300,31301,31303,31304,31308,31317,31318,31321,31324,31325,31327,31328,31333,31335,31338,31341,31349,31352,31358,31360,31362,31365,31366,31370,31371,31376,31377,31380,31390,31392,31395,31404,31411,31413,31417,31419,31420,31430,31433,31436,31438,31441,31451,31464,31465,31467,31468,31473,31476,31483,31485,31486,31495,31508,31519,31523,31527,31529,31530,31531,31533,31534,31535,31536,31537,31540,31549,31551,31552,31553,31559,31566,31573,31584,31588,31590,31593,31594,31597,31599,31602,31603,31607,31620,31625,31630,31632,31633,31638,31643,31646,31648,31653,31660,31663,31664,31666,31669,31670,31674,31675,31676,31677,31682,31685,31688,31690,31700,31702,31703,31705,31706,31707,31720,31722,31730,31732,31733,31736,31737,31738,31740,31742,31745,31746,31747,31748,31750,31753,31755,31756,31758,31759,31769,31771,31776,31781,31782,31784,31788,31793,31795,31796,31798,31801,31802,31814,31818,31829,31825,31826,31827,31833,31834,31835,31836,31837,31838,31841,31843,31847,31849,31853,31854,31856,31858,31865,31868,31869,31878,31879,31887,31892,31902,31904,31910,31920,31926,31927,31930,31931,31932,31935,31940,31943,31944,31945,31949,31951,31955,31956,31957,31959,31961,31962,31965,31974,31977,31979,31989,32003,32007,32008,32009,32015,32017,32018,32019,32022,32029,32030,32035,32038,32042,32045,32049,32060,32061,32062,32064,32065,32071,32072,32077,32081,32083,32087,32089,32090,32092,32093,32101,32103,32106,32112,32120,32122,32123,32127,32129,32130,32131,32133,32134,32136,32139,32140,32141,32145,32150,32151,32157,32158,32166,32167,32170,32179,32182,32183,32185,32194,32195,32196,32197,32198,32204,32205,32206,32215,32217,32256,32226,32229,32230,32234,32235,32237,32241,32245,32246,32249,32250,32264,32272,32273,32277,32279,32284,32285,32288,32295,32296,32300,32301,32303,32307,32310,32319,32324,32325,32327,32334,32336,32338,32344,32351,32353,32354,32357,32363,32366,32367,32371,32376,32382,32385,32390,32391,32394,32397,32401,32405,32408,32410,32413,32414,32572,32571,32573,32574,32575,32579,32580,32583,32591,32594,32595,32603,32604,32605,32609,32611,32612,32613,32614,32621,32625,32637,32638,32639,32640,32651,32653,32655,32656,32657,32662,32663,32668,32673,32674,32678,32682,32685,32692,32700,32703,32704,32707,32712,32718,32719,32731,32735,32739,32741,32744,32748,32750,32751,32754,32762,32765,32766,32767,32775,32776,32778,32781,32782,32783,32785,32787,32788,32790,32797,32798,32799,32800,32804,32806,32812,32814,32816,32820,32821,32823,32825,32826,32828,32830,32832,32836,32864,32868,32870,32877,32881,32885,32897,32904,32910,32924,32926,32934,32935,32939,32952,32953,32968,32973,32975,32978,32980,32981,32983,32984,32992,33005,33006,33008,33010,33011,33014,33017,33018,33022,33027,33035,33046,33047,33048,33052,33054,33056,33060,33063,33068,33072,33077,33082,33084,33093,33095,33098,33100,33106,33111,33120,33121,33127,33128,33129,33133,33135,33143,33153,33168,33156,33157,33158,33163,33166,33174,33176,33179,33182,33186,33198,33202,33204,33211,33227,33219,33221,33226,33230,33231,33237,33239,33243,33245,33246,33249,33252,33259,33260,33264,33265,33266,33269,33270,33272,33273,33277,33279,33280,33283,33295,33299,33300,33305,33306,33309,33313,33314,33320,33330,33332,33338,33347,33348,33349,33350,33355,33358,33359,33361,33366,33372,33376,33379,33383,33389,33396,33403,33405,33407,33408,33409,33411,33412,33415,33417,33418,33422,33425,33428,33430,33432,33434,33435,33440,33441,33443,33444,33447,33448,33449,33450,33454,33456,33458,33460,33463,33466,33468,33470,33471,33478,33488,33493,33498,33504,33506,33508,33512,33514,33517,33519,33526,33527,33533,33534,33536,33537,33543,33544,33546,33547,33620,33563,33565,33566,33567,33569,33570,33580,33581,33582,33584,33587,33591,33594,33596,33597,33602,33603,33604,33607,33613,33614,33617,33621,33622,33623,33648,33656,33661,33663,33664,33666,33668,33670,33677,33682,33684,33685,33688,33689,33691,33692,33693,33702,33703,33705,33708,33726,33727,33728,33735,33737,33743,33744,33745,33748,33757,33619,33768,33770,33782,33784,33785,33788,33793,33798,33802,33807,33809,33813,33817,33709,33839,33849,33861,33863,33864,33866,33869,33871,33873,33874,33878,33880,33881,33882,33884,33888,33892,33893,33895,33898,33904,33907,33908,33910,33912,33916,33917,33921,33925,33938,33939,33941,33950,33958,33960,33961,33962,33967,33969,33972,33978,33981,33982,33984,33986,33991,33992,33996,33999,34003,34012,34023,34026,34031,34032,34033,34034,34039,34098,34042,34043,34045,34050,34051,34055,34060,34062,34064,34076,34078,34082,34083,34084,34085,34087,34090,34091,34095,34099,34100,34102,34111,34118,34127,34128,34129,34130,34131,34134,34137,34140,34141,34142,34143,34144,34145,34146,34148,34155,34159,34169,34170,34171,34173,34175,34177,34181,34182,34185,34187,34188,34191,34195,34200,34205,34207,34208,34210,34213,34215,34228,34230,34231,34232,34236,34237,34238,34239,34242,34247,34250,34251,34254,34221,34264,34266,34271,34272,34278,34280,34285,34291,34294,34300,34303,34304,34308,34309,34317,34318,34320,34321,34322,34328,34329,34331,34334,34337,34343,34345,34358,34360,34362,34364,34365,34368,34370,34374,34386,34387,34390,34391,34392,34393,34397,34400,34401,34402,34403,34404,34409,34412,34415,34421,34422,34423,34426,34445,34449,34454,34456,34458,34460,34465,34470,34471,34472,34477,34481,34483,34484,34485,34487,34488,34489,34495,34496,34497,34499,34501,34513,34514,34517,34519,34522,34524,34528,34531,34533,34535,34440,34554,34556,34557,34564,34565,34567,34571,34574,34575,34576,34579,34580,34585,34590,34591,34593,34595,34600,34606,34607,34609,34610,34617,34618,34620,34621,34622,34624,34627,34629,34637,34648,34653,34657,34660,34661,34671,34673,34674,34683,34691,34692,34693,34694,34695,34696,34697,34699,34700,34704,34707,34709,34711,34712,34713,34718,34720,34723,34727,34732,34733,34734,34737,34741,34750,34751,34753,34760,34761,34762,34766,34773,34774,34777,34778,34780,34783,34786,34787,34788,34794,34795,34797,34801,34803,34808,34810,34815,34817,34819,34822,34825,34826,34827,34832,34841,34834,34835,34836,34840,34842,34843,34844,34846,34847,34856,34861,34862,34864,34866,34869,34874,34876,34881,34883,34885,34888,34889,34890,34891,34894,34897,34901,34902,34904,34906,34908,34911,34912,34916,34921,34929,34937,34939,34944,34968,34970,34971,34972,34975,34976,34984,34986,35002,35005,35006,35008,35018,35019,35020,35021,35022,35025,35026,35027,35035,35038,35047,35055,35056,35057,35061,35063,35073,35078,35085,35086,35087,35093,35094,35096,35097,35098,35100,35104,35110,35111,35112,35120,35121,35122,35125,35129,35130,35134,35136,35138,35141,35142,35145,35151,35154,35159,35162,35163,35164,35169,35170,35171,35179,35182,35184,35187,35189,35194,35195,35196,35197,35209,35213,35216,35220,35221,35227,35228,35231,35232,35237,35248,35252,35253,35254,35255,35260,35284,35285,35286,35287,35288,35301,35305,35307,35309,35313,35315,35318,35321,35325,35327,35332,35333,35335,35343,35345,35346,35348,35349,35358,35360,35362,35364,35366,35371,35372,35375,35381,35383,35389,35390,35392,35395,35397,35399,35401,35405,35406,35411,35414,35415,35416,35420,35421,35425,35429,35431,35445,35446,35447,35449,35450,35451,35454,35455,35456,35459,35462,35467,35471,35472,35474,35478,35479,35481,35487,35495,35497,35502,35503,35507,35510,35511,35515,35518,35523,35526,35528,35529,35530,35537,35539,35540,35541,35543,35549,35551,35564,35568,35572,35573,35574,35580,35583,35589,35590,35595,35601,35612,35614,35615,35594,35629,35632,35639,35644,35650,35651,35652,35653,35654,35656,35666,35667,35668,35673,35661,35678,35683,35693,35702,35704,35705,35708,35710,35713,35716,35717,35723,35725,35727,35732,35733,35740,35742,35743,35896,35897,35901,35902,35909,35911,35913,35915,35919,35921,35923,35924,35927,35928,35931,35933,35929,35939,35940,35942,35944,35945,35949,35955,35957,35958,35963,35966,35974,35975,35979,35984,35986,35987,35993,35995,35996,36004,36025,36026,36037,36038,36041,36043,36047,36054,36053,36057,36061,36065,36072,36076,36079,36080,36082,36085,36087,36088,36094,36095,36097,36099,36105,36114,36119,36123,36197,36201,36204,36206,36223,36226,36228,36232,36237,36240,36241,36245,36254,36255,36256,36262,36267,36268,36271,36274,36277,36279,36281,36283,36288,36293,36294,36295,36296,36298,36302,36305,36308,36309,36311,36313,36324,36325,36327,36332,36336,36284,36337,36338,36340,36349,36353,36356,36357,36358,36363,36369,36372,36374,36384,36385,36386,36387,36390,36391,36401,36403,36406,36407,36408,36409,36413,36416,36417,36427,36429,36430,36431,36436,36443,36444,36445,36446,36449,36450,36457,36460,36461,36463,36464,36465,36473,36474,36475,36482,36483,36489,36496,36498,36501,36506,36507,36509,36510,36514,36519,36521,36525,36526,36531,36533,36538,36539,36544,36545,36547,36548,36551,36559,36561,36564,36572,36584,36590,36592,36593,36599,36601,36602,36589,36608,36610,36615,36616,36623,36624,36630,36631,36632,36638,36640,36641,36643,36645,36647,36648,36652,36653,36654,36660,36661,36662,36663,36666,36672,36673,36675,36679,36687,36689,36690,36691,36692,36693,36696,36701,36702,36709,36765,36768,36769,36772,36773,36774,36789,36790,36792,36798,36800,36801,36806,36810,36811,36813,36816,36818,36819,36821,36832,36835,36836,36840,36846,36849,36853,36854,36859,36862,36866,36868,36872,36876,36888,36891,36904,36905,36911,36906,36908,36909,36915,36916,36919,36927,36931,36932,36940,36955,36957,36962,36966,36967,36972,36976,36980,36985,36997,37000,37003,37004,37006,37008,37013,37015,37016,37017,37019,37024,37025,37026,37029,37040,37042,37043,37044,37046,37053,37068,37054,37059,37060,37061,37063,37064,37077,37079,37080,37081,37084,37085,37087,37093,37074,37110,37099,37103,37104,37108,37118,37119,37120,37124,37125,37126,37128,37133,37136,37140,37142,37143,37144,37146,37148,37150,37152,37157,37154,37155,37159,37161,37166,37167,37169,37172,37174,37175,37177,37178,37180,37181,37187,37191,37192,37199,37203,37207,37209,37210,37211,37217,37220,37223,37229,37236,37241,37242,37243,37249,37251,37253,37254,37258,37262,37265,37267,37268,37269,37272,37278,37281,37286,37288,37292,37293,37294,37296,37297,37298,37299,37302,37307,37308,37309,37311,37314,37315,37317,37331,37332,37335,37337,37338,37342,37348,37349,37353,37354,37356,37357,37358,37359,37360,37361,37367,37369,37371,37373,37376,37377,37380,37381,37382,37383,37385,37386,37388,37392,37394,37395,37398,37400,37404,37405,37411,37412,37413,37414,37416,37422,37423,37424,37427,37429,37430,37432,37433,37434,37436,37438,37440,37442,37443,37446,37447,37450,37453,37454,37455,37457,37464,37465,37468,37469,37472,37473,37477,37479,37480,37481,37486,37487,37488,37493,37494,37495,37496,37497,37499,37500,37501,37503,37512,37513,37514,37517,37518,37522,37527,37529,37535,37536,37540,37541,37543,37544,37547,37551,37554,37558,37560,37562,37563,37564,37565,37567,37568,37569,37570,37571,37573,37574,37575,37576,37579,37580,37581,37582,37584,37587,37589,37591,37592,37593,37596,37597,37599,37600,37601,37603,37605,37607,37608,37612,37614,37616,37625,37627,37631,37632,37634,37640,37645,37649,37652,37653,37660,37661,37662,37663,37665,37668,37669,37671,37673,37674,37683,37684,37686,37687,37703,37704,37705,37712,37713,37714,37717,37719,37720,37722,37726,37732,37733,37735,37737,37738,37741,37743,37744,37745,37747,37748,37750,37754,37757,37759,37760,37761,37762,37768,37770,37771,37773,37775,37778,37781,37784,37787,37790,37793,37795,37796,37798,37800,37803,37812,37813,37814,37818,37801,37825,37828,37829,37830,37831,37833,37834,37835,37836,37837,37843,37849,37852,37854,37855,37858,37862,37863,37881,37879,37880,37882,37883,37885,37889,37890,37892,37896,37897,37901,37902,37903,37909,37910,37911,37919,37934,37935,37937,37938,37939,37940,37947,37951,37949,37955,37957,37960,37962,37964,37973,37977,37980,37983,37985,37987,37992,37995,37997,37998,37999,38001,38002,38020,38019,38264,38265,38270,38276,38280,38284,38285,38286,38301,38302,38303,38305,38310,38313,38315,38316,38324,38326,38330,38333,38335,38342,38344,38345,38347,38352,38353,38354,38355,38361,38362,38365,38366,38367,38368,38372,38374,38429,38430,38434,38436,38437,38438,38444,38449,38451,38455,38456,38457,38458,38460,38461,38465,38482,38484,38486,38487,38488,38497,38510,38516,38523,38524,38526,38527,38529,38530,38531,38532,38537,38545,38550,38554,38557,38559,38564,38565,38566,38569,38574,38575,38579,38586,38602,38610,23986,38616,38618,38621,38622,38623,38633,38639,38641,38650,38658,38659,38661,38665,38682,38683,38685,38689,38690,38691,38696,38705,38707,38721,38723,38730,38734,38735,38741,38743,38744,38746,38747,38755,38759,38762,38766,38771,38774,38775,38776,38779,38781,38783,38784,38793,38805,38806,38807,38809,38810,38814,38815,38818,38828,38830,38833,38834,38837,38838,38840,38841,38842,38844,38846,38847,38849,38852,38853,38855,38857,38858,38860,38861,38862,38864,38865,38868,38871,38872,38873,38877,38878,38880,38875,38881,38884,38895,38897,38900,38903,38904,38906,38919,38922,38937,38925,38926,38932,38934,38940,38942,38944,38947,38950,38955,38958,38959,38960,38962,38963,38965,38949,38974,38980,38983,38986,38993,38994,38995,38998,38999,39001,39002,39010,39011,39013,39014,39018,39020,39083,39085,39086,39088,39092,39095,39096,39098,39099,39103,39106,39109,39112,39116,39137,39139,39141,39142,39143,39146,39155,39158,39170,39175,39176,39185,39189,39190,39191,39194,39195,39196,39199,39202,39206,39207,39211,39217,39218,39219,39220,39221,39225,39226,39227,39228,39232,39233,39238,39239,39240,39245,39246,39252,39256,39257,39259,39260,39262,39263,39264,39323,39325,39327,39334,39344,39345,39346,39349,39353,39354,39357,39359,39363,39369,39379,39380,39385,39386,39388,39390,39399,39402,39403,39404,39408,39412,39413,39417,39421,39422,39426,39427,39428,39435,39436,39440,39441,39446,39454,39456,39458,39459,39460,39463,39469,39470,39475,39477,39478,39480,39495,39489,39492,39498,39499,39500,39502,39505,39508,39510,39517,39594,39596,39598,39599,39602,39604,39605,39606,39609,39611,39614,39615,39617,39619,39622,39624,39630,39632,39634,39637,39638,39639,39643,39644,39648,39652,39653,39655,39657,39660,39666,39667,39669,39673,39674,39677,39679,39680,39681,39682,39683,39684,39685,39688,39689,39691,39692,39693,39694,39696,39698,39702,39705,39707,39708,39712,39718,39723,39725,39731,39732,39733,39735,39737,39738,39741,39752,39755,39756,39765,39766,39767,39771,39774,39777,39779,39781,39782,39784,39786,39787,39788,39789,39790,39795,39797,39799,39800,39801,39807,39808,39812,39813,39814,39815,39817,39818,39819,39821,39823,39824,39828,39834,39837,39838,39846,39847,39849,39852,39856,39857,39858,39863,39864,39867,39868,39870,39871,39873,39879,39880,39886,39888,39895,39896,39901,39903,39909,39911,39914,39915,39919,39923,39927,39928,39929,39930,39933,39935,39936,39938,39947,39951,39953,39958,39960,39961,39962,39964,39966,39970,39971,39974,39975,39976,39977,39978,39985,39989,39990,39991,39997,40001,40003,40004,40005,40009,40010,40014,40015,40016,40019,40020,40022,40024,40027,40029,40030,40031,40035,40041,40042,40028,40043,40040,40046,40048,40050,40053,40055,40059,40166,40178,40183,40185,40203,40194,40209,40215,40216,40220,40221,40222,40239,40240,40242,40243,40244,40250,40252,40261,40253,40258,40259,40263,40266,40275,40276,40287,40291,40290,40293,40297,40298,40299,40304,40310,40311,40315,40316,40318,40323,40324,40326,40330,40333,40334,40338,40339,40341,40342,40343,40344,40353,40362,40364,40366,40369,40373,40377,40380,40383,40387,40391,40393,40394,40404,40405,40406,40407,40410,40414,40415,40416,40421,40423,40425,40427,40430,40432,40435,40436,40446,40458,40450,40455,40462,40464,40465,40466,40469,40470,40473,40476,40477,40570,40571,40572,40576,40578,40579,40580,40581,40583,40590,40591,40598,40600,40603,40606,40612,40616,40620,40622,40623,40624,40627,40628,40629,40646,40648,40651,40661,40671,40676,40679,40684,40685,40686,40688,40689,40690,40693,40696,40703,40706,40707,40713,40719,40720,40721,40722,40724,40726,40727,40729,40730,40731,40735,40738,40742,40746,40747,40751,40753,40754,40756,40759,40761,40762,40764,40765,40767,40769,40771,40772,40773,40774,40775,40787,40789,40790,40791,40792,40794,40797,40798,40808,40809,40813,40814,40815,40816,40817,40819,40821,40826,40829,40847,40848,40849,40850,40852,40854,40855,40862,40865,40866,40867,40869,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],ibm866:[1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,9617,9618,9619,9474,9508,9569,9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,9492,9524,9516,9500,9472,9532,9566,9567,9562,9556,9577,9574,9568,9552,9580,9575,9576,9572,9573,9561,9560,9554,9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1025,1105,1028,1108,1031,1111,1038,1118,176,8729,183,8730,8470,164,9632,160],"iso-8859-2":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,728,321,164,317,346,167,168,352,350,356,377,173,381,379,176,261,731,322,180,318,347,711,184,353,351,357,378,733,382,380,340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270,272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223,341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271,273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729],"iso-8859-3":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,294,728,163,164,null,292,167,168,304,350,286,308,173,null,379,176,295,178,179,180,181,293,183,184,305,351,287,309,189,null,380,192,193,194,null,196,266,264,199,200,201,202,203,204,205,206,207,null,209,210,211,212,288,214,215,284,217,218,219,220,364,348,223,224,225,226,null,228,267,265,231,232,233,234,235,236,237,238,239,null,241,242,243,244,289,246,247,285,249,250,251,252,365,349,729],"iso-8859-4":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,312,342,164,296,315,167,168,352,274,290,358,173,381,175,176,261,731,343,180,297,316,711,184,353,275,291,359,330,382,331,256,193,194,195,196,197,198,302,268,201,280,203,278,205,206,298,272,325,332,310,212,213,214,215,216,370,218,219,220,360,362,223,257,225,226,227,228,229,230,303,269,233,281,235,279,237,238,299,273,326,333,311,244,245,246,247,248,371,250,251,252,361,363,729],"iso-8859-5":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,173,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,8470,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,167,1118,1119],"iso-8859-6":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,null,null,null,164,null,null,null,null,null,null,null,1548,173,null,null,null,null,null,null,null,null,null,null,null,null,null,1563,null,null,null,1567,null,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,null,null,null,null,null,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,null,null,null,null,null,null,null,null,null,null,null,null,null],"iso-8859-7":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,8216,8217,163,8364,8367,166,167,168,169,890,171,172,173,null,8213,176,177,178,179,900,901,902,183,904,905,906,187,908,189,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,null,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,null],"iso-8859-8":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,null,162,163,164,165,166,167,168,169,215,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,247,187,188,189,190,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,8215,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,null,null,8206,8207,null],"iso-8859-10":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,274,290,298,296,310,167,315,272,352,358,381,173,362,330,176,261,275,291,299,297,311,183,316,273,353,359,382,8213,363,331,256,193,194,195,196,197,198,302,268,201,280,203,278,205,206,207,208,325,332,211,212,213,214,360,216,370,218,219,220,221,222,223,257,225,226,227,228,229,230,303,269,233,281,235,279,237,238,239,240,326,333,243,244,245,246,361,248,371,250,251,252,253,254,312],"iso-8859-13":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,8221,162,163,164,8222,166,167,216,169,342,171,172,173,174,198,176,177,178,179,8220,181,182,183,248,185,343,187,188,189,190,230,260,302,256,262,196,197,280,274,268,201,377,278,290,310,298,315,352,323,325,211,332,213,214,215,370,321,346,362,220,379,381,223,261,303,257,263,228,229,281,275,269,233,378,279,291,311,299,316,353,324,326,243,333,245,246,247,371,322,347,363,252,380,382,8217],"iso-8859-14":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,7682,7683,163,266,267,7690,167,7808,169,7810,7691,7922,173,174,376,7710,7711,288,289,7744,7745,182,7766,7809,7767,7811,7776,7923,7812,7813,7777,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,372,209,210,211,212,213,214,7786,216,217,218,219,220,221,374,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,373,241,242,243,244,245,246,7787,248,249,250,251,252,253,375,255],"iso-8859-15":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,8364,165,352,167,353,169,170,171,172,173,174,175,176,177,178,179,381,181,182,183,382,185,186,187,338,339,376,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255],"iso-8859-16":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,261,321,8364,8222,352,167,353,169,536,171,377,173,378,379,176,177,268,322,381,8221,182,183,382,269,537,187,338,339,376,380,192,193,194,258,196,262,198,199,200,201,202,203,204,205,206,207,272,323,210,211,212,336,214,346,368,217,218,219,220,280,538,223,224,225,226,259,228,263,230,231,232,233,234,235,236,237,238,239,273,324,242,243,244,337,246,347,369,249,250,251,252,281,539,255],"koi8-r":[9472,9474,9484,9488,9492,9496,9500,9508,9516,9524,9532,9600,9604,9608,9612,9616,9617,9618,9619,8992,9632,8729,8730,8776,8804,8805,160,8993,176,178,183,247,9552,9553,9554,1105,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,1025,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,169,1102,1072,1073,1094,1076,1077,1092,1075,1093,1080,1081,1082,1083,1084,1085,1086,1087,1103,1088,1089,1090,1091,1078,1074,1100,1099,1079,1096,1101,1097,1095,1098,1070,1040,1041,1062,1044,1045,1060,1043,1061,1048,1049,1050,1051,1052,1053,1054,1055,1071,1056,1057,1058,1059,1046,1042,1068,1067,1047,1064,1069,1065,1063,1066],"koi8-u":[9472,9474,9484,9488,9492,9496,9500,9508,9516,9524,9532,9600,9604,9608,9612,9616,9617,9618,9619,8992,9632,8729,8730,8776,8804,8805,160,8993,176,178,183,247,9552,9553,9554,1105,1108,9556,1110,1111,9559,9560,9561,9562,9563,1169,1118,9566,9567,9568,9569,1025,1028,9571,1030,1031,9574,9575,9576,9577,9578,1168,1038,169,1102,1072,1073,1094,1076,1077,1092,1075,1093,1080,1081,1082,1083,1084,1085,1086,1087,1103,1088,1089,1090,1091,1078,1074,1100,1099,1079,1096,1101,1097,1095,1098,1070,1040,1041,1062,1044,1045,1060,1043,1061,1048,1049,1050,1051,1052,1053,1054,1055,1071,1056,1057,1058,1059,1046,1042,1068,1067,1047,1064,1069,1065,1063,1066],macintosh:[196,197,199,201,209,214,220,225,224,226,228,227,229,231,233,232,234,235,237,236,238,239,241,243,242,244,246,245,250,249,251,252,8224,176,162,163,167,8226,182,223,174,169,8482,180,168,8800,198,216,8734,177,8804,8805,165,181,8706,8721,8719,960,8747,170,186,937,230,248,191,161,172,8730,402,8776,8710,171,187,8230,160,192,195,213,338,339,8211,8212,8220,8221,8216,8217,247,9674,255,376,8260,8364,8249,8250,64257,64258,8225,183,8218,8222,8240,194,202,193,203,200,205,206,207,204,211,212,63743,210,218,219,217,305,710,732,175,728,729,730,184,733,731,711],"windows-874":[8364,129,130,131,132,8230,134,135,136,137,138,139,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,152,153,154,155,156,157,158,159,160,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,null,null,null,null,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,null,null,null,null],"windows-1250":[8364,129,8218,131,8222,8230,8224,8225,136,8240,352,8249,346,356,381,377,144,8216,8217,8220,8221,8226,8211,8212,152,8482,353,8250,347,357,382,378,160,711,728,321,164,260,166,167,168,169,350,171,172,173,174,379,176,177,731,322,180,181,182,183,184,261,351,187,317,733,318,380,340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270,272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223,341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271,273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729],"windows-1251":[1026,1027,8218,1107,8222,8230,8224,8225,8364,8240,1033,8249,1034,1036,1035,1039,1106,8216,8217,8220,8221,8226,8211,8212,152,8482,1113,8250,1114,1116,1115,1119,160,1038,1118,1032,164,1168,166,167,1025,169,1028,171,172,173,174,1031,176,177,1030,1110,1169,181,182,183,1105,8470,1108,187,1112,1029,1109,1111,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103],"windows-1252":[8364,129,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,381,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,382,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255],"windows-1253":[8364,129,8218,402,8222,8230,8224,8225,136,8240,138,8249,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,152,8482,154,8250,156,157,158,159,160,901,902,163,164,165,166,167,168,169,null,171,172,173,174,8213,176,177,178,179,900,181,182,183,904,905,906,187,908,189,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,null,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,null],"windows-1254":[8364,129,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,158,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,286,209,210,211,212,213,214,215,216,217,218,219,220,304,350,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,287,241,242,243,244,245,246,247,248,249,250,251,252,305,351,255],"windows-1255":[8364,129,8218,402,8222,8230,8224,8225,710,8240,138,8249,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,154,8250,156,157,158,159,160,161,162,163,8362,165,166,167,168,169,215,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,247,187,188,189,190,191,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1520,1521,1522,1523,1524,null,null,null,null,null,null,null,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,null,null,8206,8207,null],"windows-1256":[8364,1662,8218,402,8222,8230,8224,8225,710,8240,1657,8249,338,1670,1688,1672,1711,8216,8217,8220,8221,8226,8211,8212,1705,8482,1681,8250,339,8204,8205,1722,160,1548,162,163,164,165,166,167,168,169,1726,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,1563,187,188,189,190,1567,1729,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,215,1591,1592,1593,1594,1600,1601,1602,1603,224,1604,226,1605,1606,1607,1608,231,232,233,234,235,1609,1610,238,239,1611,1612,1613,1614,244,1615,1616,247,1617,249,1618,251,252,8206,8207,1746],"windows-1257":[8364,129,8218,131,8222,8230,8224,8225,136,8240,138,8249,140,168,711,184,144,8216,8217,8220,8221,8226,8211,8212,152,8482,154,8250,156,175,731,159,160,null,162,163,164,null,166,167,216,169,342,171,172,173,174,198,176,177,178,179,180,181,182,183,248,185,343,187,188,189,190,230,260,302,256,262,196,197,280,274,268,201,377,278,290,310,298,315,352,323,325,211,332,213,214,215,370,321,346,362,220,379,381,223,261,303,257,263,228,229,281,275,269,233,378,279,291,311,299,316,353,324,326,243,333,245,246,247,371,322,347,363,252,380,382,729],"windows-1258":[8364,129,8218,402,8222,8230,8224,8225,710,8240,138,8249,338,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,154,8250,339,157,158,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,258,196,197,198,199,200,201,202,203,768,205,206,207,272,209,777,211,212,416,214,215,216,217,218,219,220,431,771,223,224,225,226,259,228,229,230,231,232,233,234,235,769,237,238,239,273,241,803,243,244,417,246,247,248,249,250,251,252,432,8363,255],"x-mac-cyrillic":[1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,8224,176,1168,163,167,8226,182,1030,174,169,8482,1026,1106,8800,1027,1107,8734,177,8804,8805,1110,181,1169,1032,1028,1108,1031,1111,1033,1113,1034,1114,1112,1029,172,8730,402,8776,8710,171,187,8230,160,1035,1115,1036,1116,1109,8211,8212,8220,8221,8216,8217,247,8222,1038,1118,1039,1119,8470,1025,1105,1103,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,8364]}})(OY||{})});var CY=yQ((PY,EQ)=>{(function(Q){if(typeof EQ<"u"&&EQ.exports&&!Q["encoding-indexes"])Q["encoding-indexes"]=RY()["encoding-indexes"];function Z(J,F,M){return F<=J&&J<=M}function z(J,F){return J.indexOf(F)!==-1}var X=Math.floor;function N(J){if(J===void 0)return{};if(J===Object(J))return J;throw TypeError("Could not convert argument to dictionary")}function S(J){var F=String(J),M=F.length,U=0,A=[];while(U<M){var w=F.charCodeAt(U);if(w<55296||w>57343)A.push(w);else if(56320<=w&&w<=57343)A.push(65533);else if(55296<=w&&w<=56319)if(U===M-1)A.push(65533);else{var R=F.charCodeAt(U+1);if(56320<=R&&R<=57343){var _=w&1023,T=R&1023;A.push(65536+(_<<10)+T),U+=1}else A.push(65533)}U+=1}return A}function O(J){var F="";for(var M=0;M<J.length;++M){var U=J[M];if(U<=65535)F+=String.fromCharCode(U);else U-=65536,F+=String.fromCharCode((U>>10)+55296,(U&1023)+56320)}return F}function B(J){return 0<=J&&J<=127}var h=B,k=-1;function m(J){this.tokens=[].slice.call(J),this.tokens.reverse()}m.prototype={endOfStream:function(){return!this.tokens.length},read:function(){if(!this.tokens.length)return k;return this.tokens.pop()},prepend:function(J){if(Array.isArray(J)){var F=J;while(F.length)this.tokens.push(F.pop())}else this.tokens.push(J)},push:function(J){if(Array.isArray(J)){var F=J;while(F.length)this.tokens.unshift(F.shift())}else this.tokens.unshift(J)}};var b=-1;function u(J,F){if(J)throw TypeError("Decoder error");return F||65533}function a(J){throw TypeError("The code point "+J+" could not be encoded.")}function XQ(){}XQ.prototype={handler:function(J,F){}};function DQ(){}DQ.prototype={handler:function(J,F){}};function WQ(J){if(J=String(J).trim().toLowerCase(),Object.prototype.hasOwnProperty.call(HQ,J))return HQ[J];return null}var UQ=[{encodings:[{labels:["unicode-1-1-utf-8","utf-8","utf8"],name:"UTF-8"}],heading:"The Encoding"},{encodings:[{labels:["866","cp866","csibm866","ibm866"],name:"IBM866"},{labels:["csisolatin2","iso-8859-2","iso-ir-101","iso8859-2","iso88592","iso_8859-2","iso_8859-2:1987","l2","latin2"],name:"ISO-8859-2"},{labels:["csisolatin3","iso-8859-3","iso-ir-109","iso8859-3","iso88593","iso_8859-3","iso_8859-3:1988","l3","latin3"],name:"ISO-8859-3"},{labels:["csisolatin4","iso-8859-4","iso-ir-110","iso8859-4","iso88594","iso_8859-4","iso_8859-4:1988","l4","latin4"],name:"ISO-8859-4"},{labels:["csisolatincyrillic","cyrillic","iso-8859-5","iso-ir-144","iso8859-5","iso88595","iso_8859-5","iso_8859-5:1988"],name:"ISO-8859-5"},{labels:["arabic","asmo-708","csiso88596e","csiso88596i","csisolatinarabic","ecma-114","iso-8859-6","iso-8859-6-e","iso-8859-6-i","iso-ir-127","iso8859-6","iso88596","iso_8859-6","iso_8859-6:1987"],name:"ISO-8859-6"},{labels:["csisolatingreek","ecma-118","elot_928","greek","greek8","iso-8859-7","iso-ir-126","iso8859-7","iso88597","iso_8859-7","iso_8859-7:1987","sun_eu_greek"],name:"ISO-8859-7"},{labels:["csiso88598e","csisolatinhebrew","hebrew","iso-8859-8","iso-8859-8-e","iso-ir-138","iso8859-8","iso88598","iso_8859-8","iso_8859-8:1988","visual"],name:"ISO-8859-8"},{labels:["csiso88598i","iso-8859-8-i","logical"],name:"ISO-8859-8-I"},{labels:["csisolatin6","iso-8859-10","iso-ir-157","iso8859-10","iso885910","l6","latin6"],name:"ISO-8859-10"},{labels:["iso-8859-13","iso8859-13","iso885913"],name:"ISO-8859-13"},{labels:["iso-8859-14","iso8859-14","iso885914"],name:"ISO-8859-14"},{labels:["csisolatin9","iso-8859-15","iso8859-15","iso885915","iso_8859-15","l9"],name:"ISO-8859-15"},{labels:["iso-8859-16"],name:"ISO-8859-16"},{labels:["cskoi8r","koi","koi8","koi8-r","koi8_r"],name:"KOI8-R"},{labels:["koi8-ru","koi8-u"],name:"KOI8-U"},{labels:["csmacintosh","mac","macintosh","x-mac-roman"],name:"macintosh"},{labels:["dos-874","iso-8859-11","iso8859-11","iso885911","tis-620","windows-874"],name:"windows-874"},{labels:["cp1250","windows-1250","x-cp1250"],name:"windows-1250"},{labels:["cp1251","windows-1251","x-cp1251"],name:"windows-1251"},{labels:["ansi_x3.4-1968","ascii","cp1252","cp819","csisolatin1","ibm819","iso-8859-1","iso-ir-100","iso8859-1","iso88591","iso_8859-1","iso_8859-1:1987","l1","latin1","us-ascii","windows-1252","x-cp1252"],name:"windows-1252"},{labels:["cp1253","windows-1253","x-cp1253"],name:"windows-1253"},{labels:["cp1254","csisolatin5","iso-8859-9","iso-ir-148","iso8859-9","iso88599","iso_8859-9","iso_8859-9:1989","l5","latin5","windows-1254","x-cp1254"],name:"windows-1254"},{labels:["cp1255","windows-1255","x-cp1255"],name:"windows-1255"},{labels:["cp1256","windows-1256","x-cp1256"],name:"windows-1256"},{labels:["cp1257","windows-1257","x-cp1257"],name:"windows-1257"},{labels:["cp1258","windows-1258","x-cp1258"],name:"windows-1258"},{labels:["x-mac-cyrillic","x-mac-ukrainian"],name:"x-mac-cyrillic"}],heading:"Legacy single-byte encodings"},{encodings:[{labels:["chinese","csgb2312","csiso58gb231280","gb2312","gb_2312","gb_2312-80","gbk","iso-ir-58","x-gbk"],name:"GBK"},{labels:["gb18030"],name:"gb18030"}],heading:"Legacy multi-byte Chinese (simplified) encodings"},{encodings:[{labels:["big5","big5-hkscs","cn-big5","csbig5","x-x-big5"],name:"Big5"}],heading:"Legacy multi-byte Chinese (traditional) encodings"},{encodings:[{labels:["cseucpkdfmtjapanese","euc-jp","x-euc-jp"],name:"EUC-JP"},{labels:["csiso2022jp","iso-2022-jp"],name:"ISO-2022-JP"},{labels:["csshiftjis","ms932","ms_kanji","shift-jis","shift_jis","sjis","windows-31j","x-sjis"],name:"Shift_JIS"}],heading:"Legacy multi-byte Japanese encodings"},{encodings:[{labels:["cseuckr","csksc56011987","euc-kr","iso-ir-149","korean","ks_c_5601-1987","ks_c_5601-1989","ksc5601","ksc_5601","windows-949"],name:"EUC-KR"}],heading:"Legacy multi-byte Korean encodings"},{encodings:[{labels:["csiso2022kr","hz-gb-2312","iso-2022-cn","iso-2022-cn-ext","iso-2022-kr"],name:"replacement"},{labels:["utf-16be"],name:"UTF-16BE"},{labels:["utf-16","utf-16le"],name:"UTF-16LE"},{labels:["x-user-defined"],name:"x-user-defined"}],heading:"Legacy miscellaneous encodings"}],HQ={};UQ.forEach(function(J){J.encodings.forEach(function(F){F.labels.forEach(function(M){HQ[M]=F})})});var QQ={},ZQ={};function wQ(J,F){if(!F)return null;return F[J]||null}function r(J,F){var M=F.indexOf(J);return M===-1?null:M}function t(J){if(!("encoding-indexes"in Q))throw Error("Indexes missing. Did you forget to include encoding-indexes.js first?");return Q["encoding-indexes"][J]}function RQ(J){if(J>39419&&J<189000||J>1237575)return null;if(J===7457)return 59335;var F=0,M=0,U=t("gb18030-ranges"),A;for(A=0;A<U.length;++A){var w=U[A];if(w[0]<=J)F=w[0],M=w[1];else break}return M+J-F}function o(J){if(J===59335)return 7457;var F=0,M=0,U=t("gb18030-ranges"),A;for(A=0;A<U.length;++A){var w=U[A];if(w[1]<=J)F=w[1],M=w[0];else break}return M+J-F}function C(J){j=j||t("jis0208").map(function(M,U){return Z(U,8272,8835)?null:M});var F=j;return F.indexOf(J)}var j;function v(J){c=c||t("big5").map(function(M,U){return U<5024?null:M});var F=c;if(J===9552||J===9566||J===9569||J===9578||J===21313||J===21317)return F.lastIndexOf(J);return r(J,F)}var c,q="utf-8";function E(J,F){if(!(this instanceof E))throw TypeError("Called as a function. Did you forget 'new'?");J=J!==void 0?String(J):q,F=N(F),this._encoding=null,this._decoder=null,this._ignoreBOM=!1,this._BOMseen=!1,this._error_mode="replacement",this._do_not_flush=!1;var M=WQ(J);if(M===null||M.name==="replacement")throw RangeError("Unknown encoding: "+J);if(!ZQ[M.name])throw Error("Decoder not present. Did you forget to include encoding-indexes.js first?");var U=this;if(U._encoding=M,Boolean(F.fatal))U._error_mode="fatal";if(Boolean(F.ignoreBOM))U._ignoreBOM=!0;if(!Object.defineProperty)this.encoding=U._encoding.name.toLowerCase(),this.fatal=U._error_mode==="fatal",this.ignoreBOM=U._ignoreBOM;return U}if(Object.defineProperty)Object.defineProperty(E.prototype,"encoding",{get:function(){return this._encoding.name.toLowerCase()}}),Object.defineProperty(E.prototype,"fatal",{get:function(){return this._error_mode==="fatal"}}),Object.defineProperty(E.prototype,"ignoreBOM",{get:function(){return this._ignoreBOM}});E.prototype.decode=function(F,M){var U;if(typeof F==="object"&&F instanceof ArrayBuffer)U=new Uint8Array(F);else if(typeof F==="object"&&"buffer"in F&&F.buffer instanceof ArrayBuffer)U=new Uint8Array(F.buffer,F.byteOffset,F.byteLength);else U=new Uint8Array(0);if(M=N(M),!this._do_not_flush)this._decoder=ZQ[this._encoding.name]({fatal:this._error_mode==="fatal"}),this._BOMseen=!1;this._do_not_flush=Boolean(M.stream);var A=new m(U),w=[],R;while(!0){var _=A.read();if(_===k)break;if(R=this._decoder.handler(A,_),R===b)break;if(R!==null)if(Array.isArray(R))w.push.apply(w,R);else w.push(R)}if(!this._do_not_flush){do{if(R=this._decoder.handler(A,A.read()),R===b)break;if(R===null)continue;if(Array.isArray(R))w.push.apply(w,R);else w.push(R)}while(!A.endOfStream());this._decoder=null}function T(e){if(z(["UTF-8","UTF-16LE","UTF-16BE"],this._encoding.name)&&!this._ignoreBOM&&!this._BOMseen){if(e.length>0&&e[0]===65279)this._BOMseen=!0,e.shift();else if(e.length>0)this._BOMseen=!0}return O(e)}return T.call(this,w)};function Y(J,F){if(!(this instanceof Y))throw TypeError("Called as a function. Did you forget 'new'?");F=N(F),this._encoding=null,this._encoder=null,this._do_not_flush=!1,this._fatal=Boolean(F.fatal)?"fatal":"replacement";var M=this;if(Boolean(F.NONSTANDARD_allowLegacyEncoding)){J=J!==void 0?String(J):q;var U=WQ(J);if(U===null||U.name==="replacement")throw RangeError("Unknown encoding: "+J);if(!QQ[U.name])throw Error("Encoder not present. Did you forget to include encoding-indexes.js first?");M._encoding=U}else if(M._encoding=WQ("utf-8"),J!==void 0&&"console"in Q)console.warn("TextEncoder constructor called with encoding label, which is ignored.");if(!Object.defineProperty)this.encoding=M._encoding.name.toLowerCase();return M}if(Object.defineProperty)Object.defineProperty(Y.prototype,"encoding",{get:function(){return this._encoding.name.toLowerCase()}});Y.prototype.encode=function(F,M){if(F=F===void 0?"":String(F),M=N(M),!this._do_not_flush)this._encoder=QQ[this._encoding.name]({fatal:this._fatal==="fatal"});this._do_not_flush=Boolean(M.stream);var U=new m(S(F)),A=[],w;while(!0){var R=U.read();if(R===k)break;if(w=this._encoder.handler(U,R),w===b)break;if(Array.isArray(w))A.push.apply(A,w);else A.push(w)}if(!this._do_not_flush){while(!0){if(w=this._encoder.handler(U,U.read()),w===b)break;if(Array.isArray(w))A.push.apply(A,w);else A.push(w)}this._encoder=null}return new Uint8Array(A)};function $(J){var F=J.fatal,M=0,U=0,A=0,w=128,R=191;this.handler=function(_,T){if(T===k&&A!==0)return A=0,u(F);if(T===k)return b;if(A===0){if(Z(T,0,127))return T;else if(Z(T,194,223))A=1,M=T&31;else if(Z(T,224,239)){if(T===224)w=160;if(T===237)R=159;A=2,M=T&15}else if(Z(T,240,244)){if(T===240)w=144;if(T===244)R=143;A=3,M=T&7}else return u(F);return null}if(!Z(T,w,R))return M=A=U=0,w=128,R=191,_.prepend(T),u(F);if(w=128,R=191,M=M<<6|T&63,U+=1,U!==A)return null;var e=M;return M=A=U=0,e}}function H(J){var F=J.fatal;this.handler=function(M,U){if(U===k)return b;if(h(U))return U;var A,w;if(Z(U,128,2047))A=1,w=192;else if(Z(U,2048,65535))A=2,w=224;else if(Z(U,65536,1114111))A=3,w=240;var R=[(U>>6*A)+w];while(A>0){var _=U>>6*(A-1);R.push(128|_&63),A-=1}return R}}QQ["UTF-8"]=function(J){return new H(J)},ZQ["UTF-8"]=function(J){return new $(J)};function G(J,F){var M=F.fatal;this.handler=function(U,A){if(A===k)return b;if(B(A))return A;var w=J[A-128];if(w===null)return u(M);return w}}function W(J,F){var M=F.fatal;this.handler=function(U,A){if(A===k)return b;if(h(A))return A;var w=r(A,J);if(w===null)a(A);return w+128}}(function(){if(!("encoding-indexes"in Q))return;UQ.forEach(function(J){if(J.heading!=="Legacy single-byte encodings")return;J.encodings.forEach(function(F){var M=F.name,U=t(M.toLowerCase());ZQ[M]=function(A){return new G(U,A)},QQ[M]=function(A){return new W(U,A)}})})})(),ZQ.GBK=function(J){return new K(J)},QQ.GBK=function(J){return new V(J,!0)};function K(J){var F=J.fatal,M=0,U=0,A=0;this.handler=function(w,R){if(R===k&&M===0&&U===0&&A===0)return b;if(R===k&&(M!==0||U!==0||A!==0))M=0,U=0,A=0,u(F);var _;if(A!==0){if(_=null,Z(R,48,57))_=RQ((((M-129)*10+U-48)*126+A-129)*10+R-48);var T=[U,A,R];if(M=0,U=0,A=0,_===null)return w.prepend(T),u(F);return _}if(U!==0){if(Z(R,129,254))return A=R,null;return w.prepend([U,R]),M=0,U=0,u(F)}if(M!==0){if(Z(R,48,57))return U=R,null;var e=M,MQ=null;M=0;var JQ=R<127?64:65;if(Z(R,64,126)||Z(R,128,254))MQ=(e-129)*190+(R-JQ);if(_=MQ===null?null:wQ(MQ,t("gb18030")),_===null&&B(R))w.prepend(R);if(_===null)return u(F);return _}if(B(R))return R;if(R===128)return 8364;if(Z(R,129,254))return M=R,null;return u(F)}}function V(J,F){var M=J.fatal;this.handler=function(U,A){if(A===k)return b;if(h(A))return A;if(A===58853)return a(A);if(F&&A===8364)return 128;var w=r(A,t("gb18030"));if(w!==null){var R=X(w/190)+129,_=w%190,T=_<63?64:65;return[R,_+T]}if(F)return a(A);w=o(A);var e=X(w/10/126/10);w=w-e*10*126*10;var MQ=X(w/10/126);w=w-MQ*10*126;var JQ=X(w/10),BQ=w-JQ*10;return[e+129,MQ+48,JQ+129,BQ+48]}}QQ.gb18030=function(J){return new V(J)},ZQ.gb18030=function(J){return new K(J)};function L(J){var F=J.fatal,M=0;this.handler=function(U,A){if(A===k&&M!==0)return M=0,u(F);if(A===k&&M===0)return b;if(M!==0){var w=M,R=null;M=0;var _=A<127?64:98;if(Z(A,64,126)||Z(A,161,254))R=(w-129)*157+(A-_);switch(R){case 1133:return[202,772];case 1135:return[202,780];case 1164:return[234,772];case 1166:return[234,780]}var T=R===null?null:wQ(R,t("big5"));if(T===null&&B(A))U.prepend(A);if(T===null)return u(F);return T}if(B(A))return A;if(Z(A,129,254))return M=A,null;return u(F)}}function P(J){var F=J.fatal;this.handler=function(M,U){if(U===k)return b;if(h(U))return U;var A=v(U);if(A===null)return a(U);var w=X(A/157)+129;if(w<161)return a(U);var R=A%157,_=R<63?64:98;return[w,R+_]}}QQ.Big5=function(J){return new P(J)},ZQ.Big5=function(J){return new L(J)};function D(J){var F=J.fatal,M=!1,U=0;this.handler=function(A,w){if(w===k&&U!==0)return U=0,u(F);if(w===k&&U===0)return b;if(U===142&&Z(w,161,223))return U=0,65216+w;if(U===143&&Z(w,161,254))return M=!0,U=w,null;if(U!==0){var R=U;U=0;var _=null;if(Z(R,161,254)&&Z(w,161,254))_=wQ((R-161)*94+(w-161),t(!M?"jis0208":"jis0212"));if(M=!1,!Z(w,161,254))A.prepend(w);if(_===null)return u(F);return _}if(B(w))return w;if(w===142||w===143||Z(w,161,254))return U=w,null;return u(F)}}function y(J){var F=J.fatal;this.handler=function(M,U){if(U===k)return b;if(h(U))return U;if(U===165)return 92;if(U===8254)return 126;if(Z(U,65377,65439))return[142,U-65377+161];if(U===8722)U=65293;var A=r(U,t("jis0208"));if(A===null)return a(U);var w=X(A/94)+161,R=A%94+161;return[w,R]}}QQ["EUC-JP"]=function(J){return new y(J)},ZQ["EUC-JP"]=function(J){return new D(J)};function x(J){var F=J.fatal,M={ASCII:0,Roman:1,Katakana:2,LeadByte:3,TrailByte:4,EscapeStart:5,Escape:6},U=M.ASCII,A=M.ASCII,w=0,R=!1;this.handler=function(_,T){switch(U){default:case M.ASCII:if(T===27)return U=M.EscapeStart,null;if(Z(T,0,127)&&T!==14&&T!==15&&T!==27)return R=!1,T;if(T===k)return b;return R=!1,u(F);case M.Roman:if(T===27)return U=M.EscapeStart,null;if(T===92)return R=!1,165;if(T===126)return R=!1,8254;if(Z(T,0,127)&&T!==14&&T!==15&&T!==27&&T!==92&&T!==126)return R=!1,T;if(T===k)return b;return R=!1,u(F);case M.Katakana:if(T===27)return U=M.EscapeStart,null;if(Z(T,33,95))return R=!1,65344+T;if(T===k)return b;return R=!1,u(F);case M.LeadByte:if(T===27)return U=M.EscapeStart,null;if(Z(T,33,126))return R=!1,w=T,U=M.TrailByte,null;if(T===k)return b;return R=!1,u(F);case M.TrailByte:if(T===27)return U=M.EscapeStart,u(F);if(Z(T,33,126)){U=M.LeadByte;var e=(w-33)*94+T-33,MQ=wQ(e,t("jis0208"));if(MQ===null)return u(F);return MQ}if(T===k)return U=M.LeadByte,_.prepend(T),u(F);return U=M.LeadByte,u(F);case M.EscapeStart:if(T===36||T===40)return w=T,U=M.Escape,null;return _.prepend(T),R=!1,U=A,u(F);case M.Escape:var JQ=w;w=0;var BQ=null;if(JQ===40&&T===66)BQ=M.ASCII;if(JQ===40&&T===74)BQ=M.Roman;if(JQ===40&&T===73)BQ=M.Katakana;if(JQ===36&&(T===64||T===66))BQ=M.LeadByte;if(BQ!==null){U=U=BQ;var aY=R;return R=!0,!aY?null:u(F)}return _.prepend([JQ,T]),R=!1,U=A,u(F)}}}function f(J){var F=J.fatal,M={ASCII:0,Roman:1,jis0208:2},U=M.ASCII;this.handler=function(A,w){if(w===k&&U!==M.ASCII)return A.prepend(w),U=M.ASCII,[27,40,66];if(w===k&&U===M.ASCII)return b;if((U===M.ASCII||U===M.Roman)&&(w===14||w===15||w===27))return a(65533);if(U===M.ASCII&&h(w))return w;if(U===M.Roman&&(h(w)&&w!==92&&w!==126||(w==165||w==8254))){if(h(w))return w;if(w===165)return 92;if(w===8254)return 126}if(h(w)&&U!==M.ASCII)return A.prepend(w),U=M.ASCII,[27,40,66];if((w===165||w===8254)&&U!==M.Roman)return A.prepend(w),U=M.Roman,[27,40,74];if(w===8722)w=65293;var R=r(w,t("jis0208"));if(R===null)return a(w);if(U!==M.jis0208)return A.prepend(w),U=M.jis0208,[27,36,66];var _=X(R/94)+33,T=R%94+33;return[_,T]}}QQ["ISO-2022-JP"]=function(J){return new f(J)},ZQ["ISO-2022-JP"]=function(J){return new x(J)};function I(J){var F=J.fatal,M=0;this.handler=function(U,A){if(A===k&&M!==0)return M=0,u(F);if(A===k&&M===0)return b;if(M!==0){var w=M,R=null;M=0;var _=A<127?64:65,T=w<160?129:193;if(Z(A,64,126)||Z(A,128,252))R=(w-T)*188+A-_;if(Z(R,8836,10715))return 48508+R;var e=R===null?null:wQ(R,t("jis0208"));if(e===null&&B(A))U.prepend(A);if(e===null)return u(F);return e}if(B(A)||A===128)return A;if(Z(A,161,223))return 65216+A;if(Z(A,129,159)||Z(A,224,252))return M=A,null;return u(F)}}function g(J){var F=J.fatal;this.handler=function(M,U){if(U===k)return b;if(h(U)||U===128)return U;if(U===165)return 92;if(U===8254)return 126;if(Z(U,65377,65439))return U-65377+161;if(U===8722)U=65293;var A=C(U);if(A===null)return a(U);var w=X(A/188),R=w<31?129:193,_=A%188,T=_<63?64:65;return[w+R,_+T]}}QQ.Shift_JIS=function(J){return new g(J)},ZQ.Shift_JIS=function(J){return new I(J)};function l(J){var F=J.fatal,M=0;this.handler=function(U,A){if(A===k&&M!==0)return M=0,u(F);if(A===k&&M===0)return b;if(M!==0){var w=M,R=null;if(M=0,Z(A,65,254))R=(w-129)*190+(A-65);var _=R===null?null:wQ(R,t("euc-kr"));if(R===null&&B(A))U.prepend(A);if(_===null)return u(F);return _}if(B(A))return A;if(Z(A,129,254))return M=A,null;return u(F)}}function d(J){var F=J.fatal;this.handler=function(M,U){if(U===k)return b;if(h(U))return U;var A=r(U,t("euc-kr"));if(A===null)return a(U);var w=X(A/190)+129,R=A%190+65;return[w,R]}}QQ["EUC-KR"]=function(J){return new d(J)},ZQ["EUC-KR"]=function(J){return new l(J)};function p(J,F){var M=J>>8,U=J&255;if(F)return[M,U];return[U,M]}function s(J,F){var M=F.fatal,U=null,A=null;this.handler=function(w,R){if(R===k&&(U!==null||A!==null))return u(M);if(R===k&&U===null&&A===null)return b;if(U===null)return U=R,null;var _;if(J)_=(U<<8)+R;else _=(R<<8)+U;if(U=null,A!==null){var T=A;if(A=null,Z(_,56320,57343))return 65536+(T-55296)*1024+(_-56320);return w.prepend(p(_,J)),u(M)}if(Z(_,55296,56319))return A=_,null;if(Z(_,56320,57343))return u(M);return _}}function n(J,F){var M=F.fatal;this.handler=function(U,A){if(A===k)return b;if(Z(A,0,65535))return p(A,J);var w=p((A-65536>>10)+55296,J),R=p((A-65536&1023)+56320,J);return w.concat(R)}}QQ["UTF-16BE"]=function(J){return new n(!0,J)},ZQ["UTF-16BE"]=function(J){return new s(!0,J)},QQ["UTF-16LE"]=function(J){return new n(!1,J)},ZQ["UTF-16LE"]=function(J){return new s(!1,J)};function $Q(J){var F=J.fatal;this.handler=function(M,U){if(U===k)return b;if(B(U))return U;return 63360+U-128}}function GQ(J){var F=J.fatal;this.handler=function(M,U){if(U===k)return b;if(h(U))return U;if(Z(U,63360,63487))return U-63360+128;return a(U)}}if(QQ["x-user-defined"]=function(J){return new GQ(J)},ZQ["x-user-defined"]=function(J){return new $Q(J)},!Q.TextEncoder)Q.TextEncoder=Y;if(!Q.TextDecoder)Q.TextDecoder=E;if(typeof EQ<"u"&&EQ.exports)EQ.exports={TextEncoder:Q.TextEncoder,TextDecoder:Q.TextDecoder,EncodingIndexes:Q["encoding-indexes"]}})(PY||{})});var TY=yQ((OZ,jY)=>{var IY=CY();jY.exports={TextEncoder:IY.TextEncoder,TextDecoder:IY.TextDecoder}});var kY=yQ((lQ,pQ)=>{(function(Q,Z){typeof lQ=="object"&&typeof pQ<"u"?pQ.exports=Z():typeof define=="function"&&define.amd?define(Z):(Q=Q||self,Q.JSBI=Z())})(lQ,function(){var{imul:Q,clz32:Z}=Math;function z(C,j){(j==null||j>C.length)&&(j=C.length);for(var v=0,c=Array(j);v<j;v++)c[v]=C[v];return c}function X(C){if(Array.isArray(C))return C}function N(C){if(C===void 0)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return C}function S(C,j,v){return j=b(j),UQ(C,XQ()?Reflect.construct(j,v||[],b(C).constructor):j.apply(C,v))}function O(C,j){if(!(C instanceof j))throw TypeError("Cannot call a class as a function")}function B(C,j,v){if(XQ())return Reflect.construct.apply(null,arguments);var c=[null];c.push.apply(c,j);var q=new(C.bind.apply(C,c));return v&&HQ(q,v.prototype),q}function h(C,j){for(var v,c=0;c<j.length;c++)v=j[c],v.enumerable=v.enumerable||!1,v.configurable=!0,"value"in v&&(v.writable=!0),Object.defineProperty(C,wQ(v.key),v)}function k(C,j,v){return j&&h(C.prototype,j),v&&h(C,v),Object.defineProperty(C,"prototype",{writable:!1}),C}function m(C,j){var v=typeof Symbol<"u"&&C[Symbol.iterator]||C["@@iterator"];if(!v){if(Array.isArray(C)||(v=t(C))||j&&C&&typeof C.length=="number"){v&&(C=v);var c=0,q=function(){};return{s:q,n:function(){return c>=C.length?{done:!0}:{done:!1,value:C[c++]}},e:function(H){throw H},f:q}}throw TypeError(`Invalid attempt to iterate non-iterable instance.
+In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var E,Y=!0,$=!1;return{s:function(){v=v.call(C)},n:function(){var H=v.next();return Y=H.done,H},e:function(H){$=!0,E=H},f:function(){try{Y||v.return==null||v.return()}finally{if($)throw E}}}}function b(C){return b=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(j){return j.__proto__||Object.getPrototypeOf(j)},b(C)}function u(C,j){if(typeof j!="function"&&j!==null)throw TypeError("Super expression must either be null or a function");C.prototype=Object.create(j&&j.prototype,{constructor:{value:C,writable:!0,configurable:!0}}),Object.defineProperty(C,"prototype",{writable:!1}),j&&HQ(C,j)}function a(C){try{return Function.toString.call(C).indexOf("[native code]")!==-1}catch(j){return typeof C=="function"}}function XQ(){try{var C=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(j){}return(XQ=function(){return!!C})()}function DQ(C,j){var v=C==null?null:typeof Symbol<"u"&&C[Symbol.iterator]||C["@@iterator"];if(v!=null){var c,q,E,Y,$=[],H=!0,G=!1;try{if(E=(v=v.call(C)).next,j===0){if(Object(v)!==v)return;H=!1}else for(;!(H=(c=E.call(v)).done)&&($.push(c.value),$.length!==j);H=!0);}catch(W){G=!0,q=W}finally{try{if(!H&&v.return!=null&&(Y=v.return(),Object(Y)!==Y))return}finally{if(G)throw q}}return $}}function WQ(){throw TypeError(`Invalid attempt to destructure non-iterable instance.
+In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function UQ(C,j){if(j&&(typeof j=="object"||typeof j=="function"))return j;if(j!==void 0)throw TypeError("Derived constructors may only return object or undefined");return N(C)}function HQ(C,j){return HQ=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(v,c){return v.__proto__=c,v},HQ(C,j)}function QQ(C,j){return X(C)||DQ(C,j)||t(C,j)||WQ()}function ZQ(C,j){if(typeof C!="object"||!C)return C;var v=C[Symbol.toPrimitive];if(v!==void 0){var c=v.call(C,j||"default");if(typeof c!="object")return c;throw TypeError("@@toPrimitive must return a primitive value.")}return(j==="string"?String:Number)(C)}function wQ(C){var j=ZQ(C,"string");return typeof j=="symbol"?j:j+""}function r(C){return r=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(j){return typeof j}:function(j){return j&&typeof Symbol=="function"&&j.constructor===Symbol&&j!==Symbol.prototype?"symbol":typeof j},r(C)}function t(C,j){if(C){if(typeof C=="string")return z(C,j);var v={}.toString.call(C).slice(8,-1);return v==="Object"&&C.constructor&&(v=C.constructor.name),v==="Map"||v==="Set"?Array.from(C):v==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(v)?z(C,j):void 0}}function RQ(C){var j=typeof Map=="function"?new Map:void 0;return RQ=function(v){function c(){return B(v,arguments,b(this).constructor)}if(v===null||!a(v))return v;if(typeof v!="function")throw TypeError("Super expression must either be null or a function");if(j!==void 0){if(j.has(v))return j.get(v);j.set(v,c)}return c.prototype=Object.create(v.prototype,{constructor:{value:c,enumerable:!1,writable:!0,configurable:!0}}),HQ(c,v)},RQ(C)}var o=function(C){var{abs:j,max:v,floor:c}=Math;function q(E,Y){var $;if(O(this,q),$=S(this,q,[E]),$.sign=Y,Object.setPrototypeOf($,q.prototype),E>q.__kMaxLength)throw RangeError("Maximum BigInt size exceeded");return $}return u(q,C),k(q,[{key:"toDebugString",value:function(){var Y,$=["BigInt["],H=m(this);try{for(H.s();!(Y=H.n()).done;){var G=Y.value;$.push((G?(G>>>0).toString(16):G)+", ")}}catch(W){H.e(W)}finally{H.f()}return $.push("]"),$.join("")}},{key:"toString",value:function(){var Y=0<arguments.length&&arguments[0]!==void 0?arguments[0]:10;if(2>Y||36<Y)throw RangeError("toString() radix argument must be between 2 and 36");return this.length===0?"0":(Y&Y-1)==0?q.__toStringBasePowerOfTwo(this,Y):q.__toStringGeneric(this,Y,!1)}},{key:"valueOf",value:function(){throw Error("Convert JSBI instances to native numbers using `toNumber`.")}},{key:"__copy",value:function(){for(var Y=new q(this.length,this.sign),$=0;$<this.length;$++)Y[$]=this[$];return Y}},{key:"__trim",value:function(){for(var Y=this.length,$=this[Y-1];$===0;)Y--,$=this[Y-1],this.pop();return Y===0&&(this.sign=!1),this}},{key:"__initializeDigits",value:function(){for(var Y=0;Y<this.length;Y++)this[Y]=0}},{key:"__clzmsd",value:function(){return q.__clz30(this.__digit(this.length-1))}},{key:"__inplaceMultiplyAdd",value:function(Y,$,H){H>this.length&&(H=this.length);for(var G=32767&Y,W=Y>>>15,K=0,V=$,L=0;L<H;L++){var P=this.__digit(L),D=32767&P,y=P>>>15,x=q.__imul(D,G),f=q.__imul(D,W),I=q.__imul(y,G),g=q.__imul(y,W),l=V+x+K;K=l>>>30,l&=1073741823,l+=((32767&f)<<15)+((32767&I)<<15),K+=l>>>30,V=g+(f>>>15)+(I>>>15),this.__setDigit(L,1073741823&l)}if(K!==0||V!==0)throw Error("implementation bug")}},{key:"__inplaceAdd",value:function(Y,$,H){for(var G,W=0,K=0;K<H;K++)G=this.__halfDigit($+K)+Y.__halfDigit(K)+W,W=G>>>15,this.__setHalfDigit($+K,32767&G);return W}},{key:"__inplaceSub",value:function(Y,$,H){var G=H-1>>>1,W=0;if(1&$){$>>=1;for(var K=this.__digit($),V=32767&K,L=0;L<G;L++){var P=Y.__digit(L),D=(K>>>15)-(32767&P)-W;W=1&D>>>15,this.__setDigit($+L,(32767&D)<<15|32767&V),K=this.__digit($+L+1),V=(32767&K)-(P>>>15)-W,W=1&V>>>15}var y=Y.__digit(L),x=(K>>>15)-(32767&y)-W;W=1&x>>>15,this.__setDigit($+L,(32767&x)<<15|32767&V);var f=y>>>15;if($+L+1>=this.length)throw RangeError("out of bounds");(1&H)==0&&(K=this.__digit($+L+1),V=(32767&K)-f-W,W=1&V>>>15,this.__setDigit($+Y.length,1073709056&K|32767&V))}else{$>>=1;for(var I=0;I<Y.length-1;I++){var g=this.__digit($+I),l=Y.__digit(I),d=(32767&g)-(32767&l)-W;W=1&d>>>15;var p=(g>>>15)-(l>>>15)-W;W=1&p>>>15,this.__setDigit($+I,(32767&p)<<15|32767&d)}var s=this.__digit($+I),n=Y.__digit(I),$Q=(32767&s)-(32767&n)-W;W=1&$Q>>>15;var GQ=0;(1&H)==0&&(GQ=(s>>>15)-(n>>>15)-W,W=1&GQ>>>15),this.__setDigit($+I,(32767&GQ)<<15|32767&$Q)}return W}},{key:"__inplaceRightShift",value:function(Y){if(Y!==0){for(var $,H=this.__digit(0)>>>Y,G=this.length-1,W=0;W<G;W++)$=this.__digit(W+1),this.__setDigit(W,1073741823&$<<30-Y|H),H=$>>>Y;this.__setDigit(G,H)}}},{key:"__digit",value:function(Y){return this[Y]}},{key:"__unsignedDigit",value:function(Y){return this[Y]>>>0}},{key:"__setDigit",value:function(Y,$){this[Y]=0|$}},{key:"__setDigitGrow",value:function(Y,$){this[Y]=0|$}},{key:"__halfDigitLength",value:function(){var Y=this.length;return 32767>=this.__unsignedDigit(Y-1)?2*Y-1:2*Y}},{key:"__halfDigit",value:function(Y){return 32767&this[Y>>>1]>>>15*(1&Y)}},{key:"__setHalfDigit",value:function(Y,$){var H=Y>>>1,G=this.__digit(H),W=1&Y?32767&G|$<<15:1073709056&G|32767&$;this.__setDigit(H,W)}}],[{key:"BigInt",value:function(Y){var $=Number.isFinite;if(typeof Y=="number"){if(Y===0)return q.__zero();if(q.__isOneDigitInt(Y))return 0>Y?q.__oneDigit(-Y,!0):q.__oneDigit(Y,!1);if(!$(Y)||c(Y)!==Y)throw RangeError("The number "+Y+" cannot be converted to BigInt because it is not an integer");return q.__fromDouble(Y)}if(typeof Y=="string"){var H=q.__fromString(Y);if(H===null)throw SyntaxError("Cannot convert "+Y+" to a BigInt");return H}if(typeof Y=="boolean")return Y===!0?q.__oneDigit(1,!1):q.__zero();if(r(Y)==="object"){if(Y.constructor===q)return Y;var G=q.__toPrimitive(Y);return q.BigInt(G)}throw TypeError("Cannot convert "+Y+" to a BigInt")}},{key:"toNumber",value:function(Y){var $=Y.length;if($===0)return 0;if($===1){var H=Y.__unsignedDigit(0);return Y.sign?-H:H}var G=Y.__digit($-1),W=q.__clz30(G),K=30*$-W;if(1024<K)return Y.sign?-1/0:1/0;var V=K-1,L=G,P=$-1,D=W+3,y=D===32?0:L<<D;y>>>=12;var x=D-12,f=12<=D?0:L<<20+D,I=20+D;for(0<x&&0<P&&(P--,L=Y.__digit(P),y|=L>>>30-x,f=L<<x+2,I=x+2);0<I&&0<P;)P--,L=Y.__digit(P),f|=30<=I?L<<I-30:L>>>30-I,I-=30;var g=q.__decideRounding(Y,I,P,L);if((g===1||g===0&&(1&f)==1)&&(f=f+1>>>0,f===0&&(y++,y>>>20!=0&&(y=0,V++,1023<V))))return Y.sign?-1/0:1/0;var l=Y.sign?-2147483648:0;return V=V+1023<<20,q.__kBitConversionInts[q.__kBitConversionIntHigh]=l|V|y,q.__kBitConversionInts[q.__kBitConversionIntLow]=f,q.__kBitConversionDouble[0]}},{key:"unaryMinus",value:function(Y){if(Y.length===0)return Y;var $=Y.__copy();return $.sign=!Y.sign,$}},{key:"bitwiseNot",value:function(Y){return Y.sign?q.__absoluteSubOne(Y).__trim():q.__absoluteAddOne(Y,!0)}},{key:"exponentiate",value:function(Y,$){if($.sign)throw RangeError("Exponent must be positive");if($.length===0)return q.__oneDigit(1,!1);if(Y.length===0)return Y;if(Y.length===1&&Y.__digit(0)===1)return Y.sign&&(1&$.__digit(0))==0?q.unaryMinus(Y):Y;if(1<$.length)throw RangeError("BigInt too big");var H=$.__unsignedDigit(0);if(H===1)return Y;if(H>=q.__kMaxLengthBits)throw RangeError("BigInt too big");if(Y.length===1&&Y.__digit(0)===2){var G=1+(0|H/30),W=Y.sign&&(1&H)!=0,K=new q(G,W);K.__initializeDigits();var V=1<<H%30;return K.__setDigit(G-1,V),K}var L=null,P=Y;for((1&H)!=0&&(L=Y),H>>=1;H!==0;H>>=1)P=q.multiply(P,P),(1&H)!=0&&(L===null?L=P:L=q.multiply(L,P));return L}},{key:"multiply",value:function(Y,$){if(Y.length===0)return Y;if($.length===0)return $;var H=Y.length+$.length;30<=Y.__clzmsd()+$.__clzmsd()&&H--;var G=new q(H,Y.sign!==$.sign);G.__initializeDigits();for(var W=0;W<Y.length;W++)q.__multiplyAccumulate($,Y.__digit(W),G,W);return G.__trim()}},{key:"divide",value:function(Y,$){if($.length===0)throw RangeError("Division by zero");if(0>q.__absoluteCompare(Y,$))return q.__zero();var H,G=Y.sign!==$.sign,W=$.__unsignedDigit(0);if($.length===1&&32767>=W){if(W===1)return G===Y.sign?Y:q.unaryMinus(Y);H=q.__absoluteDivSmall(Y,W,null)}else H=q.__absoluteDivLarge(Y,$,!0,!1);return H.sign=G,H.__trim()}},{key:"remainder",value:function(Y,$){if($.length===0)throw RangeError("Division by zero");if(0>q.__absoluteCompare(Y,$))return Y;var H=$.__unsignedDigit(0);if($.length===1&&32767>=H){if(H===1)return q.__zero();var G=q.__absoluteModSmall(Y,H);return G===0?q.__zero():q.__oneDigit(G,Y.sign)}var W=q.__absoluteDivLarge(Y,$,!1,!0);return W.sign=Y.sign,W.__trim()}},{key:"add",value:function(Y,$){var H=Y.sign;return H===$.sign?q.__absoluteAdd(Y,$,H):0<=q.__absoluteCompare(Y,$)?q.__absoluteSub(Y,$,H):q.__absoluteSub($,Y,!H)}},{key:"subtract",value:function(Y,$){var H=Y.sign;return H===$.sign?0<=q.__absoluteCompare(Y,$)?q.__absoluteSub(Y,$,H):q.__absoluteSub($,Y,!H):q.__absoluteAdd(Y,$,H)}},{key:"leftShift",value:function(Y,$){return $.length===0||Y.length===0?Y:$.sign?q.__rightShiftByAbsolute(Y,$):q.__leftShiftByAbsolute(Y,$)}},{key:"signedRightShift",value:function(Y,$){return $.length===0||Y.length===0?Y:$.sign?q.__leftShiftByAbsolute(Y,$):q.__rightShiftByAbsolute(Y,$)}},{key:"unsignedRightShift",value:function(){throw TypeError("BigInts have no unsigned right shift; use >> instead")}},{key:"lessThan",value:function(Y,$){return 0>q.__compareToBigInt(Y,$)}},{key:"lessThanOrEqual",value:function(Y,$){return 0>=q.__compareToBigInt(Y,$)}},{key:"greaterThan",value:function(Y,$){return 0<q.__compareToBigInt(Y,$)}},{key:"greaterThanOrEqual",value:function(Y,$){return 0<=q.__compareToBigInt(Y,$)}},{key:"equal",value:function(Y,$){if(Y.sign!==$.sign)return!1;if(Y.length!==$.length)return!1;for(var H=0;H<Y.length;H++)if(Y.__digit(H)!==$.__digit(H))return!1;return!0}},{key:"notEqual",value:function(Y,$){return!q.equal(Y,$)}},{key:"bitwiseAnd",value:function(Y,$){if(!Y.sign&&!$.sign)return q.__absoluteAnd(Y,$).__trim();if(Y.sign&&$.sign){var H=v(Y.length,$.length)+1,G=q.__absoluteSubOne(Y,H),W=q.__absoluteSubOne($);return G=q.__absoluteOr(G,W,G),q.__absoluteAddOne(G,!0,G).__trim()}if(Y.sign){var K=[$,Y];Y=K[0],$=K[1]}return q.__absoluteAndNot(Y,q.__absoluteSubOne($)).__trim()}},{key:"bitwiseXor",value:function(Y,$){if(!Y.sign&&!$.sign)return q.__absoluteXor(Y,$).__trim();if(Y.sign&&$.sign){var H=v(Y.length,$.length),G=q.__absoluteSubOne(Y,H),W=q.__absoluteSubOne($);return q.__absoluteXor(G,W,G).__trim()}var K=v(Y.length,$.length)+1;if(Y.sign){var V=[$,Y];Y=V[0],$=V[1]}var L=q.__absoluteSubOne($,K);return L=q.__absoluteXor(L,Y,L),q.__absoluteAddOne(L,!0,L).__trim()}},{key:"bitwiseOr",value:function(Y,$){var H=v(Y.length,$.length);if(!Y.sign&&!$.sign)return q.__absoluteOr(Y,$).__trim();if(Y.sign&&$.sign){var G=q.__absoluteSubOne(Y,H),W=q.__absoluteSubOne($);return G=q.__absoluteAnd(G,W,G),q.__absoluteAddOne(G,!0,G).__trim()}if(Y.sign){var K=[$,Y];Y=K[0],$=K[1]}var V=q.__absoluteSubOne($,H);return V=q.__absoluteAndNot(V,Y,V),q.__absoluteAddOne(V,!0,V).__trim()}},{key:"asIntN",value:function(Y,$){if($.length===0)return $;if(Y=c(Y),0>Y)throw RangeError("Invalid value: not (convertible to) a safe integer");if(Y===0)return q.__zero();if(Y>=q.__kMaxLengthBits)return $;var H=0|(Y+29)/30;if($.length<H)return $;var G=$.__unsignedDigit(H-1),W=1<<(Y-1)%30;if($.length===H&&G<W)return $;var K=(G&W)===W;if(!K)return q.__truncateToNBits(Y,$);if(!$.sign)return q.__truncateAndSubFromPowerOfTwo(Y,$,!0);if((G&W-1)==0){for(var V=H-2;0<=V;V--)if($.__digit(V)!==0)return q.__truncateAndSubFromPowerOfTwo(Y,$,!1);return $.length===H&&G===W?$:q.__truncateToNBits(Y,$)}return q.__truncateAndSubFromPowerOfTwo(Y,$,!1)}},{key:"asUintN",value:function(Y,$){if($.length===0)return $;if(Y=c(Y),0>Y)throw RangeError("Invalid value: not (convertible to) a safe integer");if(Y===0)return q.__zero();if($.sign){if(Y>q.__kMaxLengthBits)throw RangeError("BigInt too big");return q.__truncateAndSubFromPowerOfTwo(Y,$,!1)}if(Y>=q.__kMaxLengthBits)return $;var H=0|(Y+29)/30;if($.length<H)return $;var G=Y%30;if($.length==H){if(G===0)return $;var W=$.__digit(H-1);if(W>>>G==0)return $}return q.__truncateToNBits(Y,$)}},{key:"ADD",value:function(Y,$){if(Y=q.__toPrimitive(Y),$=q.__toPrimitive($),typeof Y=="string")return typeof $!="string"&&($=$.toString()),Y+$;if(typeof $=="string")return Y.toString()+$;if(Y=q.__toNumeric(Y),$=q.__toNumeric($),q.__isBigInt(Y)&&q.__isBigInt($))return q.add(Y,$);if(typeof Y=="number"&&typeof $=="number")return Y+$;throw TypeError("Cannot mix BigInt and other types, use explicit conversions")}},{key:"LT",value:function(Y,$){return q.__compare(Y,$,0)}},{key:"LE",value:function(Y,$){return q.__compare(Y,$,1)}},{key:"GT",value:function(Y,$){return q.__compare(Y,$,2)}},{key:"GE",value:function(Y,$){return q.__compare(Y,$,3)}},{key:"EQ",value:function(Y,$){for(;;){if(q.__isBigInt(Y))return q.__isBigInt($)?q.equal(Y,$):q.EQ($,Y);if(typeof Y=="number"){if(q.__isBigInt($))return q.__equalToNumber($,Y);if(r($)!=="object")return Y==$;$=q.__toPrimitive($)}else if(typeof Y=="string"){if(q.__isBigInt($))return Y=q.__fromString(Y),Y!==null&&q.equal(Y,$);if(r($)!=="object")return Y==$;$=q.__toPrimitive($)}else if(typeof Y=="boolean"){if(q.__isBigInt($))return q.__equalToNumber($,+Y);if(r($)!=="object")return Y==$;$=q.__toPrimitive($)}else if(r(Y)==="symbol"){if(q.__isBigInt($))return!1;if(r($)!=="object")return Y==$;$=q.__toPrimitive($)}else if(r(Y)==="object"){if(r($)==="object"&&$.constructor!==q)return Y==$;Y=q.__toPrimitive(Y)}else return Y==$}}},{key:"NE",value:function(Y,$){return!q.EQ(Y,$)}},{key:"DataViewGetBigInt64",value:function(Y,$){var H=2<arguments.length&&arguments[2]!==void 0&&arguments[2];return q.asIntN(64,q.DataViewGetBigUint64(Y,$,H))}},{key:"DataViewGetBigUint64",value:function(Y,$){var H=2<arguments.length&&arguments[2]!==void 0&&arguments[2],G=H?[4,0]:[0,4],W=QQ(G,2),K=W[0],V=W[1],L=Y.getUint32($+K,H),P=Y.getUint32($+V,H),D=new q(3,!1);return D.__setDigit(0,1073741823&P),D.__setDigit(1,(268435455&L)<<2|P>>>30),D.__setDigit(2,L>>>28),D.__trim()}},{key:"DataViewSetBigInt64",value:function(Y,$,H){var G=3<arguments.length&&arguments[3]!==void 0&&arguments[3];q.DataViewSetBigUint64(Y,$,H,G)}},{key:"DataViewSetBigUint64",value:function(Y,$,H){var G=3<arguments.length&&arguments[3]!==void 0&&arguments[3];H=q.asUintN(64,H);var W=0,K=0;if(0<H.length&&(K=H.__digit(0),1<H.length)){var V=H.__digit(1);K|=V<<30,W=V>>>2,2<H.length&&(W|=H.__digit(2)<<28)}var L=G?[4,0]:[0,4],P=QQ(L,2),D=P[0],y=P[1];Y.setUint32($+D,W,G),Y.setUint32($+y,K,G)}},{key:"__zero",value:function(){return new q(0,!1)}},{key:"__oneDigit",value:function(Y,$){var H=new q(1,$);return H.__setDigit(0,Y),H}},{key:"__decideRounding",value:function(Y,$,H,G){if(0<$)return-1;var W;if(0>$)W=-$-1;else{if(H===0)return-1;H--,G=Y.__digit(H),W=29}var K=1<<W;if((G&K)==0)return-1;if(K-=1,(G&K)!=0)return 1;for(;0<H;)if(H--,Y.__digit(H)!==0)return 1;return 0}},{key:"__fromDouble",value:function(Y){var $=0>Y;q.__kBitConversionDouble[0]=Y;var H,G=2047&q.__kBitConversionInts[q.__kBitConversionIntHigh]>>>20,W=G-1023,K=(0|W/30)+1,V=new q(K,$),L=1048576,P=1048575&q.__kBitConversionInts[q.__kBitConversionIntHigh]|L,D=q.__kBitConversionInts[q.__kBitConversionIntLow],y=20,x=W%30,f=0;if(x<y){var I=y-x;f=I+32,H=P>>>I,P=P<<32-I|D>>>I,D<<=32-I}else if(x===y)f=32,H=P,P=D,D=0;else{var g=x-y;f=32-g,H=P<<g|D>>>32-g,P=D<<g,D=0}V.__setDigit(K-1,H);for(var l=K-2;0<=l;l--)0<f?(f-=30,H=P>>>2,P=P<<30|D>>>2,D<<=30):H=0,V.__setDigit(l,H);return V.__trim()}},{key:"__isWhitespace",value:function(Y){return 13>=Y&&9<=Y||(159>=Y?Y==32:131071>=Y?Y==160||Y==5760:196607>=Y?(Y&=131071,10>=Y||Y==40||Y==41||Y==47||Y==95||Y==4096):Y==65279)}},{key:"__fromString",value:function(Y){var $=1<arguments.length&&arguments[1]!==void 0?arguments[1]:0,H=0,G=Y.length,W=0;if(W===G)return q.__zero();for(var K=Y.charCodeAt(W);q.__isWhitespace(K);){if(++W===G)return q.__zero();K=Y.charCodeAt(W)}if(K===43){if(++W===G)return null;K=Y.charCodeAt(W),H=1}else if(K===45){if(++W===G)return null;K=Y.charCodeAt(W),H=-1}if($===0){if($=10,K===48){if(++W===G)return q.__zero();if(K=Y.charCodeAt(W),K===88||K===120){if($=16,++W===G)return null;K=Y.charCodeAt(W)}else if(K===79||K===111){if($=8,++W===G)return null;K=Y.charCodeAt(W)}else if(K===66||K===98){if($=2,++W===G)return null;K=Y.charCodeAt(W)}}}else if($===16&&K===48){if(++W===G)return q.__zero();if(K=Y.charCodeAt(W),K===88||K===120){if(++W===G)return null;K=Y.charCodeAt(W)}}if(H!==0&&$!==10)return null;for(;K===48;){if(++W===G)return q.__zero();K=Y.charCodeAt(W)}var V=G-W,L=q.__kMaxBitsPerChar[$],P=q.__kBitsPerCharTableMultiplier-1;if(V>1073741824/L)return null;var D=L*V+P>>>q.__kBitsPerCharTableShift,y=0|(D+29)/30,x=new q(y,!1),f=10>$?$:10,I=10<$?$-10:0;if(($&$-1)==0){L>>=q.__kBitsPerCharTableShift;var g=[],l=[],d=!1;do{for(var p,s=0,n=0;;){if(p=void 0,K-48>>>0<f)p=K-48;else if((32|K)-97>>>0<I)p=(32|K)-87;else{d=!0;break}if(n+=L,s=s<<L|p,++W===G){d=!0;break}if(K=Y.charCodeAt(W),30<n+L)break}g.push(s),l.push(n)}while(!d);q.__fillFromParts(x,g,l)}else{x.__initializeDigits();var $Q=!1,GQ=0;do{for(var J,F=0,M=1;;){if(J=void 0,K-48>>>0<f)J=K-48;else if((32|K)-97>>>0<I)J=(32|K)-87;else{$Q=!0;break}var U=M*$;if(1073741823<U)break;if(M=U,F=F*$+J,GQ++,++W===G){$Q=!0;break}K=Y.charCodeAt(W)}P=30*q.__kBitsPerCharTableMultiplier-1;var A=0|(L*GQ+P>>>q.__kBitsPerCharTableShift)/30;x.__inplaceMultiplyAdd(M,F,A)}while(!$Q)}if(W!==G){if(!q.__isWhitespace(K))return null;for(W++;W<G;W++)if(K=Y.charCodeAt(W),!q.__isWhitespace(K))return null}return x.sign=H===-1,x.__trim()}},{key:"__fillFromParts",value:function(Y,$,H){for(var G=0,W=0,K=0,V=$.length-1;0<=V;V--){var L=$[V],P=H[V];W|=L<<K,K+=P,K===30?(Y.__setDigit(G++,W),K=0,W=0):30<K&&(Y.__setDigit(G++,1073741823&W),K-=30,W=L>>>P-K)}if(W!==0){if(G>=Y.length)throw Error("implementation bug");Y.__setDigit(G++,W)}for(;G<Y.length;G++)Y.__setDigit(G,0)}},{key:"__toStringBasePowerOfTwo",value:function(Y,$){var H=Y.length,G=$-1;G=(85&G>>>1)+(85&G),G=(51&G>>>2)+(51&G),G=(15&G>>>4)+(15&G);var W=G,K=$-1,V=Y.__digit(H-1),L=q.__clz30(V),P=30*H-L,D=0|(P+W-1)/W;if(Y.sign&&D++,268435456<D)throw Error("string too long");for(var y=Array(D),x=D-1,f=0,I=0,g=0;g<H-1;g++){var l=Y.__digit(g),d=(f|l<<I)&K;y[x--]=q.__kConversionChars[d];var p=W-I;for(f=l>>>p,I=30-p;I>=W;)y[x--]=q.__kConversionChars[f&K],f>>>=W,I-=W}var s=(f|V<<I)&K;for(y[x--]=q.__kConversionChars[s],f=V>>>W-I;f!==0;)y[x--]=q.__kConversionChars[f&K],f>>>=W;if(Y.sign&&(y[x--]="-"),x!==-1)throw Error("implementation bug");return y.join("")}},{key:"__toStringGeneric",value:function(Y,$,H){var G=Y.length;if(G===0)return"";if(G===1){var W=Y.__unsignedDigit(0).toString($);return H===!1&&Y.sign&&(W="-"+W),W}var K=30*G-q.__clz30(Y.__digit(G-1)),V=q.__kMaxBitsPerChar[$],L=V-1,P=K*q.__kBitsPerCharTableMultiplier;P+=L-1,P=0|P/L;var D,y,x=P+1>>1,f=q.exponentiate(q.__oneDigit($,!1),q.__oneDigit(x,!1)),I=f.__unsignedDigit(0);if(f.length===1&&32767>=I){D=new q(Y.length,!1),D.__initializeDigits();for(var g,l=0,d=2*Y.length-1;0<=d;d--)g=l<<15|Y.__halfDigit(d),D.__setHalfDigit(d,0|g/I),l=0|g%I;y=l.toString($)}else{var p=q.__absoluteDivLarge(Y,f,!0,!0);D=p.quotient;var s=p.remainder.__trim();y=q.__toStringGeneric(s,$,!0)}D.__trim();for(var n=q.__toStringGeneric(D,$,!0);y.length<x;)y="0"+y;return H===!1&&Y.sign&&(n="-"+n),n+y}},{key:"__unequalSign",value:function(Y){return Y?-1:1}},{key:"__absoluteGreater",value:function(Y){return Y?-1:1}},{key:"__absoluteLess",value:function(Y){return Y?1:-1}},{key:"__compareToBigInt",value:function(Y,$){var H=Y.sign;if(H!==$.sign)return q.__unequalSign(H);var G=q.__absoluteCompare(Y,$);return 0<G?q.__absoluteGreater(H):0>G?q.__absoluteLess(H):0}},{key:"__compareToNumber",value:function(Y,$){if(q.__isOneDigitInt($)){var H=Y.sign,G=0>$;if(H!==G)return q.__unequalSign(H);if(Y.length===0){if(G)throw Error("implementation bug");return $===0?0:-1}if(1<Y.length)return q.__absoluteGreater(H);var W=j($),K=Y.__unsignedDigit(0);return K>W?q.__absoluteGreater(H):K<W?q.__absoluteLess(H):0}return q.__compareToDouble(Y,$)}},{key:"__compareToDouble",value:function(Y,$){if($!==$)return $;if($===1/0)return-1;if($===-1/0)return 1;var H=Y.sign,G=0>$;if(H!==G)return q.__unequalSign(H);if($===0)throw Error("implementation bug: should be handled elsewhere");if(Y.length===0)return-1;q.__kBitConversionDouble[0]=$;var W=2047&q.__kBitConversionInts[q.__kBitConversionIntHigh]>>>20;if(W==2047)throw Error("implementation bug: handled elsewhere");var K=W-1023;if(0>K)return q.__absoluteGreater(H);var V=Y.length,L=Y.__digit(V-1),P=q.__clz30(L),D=30*V-P,y=K+1;if(D<y)return q.__absoluteLess(H);if(D>y)return q.__absoluteGreater(H);var x=1048576,f=1048576|1048575&q.__kBitConversionInts[q.__kBitConversionIntHigh],I=q.__kBitConversionInts[q.__kBitConversionIntLow],g=20,l=29-P;if(l!==(0|(D-1)%30))throw Error("implementation bug");var d,p=0;if(l<g){var s=g-l;p=s+32,d=f>>>s,f=f<<32-s|I>>>s,I<<=32-s}else if(l===g)p=32,d=f,f=I,I=0;else{var n=l-g;p=32-n,d=f<<n|I>>>32-n,f=I<<n,I=0}if(L>>>=0,d>>>=0,L>d)return q.__absoluteGreater(H);if(L<d)return q.__absoluteLess(H);for(var $Q=V-2;0<=$Q;$Q--){0<p?(p-=30,d=f>>>2,f=f<<30|I>>>2,I<<=30):d=0;var GQ=Y.__unsignedDigit($Q);if(GQ>d)return q.__absoluteGreater(H);if(GQ<d)return q.__absoluteLess(H)}if(f!==0||I!==0){if(p===0)throw Error("implementation bug");return q.__absoluteLess(H)}return 0}},{key:"__equalToNumber",value:function(Y,$){return q.__isOneDigitInt($)?$===0?Y.length===0:Y.length===1&&Y.sign===0>$&&Y.__unsignedDigit(0)===j($):q.__compareToDouble(Y,$)===0}},{key:"__comparisonResultToBool",value:function(Y,$){return $===0?0>Y:$===1?0>=Y:$===2?0<Y:$===3?0<=Y:void 0}},{key:"__compare",value:function(Y,$,H){if(Y=q.__toPrimitive(Y),$=q.__toPrimitive($),typeof Y=="string"&&typeof $=="string")switch(H){case 0:return Y<$;case 1:return Y<=$;case 2:return Y>$;case 3:return Y>=$}if(q.__isBigInt(Y)&&typeof $=="string")return $=q.__fromString($),$!==null&&q.__comparisonResultToBool(q.__compareToBigInt(Y,$),H);if(typeof Y=="string"&&q.__isBigInt($))return Y=q.__fromString(Y),Y!==null&&q.__comparisonResultToBool(q.__compareToBigInt(Y,$),H);if(Y=q.__toNumeric(Y),$=q.__toNumeric($),q.__isBigInt(Y)){if(q.__isBigInt($))return q.__comparisonResultToBool(q.__compareToBigInt(Y,$),H);if(typeof $!="number")throw Error("implementation bug");return q.__comparisonResultToBool(q.__compareToNumber(Y,$),H)}if(typeof Y!="number")throw Error("implementation bug");if(q.__isBigInt($))return q.__comparisonResultToBool(q.__compareToNumber($,Y),2^H);if(typeof $!="number")throw Error("implementation bug");return H===0?Y<$:H===1?Y<=$:H===2?Y>$:H===3?Y>=$:void 0}},{key:"__absoluteAdd",value:function(Y,$,H){if(Y.length<$.length)return q.__absoluteAdd($,Y,H);if(Y.length===0)return Y;if($.length===0)return Y.sign===H?Y:q.unaryMinus(Y);var G=Y.length;(Y.__clzmsd()===0||$.length===Y.length&&$.__clzmsd()===0)&&G++;for(var W,K=new q(G,H),V=0,L=0;L<$.length;L++)W=Y.__digit(L)+$.__digit(L)+V,V=W>>>30,K.__setDigit(L,1073741823&W);for(;L<Y.length;L++){var P=Y.__digit(L)+V;V=P>>>30,K.__setDigit(L,1073741823&P)}return L<K.length&&K.__setDigit(L,V),K.__trim()}},{key:"__absoluteSub",value:function(Y,$,H){if(Y.length===0)return Y;if($.length===0)return Y.sign===H?Y:q.unaryMinus(Y);for(var G,W=new q(Y.length,H),K=0,V=0;V<$.length;V++)G=Y.__digit(V)-$.__digit(V)-K,K=1&G>>>30,W.__setDigit(V,1073741823&G);for(;V<Y.length;V++){var L=Y.__digit(V)-K;K=1&L>>>30,W.__setDigit(V,1073741823&L)}return W.__trim()}},{key:"__absoluteAddOne",value:function(Y,$){var H=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null,G=Y.length;H===null?H=new q(G,$):H.sign=$;for(var W,K=1,V=0;V<G;V++)W=Y.__digit(V)+K,K=W>>>30,H.__setDigit(V,1073741823&W);return K!==0&&H.__setDigitGrow(G,1),H}},{key:"__absoluteSubOne",value:function(Y,$){var H=Y.length;$=$||H;for(var G,W=new q($,!1),K=1,V=0;V<H;V++)G=Y.__digit(V)-K,K=1&G>>>30,W.__setDigit(V,1073741823&G);if(K!==0)throw Error("implementation bug");for(var L=H;L<$;L++)W.__setDigit(L,0);return W}},{key:"__absoluteAnd",value:function(Y,$){var H=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null,G=Y.length,W=$.length,K=W;if(G<W){K=G;var V=Y,L=G;Y=$,G=W,$=V,W=L}var P=K;H===null?H=new q(P,!1):P=H.length;for(var D=0;D<K;D++)H.__setDigit(D,Y.__digit(D)&$.__digit(D));for(;D<P;D++)H.__setDigit(D,0);return H}},{key:"__absoluteAndNot",value:function(Y,$){var H=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null,G=Y.length,W=$.length,K=W;G<W&&(K=G);var V=G;H===null?H=new q(V,!1):V=H.length;for(var L=0;L<K;L++)H.__setDigit(L,Y.__digit(L)&~$.__digit(L));for(;L<G;L++)H.__setDigit(L,Y.__digit(L));for(;L<V;L++)H.__setDigit(L,0);return H}},{key:"__absoluteOr",value:function(Y,$){var H=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null,G=Y.length,W=$.length,K=W;if(G<W){K=G;var V=Y,L=G;Y=$,G=W,$=V,W=L}var P=G;H===null?H=new q(P,!1):P=H.length;for(var D=0;D<K;D++)H.__setDigit(D,Y.__digit(D)|$.__digit(D));for(;D<G;D++)H.__setDigit(D,Y.__digit(D));for(;D<P;D++)H.__setDigit(D,0);return H}},{key:"__absoluteXor",value:function(Y,$){var H=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null,G=Y.length,W=$.length,K=W;if(G<W){K=G;var V=Y,L=G;Y=$,G=W,$=V,W=L}var P=G;H===null?H=new q(P,!1):P=H.length;for(var D=0;D<K;D++)H.__setDigit(D,Y.__digit(D)^$.__digit(D));for(;D<G;D++)H.__setDigit(D,Y.__digit(D));for(;D<P;D++)H.__setDigit(D,0);return H}},{key:"__absoluteCompare",value:function(Y,$){var H=Y.length-$.length;if(H!=0)return H;for(var G=Y.length-1;0<=G&&Y.__digit(G)===$.__digit(G);)G--;return 0>G?0:Y.__unsignedDigit(G)>$.__unsignedDigit(G)?1:-1}},{key:"__multiplyAccumulate",value:function(Y,$,H,G){if($!==0){for(var W=32767&$,K=$>>>15,V=0,L=0,P=0;P<Y.length;P++,G++){var D=H.__digit(G),y=Y.__digit(P),x=32767&y,f=y>>>15,I=q.__imul(x,W),g=q.__imul(x,K),l=q.__imul(f,W),d=q.__imul(f,K);D+=L+I+V,V=D>>>30,D&=1073741823,D+=((32767&g)<<15)+((32767&l)<<15),V+=D>>>30,L=d+(g>>>15)+(l>>>15),H.__setDigit(G,1073741823&D)}for(;V!==0||L!==0;G++){var p=H.__digit(G);p+=V+L,L=0,V=p>>>30,H.__setDigit(G,1073741823&p)}}}},{key:"__internalMultiplyAdd",value:function(Y,$,H,G,W){for(var K=H,V=0,L=0;L<G;L++){var P=Y.__digit(L),D=q.__imul(32767&P,$),y=q.__imul(P>>>15,$),x=D+((32767&y)<<15)+V+K;K=x>>>30,V=y>>>15,W.__setDigit(L,1073741823&x)}if(W.length>G)for(W.__setDigit(G++,K+V);G<W.length;)W.__setDigit(G++,0);else if(K+V!==0)throw Error("implementation bug")}},{key:"__absoluteDivSmall",value:function(Y,$){var H=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;H===null&&(H=new q(Y.length,!1));for(var G=0,W=2*Y.length-1;0<=W;W-=2){var K=(G<<15|Y.__halfDigit(W))>>>0,V=0|K/$;G=0|K%$,K=(G<<15|Y.__halfDigit(W-1))>>>0;var L=0|K/$;G=0|K%$,H.__setDigit(W>>>1,V<<15|L)}return H}},{key:"__absoluteModSmall",value:function(Y,$){for(var H,G=0,W=2*Y.length-1;0<=W;W--)H=(G<<15|Y.__halfDigit(W))>>>0,G=0|H%$;return G}},{key:"__absoluteDivLarge",value:function(Y,$,H,G){var W=$.__halfDigitLength(),K=$.length,V=Y.__halfDigitLength()-W,L=null;H&&(L=new q(V+2>>>1,!1),L.__initializeDigits());var P=new q(W+2>>>1,!1);P.__initializeDigits();var D=q.__clz15($.__halfDigit(W-1));0<D&&($=q.__specialLeftShift($,D,0));for(var y=q.__specialLeftShift(Y,D,1),x=$.__halfDigit(W-1),f=0,I=V;0<=I;I--){var g=32767,l=y.__halfDigit(I+W);if(l!==x){var d=(l<<15|y.__halfDigit(I+W-1))>>>0;g=0|d/x;for(var p=0|d%x,s=$.__halfDigit(W-2),n=y.__halfDigit(I+W-2);q.__imul(g,s)>>>0>(p<<16|n)>>>0&&(g--,p+=x,!(32767<p)););}q.__internalMultiplyAdd($,g,0,K,P);var $Q=y.__inplaceSub(P,I,W+1);$Q!==0&&($Q=y.__inplaceAdd($,I,W),y.__setHalfDigit(I+W,32767&y.__halfDigit(I+W)+$Q),g--),H&&(1&I?f=g<<15:L.__setDigit(I>>>1,f|g))}if(G)return y.__inplaceRightShift(D),H?{quotient:L,remainder:y}:y;if(H)return L;throw Error("unreachable")}},{key:"__clz15",value:function(Y){return q.__clz30(Y)-15}},{key:"__specialLeftShift",value:function(Y,$,H){var G=Y.length,W=G+H,K=new q(W,!1);if($===0){for(var V=0;V<G;V++)K.__setDigit(V,Y.__digit(V));return 0<H&&K.__setDigit(G,0),K}for(var L,P=0,D=0;D<G;D++)L=Y.__digit(D),K.__setDigit(D,1073741823&L<<$|P),P=L>>>30-$;return 0<H&&K.__setDigit(G,P),K}},{key:"__leftShiftByAbsolute",value:function(Y,$){var H=q.__toShiftAmount($);if(0>H)throw RangeError("BigInt too big");var G=0|H/30,W=H%30,K=Y.length,V=W!==0&&Y.__digit(K-1)>>>30-W!=0,L=K+G+(V?1:0),P=new q(L,Y.sign);if(W===0){for(var D=0;D<G;D++)P.__setDigit(D,0);for(;D<L;D++)P.__setDigit(D,Y.__digit(D-G))}else{for(var y=0,x=0;x<G;x++)P.__setDigit(x,0);for(var f,I=0;I<K;I++)f=Y.__digit(I),P.__setDigit(I+G,1073741823&f<<W|y),y=f>>>30-W;if(V)P.__setDigit(K+G,y);else if(y!==0)throw Error("implementation bug")}return P.__trim()}},{key:"__rightShiftByAbsolute",value:function(Y,$){var{length:H,sign:G}=Y,W=q.__toShiftAmount($);if(0>W)return q.__rightShiftByMaximum(G);var K=0|W/30,V=W%30,L=H-K;if(0>=L)return q.__rightShiftByMaximum(G);var P=!1;if(G){var D=(1<<V)-1;if((Y.__digit(K)&D)!=0)P=!0;else for(var y=0;y<K;y++)if(Y.__digit(y)!==0){P=!0;break}}if(P&&V===0){var x=Y.__digit(H-1),f=~x==0;f&&L++}var I=new q(L,G);if(V===0){I.__setDigit(L-1,0);for(var g=K;g<H;g++)I.__setDigit(g-K,Y.__digit(g))}else{for(var l,d=Y.__digit(K)>>>V,p=H-K-1,s=0;s<p;s++)l=Y.__digit(s+K+1),I.__setDigit(s,1073741823&l<<30-V|d),d=l>>>V;I.__setDigit(p,d)}return P&&(I=q.__absoluteAddOne(I,!0,I)),I.__trim()}},{key:"__rightShiftByMaximum",value:function(Y){return Y?q.__oneDigit(1,!0):q.__zero()}},{key:"__toShiftAmount",value:function(Y){if(1<Y.length)return-1;var $=Y.__unsignedDigit(0);return $>q.__kMaxLengthBits?-1:$}},{key:"__toPrimitive",value:function(Y){var $=1<arguments.length&&arguments[1]!==void 0?arguments[1]:"default";if(r(Y)!=="object")return Y;if(Y.constructor===q)return Y;if(typeof Symbol<"u"&&r(Symbol.toPrimitive)==="symbol"&&Y[Symbol.toPrimitive]){var H=Y[Symbol.toPrimitive]($);if(r(H)!=="object")return H;throw TypeError("Cannot convert object to primitive value")}var G=Y.valueOf;if(G){var W=G.call(Y);if(r(W)!=="object")return W}var K=Y.toString;if(K){var V=K.call(Y);if(r(V)!=="object")return V}throw TypeError("Cannot convert object to primitive value")}},{key:"__toNumeric",value:function(Y){return q.__isBigInt(Y)?Y:+Y}},{key:"__isBigInt",value:function(Y){return r(Y)==="object"&&Y!==null&&Y.constructor===q}},{key:"__truncateToNBits",value:function(Y,$){for(var H=0|(Y+29)/30,G=new q(H,$.sign),W=H-1,K=0;K<W;K++)G.__setDigit(K,$.__digit(K));var V=$.__digit(W);if(Y%30!=0){var L=32-Y%30;V=V<<L>>>L}return G.__setDigit(W,V),G.__trim()}},{key:"__truncateAndSubFromPowerOfTwo",value:function(Y,$,H){for(var G=Math.min,W,K=0|(Y+29)/30,V=new q(K,H),L=0,P=K-1,D=0,y=G(P,$.length);L<y;L++)W=0-$.__digit(L)-D,D=1&W>>>30,V.__setDigit(L,1073741823&W);for(;L<P;L++)V.__setDigit(L,0|1073741823&-D);var x,f=P<$.length?$.__digit(P):0,I=Y%30;if(I===0)x=0-f-D,x&=1073741823;else{var g=32-I;f=f<<g>>>g;var l=1<<32-g;x=l-f-D,x&=l-1}return V.__setDigit(P,x),V.__trim()}},{key:"__digitPow",value:function(Y,$){for(var H=1;0<$;)1&$&&(H*=Y),$>>>=1,Y*=Y;return H}},{key:"__detectBigEndian",value:function(){return q.__kBitConversionDouble[0]=-0,q.__kBitConversionInts[0]!==0}},{key:"__isOneDigitInt",value:function(Y){return(1073741823&Y)===Y}}])}(RQ(Array));return o.__kMaxLength=33554432,o.__kMaxLengthBits=o.__kMaxLength<<5,o.__kMaxBitsPerChar=[0,0,32,51,64,75,83,90,96,102,107,111,115,119,122,126,128,131,134,136,139,141,143,145,147,149,151,153,154,156,158,159,160,162,163,165,166],o.__kBitsPerCharTableShift=5,o.__kBitsPerCharTableMultiplier=1<<o.__kBitsPerCharTableShift,o.__kConversionChars=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],o.__kBitConversionBuffer=new ArrayBuffer(8),o.__kBitConversionDouble=new Float64Array(o.__kBitConversionBuffer),o.__kBitConversionInts=new Int32Array(o.__kBitConversionBuffer),o.__kBitConversionIntHigh=o.__detectBigEndian()?0:1,o.__kBitConversionIntLow=o.__detectBigEndian()?1:0,o.__clz30=Z?function(C){return Z(C)-2}:function(C){var{LN2:j,log:v}=Math;return C===0?30:0|29-(0|v(C>>>0)/j)},o.__imul=Q||function(C,j){return 0|C*j},o})});var gQ=EY(TY(),1),FY=EY(kY(),1);var dQ="1.13.0.0";function LQ(){return typeof __BACKGROUND__<"u"&&__BACKGROUND__}function OQ(){return typeof __MAIN_THREAD__<"u"&&__MAIN_THREAD__}function cQ(Q,Z){var z=function(){var X=document.getElementById(Q);if(X&&X.focus)X.focus()};Z>0?setTimeout(z,Z):z()}function aQ(Q,Z){var z=function(){var X=document.getElementById(Q);if(X&&X.blur)X.blur()};Z>0?setTimeout(z,Z):z()}function sQ(Q,Z){var z=function(){var X=document.getElementById(Q);if(X&&typeof X.select==="function")X.select()};Z>0?setTimeout(z,Z):z()}function rQ(Q,Z,z,X){var N=function(){var S=document.getElementById(Q);if(S&&typeof S.setSelectionRange==="function")S.setSelectionRange(Z,z,"none")};X>0?setTimeout(N,X):N()}function iQ(Q,Z,z,X,N,S,O){var B={method:Z,headers:X};if(z)B.body=z;let h={},k=null;try{fetch(Q,B).then((m)=>{k=m.status;for(let[b,u]of m.headers)h[b]=u;if(m.status<200||m.status>=300)throw Error(m.statusText||"HTTP "+m.status);if(O=="json")return m.json();else if(O=="text")return m.text();else if(O==="arrayBuffer")return m.arrayBuffer();else if(O==="blob")return m.blob();else if(O==="bytes")return m.bytes();else if(O==="formData")return m.formData();else if(O==="none")return null}).then((m)=>N({error:null,body:m,headers:h,status:k})).catch((m)=>S({error:null,body:m,headers:h,status:k}))}catch(m){S({body:null,error:m.message,headers:h,status:k})}}function oQ(Q,Z,z,X,N,S,O,B,h){try{let k=new WebSocket(Q);return k.onopen=function(){Z()},k.onclose=function(m){z(m)},k.onerror=function(m){console.error(m),B("WebSocket error received")},k.onmessage=function(m){if(typeof m.data==="string")try{if(h){if(X)X(m.data);return}let b=JSON.parse(m.data);if(N)N(b)}catch(b){if(h&&X)X(m.data);else B(b.message)}else if(m.data instanceof Blob){if(S)S(m.data)}else if(m.data instanceof ArrayBuffer){if(O)O(m.data)}else console.error("Received unknown message type from WebSocket",m),B("Unknown message received from WebSocket")},k}catch(k){B(k.message)}}function nQ(Q){if(Q)Q.close(),Q=null}function tQ(Q,Z){if(Z&&Q&&Q.readyState===WebSocket.OPEN)Q.send(Z)}function eQ(Q,Z,z,X,N,S){try{let O=new EventSource(Q);return O.onopen=function(){Z()},O.onerror=function(){N("EventSource error received")},O.onmessage=function(B){try{if(S){if(z)z(B.data);return}let h=JSON.parse(B.data);if(X)X(h)}catch(h){if(S&&z)z(B.data);else N(h.message)}},O}catch(O){N(O.message)}}function QY(Q){if(Q)Q.close(),Q=null}function YY(Q,Z){if(!Q.classList)Q.classList=new Set;for(let z of Z)for(let X of z.trim().split(" "))if(X)Q.classList.add(X)}function ZY(Q,Z){if(!Q.parent)return;Z.nextSibling=Q.nextSibling,Z.parent=Q.parent,Q.parent.child=Z}function $Y(Q,Z={}){let z=Object.keys(Z),X=Object.values(Z);return Function(...z,Q)(...X)}function zY(Q){if(Q===null||Q===void 0)return 0;if(typeof Q==="number")return 1;if(typeof Q==="string")return 2;if(typeof Q==="boolean")return 3;if(Array.isArray(Q))return 4;return 5}function XY(Q){return function(){Q|=0,Q=Q+2654435769|0;var Z=Q^Q>>>15;return Z=Math.imul(Z,2246822507),Z=Z^Z>>>13,Z=Math.imul(Z,3266489909),((Z^Z>>>16)>>>0)/4294967296}}function qY(){let Q=new Uint32Array(1);return crypto.getRandomValues(Q)[0]}function HY(){return Math.random()}function zQ(Q,Z){switch(Q.type){case 3:for(let z of Q.children)zQ(z,Z);break;case 0:if(Q.child)zQ(Q.child,Z);break;default:Z(Q.domRef);break}}function qQ(Q){switch(Q.type){case 3:{if(!Q.children||Q.children.length===0)return null;return qQ(Q.children[0])}case 0:if(!Q.child)return null;return qQ(Q.child);default:return Q.domRef}}function NQ(Q){switch(Q.type){case 3:{if(!Q.children||Q.children.length===0)return null;return NQ(Q.children[Q.children.length-1])}case 0:if(!Q.child)return null;return NQ(Q.child);default:return Q.domRef}}function PQ(Q){return qQ(Q)}function WY(Q,Z,z){try{globalThis.cookieStore.get(Q).then((X)=>z(X?X.value:null)).catch((X)=>Z(X.message))}catch(X){Z(X.message)}}function GY(Q,Z){try{globalThis.cookieStore.getAll().then(Z).catch((z)=>Q(z.message))}catch(z){Q(z.message)}}function KY(Q,Z,z){try{globalThis.cookieStore.set(Q).then(z).catch((X)=>Z(X.message))}catch(X){Z(X.message)}}function UY(Q,Z,z){try{globalThis.cookieStore.delete(Q).then(z).catch((X)=>Z(X.message))}catch(X){Z(X.message)}}function JY(Q,Z,z){let X={name:Q.name};if(Q.path!=null)X.path=Q.path;if(Q.domain!=null)X.domain=Q.domain;if(Q.partitioned!=null)X.partitioned=Q.partitioned;try{globalThis.cookieStore.delete(X).then(z).catch((N)=>Z(N.message))}catch(N){Z(N.message)}}function KQ(Q,Z,z,X){if(!Q&&!Z)return;else if(!Q)FQ(Z,z,X);else if(!Z)xQ(Q,z,X);else if(Q.type===2&&Z.type===2)QZ(Q,Z,X);else if(Q.type===0&&Z.type===0){if(Z.key===Q.key){if(Z.child=Q.child,Z.componentId=Q.componentId,Q.child)Q.child.parent=Z;if(Z.diffProps)Z.diffProps();return}fQ(Q,Z,z,X)}else if(Q.type===3&&Z.type===3)if(Z.key===Q.key){let N=NQ(Q),S=N?N.nextSibling:X.nextSibling(Q);fY(Q.children,Z.children,z,X,S)}else fQ(Q,Z,z,X);else if(Q.type===1&&Z.type===1)if(Z.tag===Q.tag&&Z.key===Q.key)Z.domRef=Q.domRef,hY(Q,Z,X);else fQ(Q,Z,z,X);else fQ(Q,Z,z,X)}function QZ(Q,Z,z){if(Q.text!==Z.text)z.setTextContent(Q.domRef,Z.text);Z.domRef=Q.domRef;return}function fQ(Q,Z,z,X){if(Q.type===3){let O=NQ(Q),B=O?O.nextSibling:X.nextSibling(Q);if(xQ(Q,z,X),B)VQ(z,2,B,Z,X);else FQ(Z,z,X);return}switch(Q.type){case 2:break;default:IQ(Q);break}let N=qQ(Q),S=NQ(Q);if(!N||!S){let O=X.nextSibling(Q);if(O)VQ(z,2,O,Z,X);else FQ(Z,z,X)}else if(N!==S){let O=S.nextSibling;if(zQ(Q,(B)=>X.removeChild(z,B)),O)VQ(z,2,O,Z,X);else FQ(Z,z,X)}else VQ(z,1,N,Z,X);switch(Q.type){case 2:break;default:CQ(Q);break}}function xQ(Q,Z,z){switch(Q.type){case 2:break;case 3:for(let X of Q.children)xQ(X,Z,z);return;default:IQ(Q);break}switch(zQ(Q,(X)=>z.removeChild(Z,X)),Q.type){case 2:break;default:CQ(Q);break}}function CQ(Q){if(Q.type===3){for(let Z of Q.children)if(Z.type!==2)CQ(Z);return}switch(YZ(Q),Q.type){case 1:for(let Z of Q.children)if(Z.type!==2)CQ(Z);break;case 0:if(Q.child&&Q.child.type!==2)CQ(Q.child);break}}function YZ(Q){if(Q.type===1&&Q.onDestroyed)Q.onDestroyed();if(Q.type===0)UZ(Q)}function ZZ(Q){switch(Q.type){case 0:break;case 1:if(Q.onBeforeDestroyed)Q.onBeforeDestroyed();break;default:break}}function IQ(Q){if(Q.type===3){for(let Z of Q.children)if(Z.type!==2)IQ(Z);return}switch(ZZ(Q),Q.type){case 1:for(let Z of Q.children){if(Z.type===2)continue;IQ(Z)}break;case 0:if(Q.child&&Q.child.type!==2)IQ(Q.child);break}}function hY(Q,Z,z){XZ(Q?Q.props:{},Z.props,Z.domRef,Z.ns==="svg",z),zZ(Q?Q.classList:null,Z.classList,Z.domRef,z),qZ(Q?Q.css:{},Z.css,Z.domRef,z),$Z(Q,Z,z),fY(Q?Q.children:[],Z.children,Z.domRef,z),KZ(Z)}function $Z(Q,Z,z){if(!LQ()&&!OQ())return;if(Q===null&&Z.directEvents)for(let X of Z.directEvents)z.addEvent(Z.domRef,X,{capture:!1,direct:!0});for(let X of[!0,!1]){let N=vY(Q,X),S=vY(Z,X);for(let O in N)if(!(O in S))z.removeEvent(Z.domRef,O,X);for(let O in S){let B=S[O],h=N[O];if(!h||!WZ(B,h))z.addEvent(Z.domRef,O,B)}}}function zZ(Q,Z,z,X){if(!Q&&!Z)return;if(!Q){for(let N of Z)X.addClass(N,z);return}if(!Z){for(let N of Q)X.removeClass(N,z);return}for(let N of Q)if(!Z.has(N))X.removeClass(N,z);for(let N of Z)if(!Q.has(N))X.addClass(N,z);return}function XZ(Q,Z,z,X,N){var S;let O=LQ()||OQ();for(let B in Q)if(S=Z[B],S===void 0)if(X||O||!(B in z)||B==="disabled")N.removeAttribute(z,B);else N.setAttribute(z,B,"");else{if(S===Q[B]&&B!=="checked"&&B!=="value")continue;if(X)if(B==="href")N.setAttributeNS(z,"http://www.w3.org/1999/xlink","href",S);else N.setAttribute(z,B,S);else if(!O&&B in z&&!(B==="list"||B==="form"))z[B]=S;else N.setAttribute(z,B,S)}for(let B in Z){if(Q&&B in Q)continue;if(S=Z[B],X)if(B==="href")N.setAttributeNS(z,"http://www.w3.org/1999/xlink","href",S);else N.setAttribute(z,B,S);else if(!O&&B in z&&!(B==="list"||B==="form"))z[B]=Z[B];else N.setAttribute(z,B,S)}}function qZ(Q,Z,z,X){X.setInlineStyle(Q,Z,z)}function HZ(Q,Z){if(Q.length===0||Z.length===0)return!1;for(var z=0;z<Q.length;z++)if(Q[z].key===null||Q[z].key===void 0)return!1;for(var z=0;z<Z.length;z++)if(Z[z].key===null||Z[z].key===void 0)return!1;return!0}function fY(Q,Z,z,X,N=null){if(HZ(Q,Z))AZ(Q,Z,z,X,N);else for(let S=0;S<Math.max(Z.length,Q.length);S++){let O=Q[S],B=Z[S];if(!O&&B)if(N)VQ(z,2,N,B,X);else FQ(B,z,X);else KQ(O,B,z,X)}}function vY(Q,Z){let z={};if(!Q)return z;let X=Z?Q.events.captures:Q.events.bubbles;for(let N in X){let{staticKey:S,componentId:O,options:B}=X[N];if(S!==void 0&&O!==void 0)z[N]={capture:Z,staticKey:S,componentId:O,options:B}}return z}function WZ(Q,Z){return Q.staticKey===Z.staticKey&&Q.componentId===Z.componentId&&Q.options?.preventDefault===Z.options?.preventDefault&&Q.options?.stopPropagation===Z.options?.stopPropagation}function GZ(Q,Z){if(Q.ns==="svg")Q.domRef=Z.createElementNS("http://www.w3.org/2000/svg",Q.tag);else if(Q.ns==="mathml")Q.domRef=Z.createElementNS("http://www.w3.org/1998/Math/MathML",Q.tag);else Q.domRef=Z.createElement(Q.tag)}function xY(Q,Z,z){if(Z.onCreated)Z.onCreated(Z.domRef)}function VQ(Q,Z,z,X,N){switch(X.type){case 2:switch(X.domRef=N.createTextNode(X.text),Z){case 2:N.insertBefore(Q,X.domRef,z);break;case 0:N.appendChild(Q,X.domRef);break;case 1:N.replaceChild(Q,X.domRef,z);break}break;case 3:for(let S of X.children)VQ(Q,2,z,S,N);if(Z===1&&z)N.removeChild(Q,z);break;case 0:JZ(Q,Z,z,X,N);break;case 1:if(X.onBeforeCreated)X.onBeforeCreated();if(GZ(X,N),X.onCreated)X.onCreated(X.domRef);switch(hY(null,X,N),Z){case 2:N.insertBefore(Q,X.domRef,z);break;case 0:N.appendChild(Q,X.domRef);break;case 1:N.replaceChild(Q,X.domRef,z);break}break}}function KZ(Q){if(Q.tag==="canvas"&&Q.draw)Q.draw(Q.domRef)}function UZ(Q){Q.unmount(Q.componentId)}function JZ(Q,Z,z,X,N){let S=X.mount(Q);X.componentId=S.componentId,X.child=S.componentTree,S.componentTree.parent=X;let O=qQ(S.componentTree);if(S.componentTree.type!==0){if(Z===1&&z)if(!O)N.removeChild(Q,z);else if(S.componentTree.type===3)zQ(S.componentTree,(B)=>N.insertBefore(Q,B,z)),N.removeChild(Q,z);else N.replaceChild(Q,O,z);else if(Z===2)if(z)zQ(S.componentTree,(B)=>N.insertBefore(Q,B,z));else zQ(S.componentTree,(B)=>N.appendChild(Q,B))}}function FQ(Q,Z,z){VQ(Z,0,null,Q,z)}function yY(Q,Z,z,X){let N=z?qQ(z)??X.nextSibling(z):null;if(N)zQ(Z,(S)=>X.insertBefore(Q,S,N));else zQ(Z,(S)=>X.appendChild(Q,S))}function NZ(Q,Z,z,X){let N=qQ(Q),S=qQ(Z);if(N&&S&&(Q.type===1||Q.type===2)&&(Z.type===1||Z.type===2)){X.swapDOMRefs(N,S,z);return}let O=NQ(Q),B=O?O.nextSibling:X.nextSibling(Q),h=qQ(Z)??X.nextSibling(Z);if(h)zQ(Q,(k)=>X.insertBefore(z,k,h));else zQ(Q,(k)=>X.appendChild(z,k));if(B)zQ(Z,(k)=>X.insertBefore(z,k,B));else zQ(Z,(k)=>X.appendChild(z,k))}function AZ(Q,Z,z,X,N=null){var S=0,O=0,B=Q.length-1,h=Z.length-1,k,m,b,u,a,XQ,DQ;for(;;){if(O>h&&S>B)break;if(m=Z[O],b=Z[h],a=Q[S],u=Q[B],S>B){let UQ=(a?qQ(a)??X.nextSibling(a):null)??N;if(UQ)VQ(z,2,UQ,m,X);else FQ(m,z,X);Q.splice(O,0,m),O++}else if(O>h){k=B;while(B>=S)xQ(Q[B--],z,X);Q.splice(S,k-S+1);break}else if(a.key===m.key)KQ(Q[S++],Z[O++],z,X);else if(u.key===b.key)KQ(Q[B--],Z[h--],z,X);else if(a.key===b.key&&m.key===u.key)NZ(u,a,z,X),MZ(Q,S,B),KQ(Q[S++],Z[O++],z,X),KQ(Q[B--],Z[h--],z,X);else if(a.key===b.key){let WQ=NQ(u),UQ=WQ?WQ.nextSibling:X.nextSibling(u);if(UQ)zQ(a,(HQ)=>X.insertBefore(z,HQ,UQ));else zQ(a,(HQ)=>X.appendChild(z,HQ));Q.splice(B,0,Q.splice(S,1)[0]),KQ(Q[B--],Z[h--],z,X)}else if(u.key===m.key)yY(z,u,a,X),Q.splice(S,0,Q.splice(B,1)[0]),KQ(Q[S++],m,z,X),O++;else{XQ=!1,k=S;while(k<=B){if(Q[k].key===m.key){XQ=!0,DQ=Q[k];break}k++}if(XQ)Q.splice(S,0,Q.splice(k,1)[0]),KQ(Q[S++],m,z,X),yY(z,DQ,Q[S],X),O++;else{let WQ=qQ(a)??X.nextSibling(a);if(WQ)VQ(z,2,WQ,m,X);else FQ(m,z,X);Q.splice(S++,0,m),O++,B++}}}}function MZ(Q,Z,z){let X=Q[Z];Q[Z]=Q[z],Q[z]=X}function AQ(Q,Z,z,X,N){if(!z.length){if(X)console.warn('Event "'+Q.type+'" did not find an event handler to dispatch on',Z,Q);return}else if(z.length>1){if(Z.type===2)return;else if(Z.type===3){for(let S of Z.children)if(jQ(S,z[0],N)){AQ(Q,S,z,X,N);return}return}else if(Z.type===0){if(!Z.child){if(X)throw console.error("VComp has no child property set during event delegation",Z),console.error("This means the Component has not been fully mounted, this should never happen"),Error("VComp has no .child property set during event delegation");return}return AQ(Q,Z.child,z,X,N)}else if(Z.type===1){if(N.isEqual(Z.domRef,z[0])){let S=Z.events.captures[Q.type];if(S){let O=S.options;if(O.preventDefault)Q.preventDefault();if(!Q.captureStopped)S.runEvent(Q,Z.domRef);if(O.stopPropagation)Q.captureStopped=!0}z.splice(0,1);for(let O of Z.children)if(jQ(O,z[0],N)){AQ(Q,O,z,X,N);return}}return}}else if(Z.type===0){if(Z.child)AQ(Q,Z.child,z,X,N)}else if(Z.type===3){for(let S of Z.children)if(jQ(S,z[0],N)){AQ(Q,S,z,X,N);return}}else if(Z.type===1){let S=Z.events.captures[Q.type];if(S&&!Q.captureStopped){let B=S.options;if(N.isEqual(z[0],Z.domRef)){if(B.preventDefault)Q.preventDefault();if(S.runEvent(Q,z[0]),B.stopPropagation)Q.captureStopped=!0}}let O=Z.events.bubbles[Q.type];if(O&&!Q.captureStopped){let B=O.options;if(N.isEqual(z[0],Z.domRef)){if(B.preventDefault)Q.preventDefault();if(O.runEvent(Q,z[0]),!B.stopPropagation)mY(Z.parent,Q)}}else if(!Q.captureStopped)mY(Z.parent,Q)}}function mY(Q,Z){while(Q)switch(Q.type){case 2:break;case 3:Q=Q.parent;break;case 1:let z=Q.events.bubbles[Z.type];if(z){let X=z.options;if(X.preventDefault)Z.preventDefault();if(z.runEvent(Z,Q.domRef),X.stopPropagation)return}Q=Q.parent;break;case 0:if(!Q.eventPropagation)return;Q=Q.parent;break}}function TQ(Q,Z){if(typeof Q[0]==="object"){var z=[];for(var X=0;X<Q.length;X++)z.push(TQ(Q[X],Z));return z}for(let B of Q)Z=Z[B];var N;if(Z instanceof Array||"length"in Z&&Z.localName!=="select"){N=[];for(var S=0;S<Z.length;S++)N.push(TQ([],Z[S]));return N}N={};for(var O in LZ(Z)){if(Z.localName==="input"&&(O==="selectionDirection"||O==="selectionStart"||O==="selectionEnd"))continue;if(typeof Z[O]=="string"||typeof Z[O]=="number"||typeof Z[O]=="boolean")N[O]=Z[O]}return N}function jQ(Q,Z,z){switch(Q.type){case 3:for(let X of Q.children)if(jQ(X,Z,z))return!0;return!1;case 0:return Q.child?jQ(Q.child,Z,z):!1;default:return z.isEqual(Q.domRef,Z)}}function LZ(Q){var Z={},z=0;do{var X=Object.getOwnPropertyNames(Q);for(z=0;z<X.length;z++)Z[X[z]]=null}while(Q=Object.getPrototypeOf(Q));return Z}function NY(Q){var Z=0,z=Q.length>0?[Q[0]]:[];for(var X=1;X<Q.length;X++){if(z[Z].type===2&&Q[X].type===2){z[Z].text+=Q[X].text;continue}z[++Z]=Q[X]}for(let N of z)if(N.type===3)N.children=NY(N.children);return z}function AY(Q,Z,z,X,N){if(!z||!Z)return!1;if(Z.nodeType===3)return!1;if(!bQ(Q,z,X.firstChild(Z),X,N)){if(Q)console.warn("[DEBUG_HYDRATE] Could not copy DOM into virtual DOM, falling back to diff");while(X.firstChild(Z))N.removeChild(Z,X.lastChild(Z));return!1}else if(Q)console.info("[DEBUG_HYDRATE] Successfully prerendered page");return!0}function mQ(Q,Z,z){if(Q)console.warn("[DEBUG_HYDRATE] VTree differed from node",Z,z)}function bY(Q,Z){let z=NQ(Q);return z?z.nextSibling:Z}function bQ(Q,Z,z,X,N){switch(Z.type){case 0:let O=Z.mount(z.parentNode);if(Z.componentId=O.componentId,Z.child=O.componentTree,O.componentTree.parent=Z,!bQ(Q,Z.child,z,X,N))return!1;break;case 3:Z.children=NY(Z.children);for(let h of Z.children){if(!z)return mQ(Q,h,null),!1;if(!bQ(Q,h,z,X,N))return!1;z=bY(h,z)}break;case 2:if(z.nodeType!==3||Z.text.trim()!==z.textContent.trim())return mQ(Q,Z,z),!1;Z.domRef=z;break;case 1:if(z.nodeType!==1)return mQ(Q,Z,z),!1;Z.domRef=z,Z.children=NY(Z.children),xY(z,Z,N);let B=z.firstChild;for(var S=0;S<Z.children.length;S++){let h=Z.children[S];if(!B)return mQ(Q,h,null),!1;if(!bQ(Q,h,B,X,N))return!1;B=bY(h,B)}break}return!0}function uY(){}function wZ(Q,Z,z){let X=[];while(!z.isEqual(Q,Z)){let N=__GetConfig(Z)?.nodeId;if(N!==void 0)X.unshift(N);let S=z.parentNode(Z);if(S)Z=S;else return X}return X}function _Y(){return globalThis.nodeId++}var kQ=new Map,vQ=new Map,_Q=new Map;function gY(Q,Z){let z=_Q.get(Z);if(z){for(let X of z)__AddEvent(Q,"catchEvent",X,void 0);_Q.delete(Z)}vQ.delete(Z)}function uQ(Q){return __GetConfig(Q)?.nodeId}function MY(Q){return kQ.get(__GetElementUniqueID(Q))}function BZ(Q){let Z=Q.items.length;if(Z===Q.known)return;let z=[],X=[];if(Z>Q.known)for(let N=Q.known;N<Z;N++){let S=Q.items[N],O=__GetAttributeByName(S,"item-key"),B=__GetAttributeByName(S,"reuse-identifier"),h={position:N,type:"list-item","item-key":O};if(B!=null)h["reuse-identifier"]=B;z.push(h)}else for(let N=Q.known-1;N>=Z;N--)X.push({position:N});__SetAttribute(Q.node,"update-list-info",{insertAction:z,removeAction:X}),Q.known=Z}function lY(Q,Z,z,X,N){let S=N.getTarget(Q),O=z?"captures":"bubbles",B=[];for(let b=S;b;b=N.parentNode(b))if(B.push(b),N.isEqual(b,X))break;let h=z?B.slice().reverse():B,k=O==="bubbles"?"captures":"bubbles",m=!1;for(let b of h){let u=uQ(b),a=u!==void 0?vQ.get(u):void 0,XQ=a?a[O]?.[Z]??a[k]?.[Z]:void 0;if(!XQ)continue;if(m=!0,XQ.options.preventDefault&&Q.preventDefault)Q.preventDefault();if(globalThis.runtime.dispatchMainThreadEvent({componentId:XQ.componentId,staticKey:XQ.staticKey,event:Q,target:b}),XQ.options.stopPropagation)break}if(!m){let b=lynx.getJSContext(),u=wZ(X,S,N),a={event:Q,stack:u,type:"processEvent"};b.dispatchEvent({type:"Miso.events",data:a})}}var LY={delegator:(Q,Z,z,X,N)=>{for(let{name:S,capture:O}of Z)N.addEventListener(Q,S,(B)=>{let h=Array.isArray(B)?B:[B];for(let k of h)lY(k,S,O,Q,N)},O,null)},addEventListener:(Q,Z,z,X)=>{let N=X?"capture-catch":"catchEvent";return __AddEvent(Q,N,Z,{type:"worklet",value:z})},isEqual:(Q,Z)=>{return __ElementIsEqual(Q,Z)},getTarget:(Q)=>{return Q.target.elementRefptr},parentNode:(Q)=>{return __GetParent(Q)}},i={addClass:(Q,Z)=>{__AddClass(Z,Q)},removeClass:(Q,Z)=>{let z=__GetClasses(Z);if(z.includes(Q)){let X=z.filter((N)=>N!==Q);__SetClasses(Z,X.join(" "))}},addEvent:(Q,Z,z)=>{if(z.direct){__AddEvent(Q,"catchEvent",Z,{type:"worklet",value:(B)=>{let h=Array.isArray(B)?B:[B];for(let k of h)lY(k,Z,!1,globalThis.page,LY)}});let O=uQ(Q);if(O!==void 0){let B=_Q.get(O)??new Set;B.add(Z),_Q.set(O,B)}}if(z.staticKey===void 0)return;let X=uQ(Q);if(X===void 0){console.error("[miso mts] REG SKIPPED (no nodeId on node) name="+Z);return}let N=vQ.get(X)??{captures:{},bubbles:{}},S=z.capture?"captures":"bubbles";N[S][Z]={staticKey:z.staticKey,componentId:z.componentId,options:z.options},vQ.set(X,N)},removeEvent:(Q,Z,z)=>{let X=uQ(Q),N=X!==void 0?vQ.get(X):void 0;if(!N)return;let S=z?"captures":"bubbles";delete N[S][Z]},nextSibling:(Q)=>{let Z=Q.nextSibling;while(Z)switch(Z.type){case 0:case 3:{let z=PQ(Z);if(z)return z;Z=Z.nextSibling;break}default:return Z.domRef}return null},createTextNode:(Q)=>{let Z=__CreateRawText(Q);if(__SetCSSId([Z],0),globalThis.initialDraw){let z=_Y();globalThis.runtime.nodes[z]=Z,__SetConfig(Z,{nodeId:z})}return Z},createElementNS:(Q,Z)=>{return i.createElement(Z)},createElement:(Q)=>{var Z=globalThis.native.currentPageId,z=void 0;switch(Q){case"view":z=__CreateView(Z);break;case"scroll-view":z=__CreateScrollView(Z);break;case"text":z=__CreateText(Z);break;case"list":{z=__CreateList(Z,(X,N,S,O)=>{let B=kQ.get(__GetElementUniqueID(X)),h=B&&B.items[S];if(!h)return;__AppendElement(X,h);let k=__GetElementUniqueID(h);return __FlushElementTree(h,{triggerLayout:!0,operationID:O,elementID:k,listID:N}),k},()=>{},null),kQ.set(__GetElementUniqueID(z),{node:z,items:[],known:0});break}case"image":z=__CreateImage(Z);break;case"frame":z=__CreateFrame(Z);break;default:z=__CreateElement(Q,Z);break}if(!z)console.error('[createElement]: native creator returned nil for tag "'+Q+'" — falling back to <view>'),z=__CreateView(Z);if(__SetCSSId([z],0),globalThis.initialDraw){let X=_Y();globalThis.runtime.nodes[X]=z,__SetConfig(z,{nodeId:X})}return z},appendChild:(Q,Z)=>{let z=MY(Q);if(z)return z.items.push(Z),Z;return __AppendElement(Q,Z)},replaceChild:(Q,Z,z)=>{return __ReplaceElements(Q,[Z],[z])},removeChild:(Q,Z)=>{let z=MY(Q);if(z){let X=z.items.indexOf(Z);if(X>=0)z.items.splice(X,1);return Z}return kQ.delete(__GetElementUniqueID(Z)),__RemoveElement(Q,Z)},insertBefore:(Q,Z,z)=>{let X=MY(Q);if(X){let N=X.items.indexOf(z);if(N<0)X.items.push(Z);else X.items.splice(N,0,Z);return Z}return __InsertElementBefore(Q,Z,z)},swapDOMRefs:(Q,Z,z)=>{return __SwapElement(Q,Z)},setAttribute:(Q,Z,z)=>{if(Z==="id")return __SetID(Q,z);return __SetAttribute(Q,Z,z)},removeAttribute:(Q,Z)=>{return __SetAttribute(Q,Z,null)},setAttributeNS:(Q,Z,z,X)=>{return __SetAttribute(Q,z,X)},setTextContent:(Q,Z)=>{return __SetAttribute(Q,"text",Z)},setInlineStyle:(Q,Z,z)=>{if(Q!=Z)return __SetInlineStyles(z,Z)},flush:()=>{for(let Q of kQ.values())BZ(Q);return __FlushElementTree()},getRoot:()=>{return globalThis.page},getHead:()=>{return null}};function pY(){let Q=__CreatePage("0",0),Z=__GetElementUniqueID(Q);__SetCSSId([Q],0),globalThis.native.currentPageId=Z,globalThis.page=Q,globalThis.document={},globalThis.document.body=Q,SZ()}function SZ(){let Q=lynx.getJSContext(),Z={nodes:{}};Z.nodes[0]=globalThis.page,globalThis.runtime=Z,Q.addEventListener("Miso.patches",(z)=>{for(let X of z.data)FZ(X,Z);if(z.data.length>0)i.flush()})}function FZ(Q,Z){let z=null;switch(Q.type){case"createElement":z=i.createElement(Q.tag),__SetConfig(z,{nodeId:Q.nodeId}),Z.nodes[Q.nodeId]=z;break;case"createTextNode":z=i.createTextNode(Q.text),__SetConfig(z,{nodeId:Q.nodeId}),Z.nodes[Q.nodeId]=z;break;case"createElementNS":z=i.createElementNS(Q.namespace,Q.tag),__SetConfig(z,{nodeId:Q.nodeId}),Z.nodes[Q.nodeId]=z;break;case"swapDOMRefs":i.swapDOMRefs(Z.nodes[Q.nodeA],Z.nodes[Q.nodeB],Z.nodes[Q.parent]);break;case"insertBefore":i.insertBefore(Z.nodes[Q.parent],Z.nodes[Q.node],Z.nodes[Q.child]);break;case"setAttribute":i.setAttribute(Z.nodes[Q.nodeId],Q.key,Q.value);break;case"setAttributeNS":i.setAttributeNS(Z.nodes[Q.nodeId],Q.namespace,Q.key,Q.value);break;case"setTextContent":i.setTextContent(Z.nodes[Q.nodeId],Q.text);break;case"appendChild":i.appendChild(Z.nodes[Q.parent],Z.nodes[Q.child]);break;case"removeChild":{let X=Z.nodes[Q.child];i.removeChild(Z.nodes[Q.parent],X),VY(Z.nodes,X);break}case"replaceChild":{let X=Z.nodes[Q.current];i.replaceChild(Z.nodes[Q.parent],Z.nodes[Q.new],X),VY(Z.nodes,X);break}case"removeAttribute":i.removeAttribute(Z.nodes[Q.nodeId],Q.key);break;case"setInlineStyle":i.setInlineStyle(Q.current,Q.new,Z.nodes[Q.nodeId]);break;case"addClass":i.addClass(Q.key,Z.nodes[Q.nodeId]);break;case"removeClass":i.removeClass(Q.key,Z.nodes[Q.nodeId]);break;case"addEvent":i.addEvent(Z.nodes[Q.nodeId],Q.name,{capture:Q.capture,staticKey:Q.staticKey,componentId:Q.componentId,options:Q.options,direct:Q.direct});break;case"removeEvent":i.removeEvent(Z.nodes[Q.nodeId],Q.name,Q.capture);break;case"flush":i.flush();break;default:console.error("Unknown message received",Q);break}}function VY(Q,Z){let z=__GetConfig(Z)?.nodeId;if(z!==void 0)delete Q[z],gY(Z,z);for(let X=__FirstElement(Z);X;X=__NextElement(X))VY(Q,X)}function wY(){return globalThis.nodeId++}function YQ(Q){globalThis.patches.push(Q)}var dY={delegator:(Q,Z,z,X,N)=>{let S=lynx.getCoreContext();if(!S)return;S.addEventListener("Miso.events",(O)=>{let B=O.data.stack.map(function(h){return{nodeId:h}});z((h)=>{return AQ(O.data.event,h,B,X,N)})})},addEventListener:(Q,Z,z,X)=>{return},isEqual:(Q,Z)=>{return Q.nodeId===Z.nodeId},getTarget:(Q)=>{return{nodeId:0}},parentNode:(Q)=>{return{nodeId:0}}},BY={addClass:(Q,Z)=>{let z={type:"addClass",nodeId:Z.nodeId,key:Q};YQ(z);return},removeClass:(Q,Z)=>{let z={type:"removeClass",nodeId:Z.nodeId,key:Q};YQ(z);return},addEvent:(Q,Z,z)=>{let X={type:"addEvent",nodeId:Q.nodeId,name:Z,capture:z.capture,staticKey:z.staticKey,componentId:z.componentId,options:z.options,direct:z.direct};YQ(X);return},removeEvent:(Q,Z,z)=>{let X={type:"removeEvent",nodeId:Q.nodeId,name:Z,capture:z};YQ(X);return},nextSibling:(Q)=>{let Z=Q.nextSibling;while(Z)switch(Z.type){case 0:case 3:{let z=PQ(Z);if(z)return z;Z=Z.nextSibling;break}default:return Z.domRef}return null},createTextNode:(Q)=>{let Z=wY();return YQ({type:"createTextNode",text:Q,nodeId:Z}),{nodeId:Z}},createElementNS:(Q,Z)=>{let z=wY();return YQ({type:"createElementNS",namespace:Q,nodeId:z,tag:Z}),{nodeId:z}},createElement:(Q)=>{let Z=wY();return YQ({type:"createElement",nodeId:Z,tag:Q}),{nodeId:Z}},appendChild:(Q,Z)=>{let z={type:"appendChild",parent:Q.nodeId,child:Z.nodeId};YQ(z);return},replaceChild:(Q,Z,z)=>{let X={type:"replaceChild",parent:Q.nodeId,new:Z.nodeId,current:z.nodeId};YQ(X);return},removeChild:(Q,Z)=>{let z={type:"removeChild",parent:Q.nodeId,child:Z.nodeId};YQ(z);return},insertBefore:(Q,Z,z)=>{if(z===null){BY.appendChild(Q,Z);return}let X={type:"insertBefore",parent:Q.nodeId,child:z.nodeId,node:Z.nodeId};YQ(X);return},swapDOMRefs:(Q,Z,z)=>{let X={type:"swapDOMRefs",parent:z.nodeId,nodeA:Q.nodeId,nodeB:Z.nodeId};YQ(X);return},setAttribute:(Q,Z,z)=>{let X={type:"setAttribute",nodeId:Q.nodeId,key:Z,value:z};YQ(X);return},removeAttribute:(Q,Z)=>{let z={type:"removeAttribute",nodeId:Q.nodeId,key:Z};YQ(z);return},setAttributeNS:(Q,Z,z,X)=>{let N={type:"setAttributeNS",nodeId:Q.nodeId,key:z,value:X,namespace:Z};YQ(N);return},setTextContent:(Q,Z)=>{let z={type:"setTextContent",nodeId:Q.nodeId,text:Z};YQ(z);return},setInlineStyle:(Q,Z,z)=>{if(DZ(Q,Z))return;let X={type:"setInlineStyle",nodeId:z.nodeId,new:Z,current:Q};YQ(X);return},flush:()=>{let Q=globalThis.patches;if(!globalThis.initialDraw&&Q.length>0){let Z=lynx.getCoreContext();if(Z)Z.dispatchEvent({type:"Miso.patches",data:Q})}globalThis.patches=[]},getHead:function(){return null},getRoot:function(){return{nodeId:0}}};function DZ(Q,Z){let z=Object.keys(Q),X=Object.keys(Z);if(z.length!==X.length)return!1;return z.every((N)=>Q[N]===Z[N])}globalThis.TextEncoder=gQ.TextEncoder;globalThis.TextDecoder=gQ.TextDecoder;globalThis.BigInt=FY.default.BigInt;globalThis.JSBI=FY.default;if(typeof globalThis.fetch>"u")globalThis.fetch=(Q,Z)=>globalThis.lynx.fetch(Q,Z);try{if(typeof lynx.reportError==="function"){let Q=(z)=>{try{lynx.reportError(Error(z))}catch(X){}},Z=console.error.bind(console);console.error=(...z)=>{if(Z(...z),globalThis.debug)Q("[miso] "+z.map((X)=>{try{return String(X)}catch(N){return"<?>"}}).join(" "))}}}catch(Q){}globalThis.nodeId=1;globalThis.initialDraw=!0;var cY=LQ()?BY:i,SY=LQ()?dY:LY;globalThis.native={drawingContext:cY,eventContext:SY,currentPageId:void 0};globalThis.miso={drawingContext:cY,eventContext:SY,diff:KQ,hydrate:AY,version:dQ,onBTS:LQ,onMTS:OQ,callBlur:aQ,callFocus:cQ,callSelect:sQ,callSetSelectionRange:rQ,eventJSON:TQ,fetchCore:iQ,eventSourceConnect:eQ,eventSourceClose:QY,websocketConnect:oQ,websocketClose:nQ,websocketSend:tQ,updateRef:ZY,inline:$Y,typeOf:zY,mathRandom:HY,getRandomValues:qY,splitmix32:XY,populateClass:YY,delegateEvent:AQ,cookieGet:WY,cookieGetAll:GY,cookieSet:KY,cookieDelete:UY,cookieDeleteWith:JY,delegator:SY.delegator,setDrawingContext:function(Q){let Z=globalThis[Q].drawingContext,z=globalThis[Q].eventContext;if(!Z)console.error('"drawingContext" not defined at globalThis['+Q+"].drawingContext");if(!z)console.error('"eventContext" not defined at globalThis['+Q+"].eventContext");globalThis.miso.drawingContext=Z,globalThis.miso.eventContext=z}};globalThis.invokeExec=function(Q,Z,z,X,N){if(typeof lynx.createSelectorQuery!=="function")return;let S={params:z,method:Z,success:X,fail:N};return lynx.createSelectorQuery().select(Q).invoke(S).exec()};if(LQ())globalThis.lynx=lynx,globalThis.patches=[],uY();else globalThis.renderPage=()=>pY(),globalThis.runWorklet=(Q,Z)=>Q(Z);if(typeof lynx<"u")globalThis.requestAnimationFrame=lynx.requestAnimationFrame,globalThis.cancelAnimationFrame=lynx.cancelAnimationFrame;globalThis.processData=()=>{};
diff --git a/js/miso.js b/js/miso.js
new file mode 100644
--- /dev/null
+++ b/js/miso.js
@@ -0,0 +1,1376 @@
+// ts/miso/util.ts
+var version = "1.13.0.0";
+function onBTS() {
+  return typeof __BACKGROUND__ !== "undefined" && __BACKGROUND__;
+}
+function onMTS() {
+  return typeof __MAIN_THREAD__ !== "undefined" && __MAIN_THREAD__;
+}
+function callFocus(id, delay) {
+  var setFocus = function() {
+    var e = document.getElementById(id);
+    if (e && e.focus)
+      e.focus();
+  };
+  delay > 0 ? setTimeout(setFocus, delay) : setFocus();
+}
+function callBlur(id, delay) {
+  var setBlur = function() {
+    var e = document.getElementById(id);
+    if (e && e.blur)
+      e.blur();
+  };
+  delay > 0 ? setTimeout(setBlur, delay) : setBlur();
+}
+function callSelect(id, delay) {
+  var setSelect = function() {
+    var e = document.getElementById(id);
+    if (e && typeof e["select"] === "function")
+      e.select();
+  };
+  delay > 0 ? setTimeout(setSelect, delay) : setSelect();
+}
+function callSetSelectionRange(id, start, end, delay) {
+  var setSetSelectionRange = function() {
+    var e = document.getElementById(id);
+    if (e && typeof e["setSelectionRange"] === "function")
+      e.setSelectionRange(start, end, "none");
+  };
+  delay > 0 ? setTimeout(setSetSelectionRange, delay) : setSetSelectionRange();
+}
+function fetchCore(url, method, body, requestHeaders, successful, errorful, responseType) {
+  var options = { method, headers: requestHeaders };
+  if (body) {
+    options["body"] = body;
+  }
+  let headers = {};
+  let status = null;
+  try {
+    fetch(url, options).then((response) => {
+      status = response.status;
+      for (const [key, value] of response.headers) {
+        headers[key] = value;
+      }
+      if (response.status < 200 || response.status >= 300) {
+        throw new Error(response.statusText || "HTTP " + response.status);
+      }
+      if (responseType == "json") {
+        return response.json();
+      } else if (responseType == "text") {
+        return response.text();
+      } else if (responseType === "arrayBuffer") {
+        return response.arrayBuffer();
+      } else if (responseType === "blob") {
+        return response.blob();
+      } else if (responseType === "bytes") {
+        return response.bytes();
+      } else if (responseType === "formData") {
+        return response.formData();
+      } else if (responseType === "none") {
+        return null;
+      }
+    }).then((body2) => successful({ error: null, body: body2, headers, status })).catch((body2) => errorful({ error: null, body: body2, headers, status }));
+  } catch (err) {
+    errorful({ body: null, error: err.message, headers, status });
+  }
+}
+function websocketConnect(url, onOpen, onClose, onMessageText, onMessageJSON, onMessageBLOB, onMessageArrayBuffer, onError, textOnly) {
+  try {
+    let socket = new WebSocket(url);
+    socket.onopen = function() {
+      onOpen();
+    };
+    socket.onclose = function(e) {
+      onClose(e);
+    };
+    socket.onerror = function(error) {
+      console.error(error);
+      onError("WebSocket error received");
+    };
+    socket.onmessage = function(msg) {
+      if (typeof msg.data === "string") {
+        try {
+          if (textOnly) {
+            if (onMessageText)
+              onMessageText(msg.data);
+            return;
+          }
+          const json = JSON.parse(msg.data);
+          if (onMessageJSON)
+            onMessageJSON(json);
+        } catch (err) {
+          if (textOnly && onMessageText) {
+            onMessageText(msg.data);
+          } else {
+            onError(err.message);
+          }
+        }
+      } else if (msg.data instanceof Blob) {
+        if (onMessageBLOB)
+          onMessageBLOB(msg.data);
+      } else if (msg.data instanceof ArrayBuffer) {
+        if (onMessageArrayBuffer)
+          onMessageArrayBuffer(msg.data);
+      } else {
+        console.error("Received unknown message type from WebSocket", msg);
+        onError("Unknown message received from WebSocket");
+      }
+    };
+    return socket;
+  } catch (err) {
+    onError(err.message);
+  }
+}
+function websocketClose(socket) {
+  if (socket) {
+    socket.close();
+    socket = null;
+  }
+}
+function websocketSend(socket, message) {
+  if (message && socket && socket.readyState === WebSocket.OPEN) {
+    socket.send(message);
+  }
+}
+function eventSourceConnect(url, onOpen, onMessageText, onMessageJSON, onError, textOnly) {
+  try {
+    let eventSource = new EventSource(url);
+    eventSource.onopen = function() {
+      onOpen();
+    };
+    eventSource.onerror = function() {
+      onError("EventSource error received");
+    };
+    eventSource.onmessage = function(msg) {
+      try {
+        if (textOnly) {
+          if (onMessageText)
+            onMessageText(msg.data);
+          return;
+        }
+        const json = JSON.parse(msg.data);
+        if (onMessageJSON)
+          onMessageJSON(json);
+      } catch (err) {
+        if (textOnly && onMessageText) {
+          onMessageText(msg.data);
+        } else {
+          onError(err.message);
+        }
+      }
+    };
+    return eventSource;
+  } catch (err) {
+    onError(err.message);
+  }
+}
+function eventSourceClose(eventSource) {
+  if (eventSource) {
+    eventSource.close();
+    eventSource = null;
+  }
+}
+function populateClass(vnode, classes) {
+  if (!vnode.classList) {
+    vnode.classList = new Set;
+  }
+  for (const str of classes) {
+    for (const c of str.trim().split(" ")) {
+      if (c)
+        vnode.classList.add(c);
+    }
+  }
+}
+function updateRef(current, latest) {
+  if (!current.parent) {
+    return;
+  }
+  latest.nextSibling = current.nextSibling;
+  latest.parent = current.parent;
+  current.parent.child = latest;
+}
+function inline(code, context = {}) {
+  const keys = Object.keys(context);
+  const values = Object.values(context);
+  const func = new Function(...keys, code);
+  return func(...values);
+}
+function typeOf(x) {
+  if (x === null || x === undefined)
+    return 0;
+  if (typeof x === "number")
+    return 1;
+  if (typeof x === "string")
+    return 2;
+  if (typeof x === "boolean")
+    return 3;
+  if (Array.isArray(x))
+    return 4;
+  return 5;
+}
+function splitmix32(a) {
+  return function() {
+    a |= 0;
+    a = a + 2654435769 | 0;
+    var t = a ^ a >>> 15;
+    t = Math.imul(t, 2246822507);
+    t = t ^ t >>> 13;
+    t = Math.imul(t, 3266489909);
+    return ((t ^ t >>> 16) >>> 0) / 4294967296;
+  };
+}
+function getRandomValues() {
+  const array = new Uint32Array(1);
+  return crypto.getRandomValues(array)[0];
+}
+function mathRandom() {
+  return Math.random();
+}
+function forEachDOMRef(tree, cb) {
+  switch (tree.type) {
+    case 3 /* VFrag */:
+      for (const child of tree.children)
+        forEachDOMRef(child, cb);
+      break;
+    case 0 /* VComp */:
+      if (tree.child)
+        forEachDOMRef(tree.child, cb);
+      break;
+    default:
+      cb(tree.domRef);
+      break;
+  }
+}
+function getFirstDOMRef(tree) {
+  switch (tree.type) {
+    case 3 /* VFrag */: {
+      if (!tree.children || tree.children.length === 0)
+        return null;
+      return getFirstDOMRef(tree.children[0]);
+    }
+    case 0 /* VComp */:
+      if (!tree.child)
+        return null;
+      return getFirstDOMRef(tree.child);
+    default:
+      return tree.domRef;
+  }
+}
+function getLastDOMRef(tree) {
+  switch (tree.type) {
+    case 3 /* VFrag */: {
+      if (!tree.children || tree.children.length === 0)
+        return null;
+      return getLastDOMRef(tree.children[tree.children.length - 1]);
+    }
+    case 0 /* VComp */:
+      if (!tree.child)
+        return null;
+      return getLastDOMRef(tree.child);
+    default:
+      return tree.domRef;
+  }
+}
+function cookieGet(name, errorful, successful) {
+  try {
+    globalThis.cookieStore.get(name).then((c) => successful(c ? c.value : null)).catch((err) => errorful(err.message));
+  } catch (err) {
+    errorful(err.message);
+  }
+}
+function cookieGetAll(errorful, successful) {
+  try {
+    globalThis.cookieStore.getAll().then(successful).catch((err) => errorful(err.message));
+  } catch (err) {
+    errorful(err.message);
+  }
+}
+function cookieSet(cookie, errorful, successful) {
+  try {
+    globalThis.cookieStore.set(cookie).then(successful).catch((err) => errorful(err.message));
+  } catch (err) {
+    errorful(err.message);
+  }
+}
+function cookieDelete(name, errorful, successful) {
+  try {
+    globalThis.cookieStore.delete(name).then(successful).catch((err) => errorful(err.message));
+  } catch (err) {
+    errorful(err.message);
+  }
+}
+function cookieDeleteWith(cookie, errorful, successful) {
+  const opts = { name: cookie.name };
+  if (cookie.path != null)
+    opts.path = cookie.path;
+  if (cookie.domain != null)
+    opts.domain = cookie.domain;
+  if (cookie.partitioned != null)
+    opts.partitioned = cookie.partitioned;
+  try {
+    globalThis.cookieStore.delete(opts).then(successful).catch((err) => errorful(err.message));
+  } catch (err) {
+    errorful(err.message);
+  }
+}
+
+// ts/miso/dom.ts
+function diff(c, n, parent, context) {
+  if (!c && !n)
+    return;
+  else if (!c)
+    create(n, parent, context);
+  else if (!n)
+    destroy(c, parent, context);
+  else if (c.type === 2 /* VText */ && n.type === 2 /* VText */) {
+    diffVText(c, n, context);
+  } else if (c.type === 0 /* VComp */ && n.type === 0 /* VComp */) {
+    if (n.key === c.key) {
+      n.child = c.child;
+      n.componentId = c.componentId;
+      if (c.child)
+        c.child.parent = n;
+      if (n.diffProps)
+        n.diffProps();
+      return;
+    }
+    replace(c, n, parent, context);
+  } else if (c.type === 3 /* VFrag */ && n.type === 3 /* VFrag */) {
+    if (n.key === c.key) {
+      const lastRef = getLastDOMRef(c);
+      const endAnchor = lastRef ? lastRef.nextSibling : context.nextSibling(c);
+      diffChildren(c.children, n.children, parent, context, endAnchor);
+    } else {
+      replace(c, n, parent, context);
+    }
+  } else if (c.type === 1 /* VNode */ && n.type === 1 /* VNode */) {
+    if (n.tag === c.tag && n.key === c.key) {
+      n.domRef = c.domRef;
+      diffAttrs(c, n, context);
+    } else {
+      replace(c, n, parent, context);
+    }
+  } else
+    replace(c, n, parent, context);
+}
+function diffVText(c, n, context) {
+  if (c.text !== n.text)
+    context.setTextContent(c.domRef, n.text);
+  n.domRef = c.domRef;
+  return;
+}
+function replace(c, n, parent, context) {
+  if (c.type === 3 /* VFrag */) {
+    const lastRef2 = getLastDOMRef(c);
+    const anchor = lastRef2 ? lastRef2.nextSibling : context.nextSibling(c);
+    destroy(c, parent, context);
+    if (anchor) {
+      createElement(parent, 2 /* INSERT_BEFORE */, anchor, n, context);
+    } else {
+      create(n, parent, context);
+    }
+    return;
+  }
+  switch (c.type) {
+    case 2 /* VText */:
+      break;
+    default:
+      callBeforeDestroyedRecursive(c);
+      break;
+  }
+  const firstRef = getFirstDOMRef(c);
+  const lastRef = getLastDOMRef(c);
+  if (!firstRef || !lastRef) {
+    const anchor = context.nextSibling(c);
+    if (anchor) {
+      createElement(parent, 2 /* INSERT_BEFORE */, anchor, n, context);
+    } else {
+      create(n, parent, context);
+    }
+  } else if (firstRef !== lastRef) {
+    const anchor = lastRef.nextSibling;
+    forEachDOMRef(c, (ref) => context.removeChild(parent, ref));
+    if (anchor) {
+      createElement(parent, 2 /* INSERT_BEFORE */, anchor, n, context);
+    } else {
+      create(n, parent, context);
+    }
+  } else {
+    createElement(parent, 1 /* REPLACE */, firstRef, n, context);
+  }
+  switch (c.type) {
+    case 2 /* VText */:
+      break;
+    default:
+      callDestroyedRecursive(c);
+      break;
+  }
+}
+function destroy(c, parent, context) {
+  switch (c.type) {
+    case 2 /* VText */:
+      break;
+    case 3 /* VFrag */:
+      for (const child of c.children)
+        destroy(child, parent, context);
+      return;
+    default:
+      callBeforeDestroyedRecursive(c);
+      break;
+  }
+  forEachDOMRef(c, (ref) => context.removeChild(parent, ref));
+  switch (c.type) {
+    case 2 /* VText */:
+      break;
+    default:
+      callDestroyedRecursive(c);
+      break;
+  }
+}
+function callDestroyedRecursive(c) {
+  if (c.type === 3 /* VFrag */) {
+    for (const child of c.children)
+      if (child.type !== 2 /* VText */)
+        callDestroyedRecursive(child);
+    return;
+  }
+  callDestroyed(c);
+  switch (c.type) {
+    case 1 /* VNode */:
+      for (const child of c.children)
+        if (child.type !== 2 /* VText */)
+          callDestroyedRecursive(child);
+      break;
+    case 0 /* VComp */:
+      if (c.child && c.child.type !== 2 /* VText */)
+        callDestroyedRecursive(c.child);
+      break;
+  }
+}
+function callDestroyed(c) {
+  if (c.type === 1 /* VNode */ && c.onDestroyed)
+    c.onDestroyed();
+  if (c.type === 0 /* VComp */)
+    unmountComponent(c);
+}
+function callBeforeDestroyed(c) {
+  switch (c.type) {
+    case 0 /* VComp */:
+      break;
+    case 1 /* VNode */:
+      if (c.onBeforeDestroyed)
+        c.onBeforeDestroyed();
+      break;
+    default:
+      break;
+  }
+}
+function callBeforeDestroyedRecursive(c) {
+  if (c.type === 3 /* VFrag */) {
+    for (const child of c.children)
+      if (child.type !== 2 /* VText */)
+        callBeforeDestroyedRecursive(child);
+    return;
+  }
+  callBeforeDestroyed(c);
+  switch (c.type) {
+    case 1 /* VNode */:
+      for (const child of c.children) {
+        if (child.type === 2 /* VText */)
+          continue;
+        callBeforeDestroyedRecursive(child);
+      }
+      break;
+    case 0 /* VComp */:
+      if (c.child && c.child.type !== 2 /* VText */)
+        callBeforeDestroyedRecursive(c.child);
+      break;
+  }
+}
+function diffAttrs(c, n, context) {
+  diffProps(c ? c.props : {}, n.props, n.domRef, n.ns === "svg", context);
+  diffClass(c ? c.classList : null, n.classList, n.domRef, context);
+  diffCss(c ? c.css : {}, n.css, n.domRef, context);
+  diffEvents(c, n, context);
+  diffChildren(c ? c.children : [], n.children, n.domRef, context);
+  drawCanvas(n);
+}
+function diffEvents(c, n, context) {
+  if (!onBTS() && !onMTS())
+    return;
+  if (c === null && n.directEvents) {
+    for (const name of n.directEvents) {
+      context.addEvent(n.domRef, name, { capture: false, direct: true });
+    }
+  }
+  for (const capture of [true, false]) {
+    const cKeys = eventEntries(c, capture);
+    const nKeys = eventEntries(n, capture);
+    for (const name in cKeys) {
+      if (!(name in nKeys))
+        context.removeEvent(n.domRef, name, capture);
+    }
+    for (const name in nKeys) {
+      const nk = nKeys[name], ck = cKeys[name];
+      if (!ck || !sameEventKey(nk, ck))
+        context.addEvent(n.domRef, name, nk);
+    }
+  }
+}
+function diffClass(c, n, domRef, context) {
+  if (!c && !n) {
+    return;
+  }
+  if (!c) {
+    for (const className of n) {
+      context.addClass(className, domRef);
+    }
+    return;
+  }
+  if (!n) {
+    for (const className of c) {
+      context.removeClass(className, domRef);
+    }
+    return;
+  }
+  for (const className of c) {
+    if (!n.has(className)) {
+      context.removeClass(className, domRef);
+    }
+  }
+  for (const className of n) {
+    if (!c.has(className)) {
+      context.addClass(className, domRef);
+    }
+  }
+  return;
+}
+function diffProps(cProps, nProps, node, isSvg, context) {
+  var newProp;
+  const native = onBTS() || onMTS();
+  for (const c in cProps) {
+    newProp = nProps[c];
+    if (newProp === undefined) {
+      if (isSvg || native || !(c in node) || c === "disabled") {
+        context.removeAttribute(node, c);
+      } else {
+        context.setAttribute(node, c, "");
+      }
+    } else {
+      if (newProp === cProps[c] && c !== "checked" && c !== "value")
+        continue;
+      if (isSvg) {
+        if (c === "href") {
+          context.setAttributeNS(node, "http://www.w3.org/1999/xlink", "href", newProp);
+        } else {
+          context.setAttribute(node, c, newProp);
+        }
+      } else if (!native && c in node && !(c === "list" || c === "form")) {
+        node[c] = newProp;
+      } else {
+        context.setAttribute(node, c, newProp);
+      }
+    }
+  }
+  for (const n in nProps) {
+    if (cProps && n in cProps)
+      continue;
+    newProp = nProps[n];
+    if (isSvg) {
+      if (n === "href") {
+        context.setAttributeNS(node, "http://www.w3.org/1999/xlink", "href", newProp);
+      } else {
+        context.setAttribute(node, n, newProp);
+      }
+    } else if (!native && n in node && !(n === "list" || n === "form")) {
+      node[n] = nProps[n];
+    } else {
+      context.setAttribute(node, n, newProp);
+    }
+  }
+}
+function diffCss(cCss, nCss, node, context) {
+  context.setInlineStyle(cCss, nCss, node);
+}
+function shouldSync(cs, ns) {
+  if (cs.length === 0 || ns.length === 0)
+    return false;
+  for (var i = 0;i < cs.length; i++) {
+    if (cs[i].key === null || cs[i].key === undefined) {
+      return false;
+    }
+  }
+  for (var i = 0;i < ns.length; i++) {
+    if (ns[i].key === null || ns[i].key === undefined) {
+      return false;
+    }
+  }
+  return true;
+}
+function diffChildren(cs, ns, parent, context, endAnchor = null) {
+  if (shouldSync(cs, ns)) {
+    syncChildren(cs, ns, parent, context, endAnchor);
+  } else {
+    for (let i = 0;i < Math.max(ns.length, cs.length); i++) {
+      const c = cs[i], n = ns[i];
+      if (!c && n) {
+        if (endAnchor) {
+          createElement(parent, 2 /* INSERT_BEFORE */, endAnchor, n, context);
+        } else {
+          create(n, parent, context);
+        }
+      } else {
+        diff(c, n, parent, context);
+      }
+    }
+  }
+}
+function eventEntries(c, capture) {
+  const out = {};
+  if (!c)
+    return out;
+  const phase = capture ? c.events.captures : c.events.bubbles;
+  for (const name in phase) {
+    const { staticKey, componentId, options } = phase[name];
+    if (staticKey !== undefined && componentId !== undefined) {
+      out[name] = { capture, staticKey, componentId, options };
+    }
+  }
+  return out;
+}
+function sameEventKey(a, b) {
+  return a.staticKey === b.staticKey && a.componentId === b.componentId && a.options?.preventDefault === b.options?.preventDefault && a.options?.stopPropagation === b.options?.stopPropagation;
+}
+function populateDomRef(c, context) {
+  if (c.ns === "svg") {
+    c.domRef = context.createElementNS("http://www.w3.org/2000/svg", c.tag);
+  } else if (c.ns === "mathml") {
+    c.domRef = context.createElementNS("http://www.w3.org/1998/Math/MathML", c.tag);
+  } else {
+    c.domRef = context.createElement(c.tag);
+  }
+}
+function callCreated(parent, n, context) {
+  if (n.onCreated)
+    n.onCreated(n.domRef);
+}
+function createElement(parent, op, replacing, n, context) {
+  switch (n.type) {
+    case 2 /* VText */:
+      n.domRef = context.createTextNode(n.text);
+      switch (op) {
+        case 2 /* INSERT_BEFORE */:
+          context.insertBefore(parent, n.domRef, replacing);
+          break;
+        case 0 /* APPEND */:
+          context.appendChild(parent, n.domRef);
+          break;
+        case 1 /* REPLACE */:
+          context.replaceChild(parent, n.domRef, replacing);
+          break;
+      }
+      break;
+    case 3 /* VFrag */:
+      for (const child of n.children) {
+        createElement(parent, 2 /* INSERT_BEFORE */, replacing, child, context);
+      }
+      if (op === 1 /* REPLACE */ && replacing) {
+        context.removeChild(parent, replacing);
+      }
+      break;
+    case 0 /* VComp */:
+      mountComponent(parent, op, replacing, n, context);
+      break;
+    case 1 /* VNode */:
+      if (n.onBeforeCreated)
+        n.onBeforeCreated();
+      populateDomRef(n, context);
+      if (n.onCreated)
+        n.onCreated(n.domRef);
+      diffAttrs(null, n, context);
+      switch (op) {
+        case 2 /* INSERT_BEFORE */:
+          context.insertBefore(parent, n.domRef, replacing);
+          break;
+        case 0 /* APPEND */:
+          context.appendChild(parent, n.domRef);
+          break;
+        case 1 /* REPLACE */:
+          context.replaceChild(parent, n.domRef, replacing);
+          break;
+      }
+      break;
+  }
+}
+function drawCanvas(c) {
+  if (c.tag === "canvas" && c.draw)
+    c.draw(c.domRef);
+}
+function unmountComponent(c) {
+  c.unmount(c.componentId);
+}
+function mountComponent(parent, op, replacing, n, context) {
+  let mounted = n.mount(parent);
+  n.componentId = mounted.componentId;
+  n.child = mounted.componentTree;
+  mounted.componentTree.parent = n;
+  const componentDOMRef = getFirstDOMRef(mounted.componentTree);
+  if (mounted.componentTree.type !== 0 /* VComp */) {
+    if (op === 1 /* REPLACE */ && replacing) {
+      if (!componentDOMRef) {
+        context.removeChild(parent, replacing);
+      } else if (mounted.componentTree.type === 3 /* VFrag */) {
+        forEachDOMRef(mounted.componentTree, (ref) => context.insertBefore(parent, ref, replacing));
+        context.removeChild(parent, replacing);
+      } else {
+        context.replaceChild(parent, componentDOMRef, replacing);
+      }
+    } else if (op === 2 /* INSERT_BEFORE */) {
+      if (replacing) {
+        forEachDOMRef(mounted.componentTree, (ref) => context.insertBefore(parent, ref, replacing));
+      } else {
+        forEachDOMRef(mounted.componentTree, (ref) => context.appendChild(parent, ref));
+      }
+    }
+  }
+}
+function create(n, parent, context) {
+  createElement(parent, 0 /* APPEND */, null, n, context);
+}
+function insertBefore(parent, n, o, context) {
+  const anchor = o ? getFirstDOMRef(o) ?? context.nextSibling(o) : null;
+  if (anchor) {
+    forEachDOMRef(n, (ref) => context.insertBefore(parent, ref, anchor));
+  } else {
+    forEachDOMRef(n, (ref) => context.appendChild(parent, ref));
+  }
+}
+function swapDOMRef(oLast, oFirst, parent, context) {
+  const oLastRef = getFirstDOMRef(oLast);
+  const oFirstRef = getFirstDOMRef(oFirst);
+  if (oLastRef && oFirstRef && (oLast.type === 1 /* VNode */ || oLast.type === 2 /* VText */) && (oFirst.type === 1 /* VNode */ || oFirst.type === 2 /* VText */)) {
+    context.swapDOMRefs(oLastRef, oFirstRef, parent);
+    return;
+  }
+  const lastRef = getLastDOMRef(oLast);
+  const tmp = lastRef ? lastRef.nextSibling : context.nextSibling(oLast);
+  const anchor = getFirstDOMRef(oFirst) ?? context.nextSibling(oFirst);
+  if (anchor) {
+    forEachDOMRef(oLast, (ref) => context.insertBefore(parent, ref, anchor));
+  } else {
+    forEachDOMRef(oLast, (ref) => context.appendChild(parent, ref));
+  }
+  if (tmp) {
+    forEachDOMRef(oFirst, (ref) => context.insertBefore(parent, ref, tmp));
+  } else {
+    forEachDOMRef(oFirst, (ref) => context.appendChild(parent, ref));
+  }
+}
+function syncChildren(os, ns, parent, context, endAnchor = null) {
+  var oldFirstIndex = 0, newFirstIndex = 0, oldLastIndex = os.length - 1, newLastIndex = ns.length - 1, tmp, nFirst, nLast, oLast, oFirst, found, node;
+  for (;; ) {
+    if (newFirstIndex > newLastIndex && oldFirstIndex > oldLastIndex) {
+      break;
+    }
+    nFirst = ns[newFirstIndex];
+    nLast = ns[newLastIndex];
+    oFirst = os[oldFirstIndex];
+    oLast = os[oldLastIndex];
+    if (oldFirstIndex > oldLastIndex) {
+      const oFirstRef = oFirst ? getFirstDOMRef(oFirst) ?? context.nextSibling(oFirst) : null;
+      const anchor = oFirstRef ?? endAnchor;
+      if (anchor) {
+        createElement(parent, 2 /* INSERT_BEFORE */, anchor, nFirst, context);
+      } else {
+        create(nFirst, parent, context);
+      }
+      os.splice(newFirstIndex, 0, nFirst);
+      newFirstIndex++;
+    } else if (newFirstIndex > newLastIndex) {
+      tmp = oldLastIndex;
+      while (oldLastIndex >= oldFirstIndex) {
+        destroy(os[oldLastIndex--], parent, context);
+      }
+      os.splice(oldFirstIndex, tmp - oldFirstIndex + 1);
+      break;
+    } else if (oFirst.key === nFirst.key) {
+      diff(os[oldFirstIndex++], ns[newFirstIndex++], parent, context);
+    } else if (oLast.key === nLast.key) {
+      diff(os[oldLastIndex--], ns[newLastIndex--], parent, context);
+    } else if (oFirst.key === nLast.key && nFirst.key === oLast.key) {
+      swapDOMRef(oLast, oFirst, parent, context);
+      swap(os, oldFirstIndex, oldLastIndex);
+      diff(os[oldFirstIndex++], ns[newFirstIndex++], parent, context);
+      diff(os[oldLastIndex--], ns[newLastIndex--], parent, context);
+    } else if (oFirst.key === nLast.key) {
+      const lastRef = getLastDOMRef(oLast);
+      const afterOLast = lastRef ? lastRef.nextSibling : context.nextSibling(oLast);
+      if (afterOLast) {
+        forEachDOMRef(oFirst, (ref) => context.insertBefore(parent, ref, afterOLast));
+      } else {
+        forEachDOMRef(oFirst, (ref) => context.appendChild(parent, ref));
+      }
+      os.splice(oldLastIndex, 0, os.splice(oldFirstIndex, 1)[0]);
+      diff(os[oldLastIndex--], ns[newLastIndex--], parent, context);
+    } else if (oLast.key === nFirst.key) {
+      insertBefore(parent, oLast, oFirst, context);
+      os.splice(oldFirstIndex, 0, os.splice(oldLastIndex, 1)[0]);
+      diff(os[oldFirstIndex++], nFirst, parent, context);
+      newFirstIndex++;
+    } else {
+      found = false;
+      tmp = oldFirstIndex;
+      while (tmp <= oldLastIndex) {
+        if (os[tmp].key === nFirst.key) {
+          found = true;
+          node = os[tmp];
+          break;
+        }
+        tmp++;
+      }
+      if (found) {
+        os.splice(oldFirstIndex, 0, os.splice(tmp, 1)[0]);
+        diff(os[oldFirstIndex++], nFirst, parent, context);
+        insertBefore(parent, node, os[oldFirstIndex], context);
+        newFirstIndex++;
+      } else {
+        const anchor = getFirstDOMRef(oFirst) ?? context.nextSibling(oFirst);
+        if (anchor) {
+          createElement(parent, 2 /* INSERT_BEFORE */, anchor, nFirst, context);
+        } else {
+          create(nFirst, parent, context);
+        }
+        os.splice(oldFirstIndex++, 0, nFirst);
+        newFirstIndex++;
+        oldLastIndex++;
+      }
+    }
+  }
+}
+function swap(os, l, r) {
+  const k = os[l];
+  os[l] = os[r];
+  os[r] = k;
+}
+
+// ts/miso/event.ts
+function delegator(mount, events, getVTree, debug, context) {
+  const controller = "AbortController" in globalThis ? new AbortController : { signal: null, abort: null };
+  mount["abort"] = controller.abort?.bind(controller);
+  for (const event of events) {
+    context.addEventListener(mount, event.name, function(e) {
+      listener(e, mount, getVTree, debug, context);
+    }, event.capture, controller.signal);
+  }
+}
+function listener(e, mount, getVTree, debug, context) {
+  getVTree(function(vtree) {
+    if (Array.isArray(e)) {
+      for (const key of e) {
+        dispatch(key, vtree, mount, debug, context);
+      }
+    } else {
+      dispatch(e, vtree, mount, debug, context);
+    }
+  });
+}
+function dispatch(ev, vtree, mount, debug, context) {
+  var target = context.getTarget(ev);
+  if (target) {
+    let stack = buildTargetToElement(mount, target, context);
+    delegateEvent(ev, vtree, stack, debug, context);
+  }
+}
+function buildTargetToElement(element, target, context) {
+  var stack = [];
+  while (!context.isEqual(element, target)) {
+    stack.unshift(target);
+    if (target && context.parentNode(target)) {
+      target = context.parentNode(target);
+    } else {
+      return stack;
+    }
+  }
+  return stack;
+}
+function delegateEvent(event, obj, stack, debug, context) {
+  if (!stack.length) {
+    if (debug) {
+      console.warn('Event "' + event.type + '" did not find an event handler to dispatch on', obj, event);
+    }
+    return;
+  } else if (stack.length > 1) {
+    if (obj.type === 2 /* VText */) {
+      return;
+    } else if (obj.type === 3 /* VFrag */) {
+      for (const child of obj.children) {
+        if (containsDOMRef(child, stack[0], context)) {
+          delegateEvent(event, child, stack, debug, context);
+          return;
+        }
+      }
+      return;
+    } else if (obj.type === 0 /* VComp */) {
+      if (!obj.child) {
+        if (debug) {
+          console.error("VComp has no child property set during event delegation", obj);
+          console.error("This means the Component has not been fully mounted, this should never happen");
+          throw new Error("VComp has no .child property set during event delegation");
+        }
+        return;
+      }
+      return delegateEvent(event, obj.child, stack, debug, context);
+    } else if (obj.type === 1 /* VNode */) {
+      if (context.isEqual(obj.domRef, stack[0])) {
+        const eventObj = obj.events.captures[event.type];
+        if (eventObj) {
+          const options = eventObj.options;
+          if (options.preventDefault)
+            event.preventDefault();
+          if (!event["captureStopped"]) {
+            eventObj.runEvent(event, obj.domRef);
+          }
+          if (options.stopPropagation) {
+            event["captureStopped"] = true;
+          }
+        }
+        stack.splice(0, 1);
+        for (const child of obj.children) {
+          if (containsDOMRef(child, stack[0], context)) {
+            delegateEvent(event, child, stack, debug, context);
+            return;
+          }
+        }
+      }
+      return;
+    }
+  } else {
+    if (obj.type === 0 /* VComp */) {
+      if (obj.child) {
+        delegateEvent(event, obj.child, stack, debug, context);
+      }
+    } else if (obj.type === 3 /* VFrag */) {
+      for (const child of obj.children) {
+        if (containsDOMRef(child, stack[0], context)) {
+          delegateEvent(event, child, stack, debug, context);
+          return;
+        }
+      }
+    } else if (obj.type === 1 /* VNode */) {
+      const eventCaptureObj = obj.events.captures[event.type];
+      if (eventCaptureObj && !event["captureStopped"]) {
+        const options = eventCaptureObj.options;
+        if (context.isEqual(stack[0], obj.domRef)) {
+          if (options.preventDefault)
+            event.preventDefault();
+          eventCaptureObj.runEvent(event, stack[0]);
+          if (options.stopPropagation)
+            event["captureStopped"] = true;
+        }
+      }
+      const eventObj = obj.events.bubbles[event.type];
+      if (eventObj && !event["captureStopped"]) {
+        const options = eventObj.options;
+        if (context.isEqual(stack[0], obj.domRef)) {
+          if (options.preventDefault)
+            event.preventDefault();
+          eventObj.runEvent(event, stack[0]);
+          if (!options.stopPropagation) {
+            propagateWhileAble(obj.parent, event);
+          }
+        }
+      } else {
+        if (!event["captureStopped"]) {
+          propagateWhileAble(obj.parent, event);
+        }
+      }
+    }
+  }
+}
+function propagateWhileAble(vtree, event) {
+  while (vtree) {
+    switch (vtree.type) {
+      case 2 /* VText */:
+        break;
+      case 3 /* VFrag */:
+        vtree = vtree.parent;
+        break;
+      case 1 /* VNode */:
+        const eventObj = vtree.events.bubbles[event.type];
+        if (eventObj) {
+          const options = eventObj.options;
+          if (options.preventDefault)
+            event.preventDefault();
+          eventObj.runEvent(event, vtree.domRef);
+          if (options.stopPropagation) {
+            return;
+          }
+        }
+        vtree = vtree.parent;
+        break;
+      case 0 /* VComp */:
+        if (!vtree.eventPropagation)
+          return;
+        vtree = vtree.parent;
+        break;
+    }
+  }
+}
+function eventJSON(at, obj) {
+  if (typeof at[0] === "object") {
+    var ret = [];
+    for (var i = 0;i < at.length; i++) {
+      ret.push(eventJSON(at[i], obj));
+    }
+    return ret;
+  }
+  for (const a of at)
+    obj = obj[a];
+  var newObj;
+  if (obj instanceof Array || "length" in obj && obj["localName"] !== "select") {
+    newObj = [];
+    for (var j = 0;j < obj.length; j++) {
+      newObj.push(eventJSON([], obj[j]));
+    }
+    return newObj;
+  }
+  newObj = {};
+  for (var key in getAllPropertyNames(obj)) {
+    if (obj["localName"] === "input" && (key === "selectionDirection" || key === "selectionStart" || key === "selectionEnd")) {
+      continue;
+    }
+    if (typeof obj[key] == "string" || typeof obj[key] == "number" || typeof obj[key] == "boolean") {
+      newObj[key] = obj[key];
+    }
+  }
+  return newObj;
+}
+function containsDOMRef(vtree, target, context) {
+  switch (vtree.type) {
+    case 3 /* VFrag */:
+      for (const child of vtree.children)
+        if (containsDOMRef(child, target, context))
+          return true;
+      return false;
+    case 0 /* VComp */:
+      return vtree.child ? containsDOMRef(vtree.child, target, context) : false;
+    default:
+      return context.isEqual(vtree.domRef, target);
+  }
+}
+function getAllPropertyNames(obj) {
+  var props = {}, i = 0;
+  do {
+    var names = Object.getOwnPropertyNames(obj);
+    for (i = 0;i < names.length; i++) {
+      props[names[i]] = null;
+    }
+  } while (obj = Object.getPrototypeOf(obj));
+  return props;
+}
+
+// ts/miso/context/dom.ts
+var eventContext = {
+  addEventListener: (mount, event, listener2, capture, signal) => {
+    const options = { capture };
+    if (signal) {
+      options["signal"] = signal;
+    }
+    mount.addEventListener(event, listener2, options);
+  },
+  delegator: (mount, events, getVTree, debug, ctx) => {
+    delegator(mount, events, getVTree, debug, ctx);
+  },
+  isEqual: (x, y) => {
+    return x === y;
+  },
+  getTarget: (e) => {
+    return e.target;
+  },
+  parentNode: (node) => {
+    return node.parentNode;
+  }
+};
+var hydrationContext = {
+  getInlineStyle: (node, key) => {
+    return node.style[key];
+  },
+  firstChild: (node) => {
+    return node.firstChild;
+  },
+  lastChild: (node) => {
+    return node.lastChild;
+  },
+  getAttribute: (node, key) => {
+    if (key === "class")
+      return node.className;
+    if (key in node)
+      return node[key];
+    return node.getAttribute(key);
+  },
+  getTag: (node) => {
+    return node.nodeName;
+  },
+  getTextContent: (node) => {
+    return node.textContent;
+  },
+  children: (node) => {
+    return node.childNodes;
+  }
+};
+var drawingContext = {
+  nextSibling: (node) => {
+    let sibling = node.nextSibling;
+    while (sibling) {
+      switch (sibling.type) {
+        case 0 /* VComp */:
+        case 3 /* VFrag */: {
+          const ref = getFirstDOMRef(sibling);
+          if (ref)
+            return ref;
+          sibling = sibling.nextSibling;
+          break;
+        }
+        default:
+          return sibling.domRef;
+      }
+    }
+    return null;
+  },
+  createTextNode: (s) => {
+    return document.createTextNode(s);
+  },
+  createElementNS: (ns, tag) => {
+    return document.createElementNS(ns, tag);
+  },
+  appendChild: (parent, child) => {
+    return parent.appendChild(child);
+  },
+  replaceChild: (parent, n, old) => {
+    return parent.replaceChild(n, old);
+  },
+  removeChild: (parent, child) => {
+    return parent.removeChild(child);
+  },
+  createElement: (tag) => {
+    return document.createElement(tag);
+  },
+  addClass: (className, domRef) => {
+    if (className)
+      domRef.classList.add(className);
+  },
+  removeClass: (className, domRef) => {
+    if (className)
+      domRef.classList.remove(className);
+  },
+  addEvent: (_node, _name, _key) => {},
+  removeEvent: (_node, _name, _capture) => {},
+  insertBefore: (parent, child, node) => {
+    return parent.insertBefore(child, node);
+  },
+  swapDOMRefs: (oLast, oFirst, p) => {
+    const tmp = oLast.nextSibling;
+    p.insertBefore(oLast, oFirst);
+    p.insertBefore(oFirst, tmp);
+    return;
+  },
+  setInlineStyle: (cCss, nCss, node) => {
+    var result;
+    for (const key in cCss) {
+      result = nCss[key];
+      if (!result) {
+        if (key in node.style) {
+          node.style[key] = "";
+        } else {
+          node.style.setProperty(key, "");
+        }
+      } else if (result !== cCss[key]) {
+        if (key in node.style) {
+          node.style[key] = result;
+        } else {
+          node.style.setProperty(key, result);
+        }
+      }
+    }
+    for (const n in nCss) {
+      if (cCss && cCss[n])
+        continue;
+      if (n in node.style) {
+        node.style[n] = nCss[n];
+      } else {
+        node.style.setProperty(n, nCss[n]);
+      }
+    }
+    return;
+  },
+  setAttribute: (node, key, value) => {
+    return node.setAttribute(key, value);
+  },
+  setAttributeNS: (node, ns, key, value) => {
+    return node.setAttributeNS(ns, key, value);
+  },
+  removeAttribute: (node, key) => {
+    return node.removeAttribute(key);
+  },
+  setTextContent: (node, text) => {
+    node.textContent = text;
+    return;
+  },
+  flush: () => {
+    return;
+  },
+  getHead: function() {
+    return document.head;
+  },
+  getRoot: function() {
+    return document.body;
+  }
+};
+
+// ts/miso/hydrate.ts
+function collapseSiblingTextNodes(vs) {
+  var ax = 0, adjusted = vs.length > 0 ? [vs[0]] : [];
+  for (var ix = 1;ix < vs.length; ix++) {
+    if (adjusted[ax].type === 2 /* VText */ && vs[ix].type === 2 /* VText */) {
+      adjusted[ax].text += vs[ix].text;
+      continue;
+    }
+    adjusted[++ax] = vs[ix];
+  }
+  for (const v of adjusted) {
+    if (v.type === 3 /* VFrag */) {
+      v.children = collapseSiblingTextNodes(v.children);
+    }
+  }
+  return adjusted;
+}
+function hydrate(logLevel, mountPoint, vtree, context, drawingContext2) {
+  if (!vtree || !mountPoint)
+    return false;
+  if (mountPoint.nodeType === 3)
+    return false;
+  if (!walk(logLevel, vtree, context.firstChild(mountPoint), context, drawingContext2)) {
+    if (logLevel) {
+      console.warn("[DEBUG_HYDRATE] Could not copy DOM into virtual DOM, falling back to diff");
+    }
+    while (context.firstChild(mountPoint))
+      drawingContext2.removeChild(mountPoint, context.lastChild(mountPoint));
+    return false;
+  } else {
+    if (logLevel) {
+      console.info("[DEBUG_HYDRATE] Successfully prerendered page");
+    }
+  }
+  return true;
+}
+function diagnoseError(logLevel, vtree, node) {
+  if (logLevel)
+    console.warn("[DEBUG_HYDRATE] VTree differed from node", vtree, node);
+}
+function nextAfter(tree, current) {
+  const lastRef = getLastDOMRef(tree);
+  return lastRef ? lastRef.nextSibling : current;
+}
+function walk(logLevel, vtree, node, context, drawingContext2) {
+  switch (vtree.type) {
+    case 0 /* VComp */:
+      let mounted = vtree.mount(node.parentNode);
+      vtree.componentId = mounted.componentId;
+      vtree.child = mounted.componentTree;
+      mounted.componentTree.parent = vtree;
+      if (!walk(logLevel, vtree.child, node, context, drawingContext2)) {
+        return false;
+      }
+      break;
+    case 3 /* VFrag */:
+      vtree.children = collapseSiblingTextNodes(vtree.children);
+      for (const child of vtree.children) {
+        if (!node) {
+          diagnoseError(logLevel, child, null);
+          return false;
+        }
+        if (!walk(logLevel, child, node, context, drawingContext2))
+          return false;
+        node = nextAfter(child, node);
+      }
+      break;
+    case 2 /* VText */:
+      if (node.nodeType !== 3 || vtree.text.trim() !== node.textContent.trim()) {
+        diagnoseError(logLevel, vtree, node);
+        return false;
+      }
+      vtree.domRef = node;
+      break;
+    case 1 /* VNode */:
+      if (node.nodeType !== 1) {
+        diagnoseError(logLevel, vtree, node);
+        return false;
+      }
+      vtree.domRef = node;
+      vtree.children = collapseSiblingTextNodes(vtree.children);
+      callCreated(node, vtree, drawingContext2);
+      let domCursor = node.firstChild;
+      for (var i = 0;i < vtree.children.length; i++) {
+        const vdomChild = vtree.children[i];
+        if (!domCursor) {
+          diagnoseError(logLevel, vdomChild, null);
+          return false;
+        }
+        if (!walk(logLevel, vdomChild, domCursor, context, drawingContext2)) {
+          return false;
+        }
+        domCursor = nextAfter(vdomChild, domCursor);
+      }
+      break;
+  }
+  return true;
+}
+
+// ts/index.ts
+globalThis["miso"] = {
+  hydrationContext,
+  eventContext,
+  drawingContext,
+  diff,
+  hydrate,
+  version,
+  onBTS,
+  onMTS,
+  callBlur,
+  callFocus,
+  callSelect,
+  callSetSelectionRange,
+  eventJSON,
+  fetchCore,
+  eventSourceConnect,
+  eventSourceClose,
+  websocketConnect,
+  websocketClose,
+  websocketSend,
+  updateRef,
+  inline,
+  typeOf,
+  mathRandom,
+  getRandomValues,
+  splitmix32,
+  populateClass,
+  delegateEvent,
+  cookieGet,
+  cookieGetAll,
+  cookieSet,
+  cookieDelete,
+  cookieDeleteWith,
+  delegator: eventContext.delegator,
+  setDrawingContext: function(name) {
+    const drawing = globalThis[name]["drawingContext"];
+    const events = globalThis[name]["eventContext"];
+    if (!drawing) {
+      console.error('Custom rendering engine ("drawingContext") is not defined at globalThis[name].drawingContext', name);
+    }
+    if (!events) {
+      console.error('Custom event delegation ("eventContext") is not defined at globalThis[name].eventContext', name);
+    }
+    globalThis["miso"]["drawingContext"] = drawing;
+    globalThis["miso"]["eventContext"] = events;
+  }
+};
diff --git a/js/miso.prod.js b/js/miso.prod.js
new file mode 100644
--- /dev/null
+++ b/js/miso.prod.js
@@ -0,0 +1,1 @@
+var g="1.13.0.0";function M(){return typeof __BACKGROUND__<"u"&&__BACKGROUND__}function R(){return typeof __MAIN_THREAD__<"u"&&__MAIN_THREAD__}function y(z,G){var Q=function(){var U=document.getElementById(z);if(U&&U.focus)U.focus()};G>0?setTimeout(Q,G):Q()}function v(z,G){var Q=function(){var U=document.getElementById(z);if(U&&U.blur)U.blur()};G>0?setTimeout(Q,G):Q()}function u(z,G){var Q=function(){var U=document.getElementById(z);if(U&&typeof U.select==="function")U.select()};G>0?setTimeout(Q,G):Q()}function l(z,G,Q,U){var X=function(){var Y=document.getElementById(z);if(Y&&typeof Y.setSelectionRange==="function")Y.setSelectionRange(G,Q,"none")};U>0?setTimeout(X,U):X()}function x(z,G,Q,U,X,Y,$){var Z={method:G,headers:U};if(Q)Z.body=Q;let _={},W=null;try{fetch(z,Z).then((H)=>{W=H.status;for(let[B,N]of H.headers)_[B]=N;if(H.status<200||H.status>=300)throw Error(H.statusText||"HTTP "+H.status);if($=="json")return H.json();else if($=="text")return H.text();else if($==="arrayBuffer")return H.arrayBuffer();else if($==="blob")return H.blob();else if($==="bytes")return H.bytes();else if($==="formData")return H.formData();else if($==="none")return null}).then((H)=>X({error:null,body:H,headers:_,status:W})).catch((H)=>Y({error:null,body:H,headers:_,status:W}))}catch(H){Y({body:null,error:H.message,headers:_,status:W})}}function i(z,G,Q,U,X,Y,$,Z,_){try{let W=new WebSocket(z);return W.onopen=function(){G()},W.onclose=function(H){Q(H)},W.onerror=function(H){console.error(H),Z("WebSocket error received")},W.onmessage=function(H){if(typeof H.data==="string")try{if(_){if(U)U(H.data);return}let B=JSON.parse(H.data);if(X)X(B)}catch(B){if(_&&U)U(H.data);else Z(B.message)}else if(H.data instanceof Blob){if(Y)Y(H.data)}else if(H.data instanceof ArrayBuffer){if($)$(H.data)}else console.error("Received unknown message type from WebSocket",H),Z("Unknown message received from WebSocket")},W}catch(W){Z(W.message)}}function d(z){if(z)z.close(),z=null}function p(z,G){if(G&&z&&z.readyState===WebSocket.OPEN)z.send(G)}function a(z,G,Q,U,X,Y){try{let $=new EventSource(z);return $.onopen=function(){G()},$.onerror=function(){X("EventSource error received")},$.onmessage=function(Z){try{if(Y){if(Q)Q(Z.data);return}let _=JSON.parse(Z.data);if(U)U(_)}catch(_){if(Y&&Q)Q(Z.data);else X(_.message)}},$}catch($){X($.message)}}function s(z){if(z)z.close(),z=null}function c(z,G){if(!z.classList)z.classList=new Set;for(let Q of G)for(let U of Q.trim().split(" "))if(U)z.classList.add(U)}function r(z,G){if(!z.parent)return;G.nextSibling=z.nextSibling,G.parent=z.parent,z.parent.child=G}function o(z,G={}){let Q=Object.keys(G),U=Object.values(G);return Function(...Q,z)(...U)}function n(z){if(z===null||z===void 0)return 0;if(typeof z==="number")return 1;if(typeof z==="string")return 2;if(typeof z==="boolean")return 3;if(Array.isArray(z))return 4;return 5}function t(z){return function(){z|=0,z=z+2654435769|0;var G=z^z>>>15;return G=Math.imul(G,2246822507),G=G^G>>>13,G=Math.imul(G,3266489909),((G^G>>>16)>>>0)/4294967296}}function e(){let z=new Uint32Array(1);return crypto.getRandomValues(z)[0]}function zz(){return Math.random()}function q(z,G){switch(z.type){case 3:for(let Q of z.children)q(Q,G);break;case 0:if(z.child)q(z.child,G);break;default:G(z.domRef);break}}function K(z){switch(z.type){case 3:{if(!z.children||z.children.length===0)return null;return K(z.children[0])}case 0:if(!z.child)return null;return K(z.child);default:return z.domRef}}function S(z){switch(z.type){case 3:{if(!z.children||z.children.length===0)return null;return S(z.children[z.children.length-1])}case 0:if(!z.child)return null;return S(z.child);default:return z.domRef}}function Gz(z,G,Q){try{globalThis.cookieStore.get(z).then((U)=>Q(U?U.value:null)).catch((U)=>G(U.message))}catch(U){G(U.message)}}function Qz(z,G){try{globalThis.cookieStore.getAll().then(G).catch((Q)=>z(Q.message))}catch(Q){z(Q.message)}}function Uz(z,G,Q){try{globalThis.cookieStore.set(z).then(Q).catch((U)=>G(U.message))}catch(U){G(U.message)}}function Xz(z,G,Q){try{globalThis.cookieStore.delete(z).then(Q).catch((U)=>G(U.message))}catch(U){G(U.message)}}function Yz(z,G,Q){let U={name:z.name};if(z.path!=null)U.path=z.path;if(z.domain!=null)U.domain=z.domain;if(z.partitioned!=null)U.partitioned=z.partitioned;try{globalThis.cookieStore.delete(U).then(Q).catch((X)=>G(X.message))}catch(X){G(X.message)}}function A(z,G,Q,U){if(!z&&!G)return;else if(!z)D(G,Q,U);else if(!G)k(z,Q,U);else if(z.type===2&&G.type===2)Dz(z,G,U);else if(z.type===0&&G.type===0){if(G.key===z.key){if(G.child=z.child,G.componentId=z.componentId,z.child)z.child.parent=G;if(G.diffProps)G.diffProps();return}j(z,G,Q,U)}else if(z.type===3&&G.type===3)if(G.key===z.key){let X=S(z),Y=X?X.nextSibling:U.nextSibling(z);Az(z.children,G.children,Q,U,Y)}else j(z,G,Q,U);else if(z.type===1&&G.type===1)if(G.tag===z.tag&&G.key===z.key)G.domRef=z.domRef,Jz(z,G,U);else j(z,G,Q,U);else j(z,G,Q,U)}function Dz(z,G,Q){if(z.text!==G.text)Q.setTextContent(z.domRef,G.text);G.domRef=z.domRef;return}function j(z,G,Q,U){if(z.type===3){let $=S(z),Z=$?$.nextSibling:U.nextSibling(z);if(k(z,Q,U),Z)E(Q,2,Z,G,U);else D(G,Q,U);return}switch(z.type){case 2:break;default:V(z);break}let X=K(z),Y=S(z);if(!X||!Y){let $=U.nextSibling(z);if($)E(Q,2,$,G,U);else D(G,Q,U)}else if(X!==Y){let $=Y.nextSibling;if(q(z,(Z)=>U.removeChild(Q,Z)),$)E(Q,2,$,G,U);else D(G,Q,U)}else E(Q,1,X,G,U);switch(z.type){case 2:break;default:F(z);break}}function k(z,G,Q){switch(z.type){case 2:break;case 3:for(let U of z.children)k(U,G,Q);return;default:V(z);break}switch(q(z,(U)=>Q.removeChild(G,U)),z.type){case 2:break;default:F(z);break}}function F(z){if(z.type===3){for(let G of z.children)if(G.type!==2)F(G);return}switch(Iz(z),z.type){case 1:for(let G of z.children)if(G.type!==2)F(G);break;case 0:if(z.child&&z.child.type!==2)F(z.child);break}}function Iz(z){if(z.type===1&&z.onDestroyed)z.onDestroyed();if(z.type===0)kz(z)}function wz(z){switch(z.type){case 0:break;case 1:if(z.onBeforeDestroyed)z.onBeforeDestroyed();break;default:break}}function V(z){if(z.type===3){for(let G of z.children)if(G.type!==2)V(G);return}switch(wz(z),z.type){case 1:for(let G of z.children){if(G.type===2)continue;V(G)}break;case 0:if(z.child&&z.child.type!==2)V(z.child);break}}function Jz(z,G,Q){Pz(z?z.props:{},G.props,G.domRef,G.ns==="svg",Q),Rz(z?z.classList:null,G.classList,G.domRef,Q),Fz(z?z.css:{},G.css,G.domRef,Q),Mz(z,G,Q),Az(z?z.children:[],G.children,G.domRef,Q),jz(G)}function Mz(z,G,Q){if(!M()&&!R())return;if(z===null&&G.directEvents)for(let U of G.directEvents)Q.addEvent(G.domRef,U,{capture:!1,direct:!0});for(let U of[!0,!1]){let X=qz(z,U),Y=qz(G,U);for(let $ in X)if(!($ in Y))Q.removeEvent(G.domRef,$,U);for(let $ in Y){let Z=Y[$],_=X[$];if(!_||!Lz(Z,_))Q.addEvent(G.domRef,$,Z)}}}function Rz(z,G,Q,U){if(!z&&!G)return;if(!z){for(let X of G)U.addClass(X,Q);return}if(!G){for(let X of z)U.removeClass(X,Q);return}for(let X of z)if(!G.has(X))U.removeClass(X,Q);for(let X of G)if(!z.has(X))U.addClass(X,Q);return}function Pz(z,G,Q,U,X){var Y;let $=M()||R();for(let Z in z)if(Y=G[Z],Y===void 0)if(U||$||!(Z in Q)||Z==="disabled")X.removeAttribute(Q,Z);else X.setAttribute(Q,Z,"");else{if(Y===z[Z]&&Z!=="checked"&&Z!=="value")continue;if(U)if(Z==="href")X.setAttributeNS(Q,"http://www.w3.org/1999/xlink","href",Y);else X.setAttribute(Q,Z,Y);else if(!$&&Z in Q&&!(Z==="list"||Z==="form"))Q[Z]=Y;else X.setAttribute(Q,Z,Y)}for(let Z in G){if(z&&Z in z)continue;if(Y=G[Z],U)if(Z==="href")X.setAttributeNS(Q,"http://www.w3.org/1999/xlink","href",Y);else X.setAttribute(Q,Z,Y);else if(!$&&Z in Q&&!(Z==="list"||Z==="form"))Q[Z]=G[Z];else X.setAttribute(Q,Z,Y)}}function Fz(z,G,Q,U){U.setInlineStyle(z,G,Q)}function Vz(z,G){if(z.length===0||G.length===0)return!1;for(var Q=0;Q<z.length;Q++)if(z[Q].key===null||z[Q].key===void 0)return!1;for(var Q=0;Q<G.length;Q++)if(G[Q].key===null||G[Q].key===void 0)return!1;return!0}function Az(z,G,Q,U,X=null){if(Vz(z,G))fz(z,G,Q,U,X);else for(let Y=0;Y<Math.max(G.length,z.length);Y++){let $=z[Y],Z=G[Y];if(!$&&Z)if(X)E(Q,2,X,Z,U);else D(Z,Q,U);else A($,Z,Q,U)}}function qz(z,G){let Q={};if(!z)return Q;let U=G?z.events.captures:z.events.bubbles;for(let X in U){let{staticKey:Y,componentId:$,options:Z}=U[X];if(Y!==void 0&&$!==void 0)Q[X]={capture:G,staticKey:Y,componentId:$,options:Z}}return Q}function Lz(z,G){return z.staticKey===G.staticKey&&z.componentId===G.componentId&&z.options?.preventDefault===G.options?.preventDefault&&z.options?.stopPropagation===G.options?.stopPropagation}function Oz(z,G){if(z.ns==="svg")z.domRef=G.createElementNS("http://www.w3.org/2000/svg",z.tag);else if(z.ns==="mathml")z.domRef=G.createElementNS("http://www.w3.org/1998/Math/MathML",z.tag);else z.domRef=G.createElement(z.tag)}function Bz(z,G,Q){if(G.onCreated)G.onCreated(G.domRef)}function E(z,G,Q,U,X){switch(U.type){case 2:switch(U.domRef=X.createTextNode(U.text),G){case 2:X.insertBefore(z,U.domRef,Q);break;case 0:X.appendChild(z,U.domRef);break;case 1:X.replaceChild(z,U.domRef,Q);break}break;case 3:for(let Y of U.children)E(z,2,Q,Y,X);if(G===1&&Q)X.removeChild(z,Q);break;case 0:bz(z,G,Q,U,X);break;case 1:if(U.onBeforeCreated)U.onBeforeCreated();if(Oz(U,X),U.onCreated)U.onCreated(U.domRef);switch(Jz(null,U,X),G){case 2:X.insertBefore(z,U.domRef,Q);break;case 0:X.appendChild(z,U.domRef);break;case 1:X.replaceChild(z,U.domRef,Q);break}break}}function jz(z){if(z.tag==="canvas"&&z.draw)z.draw(z.domRef)}function kz(z){z.unmount(z.componentId)}function bz(z,G,Q,U,X){let Y=U.mount(z);U.componentId=Y.componentId,U.child=Y.componentTree,Y.componentTree.parent=U;let $=K(Y.componentTree);if(Y.componentTree.type!==0){if(G===1&&Q)if(!$)X.removeChild(z,Q);else if(Y.componentTree.type===3)q(Y.componentTree,(Z)=>X.insertBefore(z,Z,Q)),X.removeChild(z,Q);else X.replaceChild(z,$,Q);else if(G===2)if(Q)q(Y.componentTree,(Z)=>X.insertBefore(z,Z,Q));else q(Y.componentTree,(Z)=>X.appendChild(z,Z))}}function D(z,G,Q){E(G,0,null,z,Q)}function Kz(z,G,Q,U){let X=Q?K(Q)??U.nextSibling(Q):null;if(X)q(G,(Y)=>U.insertBefore(z,Y,X));else q(G,(Y)=>U.appendChild(z,Y))}function Tz(z,G,Q,U){let X=K(z),Y=K(G);if(X&&Y&&(z.type===1||z.type===2)&&(G.type===1||G.type===2)){U.swapDOMRefs(X,Y,Q);return}let $=S(z),Z=$?$.nextSibling:U.nextSibling(z),_=K(G)??U.nextSibling(G);if(_)q(z,(W)=>U.insertBefore(Q,W,_));else q(z,(W)=>U.appendChild(Q,W));if(Z)q(G,(W)=>U.insertBefore(Q,W,Z));else q(G,(W)=>U.appendChild(Q,W))}function fz(z,G,Q,U,X=null){var Y=0,$=0,Z=z.length-1,_=G.length-1,W,H,B,N,J,m,Wz;for(;;){if($>_&&Y>Z)break;if(H=G[$],B=G[_],J=z[Y],N=z[Z],Y>Z){let P=(J?K(J)??U.nextSibling(J):null)??X;if(P)E(Q,2,P,H,U);else D(H,Q,U);z.splice($,0,H),$++}else if($>_){W=Z;while(Z>=Y)k(z[Z--],Q,U);z.splice(Y,W-Y+1);break}else if(J.key===H.key)A(z[Y++],G[$++],Q,U);else if(N.key===B.key)A(z[Z--],G[_--],Q,U);else if(J.key===B.key&&H.key===N.key)Tz(N,J,Q,U),mz(z,Y,Z),A(z[Y++],G[$++],Q,U),A(z[Z--],G[_--],Q,U);else if(J.key===B.key){let I=S(N),P=I?I.nextSibling:U.nextSibling(N);if(P)q(J,(h)=>U.insertBefore(Q,h,P));else q(J,(h)=>U.appendChild(Q,h));z.splice(Z,0,z.splice(Y,1)[0]),A(z[Z--],G[_--],Q,U)}else if(N.key===H.key)Kz(Q,N,J,U),z.splice(Y,0,z.splice(Z,1)[0]),A(z[Y++],H,Q,U),$++;else{m=!1,W=Y;while(W<=Z){if(z[W].key===H.key){m=!0,Wz=z[W];break}W++}if(m)z.splice(Y,0,z.splice(W,1)[0]),A(z[Y++],H,Q,U),Kz(Q,Wz,z[Y],U),$++;else{let I=K(J)??U.nextSibling(J);if(I)E(Q,2,I,H,U);else D(H,Q,U);z.splice(Y++,0,H),$++,Z++}}}}function mz(z,G,Q){let U=z[G];z[G]=z[Q],z[Q]=U}function Zz(z,G,Q,U,X){let Y="AbortController"in globalThis?new AbortController:{signal:null,abort:null};z.abort=Y.abort?.bind(Y);for(let $ of G)X.addEventListener(z,$.name,function(Z){hz(Z,z,Q,U,X)},$.capture,Y.signal)}function hz(z,G,Q,U,X){Q(function(Y){if(Array.isArray(z))for(let $ of z)Nz($,Y,G,U,X);else Nz(z,Y,G,U,X)})}function Nz(z,G,Q,U,X){var Y=X.getTarget(z);if(Y){let $=gz(Q,Y,X);C(z,G,$,U,X)}}function gz(z,G,Q){var U=[];while(!Q.isEqual(z,G))if(U.unshift(G),G&&Q.parentNode(G))G=Q.parentNode(G);else return U;return U}function C(z,G,Q,U,X){if(!Q.length){if(U)console.warn('Event "'+z.type+'" did not find an event handler to dispatch on',G,z);return}else if(Q.length>1){if(G.type===2)return;else if(G.type===3){for(let Y of G.children)if(L(Y,Q[0],X)){C(z,Y,Q,U,X);return}return}else if(G.type===0){if(!G.child){if(U)throw console.error("VComp has no child property set during event delegation",G),console.error("This means the Component has not been fully mounted, this should never happen"),Error("VComp has no .child property set during event delegation");return}return C(z,G.child,Q,U,X)}else if(G.type===1){if(X.isEqual(G.domRef,Q[0])){let Y=G.events.captures[z.type];if(Y){let $=Y.options;if($.preventDefault)z.preventDefault();if(!z.captureStopped)Y.runEvent(z,G.domRef);if($.stopPropagation)z.captureStopped=!0}Q.splice(0,1);for(let $ of G.children)if(L($,Q[0],X)){C(z,$,Q,U,X);return}}return}}else if(G.type===0){if(G.child)C(z,G.child,Q,U,X)}else if(G.type===3){for(let Y of G.children)if(L(Y,Q[0],X)){C(z,Y,Q,U,X);return}}else if(G.type===1){let Y=G.events.captures[z.type];if(Y&&!z.captureStopped){let Z=Y.options;if(X.isEqual(Q[0],G.domRef)){if(Z.preventDefault)z.preventDefault();if(Y.runEvent(z,Q[0]),Z.stopPropagation)z.captureStopped=!0}}let $=G.events.bubbles[z.type];if($&&!z.captureStopped){let Z=$.options;if(X.isEqual(Q[0],G.domRef)){if(Z.preventDefault)z.preventDefault();if($.runEvent(z,Q[0]),!Z.stopPropagation)Sz(G.parent,z)}}else if(!z.captureStopped)Sz(G.parent,z)}}function Sz(z,G){while(z)switch(z.type){case 2:break;case 3:z=z.parent;break;case 1:let Q=z.events.bubbles[G.type];if(Q){let U=Q.options;if(U.preventDefault)G.preventDefault();if(Q.runEvent(G,z.domRef),U.stopPropagation)return}z=z.parent;break;case 0:if(!z.eventPropagation)return;z=z.parent;break}}function O(z,G){if(typeof z[0]==="object"){var Q=[];for(var U=0;U<z.length;U++)Q.push(O(z[U],G));return Q}for(let Z of z)G=G[Z];var X;if(G instanceof Array||"length"in G&&G.localName!=="select"){X=[];for(var Y=0;Y<G.length;Y++)X.push(O([],G[Y]));return X}X={};for(var $ in yz(G)){if(G.localName==="input"&&($==="selectionDirection"||$==="selectionStart"||$==="selectionEnd"))continue;if(typeof G[$]=="string"||typeof G[$]=="number"||typeof G[$]=="boolean")X[$]=G[$]}return X}function L(z,G,Q){switch(z.type){case 3:for(let U of z.children)if(L(U,G,Q))return!0;return!1;case 0:return z.child?L(z.child,G,Q):!1;default:return Q.isEqual(z.domRef,G)}}function yz(z){var G={},Q=0;do{var U=Object.getOwnPropertyNames(z);for(Q=0;Q<U.length;Q++)G[U[Q]]=null}while(z=Object.getPrototypeOf(z));return G}var b={addEventListener:(z,G,Q,U,X)=>{let Y={capture:U};if(X)Y.signal=X;z.addEventListener(G,Q,Y)},delegator:(z,G,Q,U,X)=>{Zz(z,G,Q,U,X)},isEqual:(z,G)=>{return z===G},getTarget:(z)=>{return z.target},parentNode:(z)=>{return z.parentNode}},Ez={getInlineStyle:(z,G)=>{return z.style[G]},firstChild:(z)=>{return z.firstChild},lastChild:(z)=>{return z.lastChild},getAttribute:(z,G)=>{if(G==="class")return z.className;if(G in z)return z[G];return z.getAttribute(G)},getTag:(z)=>{return z.nodeName},getTextContent:(z)=>{return z.textContent},children:(z)=>{return z.childNodes}},$z={nextSibling:(z)=>{let G=z.nextSibling;while(G)switch(G.type){case 0:case 3:{let Q=K(G);if(Q)return Q;G=G.nextSibling;break}default:return G.domRef}return null},createTextNode:(z)=>{return document.createTextNode(z)},createElementNS:(z,G)=>{return document.createElementNS(z,G)},appendChild:(z,G)=>{return z.appendChild(G)},replaceChild:(z,G,Q)=>{return z.replaceChild(G,Q)},removeChild:(z,G)=>{return z.removeChild(G)},createElement:(z)=>{return document.createElement(z)},addClass:(z,G)=>{if(z)G.classList.add(z)},removeClass:(z,G)=>{if(z)G.classList.remove(z)},addEvent:(z,G,Q)=>{},removeEvent:(z,G,Q)=>{},insertBefore:(z,G,Q)=>{return z.insertBefore(G,Q)},swapDOMRefs:(z,G,Q)=>{let U=z.nextSibling;Q.insertBefore(z,G),Q.insertBefore(G,U);return},setInlineStyle:(z,G,Q)=>{var U;for(let X in z)if(U=G[X],!U)if(X in Q.style)Q.style[X]="";else Q.style.setProperty(X,"");else if(U!==z[X])if(X in Q.style)Q.style[X]=U;else Q.style.setProperty(X,U);for(let X in G){if(z&&z[X])continue;if(X in Q.style)Q.style[X]=G[X];else Q.style.setProperty(X,G[X])}return},setAttribute:(z,G,Q)=>{return z.setAttribute(G,Q)},setAttributeNS:(z,G,Q,U)=>{return z.setAttributeNS(G,Q,U)},removeAttribute:(z,G)=>{return z.removeAttribute(G)},setTextContent:(z,G)=>{z.textContent=G;return},flush:()=>{return},getHead:function(){return document.head},getRoot:function(){return document.body}};function Hz(z){var G=0,Q=z.length>0?[z[0]]:[];for(var U=1;U<z.length;U++){if(Q[G].type===2&&z[U].type===2){Q[G].text+=z[U].text;continue}Q[++G]=z[U]}for(let X of Q)if(X.type===3)X.children=Hz(X.children);return Q}function _z(z,G,Q,U,X){if(!Q||!G)return!1;if(G.nodeType===3)return!1;if(!f(z,Q,U.firstChild(G),U,X)){if(z)console.warn("[DEBUG_HYDRATE] Could not copy DOM into virtual DOM, falling back to diff");while(U.firstChild(G))X.removeChild(G,U.lastChild(G));return!1}else if(z)console.info("[DEBUG_HYDRATE] Successfully prerendered page");return!0}function T(z,G,Q){if(z)console.warn("[DEBUG_HYDRATE] VTree differed from node",G,Q)}function Cz(z,G){let Q=S(z);return Q?Q.nextSibling:G}function f(z,G,Q,U,X){switch(G.type){case 0:let $=G.mount(Q.parentNode);if(G.componentId=$.componentId,G.child=$.componentTree,$.componentTree.parent=G,!f(z,G.child,Q,U,X))return!1;break;case 3:G.children=Hz(G.children);for(let _ of G.children){if(!Q)return T(z,_,null),!1;if(!f(z,_,Q,U,X))return!1;Q=Cz(_,Q)}break;case 2:if(Q.nodeType!==3||G.text.trim()!==Q.textContent.trim())return T(z,G,Q),!1;G.domRef=Q;break;case 1:if(Q.nodeType!==1)return T(z,G,Q),!1;G.domRef=Q,G.children=Hz(G.children),Bz(Q,G,X);let Z=Q.firstChild;for(var Y=0;Y<G.children.length;Y++){let _=G.children[Y];if(!Z)return T(z,_,null),!1;if(!f(z,_,Z,U,X))return!1;Z=Cz(_,Z)}break}return!0}globalThis.miso={hydrationContext:Ez,eventContext:b,drawingContext:$z,diff:A,hydrate:_z,version:g,onBTS:M,onMTS:R,callBlur:v,callFocus:y,callSelect:u,callSetSelectionRange:l,eventJSON:O,fetchCore:x,eventSourceConnect:a,eventSourceClose:s,websocketConnect:i,websocketClose:d,websocketSend:p,updateRef:r,inline:o,typeOf:n,mathRandom:zz,getRandomValues:e,splitmix32:t,populateClass:c,delegateEvent:C,cookieGet:Gz,cookieGetAll:Qz,cookieSet:Uz,cookieDelete:Xz,cookieDeleteWith:Yz,delegator:b.delegator,setDrawingContext:function(z){let G=globalThis[z].drawingContext,Q=globalThis[z].eventContext;if(!G)console.error('Custom rendering engine ("drawingContext") is not defined at globalThis[name].drawingContext',z);if(!Q)console.error('Custom event delegation ("eventContext") is not defined at globalThis[name].eventContext',z);globalThis.miso.drawingContext=G,globalThis.miso.eventContext=Q}};
diff --git a/jsbits/delegate.js b/jsbits/delegate.js
deleted file mode 100644
--- a/jsbits/delegate.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/* event delegation algorithm */
-function delegate(mountPointElement, events, getVTree) {
-    for (var event in events) {
-	mountPointElement.addEventListener(events[event][0], function(e) {
-            delegateEvent ( e
-                          , getVTree()
-                          , buildTargetToElement(mountPointElement, e.target)
-                          , []
-                          );
-	     }, events[event][1]);
-    }
-}
-
-/* Accumulate parent stack as well for propagation */
-function delegateEvent (event, obj, stack, parentStack) {
-
-    /* base case, not found */
-    if (!stack.length) return;
-
-    /* stack not length 1, recurse */
-    else if (stack.length > 1) {
-      if (obj.domRef === stack[0]) parentStack.unshift(obj);
-	for (var o = 0; o < obj.children.length; o++) {
-          if (obj.children[o].type === "vtext") continue;
-          delegateEvent ( event
-                        , obj.children[o]
-                        , stack.slice(1)
-                        , parentStack
-			                  );
-       }
-    }
-
-    /* stack.length == 1 */
-    else {
-	if (obj.domRef === stack[0]) {
-	    var eventObj = obj.events[event.type];
-	    if (eventObj) {
-		var options = eventObj.options;
-		if (options.preventDefault)
-		    event.preventDefault();
-		eventObj.runEvent(event);
-		if (!options.stopPropagation)
-		    propogateWhileAble (parentStack, event);
-	    } else {
-		 /* still propagate to parent handlers even if event not defined */
- 		 propogateWhileAble (parentStack, event);
-	      }
-	}
-    }
-}
-
-function buildTargetToElement (element, target) {
-    var stack = [];
-    while (element !== target) {
-      stack.unshift (target);
-      target = target.parentNode;
-    }
-    return stack;
-}
-
-function propogateWhileAble (parentStack, event) {
-  for (var i = 0; i < parentStack.length; i++) {
-    if (parentStack[i].events[event.type]) {
-      var eventObj = parentStack[i].events[event.type],
-          options = eventObj.options;
-        if (options.preventDefault) event.preventDefault();
-        eventObj.runEvent(event);
-  	if (options.stopPropagation) break;
-    }
-  }
-}
-
-/* Walks down obj following the path described by `at`, then filters primitive
- values (string, numbers and booleans)*/
-function objectToJSON (at, obj) {
-  /* If at is of type [[MisoString]] */
-  if (typeof at[0] == "object") {
-    var ret = [];
-    for (var i = 0; i < at.length; i++)
-      ret.push(objectToJSON(at[i], obj));
-    return (ret);
-  }
-
-  for (var i in at) obj = obj[at[i]];
-
-  /* If obj is a list-like object */
-  if (obj instanceof Array) {
-    var newObj = [];
-    for (var i = 0; i < obj.length; i++)
-      newObj.push(objectToJSON([], obj[i]));
-    return (newObj);
-  }
-
-  /* If obj is a non-list-like object */
-  var newObj = {};
-  for (var i in obj)
-    if (typeof obj[i] == "string" || typeof obj[i] == "number" || typeof obj[i] == "boolean")
-      newObj[i] = obj[i];
-  return (newObj);
-}
diff --git a/jsbits/diff.js b/jsbits/diff.js
deleted file mode 100644
--- a/jsbits/diff.js
+++ /dev/null
@@ -1,344 +0,0 @@
-/* virtual-dom diffing algorithm, applies patches as detected */
-function diff(currentObj, newObj, parent, doc) {
-    if (!currentObj && !newObj) return;
-    else if (!currentObj && newObj) createNode(newObj, parent, doc);
-    else if (currentObj && !newObj) destroyNode(currentObj, parent);
-    else {
-	if (currentObj.type === "vtext") {
-	    if (newObj.type === "vnode") replaceTextWithElement(currentObj, newObj, parent, doc);
-	    else diffTextNodes(currentObj, newObj);
-	} else {
-	    if (newObj.type === "vnode") diffVNodes(currentObj, newObj, parent, doc);
-	    else replaceElementWithText(currentObj, newObj, parent, doc);
-	}
-    }
-}
-
-function destroyNode(obj, parent) {
-    parent.removeChild(obj.domRef);
-    callDestroyedRecursive(obj);
-}
-
-function callDestroyedRecursive(obj) {
-    callDestroyed(obj);
-    for (var i in obj.children)
-	callDestroyedRecursive(obj.children[i]);
-}
-
-function callDestroyed(obj) {
-    if (obj.onDestroyed) obj.onDestroyed();
-}
-
-function diffTextNodes(c, n) {
-    if (c.text !== n.text) c.domRef.textContent = n.text;
-    n.domRef = c.domRef;
-}
-
-function replaceElementWithText(c, n, parent, doc) {
-    n.domRef = doc.createTextNode(n.text);
-    parent.replaceChild(n.domRef, c.domRef);
-    callDestroyedRecursive(c);
-}
-
-function replaceTextWithElement(c, n, parent, doc) {
-    createElement(n, doc);
-    parent.replaceChild(n.domRef, c.domRef);
-    callCreated(n);
-}
-
-function callCreated(obj) {
-    if (obj.onCreated) obj.onCreated();
-}
-
-function populate(c, n, doc) {
-    if (!c) c = {
-	props: null,
-	css: null,
-	children: []
-    }
-    diffProps(c.props, n.props, n.domRef, n.ns === "svg");
-    diffCss(c.css, n.css, n.domRef);
-    diffChildren(c.children, n.children, n.domRef, doc);
-}
-
-function diffVNodes(c, n, parent, doc) {
-    if (c.tag === n.tag && n.key === c.key) {
-	n.domRef = c.domRef;
-	populate(c, n, doc);
-    } else {
-	createElement(n, doc);
-	parent.replaceChild(n.domRef, c.domRef);
-	callDestroyedRecursive(c);
-	callCreated(n);
-    }
-}
-
-function diffProps(cProps, nProps, node, isSvg) {
-    var result, newProp, domProp;
-    /* Is current prop in new prop list? */
-    for (var c in cProps) {
-	newProp = nProps[c];
-	/* If current property no longer exists, remove it */
-	if (!newProp) {
-	    /* current key is not in node, remove it from DOM, if SVG, remove attribute */
-	    if (isSvg || !(c in node))
-		node.removeAttribute(c, cProps[c]);
-	    else
-		node[c] = '';
-	} else {
-	    /* Already on DOM from previous diff, continue */
-	    if (newProp === cProps[c]) continue;
-	    domProp = node[c];
-	    if (isSvg) {
-		if (c === "href")
-		    node.setAttributeNS("http://www.w3.org/1999/xlink", "href", newProp);
-		else
-		    node.setAttribute(c, newProp);
-	    } else if (c in node && !(c === "list" || c === "form")) {
-		node[c] = newProp;
-	    } else {
-		node.setAttribute(c, newProp);
-	    }
-	}
-    }
-    /* add remaining */
-    for (var n in nProps) {
-	if (cProps && cProps[n]) continue;
-	newProp = nProps[n];
-	/* Only add new properties, skip (continue) if they already exist in current property map */
-	if (isSvg) {
-	    if (n === "href")
-		node.setAttributeNS("http://www.w3.org/1999/xlink", "href", newProp);
-	    else
-		node.setAttribute(n, newProp);
-	} else if (n in node && !(n === "list" || n === "form")) {
-	    node[n] = nProps[n];
-	} else {
-	    node.setAttribute(n, newProp);
-	}
-    }
-}
-
-function diffCss(cCss, nCss, node) {
-    var result;
-    /* is current attribute in new attribute list? */
-    for (var c in cCss) {
-	result = nCss[c];
-	if (!result) {
-	    /* current key is not in node */
-	    node.style[c] = null;
-	} else if (result !== cCss[c]) {
-	    node.style[c] = result;
-	}
-    }
-    /* add remaining */
-    for (var n in nCss) {
-	if (cCss && cCss[n]) continue;
-	node.style[n] = nCss[n];
-    }
-}
-
-function hasKeys(ns, cs) {
-    return ns.length > 0 && cs.length > 0 && ns[0].key !== null && cs[0].key !== null;
-}
-
-function diffChildren(cs, ns, parent, doc) {
-    var longest = ns.length > cs.length ? ns.length : cs.length;
-    if (hasKeys(ns, cs)) {
-	syncChildren(cs, ns, parent, doc);
-    } else {
-	for (var i = 0; i < longest; i++)
-	    diff(cs[i], ns[i], parent, doc);
-    }
-}
-
-function createElement(obj, doc) {
-    obj.domRef = obj.ns === "svg" ?
-	doc.createElementNS("http://www.w3.org/2000/svg", obj.tag) :
-	doc.createElement(obj.tag);
-    populate(null, obj, doc);
-}
-
-function createNode(obj, parent, doc) {
-    if (obj.type === "vnode") createElement(obj, doc);
-    else obj.domRef = doc.createTextNode(obj.text);
-    parent.appendChild(obj.domRef);
-    callCreated(obj);
-}
-
-/* Child reconciliation algorithm, inspired by kivi and Bobril */
-function syncChildren(os, ns, parent, doc) {
-    var oldFirstIndex = 0,
-	newFirstIndex = 0,
-	oldLastIndex = os.length - 1,
-	newLastIndex = ns.length - 1,
-	nFirst, nLast, tmp, found, node;
-    for (;;) {
-	/* check base case, first > last for both new and old
-	  [ ] -- old children empty (fully-swapped)
-	  [ ] -- new children empty (fully-swapped)
-	*/
-	if (newFirstIndex > newLastIndex && oldFirstIndex > oldLastIndex) {
-	    break;
-	}
-
-	/* Initialize */
-	nFirst = ns[newFirstIndex];
-	nLast = ns[newLastIndex];
-	oFirst = os[oldFirstIndex];
-	oLast = os[oldLastIndex];
-	/* No more old nodes, create and insert all remaining nodes
-	   -> [ ] <- old children
-	   -> [ a b c ] <- new children
-	*/
-	if (oldFirstIndex > oldLastIndex) {
-	    diff(null, nFirst, parent, doc);
-	    /* insertBefore's semantics will append a node if the second argument provided is `null` or `undefined`.
-	       Otherwise, it will insert node.domRef before oLast.domRef. */
-	    parent.insertBefore(nFirst.domRef, oLast.domRef);
-	    os.splice(newFirstIndex, 0, nFirst);
-	    newFirstIndex++;
-	}
-	/* No more new nodes, delete all remaining nodes in old list
-	   -> [ a b c ] <- old children
-	   -> [ ] <- new children
-	*/
-	else if (newFirstIndex > newLastIndex) {
-	    tmp = oldLastIndex - oldFirstIndex;
-	    while (tmp >= 0) {
-		parent.removeChild(os[oldFirstIndex].domRef);
-		os.splice(oldFirstIndex, 1);
-		tmp--;
-	    }
-	    break;
-	}
-	/* happy path, everything aligns, we continue
-	   -> oldFirstIndex -> [ a b c ] <- oldLastIndex
-	   -> newFirstIndex -> [ a b c ] <- newLastIndex
-	   check if nFirst and oFirst align, if so, check nLast and oLast
-	*/
-	else if (oFirst.key === nFirst.key) {
-	    diff(os[oldFirstIndex++], ns[newFirstIndex++], parent, doc);
-	} else if (oLast.key === nLast.key) {
-	    diff(os[oldLastIndex--], ns[newLastIndex--], parent, doc);
-	}
-	/* flip-flop case, nodes have been swapped, in some way or another
-	   both could have been swapped.
-	   -> [ a b c ] <- old children
-	   -> [ c b a ] <- new children
-	*/
-	else if (oFirst.key === nLast.key && nFirst.key === oLast.key) {
-	    swapDomRefs(node, oFirst.domRef, oLast.domRef, parent);
-	    swap(os, oldFirstIndex, oldLastIndex);
-	    diff(os[oldFirstIndex++], ns[newFirstIndex++], parent, doc);
-	    diff(os[oldLastIndex--], ns[newLastIndex--], parent, doc);
-	}
-	/* Or just one could be swapped (d's align here)
-	       This is top left and bottom right match case.
-	       We move d to end of list, mutate old vdom to reflect the change
-	       We then continue without affecting indexes, hoping to land in a better case
-	       -> [ d a b ] <- old children
-	       -> [ a b d ] <- new children
-	       becomes
-	       -> [ a b d ] <- old children
-	       -> [ a b d ] <- new children
-	       and now we happy path
-	   */
-	else if (oFirst.key === nLast.key) {
-	    /* insertAfter */
-	    parent.insertBefore(oFirst.domRef, oLast.domRef.nextSibling);
-	    /* swap positions in old vdom */
-	    os.splice(oldLastIndex,0,os.splice(oldFirstIndex,1)[0]);
-	    diff(os[oldLastIndex--], ns[newLastIndex--], parent, doc);
-	}
-	/* This is top right and bottom lefts match case.
-	   We move d to end of list, mutate old vdom to reflect the change
-	   -> [ b a d ] <- old children
-	   -> [ d b a ] <- new children
-	   becomes
-	   -> [ d b a ] <- old children
-	   -> [ d b a ] <- new children
-	   and now we happy path
-	*/
-	else if (oLast.key === nFirst.key) {
-	    /* insertAfter */
-	    parent.insertBefore(oLast.domRef, oFirst.domRef);
-	    /* swap positions in old vdom */
-	    os.splice(oldFirstIndex,0, os.splice(oldLastIndex,1)[0]);
-	    diff(os[oldFirstIndex++], nFirst, parent, doc);
-	    newFirstIndex++;
-	}
-
-	/* The "you're screwed" case, nothing aligns, pull the ripcord, do something more fancy
-	   This can happen when the list is sorted, for example.
-	   -> [ a e c ] <- old children
-	   -> [ b e d ] <- new children
-	*/
-	else {
-	    /* final case, perform linear search to check if new key exists in old map, decide what to do from there */
-	    found = false;
-	    tmp = oldFirstIndex;
-	    while (tmp <= oldLastIndex) {
-		if (os[tmp].key === nFirst.key) {
-		    found = true;
-		    node = os[tmp];
-		    break;
-		}
-		tmp++;
-	    }
-   	        /* If new key was found in old map this means it was moved, hypothetically as below
-		   -> [ a e b c ] <- old children
-		   -> [ b e a j ] <- new children
-			^
-		   In the above case 'b' has been moved, so we need to insert 'b' before 'a' in both vDOM and DOM
-		   We also increase oldFirstIndex and newFirstIndex.
-
-		   This results in new list below w/ updated index position
-		   -> [ b a e c ] <- old children
-		   -> [ b e a j ] <- new children
-			  ^
-		*/
-	    if (found) {
-		/* Move item to correct position */
-		os.splice(oldFirstIndex,0, os.splice(tmp,1)[0]);
-  		/* Swap DOM references */
-		parent.insertBefore(node.domRef, os[oldFirstIndex].domRef);
-		/* optionally perform `diff` here */
-		diff(os[oldFirstIndex++], nFirst, parent, doc);
-		/* increment counters */
-		newFirstIndex++;
-	    }
-	    /* If new key was *not* found in the old map this means it must now be created, example below
-		   -> [ a e d c ] <- old children
-		   -> [ b e a j ] <- new children
-			^
-
-		   In the above case 'b' does not exist in the old map, so we create a new element and DOM reference.
-		   We then insertBefore in both vDOM and DOM.
-
-		   -> [ b a e d c ] <- old children
-		   -> [ b e a j   ] <- new children
-			  ^
-	       */
-	    else {
-		createElement(nFirst, doc);
-		parent.insertBefore(nFirst.domRef, oFirst.domRef);
-		os.splice(oldFirstIndex++, 0, nFirst);
-		newFirstIndex++;
-		oldLastIndex++;
-	    }
-	}
-    }
-}
-
-function swapDomRefs(tmp,a,b,p) {
-  tmp = a.nextSibling;
-  p.insertBefore(a,b);
-  p.insertBefore(b,tmp);
-}
-
-function swap(os,l,r) {
-  var k = os[l];
-  os[l] = os[r];
-  os[r] = k;
-}
diff --git a/jsbits/isomorphic.js b/jsbits/isomorphic.js
deleted file mode 100644
--- a/jsbits/isomorphic.js
+++ /dev/null
@@ -1,24 +0,0 @@
-function copyDOMIntoVTree (vtree) {
-    walk (vtree, document.body.firstChild);
-}
-
-function walk (vtree, node) {
-    var i = 0, vdomChild, domChild;
-    vtree.domRef = node;
-
-    // Fire onCreated events as though the elements had just been created.
-    callCreated(vtree);
-
-    while (i < vtree.children.length) {
-      vdomChild = vtree.children[i];
-      domChild = node.childNodes[i];
-      if (vdomChild.type === "vtext") {
-	  vdomChild.domRef = domChild;
-	  i++;
-	  continue;
-      }
-      walk(vdomChild, domChild);
-      i++;
-   }
-}
-
diff --git a/jsbits/util.js b/jsbits/util.js
deleted file mode 100644
--- a/jsbits/util.js
+++ /dev/null
@@ -1,13 +0,0 @@
-function callFocus(id) {
-  setTimeout(function(){
-    var ele = document.getElementById(id);
-    if (ele && ele.focus) ele.focus()
-  }, 50);
-}
-
-function callBlur(id) {
-  setTimeout(function(){
-    var ele = document.getElementById(id);
-    if (ele && ele.blur) ele.blur()
-  }, 50);
-}
diff --git a/miso.cabal b/miso.cabal
--- a/miso.cabal
+++ b/miso.cabal
@@ -1,330 +1,344 @@
+cabal-version:       2.2
 name:                miso
-version:             0.16.0.0
+version:             1.13.0.0
 category:            Web, Miso, Data Structures
-license:             BSD3
+license:             BSD-3-Clause
 license-file:        LICENSE
-author:              David M. Johnson <djohnson.m@gmail.com>
-maintainer:          David M. Johnson <djohnson.m@gmail.com>
-homepage:            http://github.com/dmjio/miso
-copyright:           Copyright (c) 2017-2018 David M. Johnson
+author:              David M. Johnson <code@dmj.io>
+maintainer:          David M. Johnson <code@dmj.io>
+homepage:            https://haskell-miso.org/
+copyright:           Copyright (c) 2016-2026 David M. Johnson
+bug-reports:         https://github.com/haskell-miso/miso/issues
 build-type:          Simple
 extra-source-files:  README.md
-cabal-version:       >=1.22
-synopsis:            A tasty Haskell front-end framework
+synopsis:            A tasty Haskell front-end web framework
 description:
-            Miso is a small "isomorphic" Haskell front-end framework featuring a virtual-dom, diffing / patching algorithm, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe servant-style routing and an extensible Subscription-based subsystem. Inspired by Elm, Redux and Bobril. Miso is pure by default, but side effects (like XHR) can be introduced into the system via the Effect data type. Miso makes heavy use of the GHCJS FFI and therefore has minimal dependencies.
+            Miso is a small, production-ready, component-oriented, isomorphic Haskell front-end web and mobile framework featuring a virtual-dom, recursive diffing / patching algorithm, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe servant-style routing and an extensible Subscription-based subsystem. Inspired by Elm and React. Miso is pure by default, but side effects can be introduced into the system via the Effect data type. Miso makes heavy use of the GHC FFI and therefore has minimal dependencies.
 
 extra-source-files:
   README.md
-  examples/todo-mvc/index.html
-  examples/websocket/index.html
-  examples/mario/index.html
-  examples/mario/imgs/mario.png
 
-flag examples
-  default:
-    False
-  description:
-    Builds Miso's examples
+extra-doc-files:
+  CHANGELOG.md
 
-flag tests
-  default:
-    False
-  description:
-    Builds Miso's tests
+source-repository head
+   type: git
+   location: https://github.com/haskell-miso/miso.git
 
-executable todo-mvc
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
+common cpp
+  if impl(ghcjs) || arch(javascript)
+    cpp-options:
+      -DGHCJS_BOTH
+  if flag(native)
+    cpp-options:
+      -DNATIVE
+  if impl(ghcjs)
+    cpp-options:
+      -DGHCJS_OLD
+  elif arch(javascript)
+    cpp-options:
+      -DGHCJS_NEW
+  elif arch(wasm32)
+    cpp-options:
+      -DWASM
   else
-    hs-source-dirs:
-      examples/todo-mvc
-    build-depends:
-      aeson,
-      base < 5,
-      containers,
-      miso
-    default-language:
-      Haskell2010
+    cpp-options:
+      -DVANILLA
 
-executable threejs
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      examples/three
-    build-depends:
-      aeson,
-      base < 5,
-      ghcjs-base,
-      containers,
-      miso
-    default-language:
-      Haskell2010
+  if flag(production)
+    cpp-options:
+      -DPRODUCTION
 
-executable file-reader
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      examples/file-reader
-    build-depends:
-      aeson,
-      base < 5,
-      containers,
-      ghcjs-base,
-      miso
-    default-language:
-      Haskell2010
+  if flag(ssr)
+    cpp-options:
+      -DSSR
 
-executable xhr
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      examples/xhr
-    build-depends:
-      aeson,
-      base < 5,
-      containers,
-      ghcjs-base,
-      miso
-    default-language:
-      Haskell2010
+  if flag(benchmark)
+    cpp-options:
+      -DBENCH
 
-executable canvas2d
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      examples/canvas2d
-    build-depends:
-      aeson,
-      base < 5,
-      ghcjs-base,
-      miso
-    default-language:
-      Haskell2010
+  if flag(aeson)
+    cpp-options:
+      -DAESON
 
-executable router
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      examples/router
-    build-depends:
-      aeson,
-      base < 5,
-      containers,
-      miso,
-      servant
-    default-language:
-      Haskell2010
+  if flag(text)
+    cpp-options:
+      -DMISO_TEXT
 
-executable websocket
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      examples/websocket
-    build-depends:
-      aeson,
-      base < 5,
-      containers,
-      miso
-    default-language:
-      Haskell2010
+common client
+  if impl(ghcjs) || arch(javascript) || arch(wasm32)
+    if flag(native) && flag(production)
+      js-sources:
+        js/miso-native.prod.js
+    elif flag(production)
+      js-sources:
+        js/miso.prod.js
+    elif flag(native)
+      js-sources:
+        js/miso-native.js
+    else
+      js-sources:
+        js/miso.js
 
-executable mario
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      examples/mario
-    build-depends:
-      base < 5,
-      containers,
-      miso
-    default-language:
-      Haskell2010
+flag native
+  manual:
+    True
+  default:
+    False
+  description:
+    When enabled this provides the dual-thread arch. LynxJS.org requires.
 
-executable svg
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      examples/svg
-    other-modules:
-      Touch
-    build-depends:
-      base < 5,
-      containers,
-      aeson,
-      miso
-    default-language:
-      Haskell2010
+flag benchmark
+  manual:
+    True
+  default:
+    False
+  description:
+    When enabled this outputs (in milliseconds) the time it
+    takes to build the virtual DOM on page load.
 
-executable compose-update
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      examples/compose-update
-    build-depends:
-      base < 5,
-      miso
-    default-language:
-      Haskell2010
+flag production
+  manual:
+    True
+  default:
+    False
+  description:
+    Uses miso's production quality JS (miso.prod.js).
+    This is built from calling "bun build --production"
 
-executable simple
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(examples)
-    buildable: False
-  else
-    hs-source-dirs:
-      exe
-    build-depends:
-      aeson,
-      base < 5,
-      containers,
-      miso
-    default-language:
-      Haskell2010
+flag ssr
+  manual:
+    True
+  default:
+    False
+  description:
+    Used to indicate if SSR (server-side rendering) is being used. Defaults to false.
+    Enable when performing hydration / server rendering of Html using ToHtml.
 
-executable tests
-  main-is:
-    Main.hs
-  if !impl(ghcjs) || !flag(tests)
-    buildable: False
-  else
-    hs-source-dirs:
-      tests, ghcjs-src, src
-    other-modules:
-      Miso.FFI
-    build-depends:
-      aeson,
-      base < 5,
-      bytestring,
-      hspec,
-      hspec-core,
-      ghcjs-base,
-      QuickCheck,
-      quickcheck-instances,
-      miso,
-      http-types,
-      network-uri,
-      http-api-data,
-      containers,
-      scientific,
-      servant,
-      text,
-      unordered-containers,
-      transformers,
-      vector
-    default-language:
-      Haskell2010
+flag template-haskell
+  manual:
+    True
+  default:
+    False
+  description:
+    Checks if template-haskell is enabled. If so, allows Miso.Lens.TH
 
+flag aeson
+  manual:
+    True
+  default:
+    False
+  description:
+    When enabled, the functions exposed by Miso.JSON are defined in terms
+    of aeson (Data.Aeson), and its types (Value, Object, Parser) become
+    aeson's. Miso's own Generic deriving machinery is not exported in this
+    mode; aeson provides its own.
+
+flag text
+  manual:
+    True
+  default:
+    False
+  description:
+    When enabled, this force MisoString to be Text.
+
 library
+  import:
+    client,
+    cpp
   default-language:
     Haskell2010
+  other-modules:
+    Miso.Delegate
+    Miso.Diff
+    Miso.DSL.FFI
+    Miso.Hydrate
+    Miso.FFI.Internal
+    Miso.Runtime
   exposed-modules:
     Miso
-    Miso.Util
+    Miso.Canvas
+    Miso.Cookie
+    Miso.Concurrent
+    Miso.Date
+    Miso.Data.Map
+    Miso.Data.Set
+    Miso.Data.Array
+    Miso.DSL
+    Miso.Effect
+    Miso.Event
+    Miso.Event.Decoder
+    Miso.Event.Types
+    Miso.EventSource
+    Miso.Fetch
+    Miso.FFI
     Miso.Html
     Miso.Html.Element
     Miso.Html.Event
     Miso.Html.Property
-    Miso.Event
-    Miso.Event.Decoder
-    Miso.Event.Types
+    Miso.Html.Render
+    Miso.JSON
+    Miso.JSON.Lexer
+    Miso.JSON.Parser
+    Miso.JSON.Types
+    Miso.Lens
+    Miso.Lens.Generic
+    Miso.Mathml
+    Miso.Mathml.Element
+    Miso.Mathml.Property
+    Miso.Media
+    Miso.Navigator
+    Miso.Prelude
+    Miso.Property
+    Miso.PubSub
+    Miso.Random
     Miso.Router
+    Miso.Reload
+    Miso.Runtime.Internal
+    Miso.State
+    Miso.Subscription
+    Miso.Subscription.Canvas
+    Miso.Subscription.Cookie
+    Miso.Subscription.History
+    Miso.Subscription.Keyboard
+    Miso.Subscription.Mouse
+    Miso.Subscription.OnLine
+    Miso.Subscription.RAF
+    Miso.Subscription.Util
+    Miso.Subscription.Window
     Miso.Svg
-    Miso.Svg.Attribute
+    Miso.Svg.Property
     Miso.Svg.Element
     Miso.Svg.Event
+    Miso.Storage
     Miso.String
-  other-modules:
-    Miso.Concurrent
-    Miso.Html.Internal
-  ghc-options:
-    -Wall
-  hs-source-dirs:
-    src
-  build-depends:
-    aeson,
-    base < 5,
-    bytestring,
-    containers,
-    http-api-data,
-    http-types,
-    network-uri,
-    servant,
-    text,
-    transformers
-  if impl(ghcjs)
+    Miso.CSS
+    Miso.CSS.Color
+    Miso.CSS.Types
+    Miso.Trace
+    Miso.Types
+    Miso.Util
+    Miso.Util.Lexer
+    Miso.Util.Parser
+    Miso.WebSocket
+
+  if flag(native)
+    exposed-modules:
+      Miso.Native
+      Miso.Native.MainThread
+      Miso.Native.Element
+      Miso.Native.Element.Frame
+      Miso.Native.Element.Frame.Event
+      Miso.Native.Element.Frame.Property
+      Miso.Native.Element.Image
+      Miso.Native.Element.Image.Event
+      Miso.Native.Element.Image.Method
+      Miso.Native.Element.Image.Property
+      Miso.Native.Element.List
+      Miso.Native.Element.List.Event
+      Miso.Native.Element.List.Method
+      Miso.Native.Element.List.Property
+      Miso.Native.Element.ScrollView
+      Miso.Native.Element.ScrollView.Event
+      Miso.Native.Element.ScrollView.Method
+      Miso.Native.Element.ScrollView.Property
+      Miso.Native.Element.Text
+      Miso.Native.Element.Text.Event
+      Miso.Native.Element.Text.Method
+      Miso.Native.Element.Text.Property
+      Miso.Native.Element.View
+      Miso.Native.Element.View.Event
+      Miso.Native.Element.View.Method
+      Miso.Native.Element.View.Property
+      Miso.Native.Event
+      Miso.Native.FFI
+      Miso.Native.Module
+      Miso.Native.X.Element
+      Miso.Native.X.Element.BlurView
+      Miso.Native.X.Element.BlurView.Property
+      Miso.Native.X.Element.Input
+      Miso.Native.X.Element.Input.Event
+      Miso.Native.X.Element.Input.Method
+      Miso.Native.X.Element.Input.Property
+      Miso.Native.X.Element.Overlay
+      Miso.Native.X.Element.Overlay.Event
+      Miso.Native.X.Element.Overlay.Property
+      Miso.Native.X.Element.Refresh
+      Miso.Native.X.Element.Refresh.Event
+      Miso.Native.X.Element.Refresh.Method
+      Miso.Native.X.Element.Refresh.Property
+      Miso.Native.X.Element.ScrollCoordinator
+      Miso.Native.X.Element.ScrollCoordinator.Event
+      Miso.Native.X.Element.ScrollCoordinator.Method
+      Miso.Native.X.Element.ScrollCoordinator.Property
+      Miso.Native.X.Element.Svg
+      Miso.Native.X.Element.Svg.Event
+      Miso.Native.X.Element.Svg.Property
+      Miso.Native.X.Element.Textarea
+      Miso.Native.X.Element.Textarea.Event
+      Miso.Native.X.Element.Textarea.Method
+      Miso.Native.X.Element.Textarea.Property
+      Miso.Native.X.Element.TitleBarView
+      Miso.Native.X.Element.TitleBarView.Property
+      Miso.Native.X.Element.Viewpager
+      Miso.Native.X.Element.Viewpager.Event
+      Miso.Native.X.Element.Viewpager.Method
+      Miso.Native.X.Element.Viewpager.Property
+      Miso.Native.X.Element.Webview
+      Miso.Native.X.Element.Webview.Event
+      Miso.Native.X.Element.Webview.Method
+      Miso.Native.X.Element.Webview.Property
+
+  -- Live reload (meant for WASM or Vanilla)
+  c-sources:
+    cbits/foreign.c
+
+  -- FFI declarations
+  if arch(javascript) || impl(ghcjs)
     hs-source-dirs:
-      ghcjs-src
+      ffi/js
     build-depends:
-      ghcjs-base,
-      containers,
-      scientific,
-      unordered-containers,
-      transformers,
-      vector
-    js-sources:
-      jsbits/diff.js
-      jsbits/delegate.js
-      jsbits/isomorphic.js
-      jsbits/util.js
+      ghcjs-base -any
+
+    if impl(ghcjs)
+      build-depends:
+        ghcjs-prim
+
+  elif arch(wasm32)
+    hs-source-dirs:
+      ffi/wasm
+    build-depends:
+      ghc-experimental,
+      template-haskell >= 2.21 && < 2.25
     exposed-modules:
-      Miso.Dev
-      Miso.Effect
-      Miso.Effect.Storage
-      Miso.Effect.XHR
-      Miso.Effect.DOM
-      Miso.Subscription
-      Miso.Subscription.History
-      Miso.Subscription.Keyboard
-      Miso.Subscription.Mouse
-      Miso.Subscription.WebSocket
-      Miso.Subscription.Window
-      Miso.Subscription.SSE
-      Miso.Types
+      Miso.DSL.TH
+      Miso.DSL.TH.File
     other-modules:
-      Miso.Diff
-      Miso.FFI
-      Miso.Delegate
+      Data.JSString
   else
+    hs-source-dirs:
+      ffi/ghc
+
+  if flag(template-haskell)
     exposed-modules:
-      Miso.TypeLevel
+      Miso.Lens.TH
+      Miso.FFI.QQ
     build-depends:
-      lucid,
-      servant-lucid,
-      vector
-    hs-source-dirs:
-      ghc-src
+      template-haskell >= 2.21 && < 2.25
 
-source-repository head
-   type: git
-   location: https://github.com/dmjio/miso.git
+  if flag(aeson)
+    build-depends:
+      aeson      >= 2.0 && < 3,
+      scientific < 0.4
+
+  ghc-options:
+    -Wall
+  hs-source-dirs:
+    src
+  build-depends:
+    base          < 5,
+    bytestring    < 0.13,
+    containers    < 0.9,
+    transformers  < 0.7,
+    mtl           < 2.4,
+    text          < 2.2
diff --git a/src/Miso.hs b/src/Miso.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso.hs
@@ -0,0 +1,2069 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP            #-}
+{-# LANGUAGE LambdaCase     #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -Wno-duplicate-exports #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso
+-- Copyright   :  (C) 2016-2026 David M. Johnson (@dmjio)
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = miso 🍜
+--
+-- @miso@ is a library for building web and native user interface applications. See the [GitHub group](https://github.com/haskell-miso).
+--
+-- It provides a [React](https://react.dev)-like programming experience for a simple [Haskell](https://haskell.org) dialect that emphasizes
+--
+-- * performance
+-- * purity
+-- * simplicity
+-- * extensibility
+-- * composability
+--
+-- miso addresses common areas of web development:
+--
+-- * __DOM manipulation__: @miso@ uses a [Virtual DOM](https://en.wikipedia.org/wiki/Virtual_DOM) with a diffing algorithm that is
+--   responsible for all DOM modification and t'Miso.Types.Component' lifecycle hooks.
+--
+-- * __Event delegation__: All event listeners are attached to a top-level element
+--   (typically @\<body\>@). When raised, events are routed through the virtual DOM
+--   to Haskell event handlers which cause application state changes. Internally @miso@
+--   virtualizes both the @capture@ and @bubble@ phases of the browser when it performs event routing.
+--
+-- * __Prerendering__: Prerendering is a process where the server delivers HTML
+--   to the client before the JavaScript (or WebAssembly) application bootstraps.
+--   Instead of performing an initial draw, the application will create and populate the virtual DOM from the actual DOM.
+--   This is a process known as \"hydration\". This avoids unnecessary page draws on initial page
+--   load and enhances search engine optimization. @miso@ provides its own HTML rendering
+--   ("Miso.Html.Render") to render HTML on the server and the 'miso' function exists on the client to \"hydrate\"
+--   the virtual DOM from the DOM.
+--
+-- * __Components__: A t'Miso.Types.Component' is a self-contained @miso@ application. Each
+--   bundles its own state, the logic for updating that state, and a function that
+--   renders the state to a UI template. Components can nest other components,
+--   forming UI trees of arbitrary depth.
+--
+-- * __Custom renderers__: The underlying DOM operations are able to be abstracted.
+-- This allows a custom rendering engine to be used. This is seen in the [miso-lynx](https://github.com/haskell-miso/miso-lynx) project
+-- (which allows miso to target mobile phone devices).
+--
+-- * __Lifecycle hooks__: t'Miso.Types.Component' expose 'Miso.Types.mount' and 'Miso.Types.unmount' lifecycle hooks. This allows users to define custom logic that will
+-- execute when a t'Miso.Types.Component' mounts or unmounts. 'Miso.Event.onCreated' and 'Miso.Event.onDestroyed' are 'VNode' specific lifecycle hooks.
+-- These hooks are commonly used for t'Miso.Types.Component' communication and for third-party integration with JavaScript libraries.
+--
+-- * __State management__: t'Miso.Types.Component' @model@ state can be manipulated using "Miso.Lens" or "Miso.State" in response to application events.
+--
+-- * __HTTP \/ Cookies__: "Miso.Fetch" wraps the browser's
+--   [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and "Miso.Cookie" wraps the
+--   [CookieStore API](https://developer.mozilla.org/en-US/docs/Web/API/CookieStore). Both offer two calling
+--   conventions for every operation: an asynchronous callback-based 'Effect' (e.g. 'getJSON', 'Miso.Cookie.cookieGet')
+--   that dispatches an @action@ when the browser resolves the underlying promise, and a synchronous, @_@-suffixed
+--   'IO' variant (e.g. 'getJSON_', 'Miso.Cookie.cookieGet_') that blocks the calling thread and returns an 'Either'
+--   directly — best paired with 'io' \/ 'io_' so the blocking call doesn't stall the scheduler thread.
+--
+-- = Architecture
+--
+-- * __React__: miso implements a subset of the [React](https://react.dev) architecture internals including t'Miso.Types.Component', Lifecycle hooks, Virtual DOM, Event delegation. Along with
+-- [Fragment](https://react.dev/reference/react/Fragment), [Props](https://react.dev/learn/passing-props-to-a-component) and [Context](https://react.dev/learn/passing-data-deeply-with-context) API features.
+--
+-- * __Elm__: miso also implements the [Elm](https://elm-lang.org) architecture (MVU) and the 'mailbox' communication pattern.
+--
+-- = Native (mobile)
+--
+-- Beyond the browser, miso targets __native mobile devices__ by driving the
+-- [Lynx](https://lynxjs.org) runtime instead of the DOM. The same MVU model,
+-- t'Miso.Types.Component' API, event delegation and virtual-DOM diffing carry over
+-- unchanged — only the element vocabulary differs (@view_@, @text_@, @list_@, …
+-- from "Miso.Native.Element" in place of "Miso.Html.Element"). The "Miso.Native"
+-- module is the entry point (@native@ \/ @nativeWithContext@) and documents the
+-- Lynx dual-thread (BTS \/ MTS) architecture in full. The native backend is
+-- gated behind the @native@ cabal flag (@-fnative@); web \/ WASM builds are
+-- unaffected.
+--
+-- See "Miso.Native" for details.
+--
+-- = The Model-View-Update pattern
+--
+-- The core type of miso is t'Miso.Types.Component'. The t'Miso.Types.Component' API adheres to the [Elm](https://elm-lang.org)
+-- MVU (model-view-update) interface. This is similar to a left-fold over @action@s — the t'Miso.Types.Component'
+-- @model@ is updated by 'Miso.Types.update' and rendered by 'Miso.Types.view'.
+--
+-- * __'model'__: This can be any user-defined type. An 'Eq' constraint
+--   is required. We recommend using the default derived 'Eq' instance.
+--
+-- * __'view'__: This is the templating function that is used to construct a new virtual DOM
+--   (or HTML if rendering on the server).
+--
+-- * __'update'__: The @update@ function handles how the @model@ evolves over time in response
+--   to events that are raised by the application. This function takes any @action@,
+--   updating the @model@ and optionally introduces 'IO' into the system.
+--
+-- = Your first t'Miso.Types.Component'
+--
+-- To define a t'Miso.Types.Component', the 'Miso.Types.component' smart constructor can be used.
+-- Below is an example of a simple counter t'Miso.Types.Component'.
+--
+-- @
+-- -----------------------------------------------------------------------------
+-- module Main where
+-- -----------------------------------------------------------------------------
+-- import "Miso"
+-- import "Miso.Lens"
+-- import qualified "Miso.Html.Element" as H
+-- import qualified "Miso.Html.Event" as HE
+-- import qualified "Miso.Html.Property" as HP
+-- -----------------------------------------------------------------------------
+--                       * - The type of the global @context@
+--                       |  * - The type of the @props@ inherited from the parent t'Miso.Types.Component'
+--                       |  |  * - The type of the current t'Miso.Types.Component' @model@
+--                       |  |  |  * - The type of the action that updates the @model@
+--                       |  |  |  |
+-- counter :: t'Miso.Types.Component' () () 'Int' Action
+-- counter = 'Miso.Types.component' m u v
+--   where
+--     -- | Initial @model@ value
+--     m :: 'Int'
+--     m = 0
+--                           * - The type of the global @context@
+--                           |  * - The type of the @props@ inherited from the parent t'Miso.Types.Component'
+--                           |  |  * - The type of the current t'Miso.Types.Component' @model@
+--                           |  |  |   * - The type of the action that updates the @model@
+--                           |  |  |   |
+--     u :: Action -> 'Effect' () () 'Int' Action
+--     u = \\case
+--       Add -> 'Miso.Lens.this' 'Miso.Lens.+=' 1
+--       Subtract -> 'Miso.Lens.this' 'Miso.Lens.-=' 1
+--
+--          * - The type of the global @context@
+--          |     * - The type of the @props@ inherited from the parent t'Miso.Types.Component'
+--          |     |      * - The type of the current t'Miso.Types.Component' @model@
+--          |     |      |           * - The global @context@ threaded into the 'View' (@'View' context model action@)
+--          |     |      |           |  * - The type of the action that updates t'Miso.Types.Component' @model@
+--          |     |      |           |  |
+--     v :: () -> () -> 'Int' -> 'View' () 'Int' Action
+--     v _context _props x = 'Miso.Types.vfrag'
+--       [ H.'Miso.Html.Element.button_' [ HE.'Miso.Html.Event.onClick' Add, HP.'Miso.Html.Property.id_' "add" ] [ "+" ]
+--       , 'Miso.Types.text' ('ms' x)
+--       , H.'Miso.Html.Elemment.button_' [ HE.'Miso.Html.Event.onClick' Subtract, HP.'Miso.Html.Property.id_' "subtract" ] [ "-" ]
+--       ]
+-- -----------------------------------------------------------------------------
+-- main :: 'IO' ()
+-- main = 'startApp' 'Miso.Event.Types.defaultEvents' counter
+-- -----------------------------------------------------------------------------
+-- data Action
+--   = Add
+--   | Subtract
+--   deriving ('Eq', 'Show')
+-- -----------------------------------------------------------------------------
+-- @
+--
+-- = Running your first t'Miso.Types.Component'
+--
+-- The 'startApp' (or 'miso') functions are used to run the above t'Miso.Types.Component'.
+--
+-- @
+-- main :: 'IO' ()
+-- main = 'startApp' 'Miso.Event.Types.defaultEvents' counter
+-- @
+--
+-- We recommend 'startApp' as the starting point — it sets up event listeners, performs the initial page draw,
+-- and assumes @\<body\>@ is empty.
+--
+-- The 'miso' function (and 'prerender') assume that @\<body\>@ has already been populated by the results of the 'Miso.Lens.view' function.
+-- Instead of drawing, 'miso' will perform hydration.
+-- If the structures do not match, 'miso' will fall back to drawing the page from scratch (clearing the contents of @\<body\>@ first).
+--
+-- It is possible to execute an initial action when a t'Miso.Types.Component' is first mounted. See the 'mount' (and similarly 'unmount') hooks.
+--
+-- @
+--
+-- data Action = Init
+--
+-- main :: 'IO' ()
+-- main = 'startApp' 'Miso.Event.Types.defaultEvents' counter { 'mount' = Just Init }
+--
+-- update :: Action -> 'Effect' () () model Action
+-- update = \\case
+--   Init -> 'io_' ('Miso.FFI.consoleLog' "hello world!")
+-- @
+--
+-- Note also the signature of 'startApp'.
+--
+-- @
+-- 'startApp' :: 'Eq' model => 'Events' -> 'App' model action -> 'IO' ()
+-- @
+--
+-- The 'App' type synonym is defined as:
+--
+-- @
+-- type 'App' model action = t'Miso.Types.Component' () () model action
+-- @
+--
+-- A top-level application fixes the global @context@ and @props@ to @()@.
+-- 'startApp' and 'miso' will always infer @context@ as @()@; use
+-- 'startAppWithContext' to seed a non-trivial context.
+--
+-- = t'View' DSL
+--
+-- The 'View' type represents the virtual DOM — a [Rose tree](https://en.wikipedia.org/wiki/Rose_tree)
+-- of nodes mutually recursive with t'Miso.Types.Component' via the 'Miso.Lens.view' function.
+--
+-- @
+-- data 'View' context model action
+--   = 'VNode' 'Namespace' 'Tag' ['Attribute' model action] ['View' context model action] 'DirectEvents'
+--   | 'VText' (Maybe t'Key') 'MisoString'
+--   | 'VComp' ('SomeComponent' context)
+--   | forall props . 'VCompStatic' (StaticPtr ('SomeStaticComponent' props context)) props
+--   | 'VFrag' (Maybe t'Key') ['View' context model action]
+-- @
+--
+-- 'VNode' and 'VText' have a one-to-one mapping from the virtual DOM to the physical DOM. The 'VComp' and 'VFrag' constructors are abstract (live only on the virtual DOM) and do not contain a reference to the physical DOM. The existential t'SomeComponent' is what allows embedding polymorphic t'Miso.Types.Component' within a 'View'.
+--
+-- @
+-- data t'SomeComponent' context
+--   = forall model action props . ('Eq' context, 'Eq' model, 'Eq' props)
+--   => t'SomeComponent' (Maybe t'Key') props ('Miso.Types.Component' context props model action)
+-- @
+--
+-- The smart constructors:
+--
+-- * 'node', 'vnode' — build a 'VNode'
+-- * 'Miso.Types.text', 'vtext' — build a 'VText'
+-- * 'Miso.Types.component' — build a 'VComp'
+-- * @fragment@, 'Miso.Types.vfrag', 'fragment_', 'vfrag_' — build a 'VFrag'
+-- * ('+>') — key and mount a child t'Miso.Types.Component'
+-- * 'vcomp', 'vcomp_' — build a 'VCompStatic' (see below)
+--
+-- A full list of element smart constructors built on 'node' (e.g. 'Miso.Html.Element.Miso.Html.Element.div_') can be found in "Miso.Html.Element".
+--
+-- = The global @context@
+--
+-- @context@ is miso's analogue of [React Context](https://react.dev/learn/passing-data-deeply-with-context):
+-- a __single, global value__ that is shared by __every__ t'Miso.Types.Component' in the
+-- tree, without having to thread it manually through @props@ at each level.
+--
+-- Contrast the three pieces of state a t'Miso.Types.Component' sees, by scope:
+--
+-- * __'model'__ — private to a single t'Miso.Types.Component'.
+-- * __@props@__ — passed from a parent to its immediate child.
+-- * __@context@__ — global; the same value is visible to the whole tree.
+--
+-- This is why @context@ is a type parameter on both t'Miso.Types.Component' and 'View'
+-- (@'Miso.Types.Component' context props model action@, @'View' context model action@): the
+-- parameter is threaded through the entire view tree so that every nested
+-- t'Miso.Types.Component' — reachable via t'SomeComponent' — is statically guaranteed to
+-- agree on __one__ @context@ type. There is exactly one live @context@ value per
+-- running application.
+--
+-- __Seeding__ (set the initial value):
+--
+-- * 'startAppWithContext' — the client entry point, replaces 'startApp'.
+-- * 'misoWithContext' \/ 'prerenderWithContext' — the hydrating counterparts
+--   of 'miso' \/ 'prerender', for prerendered pages.
+-- * 'setContext' — seeds the value directly. Needed for __server-side
+--   rendering__, where a 'View' is serialized to HTML without ever starting
+--   the runtime.
+-- * 'Miso.Reload.liveWithContext' \/ 'Miso.Reload.reloadWithContext' — the
+--   context-aware variants of 'Miso.Reload.live' \/ 'Miso.Reload.reload' for
+--   interactive (GHCi) development.
+--
+-- __Reading__ (in 'Miso.Types.view'):
+--
+-- The current @context@ is delivered as the __first argument__ to every
+-- t'Component'\'s 'Miso.Types.view' function, so any component — however deeply
+-- nested — can read it synchronously during render:
+--
+-- @
+-- view :: context -> props -> model -> 'View' context model action
+-- view ctx _props _model = ...
+-- @
+--
+-- __Reading__ (in 'Miso.Types.update'):
+--
+-- The current @context@ is also readable inside the 'Effect' monad, just like
+-- @props@: use 'Miso.Effect.getContext' (or 'Miso.Lens.view' with the
+-- 'Miso.Effect.context' lens):
+--
+-- @
+-- update Toggle = do
+--   ctx <- 'Miso.Effect.getContext'
+--   …
+-- @
+--
+-- __Updating__ (from 'Miso.Types.update'):
+--
+-- Mutate the @context@ with 'Miso.Effect.modifyContext' (or
+-- 'Miso.Effect.putContext' to replace it):
+--
+-- @
+-- update Toggle = 'Miso.Effect.modifyContext' (\\theme -> if theme == Light then Dark else Light)
+-- @
+--
+-- __Re-rendering on change__:
+--
+-- When the @context@ value changes (per its 'Eq' instance), every t'Miso.Types.Component'
+-- with @'Miso.Types.useContext' = True@ is re-rendered against the new value.
+-- @useContext@ defaults to @False@, so components opt in to context-driven
+-- re-renders:
+--
+-- @
+-- child = ('Miso.Types.component' m u v) { 'Miso.Types.useContext' = True }
+-- @
+--
+-- __Note:__ @useContext@ controls whether a component __reacts__ to context
+-- changes, not whether it may __change__ the context. A component (typically the
+-- top-level one) can call 'Miso.Effect.modifyContext' \/ 'Miso.Effect.putContext'
+-- with @useContext = False@; it simply won't re-render in response to context
+-- changes it (or others) make. Set @useContext = True@ on precisely those
+-- (usually nested) components whose 'Miso.Types.view' depends on the @context@
+-- and must refresh when it changes.
+--
+-- = 'VComp' (Component nodes)
+--
+-- == Composition
+--
+-- @miso@ t'Miso.Types.Component' can contain other t'Miso.Types.Component'. This is
+-- accomplished through the t'Miso.Types.Component' mounting combinator ('+>'). This combinator
+-- is responsible for encoding a typed t'Miso.Types.Component' hierarchy. All t'Miso.Types.Component' in a
+-- tree share the same global @context@ type.
+--
+-- @
+-- ('+>')
+--   :: ('Eq' context, 'Eq' model)
+--   => 'MisoString'
+--   -> t'Miso.Types.Component' context () model action
+--   -> 'View' context model action
+-- key '+>' comp = 'VComp' ('SomeComponent' (Just ('toKey' key)) () comp)
+-- @
+--
+-- Practically, using this combinator looks like:
+--
+-- @
+-- viewModel :: context -> props -> Int -> 'View' context model action
+-- viewModel _ _ _ = 'Miso.Html.Element.div_' [ 'Miso.Html.Property.id_' "container" ] [ "counter" '+>' counter ]
+-- @
+--
+-- The @\"counter\"@ string is a unique t'Key' that identifies the t'Miso.Types.Component' at runtime. These keys are very important when
+-- diffing two t'Miso.Types.Component' together. When intentionally replacing t'Miso.Types.Component' it is important
+-- to specify a new t'Key', otherwise the t'Miso.Types.Component' will not be unmounted.
+--
+-- It is possible to mount a component using the 'mount_' function, which avoids specifying a @key_@, but this should only be used
+-- when the user is certain they will not be diffing their t'Miso.Types.Component' with another t'Miso.Types.Component'. When in doubt, use the ('+>') combinator
+-- and @key_@ your t'Miso.Types.Component'.
+--
+-- == Lifecycle hooks
+--
+-- t'Component's are mounted during diffing. All t'Miso.Types.Component' are equipped with 'Miso.Types.mount' and 'Miso.Types.unmount' hooks, allowing custom actions to be dispatched in response to lifecycle events.
+--
+-- * 'Miso.Types.mount'
+-- * 'Miso.Types.unmount'
+--
+-- = 'VCompStatic' (Static component nodes)
+--
+-- 'VCompStatic' is for building native mobile apps with [LynxJS](https://lynxjs.org),
+-- via miso's dual-thread (main-thread \/ background-thread) runtime. Unlike
+-- 'VComp', it carries a @StaticPtr@ to its t'Miso.Types.Component' constructor,
+-- giving the mount a stable, cross-thread-resolvable identity (a
+-- 'GHC.StaticPtr.StaticKey') instead of relying on a manually-supplied t'Key'.
+-- This is what lets the main thread (MTS) independently reconstruct a mirror
+-- of a t'Miso.Types.Component' mounted on the background thread (BTS), including
+-- ones mounted after the initial frame, and is also how @action@s dispatched
+-- from a main-thread (@OnStatic@) handler get routed back to the correct
+-- t'Miso.Types.Component' on the background thread.
+--
+-- The 'GHC.StaticPtr.StaticKey' itself serves as the mount's identity, so
+-- there's no need for ('+>') or a manually-supplied t'Key' — use 'vcomp' \/
+-- 'vcomp_' together with 'Miso.Types.mountStatic' (or
+-- 'Miso.Types.mountStaticWithProps') to
+-- build a 'VCompStatic'.
+--
+-- See "Miso.Native" for the entry points ('Miso.Native.native',
+-- 'Miso.Native.nativeWithContext') and full documentation of the dual-thread
+-- architecture.
+--
+-- = 'VNode' (Element nodes)
+--
+-- A 'VNode' represents a [DOM element node](https://developer.mozilla.org/en-US/docs/Web/API/Element) — the most common kind of virtual DOM node.
+-- It carries a 'Namespace', a tag name, a list of 'Attribute' values, and a list of child 'View' nodes:
+--
+-- @
+-- 'VNode' 'HTML' "div" [ 'Miso.Html.Property.id_' "container" ] [ "Hello, world!" ]
+-- @
+--
+-- In practice you will rarely construct 'VNode' directly. Instead use the element smart constructors
+-- from "Miso.Html.Element", which fix the namespace and tag for you:
+--
+-- @
+-- 'Miso.Html.Element.div_'    [ 'Miso.Html.Property.id_' "container" ] [ "Hello, world!" ]
+-- 'Miso.Html.Element.button_' [ 'Miso.Html.Event.onClick' DoSomething ] [ "Click me" ]
+-- 'Miso.Html.Element.h1_'     [ 'Miso.Html.Property.className' "title" ] [ 'Miso.Types.text' ('Miso.String.ms' pageTitle) ]
+-- @
+--
+-- For elements not covered by "Miso.Html.Element", use 'node' (or its synonym 'vnode') directly:
+--
+-- @
+-- 'node' 'HTML' "details" [] [ 'node' 'HTML' "summary" [] [ "More info" ] ]
+-- @
+--
+-- SVG and MathML elements use the 'SVG' and 'MATHML' namespaces respectively,
+-- and are covered by the smart constructors in "Miso.Svg.Element" and "Miso.Mathml.Element".
+--
+-- Unlike 'VComp' and 'VFrag', 'VNode' has a one-to-one correspondence with a physical DOM element:
+-- each 'VNode' in the virtual DOM maps to exactly one element in the browser.
+--
+-- The smart constructors for 'VNode' are:
+--
+-- * 'node'  — raw constructor, takes 'Namespace', tag, attributes, children
+-- * 'vnode' — synonym for 'node'
+-- * All combinators in "Miso.Html.Element", "Miso.Svg.Element", "Miso.Mathml.Element"
+--
+-- == Lifecycle hooks
+--
+-- Like t'Miso.Types.Component', 'VNode' elements expose lifecycle hooks.
+--
+-- * 'Miso.Event.onBeforeCreated'
+-- * 'Miso.Event.onCreated' / 'Miso.Event.onCreatedWith'
+-- * 'Miso.Event.onBeforeDestroyed' / 'Miso.Event.onBeforeDestroyedWith'
+-- * 'Miso.Event.onDestroyed'
+--
+-- These are useful for initializing and tearing down third-party libraries, as in the example below using [highlight.js](https://highlightjs.org/)
+--
+-- @
+-- {-# LANGUAGE QuasiQuotes -#}
+-- {-# LANGUAGE MultilineStrings -#}
+--
+-- import "Miso"
+-- import "Miso.FFI.QQ" ('Miso.FFI.QQ.js')
+--
+-- data Action = Highlight t'Miso.Effect.DOMRef'
+--
+-- update :: Action -> 'Effect' context props model Action
+-- update = \\case
+--   Highlight domRef -> 'io_' $ do
+--     ['Miso.FFI.QQ.js'| hljs.highlight(${domRef}) |]
+--
+-- view :: context -> props -> model -> 'View' context model Action
+-- view _ _ x =
+--   'Miso.Html.Element.code_'
+--   [ 'onCreatedWith' Highlight
+--   ]
+--   [ """
+--     function addOne (x) { return x + 1; }
+--     """
+--   ]
+-- @
+--
+-- As a convention, the @*with@ variant of 'VNode' lifecycle hooks (e.g. 'Miso.Event.onCreatedWith') provides the target @DOMRef@ in the callback.
+--
+-- = 'VText' (Text nodes)
+--
+-- A 'VText' node represents a [DOM text node](https://developer.mozilla.org/en-US/docs/Web/API/Text).
+-- Unlike 'VComp' and 'VFrag', 'VText' has a one-to-one correspondence with a physical DOM node:
+-- each 'VText' in the virtual DOM maps to exactly one @Text@ node in the browser.
+--
+-- The simplest way to produce a 'VText' is via the @IsString@ instance on @'View' action@.
+-- String literals inside a child list are automatically promoted to 'VText' nodes without
+-- any extra imports:
+--
+-- @
+-- 'Miso.Html.Element.Miso.Html.Element.div_' [] [ "Hello, world!" ]
+-- @
+--
+-- For dynamic content, use the 'Miso.Types.text' smart constructor with a 'MisoString':
+--
+-- @
+-- 'Miso.Html.Element.div_' [] [ 'Miso.Types.text' ('ms' userName) ]
+-- @
+--
+-- == HTML Encoding
+--
+-- When compiling with the @ssr@ flag (server-side rendering), 'Miso.Types.text' automatically
+-- HTML-encodes its argument — @\<@, @\>@, @&@, @\"@, and @\'@ are replaced with their
+-- respective HTML entities. This prevents accidental XSS when rendering user-supplied
+-- strings on the server.
+--
+-- @
+-- -- SSR output: &lt;b&gt;bold&lt;\/b&gt;
+-- 'Miso.Types.text' "\<b\>bold\<\/b\>"
+-- @
+--
+-- To embed pre-rendered or trusted content without escaping, use 'textRaw'. It is a
+-- no-op on the client and bypasses encoding on the server:
+--
+-- @
+-- 'textRaw' "\<b\>bold\<\/b\>"   -- server and client: \<b\>bold\<\/b\>
+-- @
+--
+-- == Concatenating Multiple Strings
+--
+-- 'text_' accepts a list of 'MisoString' values and joins them with a single space,
+-- which is useful when building text from multiple pieces without manual concatenation:
+--
+-- @
+-- -- Renders: Hello world
+-- 'Miso.Html.Element.div_' [] [ 'text_' [ \"Hello\", \"world\" ] ]
+-- @
+--
+-- == Keyed Text Nodes
+--
+-- A 'VText' may optionally carry a t'Key'. Keyed text nodes participate in the same
+-- reconciliation algorithm as keyed 'VNode' and 'VFrag' nodes. Providing a stable key
+-- lets the differ identify the node across renders, preventing unnecessary DOM text node
+-- replacement when sibling order changes.
+--
+-- @
+-- 'Miso.Html.Element.ul_' [] (renderItem '<$>' items)
+--
+-- data Item = Item { itemId, itemLabel :: 'MisoString' }
+--
+-- renderItem :: Item -> 'View' context Action
+-- renderItem item = 'Miso.Html.Element.li_' [] [ 'textKey' (itemId item) (itemLabel item) ]
+-- @
+--
+-- The smart constructors for 'VText' are:
+--
+-- * 'Miso.Types.text'     — single string, HTML-encoded on the server
+-- * 'vtext'    — synonym for 'Miso.Types.text'
+-- * 'textRaw'  — single string, never HTML-encoded
+-- * 'text_'    — list of strings joined with a space
+-- * 'textKey'  — single keyed string
+-- * 'textKey_' — list of keyed strings joined with a space
+--
+-- = 'VFrag' (Fragment nodes)
+--
+-- 'VFrag' groups sibling nodes without a wrapper element in the DOM, analogous to the [React Fragment](https://react.dev/reference/react/Fragment) API (@\<\>\<\/\>@) and the browser's @DocumentFragment@.
+--
+-- @
+-- -- Renders two \<li\> elements as direct siblings, no enclosing element
+-- @fragment@ [ 'Miso.Html.Element.li_' [] [ 'Miso.Types.text' "Item A" ], 'Miso.Html.Element.li_' [] [ 'Miso.Types.text' "Item B" ] ]
+-- @
+--
+-- A 'VFrag' may optionally carry a t'Key'. Keyed fragments participate in the same
+-- reconciliation algorithm as keyed 'VNode' and 'VText' nodes, allowing the virtual
+-- DOM differ to identify, reorder, and reuse groups of siblings efficiently.
+--
+-- @
+-- -- Keyed fragment — survives reordering without full teardown\/remount
+-- 'vfrag_' "my-key" [ 'Miso.Html.Element.li_' [] [ 'Miso.Types.text' "Item A" ], 'Miso.Html.Element.li_' [] [ 'Miso.Types.text' "Item B" ] ]
+-- @
+--
+-- Fragments may be nested — a 'VFrag' child may itself be a 'VFrag'. The diff function
+-- recurses into nested fragments and processes all fragments as if they were
+-- a flat sequence of sibling DOM nodes, so nesting carries no runtime cost beyond the extra 'VFrag' constructor allocation.
+--
+-- Empty fragments (@fragment []@) in child nodes are erased from the virtual DOM tree in the
+-- Haskell layer before they reach diffing in JavaScript and are therefore a no-op.
+--
+-- The smart constructors for 'VFrag' are:
+--
+-- * @fragment@   — unkeyed fragment
+-- * 'Miso.Types.vfrag'      — unkeyed fragment (alias)
+-- * 'fragment_'  — keyed fragment
+-- * 'vfrag_'     — keyed fragment (alias, infix-friendly: @\"key\" \`vfrag_\` [...]@)
+--
+-- = t'Key'
+--
+-- A t'Key' is a unique identifier used to optimize diffing.
+--
+-- Virtual DOM nodes can be \"keyed\" (See @key_@). Keys have multiple meanings in @miso@ (and react).
+--
+-- * Keys are used to optimize child node list diffing.
+--
+-- When two lists of elements are being diffed, as long as they all have unique keys, diffing large child lists will be much faster. This optimization automatically occurs when all the elements in a 'VNode' child list contain unique keys. Unless all 'View' nodes in a child list are keyed, this optimization will not fire.
+--
+-- * Keys are used to compare two identical nodes.
+--
+-- If two `VNode` are being compared (or two 'VComp') and their keys differ, the old node will be destroyed and a new one created. Otherwise, the underlying DOM node won't be removed, but its properties will be diffed. In the case of diffing two t'Miso.Types.Component' (the 'VComp' case), if the keys differ, the 'unmount' phase will be triggered for the old 'VComp' and the 'mount' phase will be triggered for the new t'Miso.Types.Component'. The underlying DOM reference will be replaced.
+--
+-- * Keys preserve the DOM reference across updates.
+--
+-- Because a stable key keeps the same underlying DOM node in place, CSS animations on that node will not be interrupted by re-renders. Without a key, the diffing algorithm may replace or recreate the node, resetting any in-progress animation. Assigning a stable key to an animated element guarantees the DOM reference is preserved and the animation runs to completion.
+--
+-- See the @key_@ property for usage (and smart constructors like 'textKey_' and ('+>') as well).
+--
+-- @
+-- 'Miso.Html.Element.ul_'
+--   []
+--   [ 'Miso.Html.Element.li_' [ @key_@ "key-1" ] [ "a" ]
+--   , 'Miso.Html.Element.li_' [ @key_@ "key-2" ] [ "b" ]
+--   , "key-3" '+>' counter
+--   , 'textKey' "key-4" "text here"
+--   , 'vfrag_' "key-5" [ "foo", "bar" ]
+--   ]
+-- @
+--
+-- = 'Events'
+--
+-- * Event Delegation
+--
+-- By default all events are delegated through @\<body\>@. Miso supports both @capture@ and @bubble@ phases of browser events.
+-- Users can handle both phases in their applications.
+--
+-- * Using events
+--
+-- Miso exposes a 'Miso.Event.Types.defaultEvents' for convenience, these events are commonly used events and listened for on @\<body\>@. They get routed through the 'View' to the virtual DOM node that raised the event. Other 'Events' are exposed as conveniences (e.g. 'touchEvents'). All events required by all t'Miso.Types.Component' must be combined together for use when running your application (e.g. @keyboardEvents <> touchEvents@).
+--
+-- @
+-- 'touchEvents' :: 'Events'
+-- 'touchEvents' = M.'Data.Map.fromList'
+--   [ ("touchstart", 'BUBBLE')
+--   , ("touchcancel", 'BUBBLE')
+--   , ("touchmove", 'BUBBLE')
+--   , ("touchend", 'BUBBLE')
+--   ]
+-- @
+--
+-- * Defining event handlers
+--
+-- Users can define their own event handlers using the 'Miso.Event.on' combinator. By default this will define an event in the 'Miso.Event.Types.BUBBLE' phase. See 'Miso.Event.onCapture' for handling events during the 'Miso.Event.Types.CAPTURE' phase. See the module "Miso.Html.Event" for many predefined events.
+--
+-- @
+-- @onChangeWith@ :: ('MisoString' -> @DOMRef@ -> action) -> 'Attribute' model action
+-- @onChangeWith@ = 'on' "change" 'valueDecoder'
+-- @
+--
+-- The @*with@ variant of events (e.g. 'Miso.Event.onChangeWith') provides the target @DOMRef@ in the callback function.
+--
+-- * Decoding events
+--
+-- After an event has been raised, one can extract information from the event for use in their application. This is accomplished through a t'Decoder'. Many common decoders are available for use in "Miso.Event.Decoder".
+--
+-- @
+-- data t'Decoder' a
+--   = t'Decoder'
+--   { 'decoder' :: 'Miso.JSON.Value' -> 'Miso.Util.Parser.Parser' a
+--   , 'decodeAt' :: t'DecodeTarget'
+--   }
+--
+-- -- | Example of a custom t'Decoder' for the @value@ property of an event target.
+-- 'valueDecoder' :: t'Decoder' 'MisoString'
+-- 'valueDecoder' = t'Decoder' {..}
+--   where
+--     'Miso.Event.decodeAt' = t'Miso.Event.DecodeTarget' ["target"]
+--     'Miso.Event.decoder' = 'Miso.JSON.withObject' "target" $ \\o -> o 'Miso.JSON..:' "value"
+-- @
+--
+-- = Attributes / Properties
+--
+-- The 'Attribute' type carries everything that can be attached to a DOM element:
+--
+-- @
+-- data 'Attribute' model action
+--   = 'Property' 'MisoString' 'Miso.JSON.Value'          -- ^ DOM property (key/value)
+--   | 'ClassList' ['MisoString']             -- ^ 'CSS' class list
+--   | 'On' (model -> 'Sink' action -> ...)   -- ^ Fully-applied event handler
+--   | 'OnStatic' (@StaticPtr@ ('EventHandler' model action)) -- ^ @static@ handler, rebuilt on the main thread (dual-thread)
+--   | 'Styles' ('Data.Map.Strict.Map' 'MisoString' 'MisoString') -- ^ Inline style map
+-- @
+--
+-- In practice you never construct these directly. Use the smart constructors from
+-- "Miso.Html.Property", "Miso.Html.Event", "Miso.Property", and "Miso.CSS":
+--
+-- @
+-- 'Miso.Html.Element.div_'
+--   [ 'Miso.Html.Property.id_' "container"                    -- 'textProp' "id"
+--   , 'Miso.Html.Property.className' "card active"            -- 'textProp' "class"
+--   , 'Miso.Html.Property.classList' ["card", "active"]       -- 'ClassList'
+--   , 'Miso.Html.Property.disabled_'                          -- 'boolProp' "disabled" 'True'
+--   , 'Miso.Html.Event.onClick' MyAction                   -- 'On' event handler
+--   , 'Miso.CSS.style_' [ 'Miso.CSS.display' "flex" ]          -- 'Styles' map
+--   ]
+--   []
+-- @
+--
+-- == Custom properties
+--
+-- Use 'prop' (or the typed variants 'textProp', 'boolProp', 'intProp', 'doubleProp',
+-- 'objectProp') from "Miso.Property" to set arbitrary DOM properties:
+--
+-- @
+-- 'prop' "data-index" (42 :: 'Int')      -- sets element.data-index = 42
+-- 'textProp' "placeholder" "Search…"   -- sets element.placeholder
+-- 'boolProp' "checked" True            -- sets element.checked = true
+-- @
+--
+-- Note that DOM /properties/ and HTML /attributes/ are distinct. Miso tries to set
+-- properties on the DOM node object (e.g. @node.checked@) first, then falls back to setting
+-- the HTML attribute (e.g. @setAttribute("checked", ...)@). This matches what
+-- the browser actually exposes in JavaScript and avoids common pitfalls with
+-- boolean attributes.
+--
+-- == Keys
+--
+-- @key_@ (and its alias 'keyProp') attaches a reconciliation key to any element.
+-- See the @'Key'@ section for details.
+--
+-- @
+--
+-- data Item = Item { itemId, itemLabel :: 'MisoString' }
+--
+-- 'Miso.Html.Element.li_' [ @key_@ (itemId item) ] [ 'Miso.Types.text' (itemLabel item) ]
+-- @
+--
+-- = 'Effect'
+--
+-- The 'Effect' type is used to mutate the @model@ over time in response to @action@.
+-- 'Effect' also allows 'IO' to be scheduled for evaluation by the @miso@ scheduler.
+--
+-- Note: 'IO' is never evaluated inside of 'Effect', it is only scheduled.
+-- There is no @MonadIO@ instance for 'Effect'.
+--
+-- The 'Effect' type is defined as a 'Control.Monad.RWS.RWS'.
+--
+-- @
+-- type 'Effect' context props model action = 'Control.Monad.RWS.RWS' ('ComponentInfo' context props) ['Schedule' context action] model ()
+-- @
+--
+-- * The 'Control.Monad.Reader' portion of 'Effect' is t'ComponentInfo'. 'ask', 'asks', 'Miso.Lens.view' can be used to access its fields.
+-- * The 'Control.Monad.Writer' portion of 'Effect' is used to schedule t'IO' actions. 'tell' can be used to create a t'Schedule' for an 'IO' action that is executed according to 'Synchronicity'. See also 'withSink' for usage.
+-- * The 'Control.Monad.State' portion of 'Effect' is used to manipulate the @model@. 'get', 'put', 'modify', and the 'Control.Monad.State.MonadState' lenses in t'Miso.Lens.Lens' can be used to modify the @model@.
+--
+-- 'IO' can be performed either synchronously or asynchronously. By default all 'IO' is asynchronous
+--
+-- == Asynchronous 'IO'
+--
+-- * 'io': Used to introduce asynchronous 'io' into the system, see also the 'io_' variant.
+--
+-- * 'withSink': The core function (from which most other combinators are defined)
+--   that gives users access to the underlying event 'Sink'. This also allows us to
+--   introduce 'IO' into the system. The @miso@ scheduler attaches exception
+--   handlers to all 'IO' actions.
+--
+-- * For maximum flexibility, the @MonadWriter@ instance ('tell') can be used to schedule 'IO' (see the 'withSink' implementation).
+--
+-- == Synchronous 'IO'
+--
+-- * 'sync': Forces the scheduler to evaluate 'IO' synchronously. It is
+--   recommended to use the 'io' function by default, 'sync' *will* block the scheduler.
+--
+-- == 'Sink'
+--
+-- @
+-- type 'Sink' action = action -> 'IO' ()
+-- @
+--
+-- The 'Sink' function allows one to write any @action@ to the global event queue. See 'withSink' for more information.
+--
+-- == Managing @model@ state.
+--
+-- Any @MonadState@ function is allowed for use when manipulating @model@, 'Miso.State.get', 'Miso.State.put', etc. See "Miso.State".
+--
+-- The @MonadReader@ instances allows the retrieval of t'ComponentInfo' within 'Effect'.
+-- t'ComponentInfo' provides the current @ComponentId@, the parent @ComponentId@, the
+-- @DOMRef@ that the t'Miso.Types.Component' is mounted on, and the current @props@ and @context@.
+-- Read them with the 'Miso.Effect.componentInfoId', 'Miso.Effect.componentInfoParentId',
+-- 'Miso.Effect.componentInfoDOMRef', 'Miso.Effect.componentInfoProps' and
+-- 'Miso.Effect.componentInfoContext' lenses.
+--
+-- = t'Miso.Types.Component' communication
+--
+-- @miso@ provides four mechanisms for t'Miso.Types.Component' to exchange data:
+--
+-- * __Props__ — synchronous, parent-to-child read-only data passed at mount time (see below). Props are updated in the child in response to parent changes.
+-- * __Context__ — global data shared by the entire tree (see /The global @context@/ above); any t'Miso.Types.Component' can mutate it via 'Miso.Effect.modifyContext' \/ 'Miso.Effect.putContext', and read it via 'Miso.Effect.getContext'. Set @'Miso.Types.useContext' = True@ (or use 'Miso.Types.mountUseContext') on a t'Miso.Types.Component' to have it re-render whenever @context@ changes.
+-- * __Async mailbox__ — message-passing via 'mail', 'broadcast', 'checkMail'; any t'Miso.Types.Component' can send a t'Miso.JSON.Value' to any other by @ComponentId@.
+-- * __PubSub__ ("Miso.PubSub") — publish\/subscribe for fan-out messaging across unrelated t'Miso.Types.Component'.
+--
+-- == Props
+--
+-- Inspired by [React props](https://react.dev/learn/passing-props-to-a-component),
+-- @miso@ allows a parent t'Miso.Types.Component' to pass read-only data down to a child t'Miso.Types.Component'
+-- via a mechanism called /props/ (short for /properties/).
+--
+-- === Props vs. t'Miso.Types.Component'-local state
+--
+-- * __model__: t'Miso.Types.Component'-local state. It is owned and mutated exclusively by the t'Miso.Types.Component'
+--   itself through its 'Miso.Types.update' function. No other t'Miso.Types.Component' can write to it directly.
+--
+-- * __props__: Data /inherited/ from the @parent@ t'Miso.Types.Component'. Props flow downward through
+--   the t'Miso.Types.Component' hierarchy and are read-only from the child's perspective. The parent decides
+--   which props to pass at mount time; the child cannot mutate them. Props that change in
+--   the parent cause the child to re-render.
+--
+-- This mirrors the distinction in React between t'Miso.Types.Component'-local state (@useState@) and props
+-- received from above (@function MyComponent({ name }) { ... }@).
+--
+-- ==== When to use props
+--
+-- Props are best suited for /metadata/ — contextual or configuration data that the child needs
+-- to know about but should not own. Good examples: a user's display name, a theme token, a
+-- locale string, or a read-only identifier used to customise rendering.
+--
+-- If the data drives the child's own business logic — counters it increments, form fields it
+-- edits, async state it manages — that data belongs in the child's @model@ instead. Putting
+-- mutable business-logic state in @props@ would require the parent to own and thread through
+-- every change, creating unnecessary coupling. Prefer @props@ for \"what the child should
+-- know\" and @model@ for \"what the child should do\".
+--
+-- === Props in 'Miso.Types.view'
+--
+-- The 'Miso.Types.view' field of a t'Miso.Types.Component' takes the app-global @context@ as
+-- its first argument and the @props@ as its second:
+--
+-- @
+-- view :: context -> props -> model -> 'View' context model action
+-- @
+--
+-- Top-level applications have no parent, so @props@ is always @()@:
+--
+-- @
+-- view :: () -> () -> model -> 'View' () model action
+-- view _context _props model = …
+-- @
+--
+-- === Props in 'Effect' \/ 'Miso.Types.update'
+--
+-- Use 'getProps' inside the 'Effect' monad to read the current value of @props@:
+--
+-- @
+-- update :: Action -> 'Effect' context props Model Action
+-- update = \\case
+--   SomeAction -> do
+--     p <- 'getProps'
+--     'io_' ('Miso.FFI.consoleLog' (ms (show p)))
+-- @
+--
+-- Alternatively, use the 'Miso.Lens.view' combinator with the 'Miso.Effect.props' lens:
+--
+-- @
+-- update = \\case
+--   SomeAction -> do
+--     p <- 'Miso.Lens.view' 'Miso.Effect.props'
+--     …
+-- @
+--
+-- === 'App' — the top-level t'Miso.Types.Component'
+--
+-- When a t'Miso.Types.Component' is passed to 'startApp' (or 'miso') its global
+-- @context@ and @props@ are both fixed to @()@:
+--
+-- @
+-- type 'App' model action = t'Miso.Types.Component' () () model action
+-- @
+--
+-- Because there is no parent to inherit from, @props@ will always be @()@ for a
+-- root-level t'Miso.Types.Component'. You can ignore the @context@ and @props@ arguments in
+-- 'Miso.Lens.view' and skip 'getProps' in 'Miso.Types.update'. Use 'startAppWithContext'
+-- to seed a non-trivial @context@.
+--
+-- === Passing props to a child t'Miso.Types.Component'
+--
+-- Use 'mountWithProps_' (keyed) or 'mountWithProps' (unkeyed) in the parent's 'Miso.Lens.view' to
+-- mount a child and supply its props:
+--
+-- @
+-- 'mountWithProps_'
+--   :: ('Eq' context, 'Eq' childModel, 'Eq' props)
+--   => 'MisoString'
+--   -> props
+--   -> t'Miso.Types.Component' context props childModel childAction
+--   -> 'View' context model action
+-- @
+--
+-- === Example: child reading parent-supplied props
+--
+-- The following shows a parent t'Miso.Types.Component' that maintains a greeting string in its
+-- @model@ and passes it as @props@ to a child t'Miso.Types.Component'. The child renders the
+-- greeting and can also read it from within its 'Miso.Types.update' function.
+--
+-- @
+-- -----------------------------------------------------------------------------
+-- -- The props type: what the parent shares with the child
+-- newtype Greeting = Greeting 'MisoString' deriving ('Eq')
+-- -----------------------------------------------------------------------------
+-- -- Child component
+-- --
+-- --                  context props    model  action
+-- --                  |       |        |      |
+-- child :: t'Miso.Types.Component' ()      Greeting ()     ChildAction
+-- child = 'Miso.Types.component' () updateChild viewChild
+--   where
+--     viewChild :: () -> Greeting -> () -> 'View' () () ChildAction
+--     viewChild _ (Greeting g) _ =
+--       'Miso.Html.Element.div_' [] [ 'Miso.Types.text' ("Hello, " <> g <> "!") ]
+--
+--     updateChild :: ChildAction -> 'Effect' () Greeting () ChildAction
+--     updateChild = \\case
+--       ReadGreeting -> do
+--         Greeting g <- 'getProps'
+--         'io_' ('Miso.FFI.consoleLog' g)
+-- -----------------------------------------------------------------------------
+-- -- Parent component: owns the greeting, passes it to the child as props
+-- parentComp :: 'App' ParentModel ParentAction
+-- parentComp = 'Miso.Types.component' (ParentModel \"World\") 'noop' viewParent
+--   where
+--     viewParent :: () -> () -> ParentModel -> 'View' () ParentModel ParentAction
+--     viewParent _ _ (ParentModel g) = 'mountWithProps_' "child" (Greeting g) child
+-- -----------------------------------------------------------------------------
+-- newtype ParentModel = ParentModel 'MisoString' deriving ('Eq')
+--
+-- data ChildAction = ReadGreeting
+-- data ParentAction
+-- @
+--
+-- A few things to notice:
+--
+-- * @props@ flow from parent to child explicitly via 'mountWithProps_'; the child's
+--   @context@ is the shared global context (@()@ here).
+-- * 'getProps' inside the child's 'Miso.Types.update' yields a @Greeting@. The child
+--   only sees what the parent explicitly chose to share.
+-- * The root 'App' always has @context ~ ()@ and @props ~ ()@; no extra plumbing is
+--   needed when calling 'startApp'.
+--
+--
+-- == Asynchronous communication
+--
+-- Every t'Miso.Types.Component' has a 'mailbox' — a slot that receives t'Miso.JSON.Value' messages
+-- sent by other components. Messages are dispatched asynchronously via the event queue.
+--
+-- === Sending
+--
+-- * 'mail' @componentId msg@ — send to a specific @ComponentId@ (obtained via 'ask' inside 'Effect')
+-- * 'mailParent' @msg@ — send to the direct parent
+-- * 'mailChildren' @msg@ — send to all immediate children
+-- * 'mailAncestors' @msg@ — walk up the hierarchy, delivering to every ancestor
+-- * 'mailDescendants' @msg@ — walk down the hierarchy, delivering to every descendant
+-- * 'broadcast' @msg@ — deliver to every mounted t'Miso.Types.Component' except the sender
+--
+-- === Receiving with 'checkMail'
+--
+-- Wire up the 'mailbox' field on t'Miso.Types.Component' using 'checkMail', which handles
+-- JSON parsing and routes to success\/error actions:
+--
+-- @
+-- data Action
+--   = ReceivedMsg MyMsg
+--   | MailError   'MisoString'
+--
+-- myComp :: t'Miso.Types.Component' context props model Action
+-- myComp = ('Miso.Types.component' m u v) { 'mailbox' = 'checkMail' ReceivedMsg MailError }
+-- @
+--
+-- === Looking up a @ComponentId@
+--
+-- Inside 'Effect', use 'ask' to obtain a t'ComponentInfo':
+--
+-- @
+-- update = \\case
+--   SendMsg targetId -> do
+--     'io_' ('mail' targetId ("hello" :: 'MisoString'))
+--   GetMyId -> do
+--     info <- 'ask'
+--     let myId = '_componentInfoId' info
+--     ...
+-- @
+--
+-- * "Miso.PubSub" — publish\/subscribe pattern for fan-out messaging across unrelated components.
+--
+-- = Subscriptions
+--
+-- A t'Sub' is any long-running operation that is external to a t'Miso.Types.Component', but that can write
+-- to a t'Miso.Types.Component' 'Sink'. Along with the 'Sink', a 'Sub' receives an @IO model@ action
+-- returning a snapshot of its t'Miso.Types.Component'\'s current model (ignore it if unneeded).
+-- 'Sub' come in two flavors, a dynamic 'Sub' (via 'startSub' / 'stopSub') and 'subs'.
+--
+-- * 'subs'
+--
+-- @
+-- main :: t'IO' ()
+-- main = 'startApp' 'Miso.Event.Types.defaultEvents' app { 'subs' = [ timerSub ] }
+--
+-- timerSub :: 'Sub' Model Action
+-- timerSub sink _getModel = 'Control.Monad.forever' $ ('Control.Concurrent.threadDelay' 100000) >> sink Log
+--
+-- data Action = Log
+-- @
+--
+-- The 'subs' field of t'Miso.Types.Component' contains 'Sub' that exist for the lifetime of that t'Miso.Types.Component'.
+-- When a t'Miso.Types.Component' unmounts, these 'Sub' will be stopped, and their resources finalized.
+--
+-- @
+-- 'onLineSub' :: ('Bool' -> action) -> 'Sub' model action
+-- 'onLineSub' f sink = 'Miso.Subscription.Util.createSub' acquire release sink
+--   where
+--     release (cb1, cb2) = do
+--       'Miso.FFI.windowRemoveEventListener' "online"  cb1
+--       'Miso.FFI.windowRemoveEventListener' "offline" cb2
+--     acquire = do
+--       cb1 <- 'Miso.FFI.windowAddEventListener' "online"  (const $ sink (f True))
+--       cb2 <- 'Miso.FFI.windowAddEventListener' "offline" (const $ sink (f False))
+--       pure (cb1, cb2)
+-- @
+--
+-- * 'startSub' / 'stopSub'
+--
+-- At times its necessary to dynamically generate a 'Sub' in reponse to an event (e.g. starting a "Miso.WebSocket" connection
+-- when a user logs in). The 'startSub' and 'stopSub' functions facilitate dynamic 'Sub' creation / removal.
+--
+-- @
+-- update = \\case
+--   StartTimer -> 'startSub' ("timer" :: 'MisoString') timerSub
+--   StopTimer -> 'stopSub' "timer"
+--   Log -> 'io_' ('Miso.FFI.consoleLog' "log")
+--     where
+--       timerSub :: 'Sub' Model Action
+--       timerSub sink _getModel = 'Control.Monad.forever' $ ('Control.Concurrent.threadDelay' 100000) >> sink Log
+--
+-- data Action = Log
+-- @
+--
+-- * 'Miso.Subscription.Util.createSub'
+--
+-- 'Miso.Subscription.Util.createSub' is a helper function for creating a 'Sub' using the 'Control.Exception.bracket' pattern.
+-- This ensures that event listeners can be unregistered when a t'Miso.Types.Component' unmounts. For example usage
+-- please see the "Miso.Subscription" sub modules. 'Miso.Subscription.Util.createSub' is only meant to be used in scenarios where
+-- custom event listeners are required.
+--
+-- = 'Control.Monad.State.State' management
+--
+-- Miso bundles a lightweight lens library in "Miso.Lens" to minimise dependencies
+-- and payload size. Any lens library (optics, lens) also works — "Miso.Lens" is not required.
+--
+-- == Basic lens operations
+--
+-- @
+-- 'Miso.Lens.view' l              -- read a field (MonadReader)
+-- 'Miso.Lens.set'  l v            -- write a field
+-- 'Miso.Lens.over' l f            -- modify a field
+-- r 'Miso.Lens.^.' l              -- infix read
+-- r 'Data.Function.&' l 'Miso.Lens..~' v         -- infix write
+-- @
+--
+-- == @MonadState@ operators (for use inside 'Effect')
+--
+-- @
+-- l 'Miso.Lens.+=' n   -- increment a numeric field
+-- l 'Miso.Lens.-=' n   -- decrement
+-- l 'Miso.Lens.*=' n   -- multiply
+-- @
+--
+-- == 'Miso.Lens.this' — the identity lens
+--
+-- When the model /is/ the field (e.g. the model is a plain @Int@), use @this@:
+--
+-- @
+-- update = \\case
+--   Increment -> 'Miso.Lens.this' 'Miso.Lens.+=' 1
+--   Decrement -> 'Miso.Lens.this' 'Miso.Lens.-=' 1
+-- @
+--
+-- == Generating lenses
+--
+-- Three approaches, pick one:
+--
+-- * __Template Haskell__ ("Miso.Lens.TH"): 'Miso.Lens.makeLenses' / 'Miso.Lens.makeClassy' splice lenses for each record field.
+--
+-- @
+-- {-# LANGUAGE TemplateHaskell #-}
+--
+-- import "Miso.Lens.TH" ('Miso.Lens.TH.makeLenses')
+--
+-- data Model = Model { _count :: 'Int', _name :: 'MisoString' }
+--
+-- 'Miso.Lens.TH.makeLenses' ''Model
+--
+-- update = \\case
+--   Increment -> count 'Miso.Lens.+=' 1
+--   Rename n  -> name 'Miso.Lens..=' n
+-- @
+--
+-- * __Generics__ ("Miso.Lens.Generic"): 'Miso.Lens.Generic.field' \/ 'Miso.Lens.Generic.HasLens' derive lenses at compile time
+--   using @GHC.Generics@ — no TH splice required. Requires @TypeApplications@ and,
+--   optionally, @OverloadedLabels@ for the @#field@ shorthand.
+--
+-- @
+-- {-# LANGUAGE DataKinds          #-}
+-- {-# LANGUAGE DeriveGeneric      #-}
+-- {-# LANGUAGE OverloadedLabels   #-}
+-- {-# LANGUAGE TypeApplications   #-}
+--
+-- import "GHC.Generics" ('GHC.Generics.Generic')
+-- import "Miso.Lens.Generic" ('Miso.Lens.Generic.field')
+--
+-- data Model = Model { count :: 'Int', name :: 'MisoString' }
+--   deriving ('Eq', 'GHC.Generics.Generic')
+--
+-- update = \\case
+--   Increment -> 'Miso.Lens.Generic.field' \@\"count\" 'Miso.Lens.+=' 1  -- via TypeApplications
+--   Rename n  -> #name 'Miso.Lens..=' n            -- via OverloadedLabels
+-- @
+--
+-- * __Hand-written__: construct a @Lens@ directly using @lens@ and the @Lens s a@ synonym.
+--
+-- @
+-- name :: 'Miso.Lens.Lens' Person 'MisoString'
+-- name = 'Miso.Lens.lens' _name $ \\p n -> p { _name = n }
+-- @
+--
+-- = (2D/3D) Canvas support
+--
+-- Miso has full 2D and 3D canvas support via "Miso.Canvas". See also the
+-- [miso-canvas](https://github.com/haskell-miso/miso-canvas2d) example and the
+-- [three-miso](https://github.com/haskell-miso/three-miso) package for Three.js integration.
+--
+-- == The 'Miso.Canvas.Canvas' monad
+--
+-- Drawing commands run in the 'Miso.Canvas.Canvas' monad, which is a 'Control.Monad.Reader.ReaderT' over a
+-- 'Miso.Canvas.CanvasContext2D' (the raw JavaScript 'Miso.Canvas.CanvasContext2D'):
+--
+-- @
+-- type t'Miso.Canvas.Canvas' a = 'Control.Monad.Reader.ReaderT' 'Miso.Canvas.CanvasContext2D' 'IO' a
+-- @
+--
+-- == Embedding a canvas in the 'Miso.Lens.view'
+--
+-- Use the 'Miso.Canvas.canvas' smart constructor.
+-- It takes an /init/ callback (runs once on mount, returns state) and a
+-- /draw/ callback (runs on every render with the current state):
+--
+-- @
+-- 'Miso.Canvas.canvas'
+--   [ HP.'Miso.Html.Property.width_' "800", HP.'Miso.Html.Property.height_' "480" ]
+--   (\\_ -> pure ())                   -- init: called once on canvas initialization
+--   (\\() -> drawScene myModel)        -- draw: called many times, on each diff.
+-- @
+--
+-- 'Miso.Canvas.canvas_' is the variant that threads no init state at all (always passes @()@).
+--
+-- == Drawing commands
+--
+-- Common 2D primitives:
+--
+-- @
+-- drawScene :: Model -> 'Miso.Canvas.Canvas' ()
+-- drawScene model = do
+--   'Miso.Canvas.clearRect' (0, 0, 800, 480)
+--   'Miso.Canvas.fillStyle' ('Miso.CSS.Color.RGB' 30 144 255)
+--   'Miso.Canvas.beginPath' ()
+--   'Miso.Canvas.arc' (400, 240, 50, 0, 2 * pi)
+--   'Miso.Canvas.fill' ()
+--   'Miso.Canvas.font' "24px sans-serif"
+--   'Miso.Canvas.fillText' ("Score: " \<\> ms (score model), 10, 30)
+-- @
+--
+-- Available primitives include: 'Miso.Canvas.clearRect', 'Miso.Canvas.fillRect', 'Miso.Canvas.strokeRect',
+-- 'Miso.Canvas.beginPath', 'Miso.Canvas.closePath', 'Miso.Canvas.moveTo', 'Miso.Canvas.lineTo',
+-- 'Miso.Canvas.arc', 'Miso.Canvas.arcTo', 'Miso.Canvas.fill', 'Miso.Canvas.stroke',
+-- 'Miso.Canvas.fillText', 'Miso.Canvas.drawImage'.
+--
+-- Style setters: 'Miso.Canvas.fillStyle', 'Miso.Canvas.strokeStyle', 'Miso.Canvas.lineWidth', 'Miso.Canvas.font'.
+-- 'Miso.Canvas.fillStyle' and 'Miso.Canvas.strokeStyle' accept a 'Miso.Canvas.StyleArg' — use
+-- 'Miso.Canvas.color' (not 'Miso.CSS.color') to construct one from a t'Miso.CSS.Color.Color' value.
+-- See the __Canonical Import Pattern__ section for how to avoid the name collision
+-- between 'Miso.Canvas.color' and 'Miso.CSS.color'.
+--
+-- == Animation loop
+--
+-- For smooth 60 FPS canvas animations, use 'Miso.Subscription.RAF.rAFSub' from
+-- "Miso.Subscription.RAF" instead of a manual @threadDelay@ loop.
+-- It hooks into the browser's @requestAnimationFrame@ API and delivers a
+-- [DOMHighResTimeStamp](https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp)
+-- (milliseconds) on each frame:
+--
+-- @
+-- data Action = Tick 'Double'
+--
+-- main :: IO ()
+-- main = 'startApp' 'Miso.Event.Types.defaultEvents' comp { 'subs' = [ 'Miso.Subscription.RAF.rAFSub' Tick ] }
+-- @
+--
+-- = HTML
+--
+-- Miso's 'View' type doubles as an HTML serialiser via the 'Miso.Html.Render.ToHtml' class in
+-- "Miso.Html.Render". This is used for server-side rendering (SSR): build a
+-- 'View' with the normal DSL and render it to a lazy 'Data.ByteString.Lazy.ByteString'
+-- on the server.
+--
+-- @
+-- class 'Miso.Html.ToHtml' a where
+--   'Miso.Html.ToHtml.toHtml' :: a -> 'Data.ByteString.Lazy.ByteString'
+-- @
+--
+-- Instances are provided for @'View' c m a@ and @['View' c m a]@:
+--
+-- @
+-- import "Miso.Html.Render" ('Miso.Html.Render.toHtml')
+--
+-- pageHtml :: 'Data.ByteString.Lazy.ByteString'
+-- pageHtml = 'Miso.Html.Render.toHtml' $ 'Miso.Html.Element.div_' [ 'Miso.Html.Property.id_' "root" ] [ "Hello, world!" ]
+-- @
+--
+-- This is typically wired into a Servant handler on the server using the
+-- [servant-miso-html](https://github.com/haskell-miso/servant-miso-html) package,
+-- which provides an @HTML@ content-type that serialises 'View' and t'Miso.Types.Component'
+-- values directly — no manual @ByteString@ conversion needed:
+--
+-- @
+-- import Servant.Miso.Html (HTML)
+--
+-- type Home    = \"home\"    :\> Get '[HTML] ('Miso.Types.Component' context props model action)
+-- type About   = \"about\"   :\> Get '[HTML] ('View' context model action)
+-- type Contact = \"contact\" :\> Get '[HTML] ['View' context model action]
+-- type API = Home :\<|\> About :\<|\> Contact
+-- @
+--
+-- On the client, pass the matching t'Miso.Types.Component' to 'miso' (instead of 'startApp')
+-- so it hydrates the server-rendered markup rather than redrawing from scratch.
+-- See the __Prerendering__ section for the full flow.
+--
+-- = JavaScript EDSL
+--
+-- "Miso.DSL" provides a JavaScript DSL inspired by [jsaddle](https://hackage.haskell.org/package/jsaddle)
+-- for interacting with the browser from Haskell.
+--
+-- == Key operators
+--
+-- * '(Miso.DSL.!)' — property access: @obj '!' "key"@ reads @obj.key@
+-- * '(Miso.DSL.#)' — method call: @obj '#' "method" args@ calls @obj.method(args)@
+-- * 'Miso.DSL.jsg' — access a global JS variable by name
+-- * 'Miso.DSL.jsgf' — call a global JS function by name with arguments
+--
+-- @
+-- -- Read document.body.children.length
+-- document <- 'Miso.DSL.jsg' "document"
+-- len :: 'Int' <- 'Miso.DSL.fromJSValUnchecked' =<< (document 'Miso.DSL.!' "body" 'Miso.DSL.!' "children" 'Miso.DSL.!' "length")
+--
+-- -- Call console.log("hello")
+-- console <- 'Miso.DSL.jsg' "console"
+-- console 'Miso.DSL.#' "log" $ ["hello" :: 'MisoString']
+-- @
+--
+-- == Marshalling
+--
+-- 'Miso.DSL.ToJSVal' converts Haskell values to 'Miso.DSL.JSVal' for passing into JavaScript.
+-- 'Miso.DSL.FromJSVal' converts 'Miso.DSL.JSVal' back to Haskell.
+-- 'Miso.DSL.fromJSValUnchecked' throws on failure; use 'Miso.DSL.fromJSVal' for a safe @Maybe@ variant.
+--
+-- = QuasiQuotation (@inline-js@)
+--
+-- "Miso.FFI.QQ" provides the 'Miso.FFI.QQ.js' QuasiQuoter for embedding inline JavaScript
+-- directly in Haskell source. Any Haskell binding in scope can be interpolated into
+-- the JavaScript body with @${varName}@ syntax — miso uses the binding's 'Miso.DSL.ToJSVal'
+-- instance to marshal it across the boundary at runtime.
+--
+-- @
+-- {-# LANGUAGE QuasiQuotes #-}
+--
+-- import "Miso.FFI.QQ" ('Miso.FFI.QQ.js')
+--
+-- update :: Action -> 'Miso.Effect.Effect' context props model Action
+-- update = \\case
+--   Log msg -> 'io_' ['Miso.FFI.QQ.js'| console.log(${msg}) |]
+--
+-- data Action = Log 'MisoString'
+-- @
+--
+-- == Returning values from JavaScript
+--
+-- The return type is inferred from the call site via 'Miso.DSL.FromJSVal'.
+-- Use an explicit type annotation or a @do@-binding to drive inference:
+--
+-- @
+-- factorial :: 'Int' -> IO 'Int'
+-- factorial n = ['Miso.FFI.QQ.js'|
+--   let x = 1;
+--   for (let i = 1; i <= ${n}; i++) { x *= i; }
+--   return x;
+-- |]
+-- @
+--
+-- Haskell variables referenced inside the quoter must be in scope at the splice
+-- site; the compiler will report an error if a @${name}@ has no corresponding binding.
+--
+-- = Routing
+--
+-- "Miso.Router" provides a reversible, type-safe client-side router. A @Route@
+-- type encodes URL structure; the 'Miso.Router.Router' class converts between routes and
+-- t'URI' values in both directions. Use it with 'Miso.Subscription.History.routerSub'
+-- or 'Miso.Subscription.History.uriSub' to react to browser navigation.
+--
+-- == Defining a 'Miso.Router.Router' with Generics
+--
+-- Derive 'Miso.Router.Router' via "GHC.Generics" — constructor names become path segments
+-- (camel-case uses only the first hump). Use 'Miso.Router.Capture', 'Miso.Router.Path', 'Miso.Router.QueryParam',
+-- and 'Miso.Router.QueryFlag' as constructor fields to describe the URL shape:
+--
+-- @
+-- {-# LANGUAGE DeriveGeneric  #-}
+-- {-# LANGUAGE DeriveAnyClass #-}
+--
+-- import "GHC.Generics"
+-- import "Miso.Router"
+--
+-- data Route
+--   = Index                                                      -- matches "/"
+--   | About                                                      -- matches "/about"
+--   | Product ('Miso.Router.Capture' "id" Int) ('Miso.Router.QueryParam' "tab" 'MisoString')   -- matches "/product/42?tab=info"
+--   deriving stock ('Show', 'Eq', 'GHC.Generics.Generic')
+--   deriving anyclass 'Miso.Router.Router'
+-- @
+--
+-- The router is /reversible/ — 'Miso.Router.prettyRoute' re-serialises any route back to a URL:
+--
+-- @
+-- 'Miso.Router.prettyRoute' (Product ('Miso.Router.Capture' 42) ('Miso.Router.QueryParam' (Just "info")))
+-- -- "\/product\/42?tab=info"
+-- @
+--
+-- == Defining a 'Miso.Router.Router' manually
+--
+-- For full control, implement 'Miso.Router.routeParser' and 'Miso.Router.fromRoute' directly:
+--
+-- @
+-- data Route = Product 'Int'
+--
+-- instance 'Miso.Router.Router' Route where
+--   'Miso.Router.routeParser' = 'Miso.Router.routes' [ Product \<$\> ('Miso.Router.path' "product" *\> 'Miso.Router.capture') ]
+--   'Miso.Router.fromRoute' (Product n) = [ 'Miso.Router.toPath' "product", 'Miso.Router.toCapture' n ]
+-- @
+--
+-- == Subscribing to URI changes
+--
+-- 'Miso.Subscription.History.routerSub' listens to @popstate@ events and delivers
+-- the parsed route (or a 'Miso.Router.RoutingError') to your @update@ function:
+--
+-- @
+-- app = ('Miso.Types.component' m u v) { 'subs' = [ 'Miso.Router.routerSub' HandleRoute ] }
+--
+-- update = \\case
+--   HandleRoute (Right Index)       -> page 'Miso.Lens..=' HomePage
+--   HandleRoute (Right About)       -> page 'Miso.Lens..=' AboutPage
+--   HandleRoute (Left _)            -> page 'Miso.Lens..=' NotFound
+-- @
+--
+-- 'Miso.Subscription.History.uriSub' is the lower-level variant — it delivers
+-- the raw 'Miso.Router.URI' without parsing, useful when you want to handle routing yourself.
+--
+-- == Navigating programmatically
+--
+-- @
+-- 'Miso.Router.pushURI'    uri    -- push a raw t'URI' onto the History stack
+-- 'Miso.Router.pushRoute'  route  -- push a typed route (serialised via 'Miso.Router.Router')
+-- 'Miso.Router.replaceURI' uri    -- replace the current history entry
+-- 'Miso.Router.back'              -- go back one entry
+-- 'Miso.Router.forward'           -- go forward one entry
+-- @
+--
+-- == Type-safe links in 'Miso.Lens.view'
+--
+-- 'Miso.Router.href_' produces a type-safe @href@ attribute from any route:
+--
+-- @
+-- 'Miso.Html.Element.button_' [ 'Miso.Router.href_' (Product ('Miso.Router.Capture' 10) ('Miso.Router.QueryParam' Nothing)) ] [ "Go to product 10" ]
+-- @
+--
+-- = 'MisoString'
+--
+-- t'MisoString' is miso's canonical string type, chosen to minimise copying between
+-- the Haskell and JavaScript heaps:
+--
+-- * __JS / WASM backends__: t'MisoString' is @JSString@, a direct reference to a
+--   JavaScript string — no marshalling cost when passing to the DOM or FFI.
+-- * __Server / vanilla GHC__ (@-fssr@ flag): t'MisoString' is t'Data.Text'.
+--
+-- Use t'MisoString' anywhere you would otherwise reach for 'String' or t'Data.Text' in a
+-- miso application. See "Miso.String" for the full API.
+--
+-- == Converting to 'MisoString'
+--
+-- The 'ms' function (shorthand for 'toMisoString') converts any type with a
+-- 'Miso.String.ToMisoString' instance:
+--
+-- @
+-- 'ms' "hello"          -- 'String'    -> 'MisoString'
+-- 'ms' (42 :: 'Int')      -- 'Int'       -> 'MisoString'
+-- 'ms' (3.14 :: 'Double') -- 'Double'    -> 'MisoString'
+-- 'ms' myText           -- 'Data.Text.Text' -> 'MisoString'
+-- @
+--
+-- 'Miso.String.ToMisoString' instances are provided for 'String', t'Data.Text.Text',
+-- t'Data.Text.Lazy.Text', t'Data.ByteString.ByteString', 'Int', 'Word',
+-- 'Double', 'Float', and 'Char'.
+--
+-- == Converting from 'MisoString'
+--
+-- 'fromMisoString' parses a t'MisoString' back into another type (throws on failure).
+-- Use @fromMisoStringEither@ for a safe variant:
+--
+-- @
+-- 'Miso.String.fromMisoString' "42"     :: 'Int'     -- 42
+-- 'Miso.String.fromMisoString' "3.14"   :: 'Double'  -- 3.14
+-- 'Miso.String.fromMisoStringEither' s  :: 'Either' 'String' 'Int'
+-- @
+--
+-- 'Miso.String.FromMisoString' instances are provided for 'String', t'Data.Text.Text',
+-- t'Data.Text.Lazy.Text', t'Data.ByteString.ByteString', 'Int', 'Word',
+-- 'Double', and 'Float'.
+--
+-- == Multiline literals
+--
+-- With GHC's @MultilineStrings@ extension, multiline t'MisoString' literals
+-- work out of the box:
+--
+-- @
+-- {-# LANGUAGE MultilineStrings #-}
+--
+-- snippet :: 'MisoString'
+-- snippet = """
+--   line one
+--   line two
+-- """
+-- @
+--
+-- t'MisoString' is also the element type used throughout "Miso.Util.Lexer" and
+-- "Miso.Util.Parser".
+--
+-- = JSON
+--
+-- "Miso.JSON" is a [microaeson](https://hackage.haskell.org/package/microaeson)-inspired
+-- JSON library specialised to t'MisoString'. On the JS\/WASM backends it delegates
+-- encoding and decoding to the JavaScript runtime (@JSON.stringify@ \/ @JSON.parse@)
+-- for performance. On the server (@ssr@ flag) it uses a pure Haskell implementation.
+-- "Miso.JSON" is used internally by "Miso.Event.Decoder", "Miso.Fetch", and "Miso.WebSocket".
+--
+-- == 'Miso.JSON.Value'
+--
+-- The JSON t'Miso.JSON.Value' type mirrors the JSON specification:
+--
+-- @
+-- data 'Miso.JSON.Value'
+--   = 'Miso.JSON.Number' 'Double'
+--   | 'Miso.JSON.Bool'   'Bool'
+--   | 'Miso.JSON.String' 'MisoString'
+--   | 'Miso.JSON.Array'  ['Miso.JSON.Value']
+--   | 'Miso.JSON.Object' 'Miso.JSON.Object'
+--   | 'Miso.JSON.Null'
+-- @
+--
+-- == Encoding
+--
+-- Encode any 'Miso.JSON.ToJSON' instance to a t'MisoString':
+--
+-- @
+-- 'Miso.JSON.encode' value        -- uses JS runtime on client, pure on server
+-- 'Miso.JSON.encodePure' value    -- always uses pure Haskell implementation
+-- @
+--
+-- == Decoding
+--
+-- @
+-- 'Miso.JSON.decode' s            :: 'Maybe' a      -- returns 'Nothing' on failure
+-- 'Miso.JSON.eitherDecode' s      :: 'Either' 'MisoString' a
+-- @
+--
+-- == 'Miso.JSON.ToJSON' \/ 'Miso.JSON.FromJSON'
+--
+-- Derive instances via @GHC.Generics@:
+--
+-- @
+-- {-# LANGUAGE DeriveGeneric #-}
+--
+-- import "GHC.Generics"
+-- import "Miso.JSON"
+--
+-- data User = User { name :: 'MisoString', age :: 'Int' }
+--   deriving ('GHC.Generics.Generic')
+--
+-- instance 'Miso.JSON.ToJSON' User
+-- instance 'Miso.JSON.FromJSON' User
+-- @
+--
+-- Use 'Miso.JSON.genericToJSON' \/ 'Miso.JSON.genericParseJSON' with t'Options' to customise field and
+-- constructor names. 'Miso.JSON.camelTo2' is provided for converting @camelCase@ to
+-- @snake_case@ (or any separator):
+--
+-- @
+-- instance 'Miso.JSON.ToJSON' User where
+--   'Miso.JSON.toJSON' = 'Miso.JSON.genericToJSON' 'Miso.JSON.defaultOptions' { 'Miso.JSON.fieldLabelModifier' = 'Miso.JSON.camelTo2' \'_\' }
+-- @
+--
+-- == Building and Parsing Objects
+--
+-- @
+-- -- Build
+-- 'Miso.JSON.object' [ "name" 'Miso.JSON..=' 'ms' \"Alice\", "age" 'Miso.JSON..=' (30 :: 'Int') ]
+--
+-- -- Parse (inside a 'Miso.JSON.withObject' callback or event decoder)
+-- 'Miso.JSON.withObject' \"User\" $ \\o -> User
+--   '<$>' o 'Miso.JSON..:' "name"     -- required field
+--   '<*>' o 'Miso.JSON..:' "age"
+--
+-- o 'Miso.JSON..:?' "nickname"    -- optional field → Maybe a
+-- o 'Miso.JSON..:!' "nickname"    -- optional field, explicit null → Maybe a
+-- p 'Miso.JSON..!=' "anon"        -- provide a default for a Maybe parser
+-- @
+--
+-- == Pretty-Printing
+--
+-- @
+-- 'Miso.JSON.encodePretty'  value          -- indented with 'Miso.JSON.defConfig' (2-space indent)
+-- 'Miso.JSON.encodePretty'' config value   -- indented with custom 'Miso.JSON.Config'
+-- @
+--
+-- == @miso-aeson@
+--
+-- If you prefer to use the [aeson](https://hackage.haskell.org/package/aeson) library directly,
+-- the [miso-aeson](https://github.com/haskell-miso/miso-aeson) package provides a compatibility
+-- shim that bridges @aeson@\'s 'Data.Aeson.ToJSON' \/ 'Data.Aeson.FromJSON' instances with miso\'s
+-- event decoder and fetch API, so existing @aeson@-derived instances can be used without rewriting them.
+--
+-- = Styles
+--
+-- Miso does not prescribe a single CSS strategy. Three approaches work out of the box:
+--
+-- == 1. Structured DSL ("Miso.CSS")
+--
+-- 'Miso.CSS.style_' takes a list of @'Style'@ values (which are @('MisoString', 'MisoString')@ pairs).
+-- Miso manages individual properties on the @DOMRef@, merging and diffing them efficiently:
+--
+-- @
+-- import qualified "Miso.CSS" as CSS
+-- import           "Miso.CSS.Color" ('Miso.CSS.Color.RGB'(..))
+--
+-- 'Miso.Html.Element.div_'
+--   [ CSS.'Miso.CSS.style_'
+--       [ CSS.'Miso.CSS.display' "flex"
+--       , CSS.'Miso.CSS.flexDirection' "column"
+--       , CSS.'Miso.CSS.backgroundColor' ('Miso.CSS.Color.RGB' 30 30 30)
+--       , CSS.'Miso.CSS.color' ('Miso.CSS.Color.RGB' 255 255 255)
+--       ]
+--   ]
+--   []
+-- @
+--
+-- Custom properties can be constructed with the @=:@ operator (re-exported from "Miso.Util"):
+--
+-- @
+-- "user-select" @=:@ "none"
+-- @
+--
+-- == 2. Inline string ('Miso.CSS.styleInline_')
+--
+-- For simple or dynamic style strings, 'Miso.CSS.styleInline_' sets the element's @style@
+-- attribute as a raw string:
+--
+-- @
+-- CSS.'Miso.CSS.styleInline_' "display:flex; gap:8px; padding:16px"
+-- @
+--
+-- == 3. External stylesheets
+--
+-- Link external CSS files from the @\<head\>@ via the 'styles' field on t'Miso.Types.Component'
+-- (see the __Development__ section), or include them in your HTML template directly.
+-- This is the most common approach for production apps using Tailwind, Bootstrap, etc.
+--
+-- See [miso-ui](https://ui.haskell-miso.org) for a larger example.
+--
+-- = Development
+--
+-- When developing miso applications interactively it is possible to append 'styles' and 'scripts' to the @\<head\>@ portion of
+-- the page when the t'Miso.Types.Component' mounts. This is a convenience only meant to be used in development. We recommend guarding the usage behind a flag.
+--
+-- @
+-- main :: 'IO' ()
+-- main = 'startApp' 'Miso.Event.Types.defaultEvents' app
+--  where
+--    app = counter
+-- #ifdef INTERACTIVE
+--      { 'scripts' = [ 'Src' "https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js" (@False@ :: 'CacheBust') ]
+--      , 'styles' = [ 'Href' "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" (@False@ :: 'CacheBust')  ]
+--      }
+-- #endif
+-- @
+--
+-- See the [miso-sampler](https://github.com/haskell-miso/miso-sampler) repository for more information.
+--
+-- = Debugging
+--
+-- Sometimes things can go wrong. Common errors like using @onClick@ but not listening for the 'click' event are common.
+-- These are errors that cannot be caught statically (unless we use a dependently-typed language like [Idris](https://idris-lang.org)). These can be detected by enabling 'DebugAll'. Currently, debugging event delegation and page hydration is supported.
+--
+-- * 'DebugHydrate'
+-- * 'DebugEvents'
+--
+-- @
+-- counter { 'logLevel' = 'DebugAll' }
+-- @
+--
+-- = Internals
+--
+-- Internally miso uses a global event queue and a scheduler to process all
+-- events raised by t'Miso.Types.Component' throughout the lifetime of an application.
+-- Events are processed in FIFO order, batched by the t'Miso.Types.Component' that raised them.
+--
+-- * __Event queue__: All actions dispatched via a 'Sink' (from event handlers,
+--   subscriptions, or 'io' callbacks) are enqueued and drained by the scheduler.
+--
+-- * __Scheduler__: The scheduler pulls actions off the queue one batch at a time,
+--   runs the @update@ function for each, collects the resulting 'IO' work, and
+--   executes it. Rendering (VDOM diff + patch) is triggered after each batch.
+--
+-- * __'Waiter'__: A 'Miso.Concurrent.Waiter' is a synchronization primitive used
+--   internally to coordinate the event loop — it blocks the scheduler thread until
+--   new work arrives, avoiding busy-waiting.
+--
+-- * __Event delegation__: Rather than attaching listeners to individual DOM nodes,
+--   miso attaches a single capture and a single bubble listener to @\<body\>@.
+--   Incoming events are routed through the virtual DOM tree to the matching handler.
+--   This minimises listener churn when the VDOM is patched.
+--
+-- * __VDOM diffing__: The internal diff algorithm compares old and new
+--   'View' trees and emits the minimal set of DOM mutations. Keyed children (see
+--   the t'Key' section) significantly speed up child list reconciliation.
+--
+-- = Prerendering
+--
+-- Prerendering is the process of delivering HTML from a web server before the client loads and performs any drawing to the page. In miso it comes in two flavors, static
+-- or dynamic prerendering. Static prerendering assumes no model state needs to be shared between the server and client. Dynamic uses 'hydrateModel' to share @model@ state.
+--
+-- == Static prerendering
+--
+-- miso provides the 'prerender' and 'miso' functions to facilitate static prerendering. Any page can be generated from a miso 'View' using the 'Miso.Html.Render.toHtml' instance.
+--
+-- A simple example of static prerendering would be an @index.html@ page with some HTML
+--
+-- @
+-- echo "\<html\>\<head\>\<\/head\>\<body\>hello world\<\/body\>\<html\>" > index.html
+-- @
+--
+-- And a miso application that looks like:
+--
+-- @
+-- main :: IO ()
+-- main = 'prerender' 'Miso.Event.Types.defaultEvents' $ ('Miso.Types.component' () 'noop' $ \\_ () -> "hello world") { 'logLevel' = 'DebugHydrate' }
+-- @
+--
+-- Assuming the JS / WASM payload and @index.html@ are delivered together from the web server, the console should output below
+--
+-- > [DEBUG_HYDRATE] Successfully prerendered page
+--
+-- See the [miso](https://haskell-miso.org) website console for an example usage of static prerendering with 'miso' and [miso-ui](https://ui.haskell-miso.org) for 'prerender' usage.
+--
+-- == Dynamic prerendering
+--
+-- Dynamic prerendering shares @model@ state between the server and client so the
+-- client can hydrate from a meaningful initial state rather than a blank model.
+-- The @-fssr@ Cabal flag must be enabled when compiling the server.
+--
+-- The 'hydrateModel' field on t'Miso.Types.Component' is @Maybe (IO model)@. When set, the
+-- action runs once at hydration time to produce the initial model; it is ignored
+-- on subsequent remounts. A typical pattern embeds the model as JSON in the
+-- server response and reads it back on the client via the JS DSL:
+--
+-- @
+-- myComp :: 'App' Model Action
+-- myComp = ('Miso.Types.component' defaultModel updateModel viewModel)
+--   { 'hydrateModel' = Just $ do
+--       val <- 'Miso.DSL.jsg' "window" 'Miso.DSL.!' "__initialModel__"
+--       'Miso.DSL.fromJSValUnchecked' val
+--   }
+-- @
+--
+-- On the server, populate @window.__initialModel__@ by embedding the JSON
+-- in a @\<script\>@ tag alongside the rendered HTML:
+--
+-- @
+-- serverView :: context -> props -> Model -> 'View' context Action
+-- serverView _ _ m =
+--   'Miso.Html.Element.div_' []
+--     [ 'Miso.Html.Element.script_' [] [ 'textRaw' ("window.__initialModel__ = " \<\> 'Miso.JSON.encode' m) ]
+--     , appView m
+--     ]
+-- @
+--
+-- When 'hydrateModel' is @Nothing@, the static @model@ field is used instead —
+-- equivalent to static prerendering.
+--
+-----------------------------------------------------------------------------
+module Miso
+  ( -- * API
+    -- ** Miso
+    miso
+  , misoWithContext
+  , prerender
+  , prerenderWithContext
+  , (🍜)
+    -- ** App
+  , App
+  , startApp
+  , startAppWithContext
+    -- | Seed the global React-style @context@ with a value, outside of the
+    -- normal 'startAppWithContext' flow.
+    --
+    -- 'startAppWithContext' already seeds the context before the first draw, so
+    -- client applications never call 'setContext' directly. It exists for
+    -- __server-side rendering__.
+    --
+    -- During SSR you typically serialize a t'Miso.Types.View' to HTML with
+    -- 'Miso.Html.Render.toHtml' without ever starting the runtime. In that path
+    -- the global context cell is still @undefined@. For the common
+    -- @context ~ ()@ case this is harmless — 'Miso.Types.view' ignores its
+    -- @context@ argument, so the thunk is never forced. But if any
+    -- t'Miso.Types.VComp' in the tree has a 'Miso.Types.view' that inspects a
+    -- non-trivial @context@, forcing it during rendering raises an exception.
+    -- Call 'setContext' first to seed the value SSR should render against:
+    --
+    -- @
+    -- main :: 'IO' ()
+    -- main = do
+    --   'setContext' Dark
+    --   Data.ByteString.Lazy.putStr ('Miso.Html.Render.toHtml' (view Dark () model))
+    -- @
+  , setContext
+  , renderApp
+    -- ** Component
+  , Component (..)
+  , component
+  , vcomp
+  , (+>)
+  , mount_
+  , mountUseContext
+  , mountWithProps
+    -- ** View
+  , vnode
+  , vtext
+  , text_
+  , text
+  , vfrag
+  , vfrag_
+  , fragment
+  , fragment_
+    -- ** Sink
+  , withSink
+  , Sink
+    -- ** Mail
+  , mail
+  , checkMail
+  , mailParent
+  , mailChildren
+  , mailDescendants
+  , mailAncestors
+  , broadcast
+    -- ** Subscriptions
+  , startSub
+  , stopSub
+  , Sub
+    -- ** Effect
+  , issue
+  , batch
+  , io
+  , io_
+  , sync
+  , sync_
+  , for
+  -- ** JS file embedding
+#ifdef WASM
+  , evalFile
+#endif
+  , withJS
+    -- * DSL
+    -- | A JavaScript DSL for easy FFI interoperability
+  , module Miso.DSL
+    -- * Effect
+    -- | 'Effect', 'Sub', and 'Sink' types for defining update functions and subscriptions.
+  , module Miso.Effect
+    -- * Event
+    -- | Functions for specifying component lifecycle events and event handlers.
+  , module Miso.Event
+    -- * Fetch
+    -- | Interface to the Fetch API for making HTTP requests. Each function has an
+    -- asynchronous, callback-based 'Effect' variant and a synchronous, @_@-suffixed 'IO' variant.
+  , module Miso.Fetch
+    -- * PubSub
+    -- | Publish / Subscribe primitives for communication between components.
+  , module Miso.PubSub
+    -- * Property
+    -- | Construct custom properties on DOM elements.
+  , module Miso.Property
+    -- * Reload
+    -- | Support for clearing the page during live-reloading w/ WASM browser mode.
+  , module Miso.Reload
+    -- * Subscriptions
+    -- | Subscriptions for external events (mouse, keyboard, window, history, etc.).
+  , module Miso.Subscription
+    -- * Storage
+    -- | Web Storage API (Local and Session storage) interface.
+  , module Miso.Storage
+    -- * Types
+    -- | Core types for Miso applications.
+  , module Miso.Types
+    -- * Util
+    -- | Utility functions for views, parsing, and general purpose combinators.
+  , module Miso.Util
+    -- * FFI
+    -- | Foreign Function Interface (FFI) utilities for interacting with JavaScript.
+  , module Miso.FFI
+    -- * State management
+    -- | State management for Miso applications.
+  , module Miso.State
+    -- * Native mobile
+    -- | Cross thread environment detection
+  , mts
+  , bts
+  , web
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.Effect
+import           Miso.Event
+import           Miso.Fetch
+import           Miso.FFI
+import qualified Miso.FFI.Internal as FFI
+import           Miso.Property
+import           Miso.PubSub
+import           Miso.Reload
+import           Miso.Runtime
+import           Miso.State
+import           Miso.Storage
+import           Miso.Subscription
+import           Miso.Types
+import           Miso.Util
+----------------------------------------------------------------------------
+#ifdef NATIVE
+import           Miso.JSON (ToJSON, FromJSON)
+#endif
+----------------------------------------------------------------------------
+-- | Runs an @miso@ application.
+--
+-- Assumes the pre-rendered DOM is already present.
+-- Always mounts to \<body\>. Copies page into the virtual DOM.
+--
+-- @
+-- main :: 'IO' ()
+-- main = 'miso' 'Miso.Event.Types.defaultEvents' app
+-- @
+--
+-- __Warning__: if compiling with the @native@ Cabal flag, use
+-- 'Miso.Native.native' \/ 'Miso.Native.nativeWithContext' instead of this —
+-- it mounts with no 'GHC.StaticPtr.StaticKey', which is needed for
+-- cross-thread mounting, cross-thread effect handling, and main-thread events.
+miso
+#ifdef NATIVE
+  :: (Eq model, ToJSON model, ToJSON action, FromJSON model, FromJSON action)
+#else
+  :: Eq model
+#endif
+  => Events
+  -- ^ Globally delegated Events
+  -> (URI -> Component () () model action)
+  -- ^ The Component application, with the current URI as an argument
+  -> IO ()
+miso events f = do
+  comp_ <- f <$> getURI
+  initComponent events Hydrate False () (comp_ { mountPoint = Nothing })
+    Nothing () Nothing
+#ifdef NATIVE
+{-# WARNING miso "[NATIVE] If compiling with the 'native' Cabal flag, use 'Miso.Native.native' / 'Miso.Native.nativeWithContext' instead of 'miso' — it mounts with no StaticKey, which is needed for cross-thread mounting, cross-thread effect handling, and main-thread events." #-}
+#endif
+----------------------------------------------------------------------------
+-- | Like 'miso', except discards the 'Miso.Router.URI' argument.
+--
+-- Use this function if you'd like to prerender, but not use navigation.
+--
+-- @
+-- main :: 'IO' ()
+-- main = 'prerender' 'Miso.Event.Types.defaultEvents' app
+-- @
+--
+-- __Warning__: if compiling with the @native@ Cabal flag, use
+-- 'Miso.Native.native' \/ 'Miso.Native.nativeWithContext' instead of this —
+-- it mounts with no 'GHC.StaticPtr.StaticKey', which is needed for
+-- cross-thread mounting, cross-thread effect handling, and main-thread events.
+prerender
+#ifdef NATIVE
+  :: (Eq model, ToJSON model, ToJSON action, FromJSON model, FromJSON action)
+#else
+  :: Eq model
+#endif
+  => Events
+  -- ^ Globally delegated 'Events'
+  -> Component () () model action
+  -- ^ t'Miso.Types.Component' application
+  -> IO ()
+prerender events comp_ =
+  initComponent events Hydrate False () comp_ { mountPoint = Nothing }
+    Nothing () Nothing
+#ifdef NATIVE
+{-# WARNING prerender "[NATIVE] If compiling with the 'native' Cabal flag, use 'Miso.Native.native' / 'Miso.Native.nativeWithContext' instead of 'prerender' — it mounts with no StaticKey, which is needed for cross-thread mounting, cross-thread effect handling, and main-thread events." #-}
+#endif
+-----------------------------------------------------------------------------
+-- | Like 'miso', but seeds the global React-style @context@ with an
+-- initial value before hydrating. This is the hydration counterpart of
+-- 'startAppWithContext'.
+--
+-- @
+-- main :: 'IO' ()
+-- main = 'misoWithContext' 'Miso.Event.Types.defaultEvents' Light app
+--
+-- data Theme = Light | Dark deriving (Show, Eq)
+-- @
+--
+-- @since 1.13.0.0
+misoWithContext
+#ifdef NATIVE
+  :: (Eq model, ToJSON model, ToJSON action, FromJSON model, FromJSON action, Eq context)
+#else
+  :: (Eq model, Eq context)
+#endif
+  => Events
+  -- ^ Globally delegated Events
+  -> context
+  -- ^ Initial global @context@
+  -> (URI -> Component context () model action)
+  -- ^ The Component application, with the current URI as an argument
+  -> IO ()
+misoWithContext events initialContext f = do
+  comp_ <- f <$> getURI
+  initComponent events Hydrate False initialContext (comp_ { mountPoint = Nothing })
+    Nothing () Nothing
+#ifdef NATIVE
+{-# WARNING misoWithContext "[NATIVE] If compiling with the 'native' Cabal flag, use 'Miso.Native.nativeWithContext' instead of 'misoWithContext' — it mounts with no StaticKey, which is needed for cross-thread mounting, cross-thread effect handling, and main-thread events." #-}
+#endif
+-----------------------------------------------------------------------------
+-- | Like 'prerender', but seeds the global React-style @context@ with an
+-- initial value before hydrating.
+--
+-- @since 1.13.0.0
+prerenderWithContext
+#ifdef NATIVE
+  :: (Eq model, ToJSON model, ToJSON action, FromJSON model, FromJSON action, Eq context)
+#else
+  :: (Eq model, Eq context)
+#endif
+  => Events
+  -- ^ Globally delegated 'Events'
+  -> context
+  -- ^ Initial global @context@
+  -> Component context () model action
+  -- ^ t'Miso.Types.Component' application
+  -> IO ()
+prerenderWithContext events initialContext comp_ =
+  initComponent events Hydrate False initialContext comp_ { mountPoint = Nothing }
+    Nothing () Nothing
+#ifdef NATIVE
+{-# WARNING prerenderWithContext "[NATIVE] If compiling with the 'native' Cabal flag, use 'Miso.Native.nativeWithContext' instead of 'prerenderWithContext' — it mounts with no StaticKey, which is needed for cross-thread mounting, cross-thread effect handling, and main-thread events." #-}
+#endif
+-----------------------------------------------------------------------------
+-- | Like 'miso', except it does not perform page hydration.
+--
+-- This function draws your application on an empty <body>
+--
+-- You will most likely want to use this function for your application
+-- unless you are using prerendering.
+--
+-- @
+--
+-- main :: 'IO' ()
+-- main = 'startApp' 'Miso.Event.Types.defaultEvents' app
+-- @
+--
+-- __Warning__: if compiling with the @native@ Cabal flag, use
+-- 'Miso.Native.native' \/ 'Miso.Native.nativeWithContext' instead of this —
+-- it mounts with no 'GHC.StaticPtr.StaticKey', which is needed for
+-- cross-thread mounting, cross-thread effect handling, and main-thread events.
+startApp
+#ifdef NATIVE
+  :: (Eq model, ToJSON model, ToJSON action, FromJSON model, FromJSON action)
+#else
+  :: Eq model
+#endif
+  => Events
+  -- ^ Globally delegated 'Events'
+  -> Component () () model action
+  -- ^ t'Miso.Types.Component' application
+  -> IO ()
+startApp events comp_ = initComponent events Draw False () comp_ Nothing () Nothing
+#ifdef NATIVE
+{-# WARNING startApp "[NATIVE] If compiling with the 'native' Cabal flag, use 'Miso.Native.native' / 'Miso.Native.nativeWithContext' instead of 'startApp' — it mounts with no StaticKey, which is needed for cross-thread mounting, cross-thread effect handling, and main-thread events." #-}
+#endif
+-----------------------------------------------------------------------------
+-- | Like 'startApp', but seeds the global React-style @context@ with an
+-- initial value.
+--
+-- The @context@ can be read in every t'Component'\'s 'Miso.Types.view' and
+-- mutated from any t'Component'\'s @update@ via 'Miso.Effect.modifyContext' \/
+-- 'Miso.Effect.putContext'. Any t'Miso.Types.Component' with @useContext = True@ is
+-- re-rendered whenever the context changes.
+--
+-- @
+-- main :: 'IO' ()
+-- main = 'startAppWithContext' 'Miso.Event.Types.defaultEvents' Light app
+--
+-- data Theme = Light | Dark deriving (Show, Eq)
+-- @
+--
+-- For server-side rendering (where the runtime is never started) seed the
+-- context with 'setContext' before serializing the 'Miso.Types.View'.
+--
+-- __Warning__: if compiling with the @native@ Cabal flag, use
+-- 'Miso.Native.nativeWithContext' instead of this — it mounts with no
+-- 'GHC.StaticPtr.StaticKey', which is needed for cross-thread mounting,
+-- cross-thread effect handling, and main-thread events.
+--
+-- @since 1.13.0.0
+startAppWithContext
+#ifdef NATIVE
+  :: (Eq model, ToJSON model, ToJSON action, FromJSON model, FromJSON action, Eq context)
+#else
+  :: (Eq model, Eq context)
+#endif
+  => Events
+  -- ^ Globally delegated 'Events'
+  -> context
+  -- ^ Initial global @context@
+  -> Component context () model action
+  -- ^ t'Miso.Types.Component' application
+  -> IO ()
+startAppWithContext events initialContext comp_ =
+  initComponent events Draw False initialContext comp_ Nothing () Nothing
+#ifdef NATIVE
+{-# WARNING startAppWithContext "[NATIVE] If compiling with the 'native' Cabal flag, use 'Miso.Native.nativeWithContext' instead of 'startAppWithContext' — it mounts with no StaticKey, which is needed for cross-thread mounting, cross-thread effect handling, and main-thread events." #-}
+#endif
+-----------------------------------------------------------------------------
+-- | Alias for 'Miso.miso'.
+(🍜)
+#ifdef NATIVE
+  :: (Eq model, ToJSON model, ToJSON action, FromJSON model, FromJSON action)
+#else
+  :: Eq model
+#endif
+  => Events
+  -- ^ Globally delegated 'Events'
+  -> (URI -> Component () () model action)
+  -- ^ t'Miso.Types.Component' application, with the current URI as an argument
+  -> IO ()
+(🍜) = miso
+----------------------------------------------------------------------------
+-- | Runs a 'miso' application, but with a custom rendering engine.
+--
+-- The 'MisoString' specified here is the variable name of a globally-scoped
+-- JS object that implements the context interface per @ts\/miso\/context\/dom.ts@
+-- This is necessary for native support.
+--
+-- It is expected to be run on an empty @\<body\>@
+--
+-- @
+-- main :: IO ()
+-- main = 'renderApp' 'Miso.Event.Types.defaultEvents' "my-context" app
+-- @
+renderApp
+#ifdef NATIVE
+  :: (Eq model, ToJSON model, ToJSON action, FromJSON model, FromJSON action)
+#else
+  :: Eq model
+#endif
+  => Events
+  -- ^ Globally delegated 'Events'
+  -> MisoString
+  -- ^ Name of the JS object that contains the drawing context
+  -> Component () () model action
+  -- ^ t'Miso.Types.Component' application
+  -> IO ()
+renderApp events renderer comp_ = do
+  FFI.setDrawingContext renderer
+  initComponent events Draw False () comp_ Nothing () Nothing
+----------------------------------------------------------------------------
diff --git a/src/Miso/CSS.hs b/src/Miso/CSS.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/CSS.hs
@@ -0,0 +1,2024 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.CSS
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.CSS" is a typed DSL for constructing CSS properties, stylesheets,
+-- animations, and media queries in miso applications. Two styling modes are
+-- available:
+--
+-- * __Structured styles__ ('style_'): CSS properties are stored in a
+--   'Data.Map.Map' and diffed by the virtual DOM, so only changed properties
+--   are written to the DOM node on each render. Prefer this for dynamic styles.
+--
+-- * __Inline string styles__ ('styleInline_'): a raw CSS string is set on the
+--   @style@ attribute verbatim and is not diffed. Useful for static one-liners
+--   or values that the structured combinators do not yet cover.
+--
+-- = Quick start
+--
+-- @
+-- import qualified "Miso.CSS"       as CSS
+-- import           "Miso.CSS.Color" ('Miso.CSS.Color.red', 'Miso.CSS.Color.rgba')
+--
+-- myView :: 'Miso.Types.View' Model Action
+-- myView =
+--   'Miso.Html.Element.div_'
+--     [ CSS.'Miso.CSS.style_'
+--         [ CSS.'Miso.CSS.display'        "flex"
+--         , CSS.'Miso.CSS.flexDirection'  "column"
+--         , CSS.'Miso.CSS.gap'            (CSS.'Miso.CSS.px' 8)
+--         , CSS.'Miso.CSS.padding'        (CSS.'Miso.CSS.px' 16)
+--         , CSS.'Miso.CSS.backgroundColor' 'Miso.CSS.Color.red'
+--         , CSS.'Miso.CSS.borderRadius'   (CSS.'Miso.CSS.px' 4)
+--         ]
+--     ] [ 'Miso.text' "Hello, miso!" ]
+-- @
+--
+-- = Global Stylesheets
+--
+-- Construct a t'StyleSheet' with 'sheet_' and 'selector_', then render it to
+-- a 'MisoString' with 'renderStyleSheet' for injection into a @\<style\>@ tag:
+--
+-- @
+-- mySheet :: t'StyleSheet'
+-- mySheet = 'sheet_'
+--   [ 'selector_' "body"
+--       [ CSS.'margin'     (CSS.'px' 0)
+--       , CSS.'fontFamily' "sans-serif"
+--       ]
+--   , 'selector_' ".card"
+--       [ CSS.'backgroundColor' ('rgba' 255 255 255 0.9)
+--       , CSS.'borderRadius'    (CSS.'px' 4)
+--       ]
+--   ]
+-- @
+--
+-- = Animations and Media Queries
+--
+-- @
+-- myAnimation :: t'Styles'
+-- myAnimation = 'keyframes_' "slide-in"
+--   [ 'from_' [ CSS.'transform' "translateX(-100%)" ]
+--   , 'to_'   [ CSS.'transform' "translateX(0)" ]
+--   ]
+--
+-- myMedia :: t'Styles'
+-- myMedia = 'media_' ('screen_' \`and_\` 'minWidth_' (CSS.'px' 480))
+--   [ 'rule_' "header" [ CSS.'height' "auto" ]
+--   , 'rule_' "nav"    [ CSS.'display' "flex" ]
+--   ]
+-- @
+--
+-- = CSS Units
+--
+-- Use the unit helpers to build length and time values:
+-- 'px', 'pt', 'em', 'rem', 'vh', 'vw', 'pct', 'ms', 's', 'deg', 'rad', 'turn'.
+--
+-- @
+-- CSS.'style_'
+--   [ CSS.'width'      (CSS.'pct' 100)
+--   , CSS.'fontSize'   (CSS.'rem' 1.5)
+--   , CSS.'transition' ("opacity " <> CSS.'ms' 300 <> " ease")
+--   ]
+-- @
+--
+-- = Colors
+--
+-- The 'Color' type and named colors are re-exported from "Miso.CSS.Color":
+--
+-- @
+-- CSS.'backgroundColor' (CSS.'rgb' 30 144 255)
+-- CSS.'color'           CSS.'white'
+-- CSS.'borderColor'     (CSS.'rgba' 0 0 0 0.2)
+-- @
+--
+-- __Note:__ 'color' in this module and 'Miso.Canvas.color' share the same
+-- name but have different types. Always qualify @import qualified Miso.CSS as CSS@
+-- when also importing "Miso.Canvas".
+--
+-----------------------------------------------------------------------------
+module Miso.CSS
+  ( -- *** Types
+    module Miso.CSS.Types
+    -- *** Smart Constructor
+  , style_
+  , styleInline_
+  , sheet_
+  , selector_
+    -- *** Render
+  , renderStyleSheet
+    -- *** Combinators
+  , alignContent
+  , alignItems
+  , alignSelf
+  , animationDelay
+  , animationDirection
+  , animationDuration
+  , animationFillMode
+  , animationIterationCount
+  , animation
+  , animationName
+  , animationPlayState
+  , animationTimingFunction
+  , aspectRatio
+  , backgroundClip
+  , backgroundColor
+  , backgroundImage
+  , background
+  , backgroundOrigin
+  , backgroundPosition
+  , backgroundRepeat
+  , backgroundSize
+  , borderBottomColor
+  , borderBottomLeftRadius
+  , borderBottom
+  , borderBottomRightRadius
+  , borderBottomStyle
+  , borderBottomWidth
+  , borderCollapse
+  , borderColor
+  , borderEndEndRadius
+  , borderEndStartRadius
+  , borderInlineEndColor
+  , borderInlineEndStyle
+  , borderInlineEndWidth
+  , borderInlineStartColor
+  , borderInlineStartStyle
+  , borderInlineStartWidth
+  , borderLeftColor
+  , borderLeft
+  , borderLeftStyle
+  , borderLeftWidth
+  , border
+  , borderRadius
+  , borderRightColor
+  , borderRight
+  , borderRightStyle
+  , borderRightWidth
+  , borderStartEndRadius
+  , borderStartStartRadius
+  , borderStyle
+  , borderTopColor
+  , borderTopLeftRadius
+  , borderTop
+  , borderTopRightRadius
+  , borderTopStyle
+  , borderTopWidth
+  , borderWidth
+  , bottom
+  , boxShadow
+  , boxSizing
+  , clipPath
+  , accentColor
+  , appearance
+  , backdropFilter
+  , caretColor
+  , color
+  , columnGap
+  , cursor
+  , direction
+  , display
+  , fill
+  , filter
+  , flexBasis
+  , flexDirection
+  , flexFlow
+  , flexGrow
+  , flex
+  , flexShrink
+  , flexWrap
+  , fontFamily
+  , fontSize
+  , fontStretch
+  , fontStyle
+  , fontVariant
+  , fontWeight
+  , gap
+  , gridAutoColumns
+  , gridAutoFlow
+  , gridAutoRows
+  , gridColumn
+  , gridColumnEnd
+  , gridColumnSpan
+  , gridColumnStart
+  , gridRow
+  , gridRowEnd
+  , gridRowSpan
+  , gridRowStart
+  , gridTemplateColumns
+  , gridTemplateRows
+  , height
+  , imageRendering
+  , insetInlineEnd
+  , insetInlineStart
+  , justifyContent
+  , justifyItems
+  , justifySelf
+  , left
+  , letterSpacing
+  , linearCrossGravity
+  , linearDirection
+  , linearGravity
+  , linearLayoutGravity
+  , linearWeight
+  , linearWeightSum
+  , lineHeight
+  , marginBottom
+  , marginInlineEnd
+  , marginInlineStart
+  , marginLeft
+  , margin
+  , marginRight
+  , marginTop
+  , maskImage
+  , mask
+  , maxHeight
+  , maxWidth
+  , minHeight
+  , minWidth
+  , mixBlendMode
+  , objectFit
+  , objectPosition
+  , opacity
+  , order
+  , outline
+  , outlineColor
+  , outlineOffset
+  , outlineStyle
+  , outlineWidth
+  , overflow
+  , overflowX
+  , overflowY
+  , overscrollBehavior
+  , paddingBottom
+  , paddingInlineEnd
+  , paddingInlineStart
+  , paddingLeft
+  , padding
+  , paddingRight
+  , paddingTop
+  , perspective
+  , pointerEvents
+  , position
+  , relativeAlignBottom
+  , relativeAlignInlineEnd
+  , relativeAlignInlineStart
+  , relativeAlignLeft
+  , relativeAlignRight
+  , relativeAlignTop
+  , relativeBottomOf
+  , relativeCenter
+  , relativeId
+  , relativeInlineEndOf
+  , relativeInlineStartOf
+  , relativeLayoutOnce
+  , relativeLeftOf
+  , relativeRightOf
+  , relativeTopOf
+  , resize
+  , right
+  , rowGap
+  , scrollBehavior
+  , stroke
+  , strokeWidth
+  , textAlign
+  , textDecoration
+  , textIndent
+  , textOverflow
+  , textShadow
+  , textStrokeColor
+  , textStroke
+  , textStrokeWidth
+  , textTransform
+  , top
+  , transform
+  , transforms
+  , transformOrigin
+    -- *** Transform functions
+  , translate
+  , translateX
+  , translateY
+  , translateZ
+  , translate3d
+  , rotate
+  , rotateX
+  , rotateY
+  , rotateZ
+  , rotate3d
+  , scale
+  , scaleXY
+  , scale3d
+  , scaleX
+  , scaleY
+  , scaleZ
+  , perspectiveFn
+  , matrix3d
+  , skew
+  , skewX
+  , skewY
+  , transitionDelay
+  , transitionDuration
+  , transition
+  , transition_
+  , transitionProperty
+  , transitionTimingFunction
+  , cubicBezier
+  , userSelect
+  , verticalAlign
+  , visibility
+  , whiteSpace
+  , width
+  , willChange
+  , wordBreak
+  , xAutoFontSize
+  , xAutoFontSizePresetSizes
+  , xHandleColor
+  , xHandleSize
+  , zIndex
+  -- *** Colors
+  , module Miso.CSS.Color
+  -- *** Units
+  , px
+  , ppx
+  , pct
+  , pt
+  , vw
+  , vh
+  , deg
+  , turn
+  , rad
+  , rpx
+  , rem
+  , em
+  , s
+  , ms
+  -- *** Misc
+  , url
+  , matrix
+  -- *** Animation
+  , keyframes_
+  , from_
+  , to_
+  , at
+  -- *** Media Queries
+  , media_
+  , rule_
+    -- *** Media query combinators
+  , screen_
+  , print_
+  , all_
+  , and_
+  , or_
+  , not_
+  , minWidth_
+  , maxWidth_
+  , minHeight_
+  , maxHeight_
+  , orientation_
+  , prefersColorScheme_
+  , prefersReducedMotion_
+  , hover_
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+import           Miso.String (MisoString)
+import qualified Miso.String as MS
+import           Miso.CSS.Color
+import           Miso.CSS.Types
+import           Miso.Property
+import           Miso.Types (Attribute)
+import qualified Miso.Types as MT
+import           Miso.Util ((=:))
+-----------------------------------------------------------------------------
+import           Prelude hiding (filter, rem)
+-----------------------------------------------------------------------------
+-- | Font sizing in terms of *pt*
+--
+-- @
+-- >>> pt 10
+-- "10pt"
+-- @
+--
+pt :: Int -> MisoString
+pt x = MS.ms x <> "pt"
+-----------------------------------------------------------------------------
+-- | Font sizing in terms of *px*
+--
+-- @
+-- >>> px 10
+-- "10px"
+-- @
+--
+px :: Int -> MisoString
+px x = MS.ms x <> "px"
+-----------------------------------------------------------------------------
+-- | Degree specification
+--
+-- @
+-- >>> deg 10
+-- "10deg"
+-- @
+--
+deg :: Double -> MisoString
+deg x = MS.ms x <> "deg"
+-----------------------------------------------------------------------------
+-- | Turn constructor, useful for specifying rotations
+--
+-- @
+-- >>> turn 10.0
+-- "10.0turn"
+-- @
+--
+turn :: Double -> MisoString
+turn x = MS.ms x <> "turn"
+-----------------------------------------------------------------------------
+-- | Radial constructor
+--
+-- @
+-- >>> rad 10.0
+-- "10.0rad"
+-- @
+--
+rad :: Double -> MisoString
+rad x = MS.ms x <> "rad"
+-----------------------------------------------------------------------------
+-- | Responsive pixel sizing, *rpx*
+--
+-- @
+-- >>> rpx 10.0
+-- "10.0rpx"
+-- @
+--
+rpx :: Double -> MisoString
+rpx x = MS.ms x <> "rpx"
+-----------------------------------------------------------------------------
+-- | Relative *em* sizing
+--
+-- @
+-- >>> rem 10.0
+-- "10.0rem"
+-- @
+--
+rem :: Double -> MisoString
+rem x = MS.ms x <> "rem"
+-----------------------------------------------------------------------------
+-- | *em* sizing
+--
+-- @
+-- >>> em 10.0
+-- "10.0em"
+-- @
+--
+em :: Double -> MisoString
+em x = MS.ms x <> "em"
+-----------------------------------------------------------------------------
+-- | Viewport height
+--
+-- @
+-- >>> vh 10.0
+-- "10.0vh"
+-- @
+--
+vh :: Double -> MisoString
+vh x = MS.ms x <> "vh"
+-----------------------------------------------------------------------------
+-- | Viewport width
+--
+-- @
+-- >>> vw 10.0
+-- "10.0vw"
+-- @
+--
+vw :: Double -> MisoString
+vw x = MS.ms x <> "vw"
+-----------------------------------------------------------------------------
+-- | Duration in seconds
+--
+-- @
+-- >>> s 10.0
+-- "10.0s"
+-- @
+--
+s :: Double -> MisoString
+s x = MS.ms x <> "s"
+-----------------------------------------------------------------------------
+-- | Duration in milliseconds
+--
+-- @
+-- >>> ms 10.0
+-- "10.0ms"
+-- @
+--
+ms :: Double -> MisoString
+ms x = MS.ms x <> "ms"
+-----------------------------------------------------------------------------
+-- | Wraps a value in the CSS @url()@ function, used for background images and similar.
+--
+-- @
+-- >>> url "dog.png"
+-- "url(dog.png)"
+-- @
+--
+-- @
+-- backgroundImage (url "banner.png")
+-- @
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/CSS/url>
+--
+url :: MisoString -> MisoString
+url x = "url(" <> x <> ")"
+-----------------------------------------------------------------------------
+-- | Constructs a 2D CSS transformation matrix string: @matrix(a, b, c, d, tx, ty)@.
+--
+-- The six parameters define a 2D affine transformation: @a@ and @d@ scale,
+-- @b@ and @c@ skew, and @tx@\/@ty@ translate.
+--
+-- @
+-- transform (matrix 1 0 0 1 50 100)  -- translate by (50, 100)
+-- @
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix>
+--
+matrix
+  :: Double  -- ^ a  — scale x
+  -> Double  -- ^ b  — skew y
+  -> Double  -- ^ c  — skew x
+  -> Double  -- ^ d  — scale y
+  -> Double  -- ^ tx — translate x
+  -> Double  -- ^ ty — translate y
+  -> MisoString
+matrix a b c d tx ty = "matrix(" <> values <> ")"
+  where
+    values =
+      MS.intercalate ","
+      [ MS.ms a
+      , MS.ms b
+      , MS.ms c
+      , MS.ms d
+      , MS.ms tx
+      , MS.ms ty
+      ]
+-----------------------------------------------------------------------------
+-- | Percentage unit.
+--
+-- @
+-- >>> pct 50.0
+-- "50.0%"
+-- @
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/CSS/percentage>
+pct :: Double -> MisoString
+pct x = MS.ms x <> "%"
+-----------------------------------------------------------------------------
+-- | Physical pixel unit (@ppx@), used in some native\/mobile rendering contexts.
+--
+-- @
+-- >>> ppx 2.0
+-- "2.0ppx"
+-- @
+--
+ppx :: Double -> MisoString
+ppx x = MS.ms x <> "ppx"
+-----------------------------------------------------------------------------
+-- | Constructs a t'Styles' entry pairing a CSS selector with a list of properties.
+-- Combine multiple entries with 'sheet_'.
+--
+-- @
+-- sheet_
+--   [ selector_ ".card"  [ backgroundColor white, borderRadius (px 4) ]
+--   , selector_ ".title" [ fontSize (rem 1.5), fontWeight "bold" ]
+--   ]
+-- @
+--
+selector_ :: MisoString -> [Style] -> Styles
+selector_ k v = Styles (k,v)
+-----------------------------------------------------------------------------
+-- | Constructs a t'StyleSheet' from a list of t'Styles' entries.
+--
+-- Combine with 'selector_', 'keyframes_', and 'media_' to build a full
+-- stylesheet, then render it to a 'MisoString' with 'renderStyleSheet'.
+--
+-- @
+-- mySheet :: StyleSheet
+-- mySheet = sheet_
+--   [ selector_ "body"   [ margin (px 0), fontFamily "sans-serif" ]
+--   , selector_ "button" [ cursor "pointer", borderRadius (px 4) ]
+--   ]
+-- @
+--
+sheet_ :: [Styles] -> StyleSheet
+sheet_ = StyleSheet
+-----------------------------------------------------------------------------
+-- | Constructs a structured @style@ attribute from a list of CSS properties.
+--
+-- Each 'Style' is a @(property, value)@ pair produced by the combinators in
+-- this module. Miso tracks the properties as a 'Data.Map.Map', diffs them on
+-- each render, and applies only the changed properties to the DOM. Properties
+-- absent from the list are removed from the node.
+--
+-- @
+-- div_
+--   [ style_
+--       [ display       "flex"
+--       , flexDirection "column"
+--       , gap           (px 8)
+--       , backgroundColor red
+--       ]
+--   ] []
+-- @
+--
+-- See also 'styleInline_' for setting raw CSS strings.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/CSS>
+--
+style_ :: [Style] -> Attribute model action
+style_ = MT.Styles . M.fromList
+-----------------------------------------------------------------------------
+-- | Sets the @style@ attribute to a raw CSS string.
+--
+-- Unlike 'style_', the string is applied verbatim and is not tracked or
+-- diffed by the virtual DOM. Suitable for static styles or CSS values that
+-- the structured combinators do not yet cover.
+--
+-- @
+-- div_ [ styleInline_ "background-color:red; color:blue;" ] [ "foo" ]
+-- @
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/CSS>
+--
+styleInline_ ::  MisoString -> Attribute model action
+styleInline_ = textProp "style"
+-----------------------------------------------------------------------------
+-- | Renders a t'Styles' to a t'MisoString'
+renderStyles :: Int -> Styles -> MisoString
+renderStyles indent (Styles (sel,styles)) = MS.unlines
+  [ sel <> " {" <> MS.replicate indent " "
+  , MS.intercalate "\n"
+        [ mconcat
+          [ MS.replicate (indent + 2) " " <> k
+          , " : "
+          , v
+          , ";"
+          ]
+        | (k,v) <- styles
+        ]
+  , MS.replicate indent " " <> "}"
+  ]
+renderStyles indent (KeyFrame name frames) = MS.intercalate " "
+  [ "@keyframes"
+  , name
+  , "{\n"
+  , MS.intercalate "\n  "
+    [ renderStyles (indent + 2) (Styles frame)
+    | frame <- frames
+    ]
+  , "}\n"
+  ]
+renderStyles indent (Media name frames) = MS.intercalate " "
+  [ "@media"
+  , name
+  , "{\n"
+  , MS.intercalate "\n  "
+    [ renderStyles (indent + 2) (Styles frame)
+    | frame <- frames
+    ]
+  , "}\n"
+  ]
+-----------------------------------------------------------------------------
+-- | Renders a t'StyleSheet' to a 'MisoString' suitable for injection into a
+-- @\<style\>@ tag.
+--
+-- @
+-- view_ :: View context action
+-- view_ = style [] [ text (renderStyleSheet mySheet) ]
+-- @
+--
+renderStyleSheet :: StyleSheet -> MisoString
+renderStyleSheet styleSheet = MS.intercalate "\n"
+  [ renderStyles 0 styles
+  | styles <- getStyleSheet styleSheet
+  ]
+-----------------------------------------------------------------------------
+-- | Constructs a CSS @\@keyframes@ animation rule.
+--
+-- The first argument is the animation name; the second is a list of
+-- @(keyframe-selector, [Style])@ pairs. Keyframe selectors are either
+-- @"from"@\/@"to"@ or a percentage string produced by 'pct'.
+--
+-- @
+-- slideIn :: Styles
+-- slideIn = keyframes_ "slide-in"
+--   [ from_ [ transform "translateX(-100%)" ]
+--   , at (pct 50) [ opacity 0.5 ]
+--   , to_   [ transform "translateX(0)" ]
+--   ]
+-- @
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes>
+--
+keyframes_ :: MisoString -> [KeyframeStop] -> Styles
+keyframes_ name stops = KeyFrame name (map getKeyframeStop stops)
+-----------------------------------------------------------------------------
+-- | The @from@ stop in a '@keyframes' rule (equivalent to @0%@).
+from_ :: [Style] -> KeyframeStop
+from_ styles = KeyframeStop ("from", styles)
+-----------------------------------------------------------------------------
+-- | The @to@ stop in a '@keyframes' rule (equivalent to @100%@).
+to_ :: [Style] -> KeyframeStop
+to_ styles = KeyframeStop ("to", styles)
+-----------------------------------------------------------------------------
+-- | A keyframe stop at a given position, typically built with 'pct'.
+--
+-- > at (pct 50) [ opacity 0.5 ]
+--
+at :: MisoString -> [Style] -> KeyframeStop
+at stop styles = KeyframeStop (stop, styles)
+-----------------------------------------------------------------------------
+-- | Constructs a CSS @\@media@ query rule.
+--
+-- The first argument is the media condition string; the second is a list of
+-- @(selector, [Style])@ pairs scoped to that query.
+--
+-- @
+-- responsive :: t'Styles'
+-- responsive = 'media_' ('screen_' \`and_\` 'minWidth_' (px 480))
+--   [ 'rule_' "header" [ 'height' "auto" ]
+--   , 'rule_' "ul"     [ 'display' "block" ]
+--   ]
+-- @
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/CSS/@media>
+--
+media_ :: MediaQuery -> [MediaRule] -> Styles
+media_ (MediaQuery q) rules = Media q (map getMediaRule rules)
+-----------------------------------------------------------------------------
+-- | A selector rule inside a 'media_' block.
+--
+-- > rule_ "header" [ height "auto" ]
+--
+rule_ :: MisoString -> [Style] -> MediaRule
+rule_ sel styles = MediaRule (sel, styles)
+-----------------------------------------------------------------------------
+-- | The @screen@ media type.
+screen_ :: MediaQuery
+screen_ = MediaQuery "screen"
+-----------------------------------------------------------------------------
+-- | The @print@ media type.
+print_ :: MediaQuery
+print_ = MediaQuery "print"
+-----------------------------------------------------------------------------
+-- | The @all@ media type (matches all devices).
+all_ :: MediaQuery
+all_ = MediaQuery "all"
+-----------------------------------------------------------------------------
+-- | Logical @and@ for media queries.
+--
+-- > screen_ \`and_\` minWidth_ (px 480)
+--
+and_ :: MediaQuery -> MediaQuery -> MediaQuery
+and_ (MediaQuery a) (MediaQuery b) = MediaQuery (a <> " and " <> b)
+-----------------------------------------------------------------------------
+-- | Logical @or@ for media queries (comma-separated).
+--
+-- > screen_ \`or_\` print_
+--
+or_ :: MediaQuery -> MediaQuery -> MediaQuery
+or_ (MediaQuery a) (MediaQuery b) = MediaQuery (a <> ", " <> b)
+-----------------------------------------------------------------------------
+-- | Logical @not@ for media queries.
+--
+-- > not_ print_
+--
+not_ :: MediaQuery -> MediaQuery
+not_ (MediaQuery q) = MediaQuery ("not " <> q)
+-----------------------------------------------------------------------------
+-- | @min-width@ media feature. Use unit constructors like 'px' or 'em'.
+minWidth_ :: MisoString -> MediaQuery
+minWidth_ x = MediaQuery ("(min-width: " <> x <> ")")
+-----------------------------------------------------------------------------
+-- | @max-width@ media feature.
+maxWidth_ :: MisoString -> MediaQuery
+maxWidth_ x = MediaQuery ("(max-width: " <> x <> ")")
+-----------------------------------------------------------------------------
+-- | @min-height@ media feature.
+minHeight_ :: MisoString -> MediaQuery
+minHeight_ x = MediaQuery ("(min-height: " <> x <> ")")
+-----------------------------------------------------------------------------
+-- | @max-height@ media feature.
+maxHeight_ :: MisoString -> MediaQuery
+maxHeight_ x = MediaQuery ("(max-height: " <> x <> ")")
+-----------------------------------------------------------------------------
+-- | @orientation@ media feature. Use @\"portrait\"@ or @\"landscape\"@.
+orientation_ :: MisoString -> MediaQuery
+orientation_ x = MediaQuery ("(orientation: " <> x <> ")")
+-----------------------------------------------------------------------------
+-- | @prefers-color-scheme@ media feature. Use @\"light\"@ or @\"dark\"@.
+prefersColorScheme_ :: MisoString -> MediaQuery
+prefersColorScheme_ x = MediaQuery ("(prefers-color-scheme: " <> x <> ")")
+-----------------------------------------------------------------------------
+-- | @prefers-reduced-motion@ media feature. Use @\"reduce\"@ or @\"no-preference\"@.
+prefersReducedMotion_ :: MisoString -> MediaQuery
+prefersReducedMotion_ x = MediaQuery ("(prefers-reduced-motion: " <> x <> ")")
+-----------------------------------------------------------------------------
+-- | @hover@ media feature. Use @\"hover\"@ or @\"none\"@.
+hover_ :: MisoString -> MediaQuery
+hover_ x = MediaQuery ("(hover: " <> x <> ")")
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/align-content
+--
+alignContent :: MisoString -> Style
+alignContent x = "align-content" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
+--
+alignItems :: MisoString -> Style
+alignItems x = "align-items" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/align-self
+--
+alignSelf :: MisoString -> Style
+alignSelf x = "align-self" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-delay
+--
+animationDelay :: MisoString -> Style
+animationDelay x = "animation-delay" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction
+--
+animationDirection :: MisoString -> Style
+animationDirection x = "animation-direction" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-duration
+--
+animationDuration :: MisoString -> Style
+animationDuration x = "animation-duration" =: x
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode>
+--
+animationFillMode :: MisoString -> Style
+animationFillMode x = "animation-fill-mode" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-iteration-count
+--
+animationIterationCount :: MisoString -> Style
+animationIterationCount x = "animation-iteration-count" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation
+--
+animation :: MisoString -> Style
+animation x = "animation" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-name
+--
+animationName :: MisoString -> Style
+animationName x = "animation-name" =: x
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/CSS/animation-play-state>
+--
+animationPlayState :: MisoString -> Style
+animationPlayState x = "animation-play-state" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function
+--
+animationTimingFunction :: MisoString -> Style
+animationTimingFunction x = "animation-timing-function" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio
+--
+aspectRatio :: MisoString -> Style
+aspectRatio x = "aspect-ratio" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-clip
+--
+backgroundClip :: MisoString -> Style
+backgroundClip x = "background-clip" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-color
+--
+backgroundColor :: Color -> Style
+backgroundColor x = "background-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-image
+--
+backgroundImage :: MisoString -> Style
+backgroundImage x = "background-image" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background
+--
+background :: MisoString -> Style
+background x = "background" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-origin
+--
+backgroundOrigin :: MisoString -> Style
+backgroundOrigin x = "background-origin" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-position
+--
+backgroundPosition :: MisoString -> Style
+backgroundPosition x = "background-position" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat
+--
+backgroundRepeat :: MisoString -> Style
+backgroundRepeat x = "background-repeat" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-size
+--
+backgroundSize :: MisoString -> Style
+backgroundSize x = "background-size" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-color
+--
+borderBottomColor :: Color -> Style
+borderBottomColor x = "border-bottom-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-left-radius
+--
+borderBottomLeftRadius :: MisoString -> Style
+borderBottomLeftRadius x = "border-bottom-left-radius" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom
+--
+borderBottom :: MisoString -> Style
+borderBottom x = "border-bottom" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-right-radius
+--
+borderBottomRightRadius :: MisoString -> Style
+borderBottomRightRadius x = "border-bottom-right-radius" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-style
+--
+borderBottomStyle :: MisoString -> Style
+borderBottomStyle x = "border-bottom-style" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-width
+--
+borderBottomWidth :: MisoString -> Style
+borderBottomWidth x = "border-bottom-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-collapse
+--
+borderCollapse :: MisoString -> Style
+borderCollapse x = "border-collapse" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-color
+--
+borderColor :: Color -> Style
+borderColor x = "border-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-end-radius
+--
+borderEndEndRadius :: MisoString -> Style
+borderEndEndRadius x = "border-end-end-radius" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-end-start-radius
+--
+borderEndStartRadius :: MisoString -> Style
+borderEndStartRadius x = "border-end-start-radius" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-end-color
+--
+borderInlineEndColor :: Color -> Style
+borderInlineEndColor x = "border-inline-end-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-end-style
+--
+borderInlineEndStyle :: MisoString -> Style
+borderInlineEndStyle x = "border-inline-end-style" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-end-width
+--
+borderInlineEndWidth :: MisoString -> Style
+borderInlineEndWidth x = "border-inline-end-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-start-color
+--
+borderInlineStartColor :: Color -> Style
+borderInlineStartColor x = "border-inline-start-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-start-style
+--
+borderInlineStartStyle :: MisoString -> Style
+borderInlineStartStyle x = "border-inline-start-style" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-start-width
+--
+borderInlineStartWidth :: MisoString -> Style
+borderInlineStartWidth x = "border-inline-start-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-left-color
+--
+borderLeftColor :: Color -> Style
+borderLeftColor x = "border-left-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-left
+--
+borderLeft :: MisoString -> Style
+borderLeft x = "border-left" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-left-style
+--
+borderLeftStyle :: MisoString -> Style
+borderLeftStyle x = "border-left-style" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-left-width
+--
+borderLeftWidth :: MisoString -> Style
+borderLeftWidth x = "border-left-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border
+--
+border :: MisoString -> Style
+border x = "border" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
+--
+borderRadius :: MisoString -> Style
+borderRadius x = "border-radius" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-right-color
+--
+borderRightColor :: Color -> Style
+borderRightColor x = "border-right-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-right
+--
+borderRight :: MisoString -> Style
+borderRight x = "border-right" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-right-style
+--
+borderRightStyle :: MisoString -> Style
+borderRightStyle x = "border-right-style" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-right-width
+--
+borderRightWidth :: MisoString -> Style
+borderRightWidth x = "border-right-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-start-end-radius
+--
+borderStartEndRadius :: MisoString -> Style
+borderStartEndRadius x = "border-start-end-radius" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-start-start-radius
+--
+borderStartStartRadius :: MisoString -> Style
+borderStartStartRadius x = "border-start-start-radius" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-style
+--
+borderStyle :: MisoString -> Style
+borderStyle x = "border-style" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-color
+--
+borderTopColor :: Color -> Style
+borderTopColor x = "border-top-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-left-radius
+--
+borderTopLeftRadius :: MisoString -> Style
+borderTopLeftRadius x = "border-top-left-radius" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top
+--
+borderTop :: MisoString -> Style
+borderTop x = "border-top" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-right-radius
+--
+borderTopRightRadius :: MisoString -> Style
+borderTopRightRadius x = "border-top-right-radius" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-style
+--
+borderTopStyle :: MisoString -> Style
+borderTopStyle x = "border-top-style" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-width
+--
+borderTopWidth :: MisoString -> Style
+borderTopWidth x = "border-top-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-width
+--
+borderWidth :: MisoString -> Style
+borderWidth x = "border-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/bottom
+--
+bottom :: MisoString -> Style
+bottom x = "bottom" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow
+--
+boxShadow :: MisoString -> Style
+boxShadow x = "box-shadow" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing
+--
+boxSizing :: MisoString -> Style
+boxSizing x = "box-sizing" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path
+--
+clipPath :: MisoString -> Style
+clipPath x = "clip-path" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/accent-color
+--
+accentColor :: Color -> Style
+accentColor x = "accent-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/appearance
+--
+appearance :: MisoString -> Style
+appearance x = "appearance" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter
+--
+backdropFilter :: MisoString -> Style
+backdropFilter x = "backdrop-filter" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/caret-color
+--
+caretColor :: Color -> Style
+caretColor x = "caret-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/color
+--
+color :: Color -> Style
+color x = "color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/column-gap
+--
+columnGap :: MisoString -> Style
+columnGap x = "column-gap" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/direction
+--
+direction :: MisoString -> Style
+direction x = "direction" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/display
+--
+display :: MisoString -> Style
+display x = "display" =: x
+-----------------------------------------------------------------------------
+-- | SVG [fill](https://developer.mozilla.org/en-US/docs/Web/CSS/fill) color.
+--
+-- > fill red
+--
+fill :: Color -> Style
+fill x = "fill" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/filter
+--
+filter :: MisoString -> Style
+filter x = "filter" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis
+--
+flexBasis :: MisoString -> Style
+flexBasis x = "flex-basis" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction
+--
+flexDirection :: MisoString -> Style
+flexDirection x = "flex-direction" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-flow
+--
+flexFlow :: MisoString -> Style
+flexFlow x = "flex-flow" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow
+--
+flexGrow :: Double -> Style
+flexGrow x = "flex-grow" =: MS.ms x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex
+--
+flex :: MisoString -> Style
+flex x = "flex" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-shrink
+--
+flexShrink :: Double -> Style
+flexShrink x = "flex-shrink" =: MS.ms x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap
+--
+flexWrap :: MisoString -> Style
+flexWrap x = "flex-wrap" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-family
+--
+fontFamily :: MisoString -> Style
+fontFamily x = "font-family" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-size
+--
+fontSize :: MisoString -> Style
+fontSize x = "font-size" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-stretch
+--
+fontStretch :: MisoString -> Style
+fontStretch x = "font-stretch" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-style
+--
+fontStyle :: MisoString -> Style
+fontStyle x = "font-style" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant
+--
+fontVariant :: MisoString -> Style
+fontVariant x = "font-variant" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight
+--
+fontWeight :: MisoString -> Style
+fontWeight x = "font-weight" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
+--
+cursor :: MisoString -> Style
+cursor x = "cursor" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/gap
+--
+gap :: MisoString -> Style
+gap x = "gap" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-columns
+--
+gridAutoColumns :: MisoString -> Style
+gridAutoColumns x = "grid-auto-columns" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow
+--
+gridAutoFlow :: MisoString -> Style
+gridAutoFlow x = "grid-auto-flow" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-rows
+--
+gridAutoRows :: MisoString -> Style
+gridAutoRows x = "grid-auto-rows" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column
+--
+gridColumn :: MisoString -> Style
+gridColumn x = "grid-column" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-end
+--
+gridColumnEnd :: MisoString -> Style
+gridColumnEnd x = "grid-column-end" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-span
+--
+gridColumnSpan :: MisoString -> Style
+gridColumnSpan x = "grid-column-span" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-start
+--
+gridColumnStart :: MisoString -> Style
+gridColumnStart x = "grid-column-start" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row
+--
+gridRow :: MisoString -> Style
+gridRow x = "grid-row" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-end
+--
+gridRowEnd :: MisoString -> Style
+gridRowEnd x = "grid-row-end" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-span
+--
+gridRowSpan :: MisoString -> Style
+gridRowSpan x = "grid-row-span" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-start
+--
+gridRowStart :: MisoString -> Style
+gridRowStart x = "grid-row-start" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
+--
+gridTemplateColumns :: MisoString -> Style
+gridTemplateColumns x = "grid-template-columns" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-rows
+--
+gridTemplateRows :: MisoString -> Style
+gridTemplateRows x = "grid-template-rows" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/height
+--
+height :: MisoString -> Style
+height x = "height" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering
+--
+imageRendering :: MisoString -> Style
+imageRendering x = "image-rendering" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/inset-inline-end
+--
+insetInlineEnd :: MisoString -> Style
+insetInlineEnd x = "inset-inline-end" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/inset-inline-start
+--
+insetInlineStart :: MisoString -> Style
+insetInlineStart x = "inset-inline-start" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content
+--
+justifyContent :: MisoString -> Style
+justifyContent x = "justify-content" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items
+--
+justifyItems :: MisoString -> Style
+justifyItems x = "justify-items" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/justify-self
+--
+justifySelf :: MisoString -> Style
+justifySelf x = "justify-self" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/left
+--
+left :: MisoString -> Style
+left x = "left" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/letter-spacing
+--
+letterSpacing :: MisoString -> Style
+letterSpacing x = "letter-spacing" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-cross-gravity
+--
+linearCrossGravity :: MisoString -> Style
+linearCrossGravity x = "linear-cross-gravity" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-direction
+--
+linearDirection :: MisoString -> Style
+linearDirection x = "linear-direction" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gravity
+--
+linearGravity :: MisoString -> Style
+linearGravity x = "linear-gravity" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-layout-gravity
+--
+linearLayoutGravity :: MisoString -> Style
+linearLayoutGravity x = "linear-layout-gravity" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-weight
+--
+linearWeight :: MisoString -> Style
+linearWeight x = "linear-weight" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-weight-sum
+--
+linearWeightSum :: MisoString -> Style
+linearWeightSum x = "linear-weight-sum" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
+--
+lineHeight :: MisoString -> Style
+lineHeight x = "line-height" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-bottom
+--
+marginBottom :: MisoString -> Style
+marginBottom x = "margin-bottom" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inline-end
+--
+marginInlineEnd :: MisoString -> Style
+marginInlineEnd x = "margin-inline-end" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inline-start
+--
+marginInlineStart :: MisoString -> Style
+marginInlineStart x = "margin-inline-start" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-left
+--
+marginLeft :: MisoString -> Style
+marginLeft x = "margin-left" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin
+--
+margin :: MisoString -> Style
+margin x = "margin" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-right
+--
+marginRight :: MisoString -> Style
+marginRight x = "margin-right" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-top
+--
+marginTop :: MisoString -> Style
+marginTop x = "margin-top" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/mask-image
+--
+maskImage :: MisoString -> Style
+maskImage x = "mask-image" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/mask
+--
+mask :: MisoString -> Style
+mask x = "mask" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/max-height
+--
+maxHeight :: MisoString -> Style
+maxHeight x = "max-height" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/max-width
+--
+maxWidth :: MisoString -> Style
+maxWidth x = "max-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/min-height
+--
+minHeight :: MisoString -> Style
+minHeight x = "min-height" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/min-width
+--
+minWidth :: MisoString -> Style
+minWidth x = "min-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
+--
+mixBlendMode :: MisoString -> Style
+mixBlendMode x = "mix-blend-mode" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
+--
+objectFit :: MisoString -> Style
+objectFit x = "object-fit" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/object-position
+--
+objectPosition :: MisoString -> Style
+objectPosition x = "object-position" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/opacity
+--
+opacity :: Double -> Style
+opacity x = "opacity" =: MS.ms x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/order
+--
+order :: Int -> Style
+order x = "order" =: MS.ms x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/outline
+--
+outline :: MisoString -> Style
+outline x = "outline" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/outline-color
+--
+outlineColor :: Color -> Style
+outlineColor x = "outline-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/outline-offset
+--
+outlineOffset :: MisoString -> Style
+outlineOffset x = "outline-offset" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/outline-style
+--
+outlineStyle :: MisoString -> Style
+outlineStyle x = "outline-style" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/outline-width
+--
+outlineWidth :: MisoString -> Style
+outlineWidth x = "outline-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/overflow
+--
+overflow :: MisoString -> Style
+overflow x = "overflow" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-x
+--
+overflowX :: MisoString -> Style
+overflowX x = "overflow-x" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-y
+--
+overflowY :: MisoString -> Style
+overflowY x = "overflow-y" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior
+--
+overscrollBehavior :: MisoString -> Style
+overscrollBehavior x = "overscroll-behavior" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-bottom
+--
+paddingBottom :: MisoString -> Style
+paddingBottom x = "padding-bottom" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-inline-end
+--
+paddingInlineEnd :: MisoString -> Style
+paddingInlineEnd x = "padding-inline-end" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-inline-start
+--
+paddingInlineStart :: MisoString -> Style
+paddingInlineStart x = "padding-inline-start" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-left
+--
+paddingLeft :: MisoString -> Style
+paddingLeft x = "padding-left" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding
+--
+padding :: MisoString -> Style
+padding x = "padding" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-right
+--
+paddingRight :: MisoString -> Style
+paddingRight x = "padding-right" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-top
+--
+paddingTop :: MisoString -> Style
+paddingTop x = "padding-top" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/perspective
+--
+perspective :: MisoString -> Style
+perspective x = "perspective" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events
+--
+pointerEvents :: MisoString -> Style
+pointerEvents x = "pointer-events" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/position
+--
+position :: MisoString -> Style
+position x = "position" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-bottom
+--
+relativeAlignBottom :: MisoString -> Style
+relativeAlignBottom x = "relative-align-bottom" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-inline-end
+--
+relativeAlignInlineEnd :: MisoString -> Style
+relativeAlignInlineEnd x = "relative-align-inline-end" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-inline-start
+--
+relativeAlignInlineStart :: MisoString -> Style
+relativeAlignInlineStart x = "relative-align-inline-start" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-left
+--
+relativeAlignLeft :: MisoString -> Style
+relativeAlignLeft x = "relative-align-left" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-right
+--
+relativeAlignRight :: MisoString -> Style
+relativeAlignRight x = "relative-align-right" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-top
+--
+relativeAlignTop :: MisoString -> Style
+relativeAlignTop x = "relative-align-top" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-bottom-of
+--
+relativeBottomOf :: MisoString -> Style
+relativeBottomOf x = "relative-bottom-of" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-center
+--
+relativeCenter :: MisoString -> Style
+relativeCenter x = "relative-center" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-id
+--
+relativeId :: MisoString -> Style
+relativeId x = "relative-id" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-inline-end-of
+--
+relativeInlineEndOf :: MisoString -> Style
+relativeInlineEndOf x = "relative-inline-end-of" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-inline-start-of
+--
+relativeInlineStartOf :: MisoString -> Style
+relativeInlineStartOf x = "relative-inline-start-of" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-layout-once
+--
+relativeLayoutOnce :: MisoString -> Style
+relativeLayoutOnce x = "relative-layout-once" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-left-of
+--
+relativeLeftOf :: MisoString -> Style
+relativeLeftOf x = "relative-left-of" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-right-of
+--
+relativeRightOf :: MisoString -> Style
+relativeRightOf x = "relative-right-of" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-top-of
+--
+relativeTopOf :: MisoString -> Style
+relativeTopOf x = "relative-top-of" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/resize
+--
+resize :: MisoString -> Style
+resize x = "resize" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/right
+--
+right :: MisoString -> Style
+right x = "right" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap
+--
+rowGap :: MisoString -> Style
+rowGap x = "row-gap" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior
+--
+scrollBehavior :: MisoString -> Style
+scrollBehavior x = "scroll-behavior" =: x
+-----------------------------------------------------------------------------
+-- | SVG [stroke](https://developer.mozilla.org/en-US/docs/Web/CSS/stroke) color.
+--
+-- > stroke black
+--
+stroke :: Color -> Style
+stroke x = "stroke" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/stroke-width
+--
+strokeWidth :: MisoString -> Style
+strokeWidth x = "stroke-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-align
+--
+textAlign :: MisoString -> Style
+textAlign x = "text-align" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration
+--
+textDecoration :: MisoString -> Style
+textDecoration x = "text-decoration" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-indent
+--
+textIndent :: MisoString -> Style
+textIndent x = "text-indent" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-overflow
+--
+textOverflow :: MisoString -> Style
+textOverflow x = "text-overflow" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow
+--
+textShadow :: MisoString -> Style
+textShadow x = "text-shadow" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-stroke-color
+--
+textStrokeColor :: Color -> Style
+textStrokeColor x = "text-stroke-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-stroke
+--
+textStroke :: MisoString -> Style
+textStroke x = "text-stroke" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-stroke-width
+--
+textStrokeWidth :: MisoString -> Style
+textStrokeWidth x = "text-stroke-width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-transform
+--
+textTransform :: MisoString -> Style
+textTransform x = "text-transform" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/top
+--
+top :: MisoString -> Style
+top x = "top" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform
+--
+transform :: MisoString -> Style
+transform x = "transform" =: x
+-----------------------------------------------------------------------------
+-- | Apply a list of t'TransformFn' values as a @transform@ style.
+--
+-- @
+-- transforms [ translate (px 10) (pct 50), rotate (deg 45), scaleX 1.5 ]
+-- @
+--
+transforms :: [TransformFn] -> Style
+transforms fns = "transform" =: MS.intercalate " " (map renderTransformFn fns)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin
+--
+transformOrigin :: MisoString -> Style
+transformOrigin x = "transform-origin" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate
+--
+-- >>> renderTransformFn (translate (px 10) (pct 50))
+-- "translate(10px,50.0%)"
+--
+translate :: MisoString -> MisoString -> TransformFn
+translate x y = TransformFn $ "translate(" <> x <> "," <> y <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateX
+--
+translateX :: MisoString -> TransformFn
+translateX x = TransformFn $ "translateX(" <> x <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateY
+--
+translateY :: MisoString -> TransformFn
+translateY y = TransformFn $ "translateY(" <> y <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translateZ
+--
+translateZ :: MisoString -> TransformFn
+translateZ z = TransformFn $ "translateZ(" <> z <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate3d
+--
+translate3d :: MisoString -> MisoString -> MisoString -> TransformFn
+translate3d x y z = TransformFn $ "translate3d(" <> MS.intercalate "," [x, y, z] <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate
+--
+-- >>> renderTransformFn (rotate (deg 45))
+-- "rotate(45.0deg)"
+--
+rotate :: MisoString -> TransformFn
+rotate a = TransformFn $ "rotate(" <> a <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotateX
+--
+rotateX :: MisoString -> TransformFn
+rotateX a = TransformFn $ "rotateX(" <> a <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotateY
+--
+rotateY :: MisoString -> TransformFn
+rotateY a = TransformFn $ "rotateY(" <> a <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotateZ
+--
+rotateZ :: MisoString -> TransformFn
+rotateZ a = TransformFn $ "rotateZ(" <> a <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate3d
+-- x, y, z are unitless direction vector components; angle uses a unit constructor like 'deg'.
+--
+rotate3d :: Double -> Double -> Double -> MisoString -> TransformFn
+rotate3d x y z a = TransformFn $ "rotate3d(" <> MS.intercalate "," [MS.ms x, MS.ms y, MS.ms z, a] <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale
+-- Uniform scale on both axes.
+--
+-- >>> renderTransformFn (scale 1.5)
+-- "scale(1.5)"
+--
+scale :: Double -> TransformFn
+scale n = TransformFn $ "scale(" <> MS.ms n <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale
+-- Non-uniform scale: separate X and Y factors.
+--
+scaleXY :: Double -> Double -> TransformFn
+scaleXY x y = TransformFn $ "scale(" <> MS.ms x <> "," <> MS.ms y <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale3d
+--
+scale3d :: Double -> Double -> Double -> TransformFn
+scale3d x y z = TransformFn $ "scale3d(" <> MS.intercalate "," [MS.ms x, MS.ms y, MS.ms z] <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleX
+--
+scaleX :: Double -> TransformFn
+scaleX n = TransformFn $ "scaleX(" <> MS.ms n <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleY
+--
+scaleY :: Double -> TransformFn
+scaleY n = TransformFn $ "scaleY(" <> MS.ms n <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleZ
+--
+scaleZ :: Double -> TransformFn
+scaleZ n = TransformFn $ "scaleZ(" <> MS.ms n <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/perspective
+-- The @perspective()@ transform function, distinct from the @perspective@ CSS property.
+--
+-- >>> renderTransformFn (perspectiveFn (px 500))
+-- "perspective(500px)"
+--
+perspectiveFn :: MisoString -> TransformFn
+perspectiveFn d = TransformFn $ "perspective(" <> d <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix3d
+-- 4x4 homogeneous matrix in column-major order; each tuple is one column.
+--
+-- > matrix3d (1,0,0,0) (0,1,0,0) (0,0,1,0) (10,20,0,1)
+--
+matrix3d
+  :: (Double, Double, Double, Double)
+  -> (Double, Double, Double, Double)
+  -> (Double, Double, Double, Double)
+  -> (Double, Double, Double, Double)
+  -> TransformFn
+matrix3d (a1,b1,c1,d1) (a2,b2,c2,d2) (a3,b3,c3,d3) (a4,b4,c4,d4) =
+  TransformFn $ "matrix3d(" <> values <> ")"
+  where
+    values = MS.intercalate ","
+      [ MS.ms a1, MS.ms b1, MS.ms c1, MS.ms d1
+      , MS.ms a2, MS.ms b2, MS.ms c2, MS.ms d2
+      , MS.ms a3, MS.ms b3, MS.ms c3, MS.ms d3
+      , MS.ms a4, MS.ms b4, MS.ms c4, MS.ms d4
+      ]
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/skew
+--
+skew :: MisoString -> MisoString -> TransformFn
+skew x y = TransformFn $ "skew(" <> x <> "," <> y <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/skewX
+--
+skewX :: MisoString -> TransformFn
+skewX a = TransformFn $ "skewX(" <> a <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/skewY
+--
+skewY :: MisoString -> TransformFn
+skewY a = TransformFn $ "skewY(" <> a <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition-delay
+--
+transitionDelay :: MisoString -> Style
+transitionDelay x = "transition-delay" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition-duration
+--
+transitionDuration :: MisoString -> Style
+transitionDuration x = "transition-duration" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition
+--
+transition :: MisoString -> Style
+transition x = "transition" =: x
+-----------------------------------------------------------------------------
+-- | Single-property @transition@ shorthand: @property@, @duration@, and
+-- @timing-function@ combined into one @transition@ 'Style' — i.e. __one__ inline
+-- key, not the three @transition-*@ longhands.
+--
+-- Prefer this whenever the tween is also reset imperatively elsewhere (e.g.
+-- @transition: none@ on the main thread, see "Miso.Native.MainThread"): the reset
+-- lands on the @transition@ key, and separate longhands would survive it.
+--
+-- >>> transition_ "transform" (s 0.3) (cubicBezier 0.22 1 0.36 1)
+-- ("transition","transform 0.3s cubic-bezier(0.22,1,0.36,1)")
+--
+-- @since 1.13.0.0
+transition_ :: MisoString -> MisoString -> MisoString -> Style
+transition_ property duration timing =
+  "transition" =: (property <> " " <> duration <> " " <> timing)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition-property
+--
+transitionProperty :: MisoString -> Style
+transitionProperty x = "transition-property" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-function
+--
+transitionTimingFunction :: MisoString -> Style
+transitionTimingFunction x = "transition-timing-function" =: x
+-----------------------------------------------------------------------------
+-- | A @cubic-bezier()@ easing value, for use with 'transition',
+-- 'transitionTimingFunction', or an animation's timing function. Unlike the
+-- @translate@\/@rotate@\/… helpers this is a /timing/ function, not a
+-- t'TransformFn', so it produces a bare 'MisoString' value.
+--
+-- >>> cubicBezier 0.22 1 0.36 1
+-- "cubic-bezier(0.22,1,0.36,1)"
+--
+-- @since 1.13.0.0
+cubicBezier :: Double -> Double -> Double -> Double -> MisoString
+cubicBezier a b c d =
+  "cubic-bezier(" <> MS.intercalate "," (map MS.ms [a, b, c, d]) <> ")"
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/user-select
+--
+userSelect :: MisoString -> Style
+userSelect x = "user-select" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align
+--
+verticalAlign :: MisoString -> Style
+verticalAlign x = "vertical-align" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/visibility
+--
+visibility :: MisoString -> Style
+visibility x = "visibility" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/white-space
+--
+whiteSpace :: MisoString -> Style
+whiteSpace x = "white-space" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/width
+--
+width :: MisoString -> Style
+width x = "width" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/will-change
+--
+willChange :: MisoString -> Style
+willChange x = "will-change" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/word-break
+--
+wordBreak :: MisoString -> Style
+wordBreak x = "word-break" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/xAutoFontSize
+--
+xAutoFontSize :: MisoString -> Style
+xAutoFontSize x = "-x-auto-font-size" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/xAutoFontSizePresetSizes
+--
+xAutoFontSizePresetSizes :: MisoString -> Style
+xAutoFontSizePresetSizes x = "-x-auto-font-size-preset-sizes" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/xHandleColor
+--
+xHandleColor :: Color -> Style
+xHandleColor x = "-x-handle-color" =: renderColor x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/xHandleSize
+--
+xHandleSize :: MisoString -> Style
+xHandleSize x = "-x-handle-size" =: x
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/z-index
+--
+zIndex :: Int -> Style
+zIndex x = "z-index" =: MS.ms x
+-----------------------------------------------------------------------------
diff --git a/src/Miso/CSS/Color.hs b/src/Miso/CSS/Color.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/CSS/Color.hs
@@ -0,0 +1,1901 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE ScopedTypeVariables   #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE TypeApplications      #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -fno-warn-orphans  #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.CSS.Color
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.CSS.Color" provides the 'Color' type and smart constructors for every
+-- CSS color format, plus the full set of
+-- <https://www.w3.org/TR/css-color-4/#named-colors CSS named colors>.
+--
+-- Colors are produced by smart constructors ('rgb', 'rgba', 'hsl', 'hsla',
+-- 'oklch', 'oklcha', 'hex', 'var') and consumed by 'renderColor', which
+-- serialises a 'Color' to a 'Miso.String.MisoString' suitable for use as a
+-- CSS property value. All color constructors are re-exported from "Miso.CSS".
+--
+-- = Color formats
+--
+-- ['rgb' r g b] @rgb(r,g,b)@ — <https://www.w3.org/TR/css-color-4/#rgb-functions RGB>
+-- ['rgba' r g b a] @rgba(r,g,b,a)@ — <https://www.w3.org/TR/css-color-4/#rgb-functions RGBA>
+-- ['hsl' h s l] @hsl(h,s,l)@ — <https://www.w3.org/TR/css-color-4/#the-hsl-notation HSL>
+-- ['hsla' h s l a] @hsla(h,s,l,a)@ — <https://www.w3.org/TR/css-color-4/#the-hsl-notation HSLA>
+-- ['oklch' l c h] @oklch(l% c h)@ — <https://www.w3.org/TR/css-color-4/#the-oklch-notation OKLCH>
+-- ['oklcha' l c h a] @oklch(l% c h / a)@ — <https://www.w3.org/TR/css-color-4/#the-oklch-notation OKLCHA>
+-- ['hex' s] @#s@ — <https://www.w3.org/TR/css-color-4/#hex-notation Hex>
+-- ['var' name] @var(--name)@ — <https://www.w3.org/TR/css-variables/ CSS Variables>
+--
+-- = Quick start
+--
+-- @
+-- import qualified "Miso.CSS"       as CSS
+-- import           "Miso.CSS.Color"
+--
+-- myView :: 'Miso.Types.View' Model Action
+-- myView =
+--   'Miso.Html.Element.div_'
+--     [ CSS.'Miso.CSS.style_'
+--         [ CSS.'Miso.CSS.backgroundColor' 'cornflowerblue'
+--         , CSS.'Miso.CSS.color'           ('rgba' 255 255 255 0.9)
+--         , CSS.'Miso.CSS.borderColor'     ('hex' "333")
+--         ]
+--     ] []
+-- @
+--
+-- = Overloaded hex literals
+--
+-- With @-XOverloadedLabels@, hex color strings can be written as label
+-- literals directly where a 'Color' or 'Miso.String.MisoString' is expected.
+-- The leading @#@ is inserted automatically:
+--
+-- @
+-- {-\# LANGUAGE OverloadedLabels \#-}
+--
+-- myColor :: 'Color'
+-- myColor = #ff6347          -- equivalent to 'hex' \"ff6347\"
+--
+-- myString :: 'Miso.String.MisoString'
+-- myString = #cccccc         -- equivalent to \"#cccccc\"
+-- @
+--
+-- = Named colors
+--
+-- All 148 <https://www.w3.org/TR/css-color-4/#named-colors CSS named colors>
+-- are available as top-level values (e.g. 'red', 'blue', 'cornflowerblue').
+-- Each is defined as an 'rgba' value with full opacity (@alpha = 1@) and
+-- renders to its @rgba(…)@ form via 'renderColor'.
+--
+-- = See also
+--
+-- * "Miso.CSS" — CSS property DSL that consumes 'Color' values
+-- * "Miso.CSS.Types" — low-level CSS types
+-----------------------------------------------------------------------------
+module Miso.CSS.Color
+  ( -- *** Types
+    Color (RGB, RGBA, HSL, HSLA, OKLCH, OKLCHA, Hex)
+    -- *** Smart constructor
+  , rgba
+  , rgb
+  , hsl
+  , hsla
+  , oklch
+  , oklcha
+  , hex
+  , var
+    -- *** Render
+  , renderColor
+    -- *** Colors
+  , transparent
+  , aliceblue
+  , antiquewhite
+  , aqua
+  , aquamarine
+  , azure
+  , beige
+  , bisque
+  , black
+  , blanchedalmond
+  , blue
+  , blueviolet
+  , brown
+  , burlywood
+  , cadetblue
+  , chartreuse
+  , chocolate
+  , coral
+  , cornflowerblue
+  , cornsilk
+  , crimson
+  , cyan
+  , darkblue
+  , darkcyan
+  , darkgoldenrod
+  , darkgray
+  , darkgreen
+  , darkgrey
+  , darkkhaki
+  , darkmagenta
+  , darkolivegreen
+  , darkorange
+  , darkorchid
+  , darkred
+  , darksalmon
+  , darkseagreen
+  , darkslateblue
+  , darkslategray
+  , darkslategrey
+  , darkturquoise
+  , darkviolet
+  , deeppink
+  , deepskyblue
+  , dimgray
+  , dimgrey
+  , dodgerblue
+  , firebrick
+  , floralwhite
+  , forestgreen
+  , fuchsia
+  , gainsboro
+  , ghostwhite
+  , gold
+  , goldenrod
+  , gray
+  , green
+  , greenyellow
+  , grey
+  , honeydew
+  , hotpink
+  , indianred
+  , indigo
+  , ivory
+  , khaki
+  , lavender
+  , lavenderblush
+  , lawngreen
+  , lemonchiffon
+  , lightblue
+  , lightcoral
+  , lightcyan
+  , lightgoldenrodyellow
+  , lightgray
+  , lightgreen
+  , lightgrey
+  , lightpink
+  , lightsalmon
+  , lightseagreen
+  , lightskyblue
+  , lightslategray
+  , lightslategrey
+  , lightsteelblue
+  , lightyellow
+  , lime
+  , limegreen
+  , linen
+  , magenta
+  , maroon
+  , mediumaquamarine
+  , mediumblue
+  , mediumorchid
+  , mediumpurple
+  , mediumseagreen
+  , mediumslateblue
+  , mediumspringgreen
+  , mediumturquoise
+  , mediumvioletred
+  , midnightblue
+  , mintcream
+  , mistyrose
+  , moccasin
+  , navajowhite
+  , navy
+  , oldlace
+  , olive
+  , olivedrab
+  , orange
+  , orangered
+  , orchid
+  , palegoldenrod
+  , palegreen
+  , paleturquoise
+  , palevioletred
+  , papayawhip
+  , peachpuff
+  , peru
+  , pink
+  , plum
+  , powderblue
+  , purple
+  , red
+  , rosybrown
+  , royalblue
+  , saddlebrown
+  , salmon
+  , sandybrown
+  , seagreen
+  , seashell
+  , sienna
+  , silver
+  , skyblue
+  , slateblue
+  , slategray
+  , slategrey
+  , snow
+  , springgreen
+  , steelblue
+  , tan
+  , teal
+  , thistle
+  , tomato
+  , turquoise
+  , violet
+  , wheat
+  , white
+  , whitesmoke
+  , yellow
+  , yellowgreen
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.String (MisoString, ms)
+import qualified Miso.String as MS
+-----------------------------------------------------------------------------
+import           Data.Proxy
+import           GHC.TypeLits
+import           GHC.OverloadedLabels
+import           Miso.DSL (ToJSVal(..), ToArgs(..))
+import           Prelude hiding (tan)
+-----------------------------------------------------------------------------
+-- | Data type for expressing Color
+data Color
+  = RGBA Int Int Int Double
+  -- ^ Red, green, blue and alpha transparency. See [here](https://www.w3schools.com/colors/colors_rgb.asp)
+  | RGB Int Int Int
+  -- ^ Red, green, blue. See [here](https://www.w3schools.com/colors/colors_rgb.asp)
+  | HSL Int Int Int
+  -- ^ Hue, saturation, light. See [here](https://www.w3schools.com/colors/colors_hsl.asp)
+  | HSLA Int Int Int Double
+  -- ^ Hue, saturation, light and alpha transparency. See [here](https://www.w3schools.com/colors/colors_hsl.asp)
+  | Hex MisoString
+  -- ^ Hexadecimal representation of a color. See [here](https://www.w3schools.com/colors/colors_hexadecimal.asp)
+  | VarColor MisoString
+  -- ^ A CSS variable
+  | OKLCH Double Double Double
+  -- ^ Lightness, Chroma, Hue. See [oklch](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch).
+  | OKLCHA Double Double Double Double
+  -- ^ Lightness, Chroma, Hue, Alpha. See [oklhc](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch).
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | 'IsLabel' instance on 'Color'
+--
+-- @
+-- grey :: Color
+-- grey = #cccccc
+-- @
+instance KnownSymbol color => IsLabel color Color where
+  fromLabel = Hex (ms color)
+    where
+      color = symbolVal (Proxy @color)
+-----------------------------------------------------------------------------
+-- | 'IsLabel' instance on 'MisoString' for construction of hex colors as strings
+--
+-- @
+-- grey :: MisoString
+-- grey = #cccccc
+-- @
+instance KnownSymbol hex => IsLabel hex MisoString where
+  fromLabel = ms ("#" <> symbolVal (Proxy @hex))
+-----------------------------------------------------------------------------
+-- | 'ToArgs' instance for 'Color'
+instance ToArgs Color where
+  toArgs color = (:[]) <$> toJSVal color
+-----------------------------------------------------------------------------
+-- | 'ToJSVal' instance for 'Color'
+instance ToJSVal Color where
+  toJSVal = toJSVal . renderColor
+-----------------------------------------------------------------------------
+-- | Renders a 'Color' as 'MisoString'
+--
+-- >>> renderColor (hex "ccc")
+-- "#ccc"
+--
+renderColor :: Color -> MisoString
+renderColor (RGBA r g b a) = "rgba(" <> values <> ")"
+  where
+    values = MS.intercalate ","
+      [ MS.ms r
+      , MS.ms g
+      , MS.ms b
+      , MS.ms a
+      ]
+renderColor (RGB r g b) = "rgb(" <> values <> ")"
+  where
+    values = MS.intercalate ","
+      [ MS.ms r
+      , MS.ms g
+      , MS.ms b
+      ]
+renderColor (HSLA h s l a) = "hsla(" <> values <> ")"
+  where
+    values = MS.intercalate ","
+      [ MS.ms h
+      , MS.ms s
+      , MS.ms l
+      , MS.ms a
+      ]
+renderColor (HSL h s l) = "hsl(" <> values <> ")"
+  where
+    values = MS.intercalate ","
+      [ MS.ms h
+      , MS.ms s
+      , MS.ms l
+      ]
+renderColor (OKLCH l c h) = "oklch(" <> values <> ")"
+  where
+    values = MS.intercalate " "
+      [ MS.ms l <> "%"
+      , MS.ms c
+      , MS.ms h
+      ]
+renderColor (OKLCHA l c h a) = "oklch(" <> values <> ")"
+  where
+    values = MS.intercalate " "
+      [ MS.ms l <> "%"
+      , MS.ms c
+      , MS.ms h
+      ] <> " / " <> MS.ms a
+renderColor (Hex s) = "#" <> s
+renderColor (VarColor n) = "var(--" <> n <> ")"
+-----------------------------------------------------------------------------
+-- | Smart constructor for a [CSS variable](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties).
+--
+-- >>> renderColor (var "foo")
+-- "var(--foo)"
+--
+var :: MisoString -> Color
+var = VarColor
+-----------------------------------------------------------------------------
+-- | Smart constructor for an [RGBA](https://www.w3schools.com/css/css_colors_rgb.asp) 'Color' value.
+--
+-- >>> renderColor (rgba 0 0 0 1.0)
+-- "rgba(0,0,0,1.0)"
+--
+rgba :: Int -> Int -> Int -> Double -> Color
+rgba = RGBA
+-----------------------------------------------------------------------------
+-- | Smart constructor for an [RGB](https://www.w3schools.com/css/css_colors_rgb.asp) 'Color' value.
+--
+-- >>> renderColor (rgb 0 0 0)
+-- "rgb(0,0,0)"
+--
+rgb :: Int -> Int -> Int -> Color
+rgb = RGB
+-----------------------------------------------------------------------------
+-- | Smart constructor for an [HSL](https://www.w3schools.com/css/css_colors_hsl.asp) 'Color' value.
+--
+-- >>> renderColor (hsl 0 0 0)
+-- "hsl(0,0,0)"
+--
+hsl :: Int -> Int -> Int -> Color
+hsl = HSL
+-----------------------------------------------------------------------------
+-- | Smart constructor for a [HSLA](https://www.w3schools.com/css/css_colors_hsl.asp) 'Color' value.
+--
+-- >>> renderColor (hsla 0 0 0 1.0)
+-- "hsla(0,0,0,1.0)"
+--
+hsla :: Int -> Int -> Int -> Double -> Color
+hsla = HSLA
+-----------------------------------------------------------------------------
+-- | Smart constructor for a 'Hex' 'Color'
+--
+-- >>> renderColor (hex "ccc")
+-- "#ccc"
+--
+hex :: MisoString -> Color
+hex = Hex
+-----------------------------------------------------------------------------
+-- | Smart constructor for an 'OKLCH' 'Color'
+--
+-- >>> renderColor (oklch 40.1 0.123 0.123)
+-- "oklch(40.1% 0.123 0.123)"
+--
+oklch :: Double -> Double -> Double -> Color
+oklch = OKLCH
+-----------------------------------------------------------------------------
+-- | Smart constructor for an 'OKLCHA' 'Color' with alpha transparency
+--
+-- >>> renderColor (oklcha 40.1 0.123 0.123 0.5)
+-- "oklcha(40.1% 0.123 0.123 / 0.5)"
+--
+oklcha :: Double -> Double -> Double -> Double -> Color
+oklcha = OKLCHA
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'transparent' color
+--
+-- >>> renderColor transparent
+-- "rgba(0,0,0,0.0)"
+--
+transparent :: Color
+transparent = rgba 0 0 0 0
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'aliceblue' 'Color'.
+--
+-- >>> renderColor aliceblue
+-- "rgba(240,248,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYWxpY2VibHVlIi8+PC9zdmc+>>
+--
+aliceblue :: Color
+aliceblue = rgba 240 248 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'antiquewhite' 'Color'.
+--
+-- >>> renderColor antiquewhite
+-- "rgba(250,235,215,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYW50aXF1ZXdoaXRlIi8+PC9zdmc+>>
+--
+antiquewhite :: Color
+antiquewhite = rgba 250 235 215 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'aqua' 'Color'.
+--
+-- >>> renderColor aqua
+-- "rgba(0,255,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYXF1YSIvPjwvc3ZnPg==>>
+--
+aqua :: Color
+aqua = rgba 0 255 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'aquamarine' 'Color'.
+--
+-- >>> renderColor aquamarine
+-- "rgba(127,255,212,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYXF1YW1hcmluZSIvPjwvc3ZnPg==>>
+--
+aquamarine :: Color
+aquamarine = rgba 127 255 212 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'azure' 'Color'.
+--
+-- >>> renderColor azure
+-- "rgba(240,255,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYXp1cmUiLz48L3N2Zz4=>>
+--
+azure :: Color
+azure = rgba 240 255 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'beige' 'Color'.
+--
+-- >>> renderColor beige
+-- "rgba(245,245,220,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmVpZ2UiLz48L3N2Zz4=>>
+--
+beige :: Color
+beige = rgba 245 245 220 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'bisque' 'Color'.
+--
+-- >>> renderColor bisque
+-- "rgba(255,228,196,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmlzcXVlIi8+PC9zdmc+>>
+--
+bisque :: Color
+bisque = rgba 255 228 196 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'black' 'Color'.
+--
+-- >>> renderColor black
+-- "rgba(0,0,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmxhY2siLz48L3N2Zz4=>>
+--
+black :: Color
+black = rgba 0 0 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'blanchedalmond' 'Color'.
+--
+-- >>> renderColor blanchedalmond
+-- "rgba(255,235,205,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmxhbmNoZWRhbG1vbmQiLz48L3N2Zz4=>>
+--
+blanchedalmond :: Color
+blanchedalmond = rgba 255 235 205 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'blue' 'Color'.
+--
+-- >>> renderColor blue
+-- "rgba(0,0,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmx1ZSIvPjwvc3ZnPg==>>
+--
+blue :: Color
+blue = rgba 0 0 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'blueviolet' 'Color'.
+--
+-- >>> renderColor blueviolet
+-- "rgba(138,43,226,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmx1ZXZpb2xldCIvPjwvc3ZnPg==>>
+--
+blueviolet :: Color
+blueviolet = rgba 138 43 226 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'brown' 'Color'.
+--
+-- >>> renderColor brown
+-- "rgba(165,42,42,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYnJvd24iLz48L3N2Zz4=>>
+--
+brown :: Color
+brown = rgba 165 42 42 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'burlywood' 'Color'.
+--
+-- >>> renderColor burlywood
+-- "rgba(222,184,135,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYnVybHl3b29kIi8+PC9zdmc+>>
+--
+burlywood :: Color
+burlywood = rgba 222 184 135 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'cadetblue' 'Color'.
+--
+-- >>> renderColor cadetblue
+-- "rgba(95,158,160,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY2FkZXRibHVlIi8+PC9zdmc+>>
+--
+cadetblue :: Color
+cadetblue = rgba 95 158 160 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'chartreuse' 'Color'.
+--
+-- >>> renderColor chartreuse
+-- "rgba(127,255,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY2hhcnRyZXVzZSIvPjwvc3ZnPg==>>
+--
+chartreuse :: Color
+chartreuse = rgba 127 255 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'chocolate' 'Color'.
+--
+-- >>> renderColor chocolate
+-- "rgba(210,105,30,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY2hvY29sYXRlIi8+PC9zdmc+>>
+--
+chocolate :: Color
+chocolate = rgba 210 105 30 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'coral' 'Color'.
+--
+-- >>> renderColor coral
+-- "rgba(255,127,80,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY29yYWwiLz48L3N2Zz4=>>
+--
+coral :: Color
+coral = rgba 255 127 80 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'cornflowerblue' 'Color'.
+--
+-- >>> renderColor cornflowerblue
+-- "rgba(100,149,237,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY29ybmZsb3dlcmJsdWUiLz48L3N2Zz4=>>
+--
+cornflowerblue :: Color
+cornflowerblue = rgba 100 149 237 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'cornsilk' 'Color'.
+--
+-- >>> renderColor cornsilk
+-- "rgba(255,248,220,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY29ybnNpbGsiLz48L3N2Zz4=>>
+--
+cornsilk :: Color
+cornsilk = rgba 255 248 220 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'crimson' 'Color'.
+--
+-- >>> renderColor crimson
+-- "rgba(220,20,60,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY3JpbXNvbiIvPjwvc3ZnPg==>>
+--
+crimson :: Color
+crimson = rgba 220 20 60 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'cyan' 'Color'.
+--
+-- >>> renderColor cyan
+-- "rgba(0,255,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY3lhbiIvPjwvc3ZnPg==>>
+--
+cyan :: Color
+cyan = rgba 0 255 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkblue' 'Color'.
+--
+-- >>> renderColor darkblue
+-- "rgba(0,0,139,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2JsdWUiLz48L3N2Zz4=>>
+--
+darkblue :: Color
+darkblue = rgba 0 0 139 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkcyan' 'Color'.
+--
+-- >>> renderColor darkcyan
+-- "rgba(0,139,139,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2N5YW4iLz48L3N2Zz4=>>
+--
+darkcyan :: Color
+darkcyan = rgba 0 139 139 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkgoldenrod' 'Color'.
+--
+-- >>> renderColor darkgoldenrod
+-- "rgba(184,134,11,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2dvbGRlbnJvZCIvPjwvc3ZnPg==>>
+--
+darkgoldenrod :: Color
+darkgoldenrod = rgba 184 134 11 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkgray' 'Color'.
+--
+-- >>> renderColor darkgray
+-- "rgba(169,169,169,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2dyYXkiLz48L3N2Zz4=>>
+--
+darkgray :: Color
+darkgray = rgba 169 169 169 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkgreen' 'Color'.
+--
+-- >>> renderColor darkgreen
+-- "rgba(0,100,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2dyZWVuIi8+PC9zdmc+>>
+--
+darkgreen :: Color
+darkgreen = rgba 0 100 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkgrey' 'Color'.
+--
+-- >>> renderColor darkgrey
+-- "rgba(169,169,169,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2dyZXkiLz48L3N2Zz4=>>
+--
+darkgrey :: Color
+darkgrey = rgba 169 169 169 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkkhaki' 'Color'.
+--
+-- >>> renderColor darkkhaki
+-- "rgba(189,183,107,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2toYWtpIi8+PC9zdmc+>>
+--
+darkkhaki :: Color
+darkkhaki = rgba 189 183 107 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkmagenta' 'Color'.
+--
+-- >>> renderColor darkmagenta
+-- "rgba(139,0,139,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya21hZ2VudGEiLz48L3N2Zz4=>>
+--
+darkmagenta :: Color
+darkmagenta = rgba 139 0 139 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkolivegreen' 'Color'.
+--
+-- >>> renderColor darkolivegreen
+-- "rgba(85,107,47,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya29saXZlZ3JlZW4iLz48L3N2Zz4=>>
+--
+darkolivegreen :: Color
+darkolivegreen = rgba 85 107 47 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkorange' 'Color'.
+--
+-- >>> renderColor darkorange
+-- "rgba(255,140,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya29yYW5nZSIvPjwvc3ZnPg==>>
+--
+darkorange :: Color
+darkorange = rgba 255 140 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkorchid' 'Color'.
+--
+-- >>> renderColor darkorchid
+-- "rgba(153,50,204,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya29yY2hpZCIvPjwvc3ZnPg==>>
+--
+darkorchid :: Color
+darkorchid = rgba 153 50 204 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkred' 'Color'.
+--
+-- >>> renderColor darkred
+-- "rgba(139,0,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3JlZCIvPjwvc3ZnPg==>>
+--
+darkred :: Color
+darkred = rgba 139 0 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darksalmon' 'Color'.
+--
+-- >>> renderColor darksalmon
+-- "rgba(233,150,122,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NhbG1vbiIvPjwvc3ZnPg==>>
+--
+darksalmon :: Color
+darksalmon = rgba 233 150 122 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkseagreen' 'Color'.
+--
+-- >>> renderColor darkseagreen
+-- "rgba(143,188,143,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NlYWdyZWVuIi8+PC9zdmc+>>
+--
+darkseagreen :: Color
+darkseagreen = rgba 143 188 143 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkslateblue' 'Color'.
+--
+-- >>> renderColor darkslateblue
+-- "rgba(72,61,139,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NsYXRlYmx1ZSIvPjwvc3ZnPg==>>
+--
+darkslateblue :: Color
+darkslateblue = rgba 72 61 139 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkslategray' 'Color'.
+--
+-- >>> renderColor darkslategray
+-- "rgba(47,79,79,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NsYXRlZ3JheSIvPjwvc3ZnPg==>>
+--
+darkslategray :: Color
+darkslategray = rgba 47 79 79 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkslategrey' 'Color'.
+--
+-- >>> renderColor darkslategrey
+-- "rgba(47,79,79,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NsYXRlZ3JleSIvPjwvc3ZnPg==>>
+--
+darkslategrey :: Color
+darkslategrey = rgba 47 79 79 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkturquoise' 'Color'.
+--
+-- >>> renderColor darkturquoise
+-- "rgba(0,206,209,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3R1cnF1b2lzZSIvPjwvc3ZnPg==>>
+--
+darkturquoise :: Color
+darkturquoise = rgba 0 206 209 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'darkviolet' 'Color'.
+--
+-- >>> renderColor darkviolet
+-- "rgba(148,0,211,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3Zpb2xldCIvPjwvc3ZnPg==>>
+--
+darkviolet :: Color
+darkviolet = rgba 148 0 211 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'deeppink' 'Color'.
+--
+-- >>> renderColor deeppink
+-- "rgba(255,20,147,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGVlcHBpbmsiLz48L3N2Zz4=>>
+--
+deeppink :: Color
+deeppink = rgba 255 20 147 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'deepskyblue' 'Color'.
+--
+-- >>> renderColor deepskyblue
+-- "rgba(0,191,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGVlcHNreWJsdWUiLz48L3N2Zz4=>>
+--
+deepskyblue :: Color
+deepskyblue = rgba 0 191 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'dimgray' 'Color'.
+--
+-- >>> renderColor dimgray
+-- "rgba(105,105,105,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGltZ3JheSIvPjwvc3ZnPg==>>
+--
+dimgray :: Color
+dimgray = rgba 105 105 105 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'dimgrey' 'Color'.
+--
+-- >>> renderColor dimgrey
+-- "rgba(105,105,105,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGltZ3JleSIvPjwvc3ZnPg==>>
+--
+dimgrey :: Color
+dimgrey = rgba 105 105 105 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'dodgerblue' 'Color'.
+--
+-- >>> renderColor dodgerblue
+-- "rgba(30,144,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZG9kZ2VyYmx1ZSIvPjwvc3ZnPg==>>
+--
+dodgerblue :: Color
+dodgerblue = rgba 30 144 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'firebrick' 'Color'.
+--
+-- >>> renderColor firebrick
+-- "rgba(178,34,34,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZmlyZWJyaWNrIi8+PC9zdmc+>>
+--
+firebrick :: Color
+firebrick = rgba 178 34 34 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'floralwhite' 'Color'.
+--
+-- >>> renderColor floralwhite
+-- "rgba(255,250,240,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZmxvcmFsd2hpdGUiLz48L3N2Zz4=>>
+--
+floralwhite :: Color
+floralwhite = rgba 255 250 240 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'forestgreen' 'Color'.
+--
+-- >>> renderColor forestgreen
+-- "rgba(34,139,34,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZm9yZXN0Z3JlZW4iLz48L3N2Zz4=>>
+--
+forestgreen :: Color
+forestgreen = rgba 34 139 34 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'fuchsia' 'Color'.
+--
+-- >>> renderColor fuchsia
+-- "rgba(255,0,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZnVjaHNpYSIvPjwvc3ZnPg==>>
+--
+fuchsia :: Color
+fuchsia = rgba 255 0 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'gainsboro' 'Color'.
+--
+-- >>> renderColor gainsboro
+-- "rgba(220,220,220,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ2FpbnNib3JvIi8+PC9zdmc+>>
+--
+gainsboro :: Color
+gainsboro = rgba 220 220 220 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'ghostwhite' 'Color'.
+--
+-- >>> renderColor ghostwhite
+-- "rgba(248,248,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ2hvc3R3aGl0ZSIvPjwvc3ZnPg==>>
+--
+ghostwhite :: Color
+ghostwhite = rgba 248 248 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'gold' 'Color'.
+--
+-- >>> renderColor gold
+-- "rgba(255,215,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ29sZCIvPjwvc3ZnPg==>>
+--
+gold :: Color
+gold = rgba 255 215 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'goldenrod' 'Color'.
+--
+-- >>> renderColor goldenrod
+-- "rgba(218,165,32,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ29sZGVucm9kIi8+PC9zdmc+>>
+--
+goldenrod :: Color
+goldenrod = rgba 218 165 32 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'gray' 'Color'.
+--
+-- >>> renderColor gray
+-- "rgba(128,128,128,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ3JheSIvPjwvc3ZnPg==>>
+--
+gray :: Color
+gray = rgba 128 128 128 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'green' 'Color'.
+--
+-- >>> renderColor green
+-- "rgba(0,128,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ3JlZW4iLz48L3N2Zz4=>>
+--
+green :: Color
+green = rgba 0 128 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'greenyellow' 'Color'.
+--
+-- >>> renderColor greenyellow
+-- "rgba(173,255,47,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ3JlZW55ZWxsb3ciLz48L3N2Zz4=>>
+--
+greenyellow :: Color
+greenyellow = rgba 173 255 47 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'grey' 'Color'.
+--
+-- >>> renderColor grey
+-- "rgba(128,128,128,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ3JleSIvPjwvc3ZnPg==>>
+--
+grey :: Color
+grey = rgba 128 128 128 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'honeydew' 'Color'.
+--
+-- >>> renderColor honeydew
+-- "rgba(240,255,240,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaG9uZXlkZXciLz48L3N2Zz4=>>
+--
+honeydew :: Color
+honeydew = rgba 240 255 240 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'hotpink' 'Color'.
+--
+-- >>> renderColor hotpink
+-- "rgba(255,105,180,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaG90cGluayIvPjwvc3ZnPg==>>
+--
+hotpink :: Color
+hotpink = rgba 255 105 180 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'indianred' 'Color'.
+--
+-- >>> renderColor indianred
+-- "rgba(205,92,92,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaW5kaWFucmVkIi8+PC9zdmc+>>
+--
+indianred :: Color
+indianred = rgba 205 92 92 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'indigo' 'Color'.
+--
+-- >>> renderColor indigo
+-- "rgba(75,0,130,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaW5kaWdvIi8+PC9zdmc+>>
+--
+indigo :: Color
+indigo = rgba 75 0 130 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'ivory' 'Color'.
+--
+-- >>> renderColor ivory
+-- "rgba(255,255,240,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaXZvcnkiLz48L3N2Zz4=>>
+--
+ivory :: Color
+ivory = rgba 255 255 240 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'khaki' 'Color'.
+--
+-- >>> renderColor khaki
+-- "rgba(240,230,140,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ia2hha2kiLz48L3N2Zz4=>>
+--
+khaki :: Color
+khaki = rgba 240 230 140 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lavender' 'Color'.
+--
+-- >>> renderColor lavender
+-- "rgba(230,230,250,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGF2ZW5kZXIiLz48L3N2Zz4=>>
+--
+lavender :: Color
+lavender = rgba 230 230 250 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lavenderblush' 'Color'.
+--
+-- >>> renderColor lavenderblush
+-- "rgba(255,240,245,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGF2ZW5kZXJibHVzaCIvPjwvc3ZnPg==>>
+--
+lavenderblush :: Color
+lavenderblush = rgba 255 240 245 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lawngreen' 'Color'.
+--
+-- >>> renderColor lawngreen
+-- "rgba(124,252,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGF3bmdyZWVuIi8+PC9zdmc+>>
+--
+lawngreen :: Color
+lawngreen = rgba 124 252 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lemonchiffon' 'Color'.
+--
+-- >>> renderColor lemonchiffon
+-- "rgba(255,250,205,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGVtb25jaGlmZm9uIi8+PC9zdmc+>>
+--
+lemonchiffon :: Color
+lemonchiffon = rgba 255 250 205 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightblue' 'Color'.
+--
+-- >>> renderColor lightblue
+-- "rgba(173,216,230,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRibHVlIi8+PC9zdmc+>>
+--
+lightblue :: Color
+lightblue = rgba 173 216 230 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightcoral' 'Color'.
+--
+-- >>> renderColor lightcoral
+-- "rgba(240,128,128,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRjb3JhbCIvPjwvc3ZnPg==>>
+--
+lightcoral :: Color
+lightcoral = rgba 240 128 128 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightcyan' 'Color'.
+--
+-- >>> renderColor lightcyan
+-- "rgba(224,255,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRjeWFuIi8+PC9zdmc+>>
+--
+lightcyan :: Color
+lightcyan = rgba 224 255 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightgoldenrodyellow' 'Color'.
+--
+-- >>> renderColor lightgoldenrodyellow
+-- "rgba(250,250,210,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRnb2xkZW5yb2R5ZWxsb3ciLz48L3N2Zz4=>>
+--
+lightgoldenrodyellow :: Color
+lightgoldenrodyellow = rgba 250 250 210 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightgray' 'Color'.
+--
+-- >>> renderColor lightgray
+-- "rgba(211,211,211,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRncmF5Ii8+PC9zdmc+>>
+--
+lightgray :: Color
+lightgray = rgba 211 211 211 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightgreen' 'Color'.
+--
+-- >>> renderColor lightgreen
+-- "rgba(144,238,144,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRncmVlbiIvPjwvc3ZnPg==>>
+--
+lightgreen :: Color
+lightgreen = rgba 144 238 144 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightgrey' 'Color'.
+--
+-- >>> renderColor lightgrey
+-- "rgba(211,211,211,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRncmV5Ii8+PC9zdmc+>>
+--
+lightgrey :: Color
+lightgrey = rgba 211 211 211 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightpink' 'Color'.
+--
+-- >>> renderColor lightpink
+-- "rgba(255,182,193,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRwaW5rIi8+PC9zdmc+>>
+--
+lightpink :: Color
+lightpink = rgba 255 182 193 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightsalmon' 'Color'.
+--
+-- >>> renderColor lightsalmon
+-- "rgba(255,160,122,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzYWxtb24iLz48L3N2Zz4=>>
+--
+lightsalmon :: Color
+lightsalmon = rgba 255 160 122 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightseagreen' 'Color'.
+--
+-- >>> renderColor lightseagreen
+-- "rgba(32,178,170,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzZWFncmVlbiIvPjwvc3ZnPg==>>
+--
+lightseagreen :: Color
+lightseagreen = rgba 32 178 170 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightskyblue' 'Color'.
+--
+-- >>> renderColor lightskyblue
+-- "rgba(135,206,250,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRza3libHVlIi8+PC9zdmc+>>
+--
+lightskyblue :: Color
+lightskyblue = rgba 135 206 250 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightslategray' 'Color'.
+--
+-- >>> renderColor lightslategray
+-- "rgba(119,136,153,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzbGF0ZWdyYXkiLz48L3N2Zz4=>>
+--
+lightslategray :: Color
+lightslategray = rgba 119 136 153 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightslategrey' 'Color'.
+--
+-- >>> renderColor lightslategrey
+-- "rgba(119,136,153,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzbGF0ZWdyZXkiLz48L3N2Zz4=>>
+--
+lightslategrey :: Color
+lightslategrey = rgba 119 136 153 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightsteelblue' 'Color'.
+--
+-- >>> renderColor lightsteelblue
+-- "rgba(176,196,222,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzdGVlbGJsdWUiLz48L3N2Zz4=>>
+--
+lightsteelblue :: Color
+lightsteelblue = rgba 176 196 222 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lightyellow' 'Color'.
+--
+-- >>> renderColor lightyellow
+-- "rgba(255,255,224,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHR5ZWxsb3ciLz48L3N2Zz4=>>
+--
+lightyellow :: Color
+lightyellow = rgba 255 255 224 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'lime' 'Color'.
+--
+-- >>> renderColor lime
+-- "rgba(0,255,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGltZSIvPjwvc3ZnPg==>>
+--
+lime :: Color
+lime = rgba 0 255 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'limegreen' 'Color'.
+--
+-- >>> renderColor limegreen
+-- "rgba(50,205,50,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGltZWdyZWVuIi8+PC9zdmc+>>
+--
+limegreen :: Color
+limegreen = rgba 50 205 50 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'linen' 'Color'.
+--
+-- >>> renderColor linen
+-- "rgba(250,240,230,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGluZW4iLz48L3N2Zz4=>>
+--
+linen :: Color
+linen = rgba 250 240 230 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'magenta' 'Color'.
+--
+-- >>> renderColor magenta
+-- "rgba(255,0,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWFnZW50YSIvPjwvc3ZnPg==>>
+--
+magenta :: Color
+magenta = rgba 255 0 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'maroon' 'Color'.
+--
+-- >>> renderColor maroon
+-- "rgba(128,0,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWFyb29uIi8+PC9zdmc+>>
+--
+maroon :: Color
+maroon = rgba 128 0 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mediumaquamarine' 'Color'.
+--
+-- >>> renderColor mediumaquamarine
+-- "rgba(102,205,170,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtYXF1YW1hcmluZSIvPjwvc3ZnPg==>>
+--
+mediumaquamarine :: Color
+mediumaquamarine = rgba 102 205 170 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mediumblue' 'Color'.
+--
+-- >>> renderColor mediumblue
+-- "rgba(0,0,205,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtYmx1ZSIvPjwvc3ZnPg==>>
+--
+mediumblue :: Color
+mediumblue = rgba 0 0 205 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mediumorchid' 'Color'.
+--
+-- >>> renderColor mediumorchid
+-- "rgba(186,85,211,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtb3JjaGlkIi8+PC9zdmc+>>
+--
+mediumorchid :: Color
+mediumorchid = rgba 186 85 211 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mediumpurple' 'Color'.
+--
+-- >>> renderColor mediumpurple
+-- "rgba(147,112,219,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtcHVycGxlIi8+PC9zdmc+>>
+--
+mediumpurple :: Color
+mediumpurple = rgba 147 112 219 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mediumseagreen' 'Color'.
+--
+-- >>> renderColor mediumseagreen
+-- "rgba(60,179,113,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtc2VhZ3JlZW4iLz48L3N2Zz4=>>
+--
+mediumseagreen :: Color
+mediumseagreen = rgba 60 179 113 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mediumslateblue' 'Color'.
+--
+-- >>> renderColor mediumslateblue
+-- "rgba(123,104,238,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtc2xhdGVibHVlIi8+PC9zdmc+>>
+--
+mediumslateblue :: Color
+mediumslateblue = rgba 123 104 238 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mediumspringgreen' 'Color'.
+--
+-- >>> renderColor mediumspringgreen
+-- "rgba(0,250,154,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtc3ByaW5nZ3JlZW4iLz48L3N2Zz4=>>
+--
+mediumspringgreen :: Color
+mediumspringgreen = rgba 0 250 154 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mediumturquoise' 'Color'.
+--
+-- >>> renderColor mediumturquoise
+-- "rgba(72,209,204,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtdHVycXVvaXNlIi8+PC9zdmc+>>
+--
+mediumturquoise :: Color
+mediumturquoise = rgba 72 209 204 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mediumvioletred' 'Color'.
+--
+-- >>> renderColor mediumvioletred
+-- "rgba(199,21,133,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtdmlvbGV0cmVkIi8+PC9zdmc+>>
+--
+mediumvioletred :: Color
+mediumvioletred = rgba 199 21 133 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'midnightblue' 'Color'.
+--
+-- >>> renderColor midnightblue
+-- "rgba(25,25,112,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWlkbmlnaHRibHVlIi8+PC9zdmc+>>
+--
+midnightblue :: Color
+midnightblue = rgba 25 25 112 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mintcream' 'Color'.
+--
+-- >>> renderColor mintcream
+-- "rgba(245,255,250,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWludGNyZWFtIi8+PC9zdmc+>>
+--
+mintcream :: Color
+mintcream = rgba 245 255 250 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'mistyrose' 'Color'.
+--
+-- >>> renderColor mistyrose
+-- "rgba(255,228,225,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWlzdHlyb3NlIi8+PC9zdmc+>>
+--
+mistyrose :: Color
+mistyrose = rgba 255 228 225 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'moccasin' 'Color'.
+--
+-- >>> renderColor moccasin
+-- "rgba(255,228,181,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibW9jY2FzaW4iLz48L3N2Zz4=>>
+--
+moccasin :: Color
+moccasin = rgba 255 228 181 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'navajowhite' 'Color'.
+--
+-- >>> renderColor navajowhite
+-- "rgba(255,222,173,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibmF2YWpvd2hpdGUiLz48L3N2Zz4=>>
+--
+navajowhite :: Color
+navajowhite = rgba 255 222 173 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'navy' 'Color'.
+--
+-- >>> renderColor navy
+-- "rgba(0,0,128,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibmF2eSIvPjwvc3ZnPg==>>
+--
+navy :: Color
+navy = rgba 0 0 128 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'oldlace' 'Color'.
+--
+-- >>> renderColor oldlace
+-- "rgba(253,245,230,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib2xkbGFjZSIvPjwvc3ZnPg==>>
+--
+oldlace :: Color
+oldlace = rgba 253 245 230 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'olive' 'Color'.
+--
+-- >>> renderColor olive
+-- "rgba(128,128,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib2xpdmUiLz48L3N2Zz4=>>
+--
+olive :: Color
+olive = rgba 128 128 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'olivedrab' 'Color'.
+--
+-- >>> renderColor olivedrab
+-- "rgba(107,142,35,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib2xpdmVkcmFiIi8+PC9zdmc+>>
+--
+olivedrab :: Color
+olivedrab = rgba 107 142 35 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'orange' 'Color'.
+--
+-- >>> renderColor orange
+-- "rgba(255,165,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib3JhbmdlIi8+PC9zdmc+>>
+--
+orange :: Color
+orange = rgba 255 165 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'orangered' 'Color'.
+--
+-- >>> renderColor orangered
+-- "rgba(255,69,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib3JhbmdlcmVkIi8+PC9zdmc+>>
+--
+orangered :: Color
+orangered = rgba 255 69 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'orchid' 'Color'.
+--
+-- >>> renderColor orchid
+-- "rgba(218,112,214,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib3JjaGlkIi8+PC9zdmc+>>
+--
+orchid :: Color
+orchid = rgba 218 112 214 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'palegoldenrod' 'Color'.
+--
+-- >>> renderColor palegoldenrod
+-- "rgba(238,232,170,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFsZWdvbGRlbnJvZCIvPjwvc3ZnPg==>>
+--
+palegoldenrod :: Color
+palegoldenrod = rgba 238 232 170 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'palegreen' 'Color'.
+--
+-- >>> renderColor palegreen
+-- "rgba(152,251,152,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFsZWdyZWVuIi8+PC9zdmc+>>
+--
+palegreen :: Color
+palegreen = rgba 152 251 152 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'paleturquoise' 'Color'.
+--
+-- >>> renderColor paleturquoise
+-- "rgba(175,238,238,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFsZXR1cnF1b2lzZSIvPjwvc3ZnPg==>>
+--
+paleturquoise :: Color
+paleturquoise = rgba 175 238 238 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'palevioletred' 'Color'.
+--
+-- >>> renderColor palevioletred
+-- "rgba(219,112,147,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFsZXZpb2xldHJlZCIvPjwvc3ZnPg==>>
+--
+palevioletred :: Color
+palevioletred = rgba 219 112 147 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'papayawhip' 'Color'.
+--
+-- >>> renderColor papayawhip
+-- "rgba(255,239,213,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFwYXlhd2hpcCIvPjwvc3ZnPg==>>
+--
+papayawhip :: Color
+papayawhip = rgba 255 239 213 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'peachpuff' 'Color'.
+--
+-- >>> renderColor peachpuff
+-- "rgba(255,218,185,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGVhY2hwdWZmIi8+PC9zdmc+>>
+--
+peachpuff :: Color
+peachpuff = rgba 255 218 185 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'peru' 'Color'.
+--
+-- >>> renderColor peru
+-- "rgba(205,133,63,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGVydSIvPjwvc3ZnPg==>>
+--
+peru :: Color
+peru = rgba 205 133 63 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'pink' 'Color'.
+--
+-- >>> renderColor pink
+-- "rgba(255,192,203,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGluayIvPjwvc3ZnPg==>>
+--
+pink :: Color
+pink = rgba 255 192 203 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'plum' 'Color'.
+--
+-- >>> renderColor plum
+-- "rgba(221,160,221,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGx1bSIvPjwvc3ZnPg==>>
+--
+plum :: Color
+plum = rgba 221 160 221 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'powderblue' 'Color'.
+--
+-- >>> renderColor powderblue
+-- "rgba(176,224,230,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icG93ZGVyYmx1ZSIvPjwvc3ZnPg==>>
+--
+powderblue :: Color
+powderblue = rgba 176 224 230 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'purple' 'Color'.
+--
+-- >>> renderColor purple
+-- "rgba(128,0,128,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icHVycGxlIi8+PC9zdmc+>>
+--
+purple :: Color
+purple = rgba 128 0 128 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'red' 'Color'.
+--
+-- >>> renderColor red
+-- "rgba(255,0,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icmVkIi8+PC9zdmc+>>
+--
+red :: Color
+red = rgba 255 0 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'rosybrown' 'Color'.
+--
+-- >>> renderColor rosybrown
+-- "rgba(188,143,143,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icm9zeWJyb3duIi8+PC9zdmc+>>
+--
+rosybrown :: Color
+rosybrown = rgba 188 143 143 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'royalblue' 'Color'.
+--
+-- >>> renderColor royalblue
+-- "rgba(65,105,225,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icm95YWxibHVlIi8+PC9zdmc+>>
+--
+royalblue :: Color
+royalblue = rgba 65 105 225 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'saddlebrown' 'Color'.
+--
+-- >>> renderColor saddlebrown
+-- "rgba(139,69,19,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2FkZGxlYnJvd24iLz48L3N2Zz4=>>
+--
+saddlebrown :: Color
+saddlebrown = rgba 139 69 19 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'salmon' 'Color'.
+--
+-- >>> renderColor salmon
+-- "rgba(250,128,114,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2FsbW9uIi8+PC9zdmc+>>
+--
+salmon :: Color
+salmon = rgba 250 128 114 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'sandybrown' 'Color'.
+--
+-- >>> renderColor sandybrown
+-- "rgba(244,164,96,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2FuZHlicm93biIvPjwvc3ZnPg==>>
+--
+sandybrown :: Color
+sandybrown = rgba 244 164 96 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'seagreen' 'Color'.
+--
+-- >>> renderColor seagreen
+-- "rgba(46,139,87,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2VhZ3JlZW4iLz48L3N2Zz4=>>
+--
+seagreen :: Color
+seagreen = rgba 46 139 87 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'seashell' 'Color'.
+--
+-- >>> renderColor seashell
+-- "rgba(255,245,238,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2Vhc2hlbGwiLz48L3N2Zz4=>>
+--
+seashell :: Color
+seashell = rgba 255 245 238 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'sienna' 'Color'.
+--
+-- >>> renderColor sienna
+-- "rgba(160,82,45,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2llbm5hIi8+PC9zdmc+>>
+--
+sienna :: Color
+sienna = rgba 160 82 45 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'silver' 'Color'.
+--
+-- >>> renderColor silver
+-- "rgba(192,192,192,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2lsdmVyIi8+PC9zdmc+>>
+--
+silver :: Color
+silver = rgba 192 192 192 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'skyblue' 'Color'.
+--
+-- >>> renderColor skyblue
+-- "rgba(135,206,235,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2t5Ymx1ZSIvPjwvc3ZnPg==>>
+--
+skyblue :: Color
+skyblue = rgba 135 206 235 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'slateblue' 'Color'.
+--
+-- >>> renderColor slateblue
+-- "rgba(106,90,205,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2xhdGVibHVlIi8+PC9zdmc+>>
+--
+slateblue :: Color
+slateblue = rgba 106 90 205 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'slategray' 'Color'.
+--
+-- >>> renderColor slategray
+-- "rgba(112,128,144,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2xhdGVncmF5Ii8+PC9zdmc+>>
+--
+slategray :: Color
+slategray = rgba 112 128 144 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'slategrey' 'Color'.
+--
+-- >>> renderColor slategrey
+-- "rgba(112,128,144,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2xhdGVncmV5Ii8+PC9zdmc+>>
+--
+slategrey :: Color
+slategrey = rgba 112 128 144 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'snow' 'Color'.
+--
+-- >>> renderColor snow
+-- "rgba(255,250,250,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic25vdyIvPjwvc3ZnPg==>>
+--
+snow :: Color
+snow = rgba 255 250 250 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'springgreen' 'Color'.
+--
+-- >>> renderColor springgreen
+-- "rgba(0,255,127,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic3ByaW5nZ3JlZW4iLz48L3N2Zz4=>>
+--
+springgreen :: Color
+springgreen = rgba 0 255 127 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'steelblue' 'Color'.
+--
+-- >>> renderColor steelblue
+-- "rgba(70,130,180,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic3RlZWxibHVlIi8+PC9zdmc+>>
+--
+steelblue :: Color
+steelblue = rgba 70 130 180 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'tan' 'Color'.
+--
+-- >>> renderColor tan
+-- "rgba(210,180,140,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idGFuIi8+PC9zdmc+>>
+--
+tan :: Color
+tan = rgba 210 180 140 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'teal' 'Color'.
+--
+-- >>> renderColor teal
+-- "rgba(0,128,128,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idGVhbCIvPjwvc3ZnPg==>>
+--
+teal :: Color
+teal = rgba 0 128 128 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'thistle' 'Color'.
+--
+-- >>> renderColor thistle
+-- "rgba(216,191,216,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idGhpc3RsZSIvPjwvc3ZnPg==>>
+--
+thistle :: Color
+thistle = rgba 216 191 216 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'tomato' 'Color'.
+--
+-- >>> renderColor tomato
+-- "rgba(255,99,71,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idG9tYXRvIi8+PC9zdmc+>>
+--
+tomato :: Color
+tomato = rgba 255 99 71 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'turquoise' 'Color'.
+--
+-- >>> renderColor turquoise
+-- "rgba(64,224,208,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idHVycXVvaXNlIi8+PC9zdmc+>>
+--
+turquoise :: Color
+turquoise = rgba 64 224 208 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'violet' 'Color'.
+--
+-- >>> renderColor violet
+-- "rgba(238,130,238,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idmlvbGV0Ii8+PC9zdmc+>>
+--
+violet :: Color
+violet = rgba 238 130 238 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'wheat' 'Color'.
+--
+-- >>> renderColor wheat
+-- "rgba(245,222,179,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0id2hlYXQiLz48L3N2Zz4=>>
+--
+wheat :: Color
+wheat = rgba 245 222 179 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'white' 'Color'.
+--
+-- >>> renderColor white
+-- "rgba(255,255,255,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=>>
+--
+white :: Color
+white = rgba 255 255 255 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'whitesmoke' 'Color'.
+--
+-- >>> renderColor whitesmoke
+-- "rgba(245,245,245,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0id2hpdGVzbW9rZSIvPjwvc3ZnPg==>>
+--
+whitesmoke :: Color
+whitesmoke = rgba 245 245 245 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'yellow' 'Color'.
+--
+-- >>> renderColor yellow
+-- "rgba(255,255,0,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ieWVsbG93Ii8+PC9zdmc+>>
+--
+yellow :: Color
+yellow = rgba 255 255 0 1
+-----------------------------------------------------------------------------
+-- | Smart constructor for the 'yellowgreen' 'Color'.
+--
+-- >>> renderColor yellowgreen
+-- "rgba(154,205,50,1.0)"
+--
+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ieWVsbG93Z3JlZW4iLz48L3N2Zz4=>>
+--
+yellowgreen :: Color
+yellowgreen = rgba 154 205 50 1
+-----------------------------------------------------------------------------
diff --git a/src/Miso/CSS/Types.hs b/src/Miso/CSS/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/CSS/Types.hs
@@ -0,0 +1,130 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.CSS.Types
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.CSS.Types" defines the core data types that back the CSS DSL in
+-- "Miso.CSS". There are three layers:
+--
+-- * 'Style' — a single CSS property\/value pair (@(\"color\", \"red\")@).
+-- * t'Styles' — one rule block: either a selector rule, a
+--   <https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes \@keyframes>
+--   animation, or a
+--   <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries \@media>
+--   query.
+-- * t'StyleSheet' — an ordered list of t'Styles' rule blocks that together form
+--   a complete
+--   <https://developer.mozilla.org/en-US/docs/Web/API/StyleSheet stylesheet>.
+--
+-- In normal usage you never construct these types directly — the smart
+-- constructors in "Miso.CSS" (@sheet_@, @selector_@, @keyframes_@, @media_@)
+-- build them for you. This module is exported for downstream code that
+-- inspects or extends the CSS representation.
+--
+-- = Type hierarchy
+--
+-- @
+-- t'StyleSheet'          -- rendered to a \<style\> tag
+--   └─ ['Styles']       -- one rule block each
+--        ├─ t'Styles'    (selector → ['Style'])
+--        ├─ 'KeyFrame'  (animation-name → [(stop, ['Style'])])
+--        └─ 'Media'     (media-query   → [(selector, ['Style'])])
+--
+-- 'Style' = ('MisoString', 'MisoString')   -- property, value
+-- @
+--
+-- = See also
+--
+-- * "Miso.CSS" — smart constructors and property combinators built on these types
+-- * "Miso.CSS.Color" — 'Miso.CSS.Color.Color' type used as property values
+-----------------------------------------------------------------------------
+module Miso.CSS.Types
+  ( -- *** Types
+    Style
+  , Styles (..)
+  , StyleSheet (..)
+  , TransformFn (..)
+  , KeyframeStop (..)
+  , MediaRule (..)
+  , MediaQuery (..)
+  ) where
+-----------------------------------------------------------------------------
+import Miso.String (MisoString)
+-----------------------------------------------------------------------------
+-- | Type for a CSS StyleSheet. Internally it maps From CSS selectors to t'Styles'.
+--
+-- @
+-- testSheet :: StyleSheet
+-- testSheet =
+--    sheet_
+--    [ selector_ ".name"
+--        [ backgroundColor red
+--        , alignContent "top"
+--        ]
+--    , selector_ "#container"
+--        [ backgroundColor blue
+--        , alignContent "center"
+--        ]
+--    , keyframes_ "slide-in"
+--      [ from_ [ transforms [ translateX (pct 0) ] ]
+--      , at (pct 50)
+--        [ backgroundColor red
+--        , backgroundSize "10px"
+--        ]
+--      , to_ [ transforms [ translateX (pct 100) ] ]
+--      ]
+--    , media_ (screen_ `and_` minWidth_ (px 480))
+--      [ rule_ "header" [ height "auto" ]
+--      , rule_ "ul"     [ display "block" ]
+--      ]
+--    ]
+-- @
+--
+newtype StyleSheet = StyleSheet
+  { getStyleSheet :: [Styles]
+  -- ^ Ordered list of CSS rule blocks that make up the stylesheet
+  } deriving (Eq, Show)
+-----------------------------------------------------------------------------
+-- | Type for a CSS 'Style'
+--
+type Style = (MisoString, MisoString)
+-----------------------------------------------------------------------------
+-- | An individual CSS <https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function transform function>.
+-- Construct values with @translate@, @rotate@, @scale@, etc., then combine with 'Miso.CSS.transforms'.
+--
+-- @
+-- transforms [ translate (px 10) (pct 50), rotate (deg 45), scaleX 1.5 ]
+-- @
+--
+newtype TransformFn = TransformFn
+  { renderTransformFn :: MisoString
+  -- ^ The serialised CSS transform function string (e.g. @\"rotate(45deg)\"@)
+  } deriving (Eq, Show)
+-----------------------------------------------------------------------------
+-- | A CSS rule block. One of: a selector rule, a @\@keyframes@ animation, or a @\@media@ query.
+data Styles
+  = Styles (MisoString, [Style])
+  | KeyFrame MisoString [(MisoString, [Style])]
+  | Media MisoString [(MisoString, [Style])]
+  deriving (Eq, Show)
+-----------------------------------------------------------------------------
+-- | A single stop in a '@keyframes' rule. Construct with @from_@, @to_@, or @at@.
+newtype KeyframeStop = KeyframeStop { getKeyframeStop :: (MisoString, [Style]) }
+  deriving (Eq, Show)
+-----------------------------------------------------------------------------
+-- | A selector rule inside a '@media' block. Construct with 'Miso.CSS.rule_'.
+newtype MediaRule = MediaRule { getMediaRule :: (MisoString, [Style]) }
+  deriving (Eq, Show)
+-----------------------------------------------------------------------------
+-- | A CSS [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries).
+-- Construct with 'Miso.CSS.screen_', 'Miso.CSS.print_', 'Miso.CSS.all_', 'Miso.CSS.minWidth_', etc.,
+-- and compose with 'Miso.CSS.and_', 'Miso.CSS.or_', 'Miso.CSS.not_'.
+newtype MediaQuery = MediaQuery { renderMediaQuery :: MisoString }
+  deriving (Eq, Show)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Canvas.hs b/src/Miso/Canvas.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Canvas.hs
@@ -0,0 +1,717 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE CPP #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Canvas
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Canvas" is a typed Haskell wrapper around the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API HTML5 Canvas 2D API>.
+-- It lets you draw graphics imperatively inside a miso 'Miso.Types.View'
+-- without leaving Haskell.
+--
+-- The central abstraction is the 'Canvas' monad:
+--
+-- @
+-- type 'Canvas' a = 'Control.Monad.Reader.ReaderT' 'CanvasContext2D' IO a
+-- @
+--
+-- Every drawing operation ('fillRect', 'arc', 'fillText', …) is a 'Canvas'
+-- action that reads the implicit
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D CanvasRenderingContext2D>
+-- and calls the corresponding JavaScript method.
+--
+-- = Quick start
+--
+-- Wire a canvas element into your view using 'canvas'. The runtime calls
+-- @init@ once when the DOM node is created and @draw@ after every VDOM
+-- update, passing the state returned by @init@:
+--
+-- @
+-- import           "Miso"
+-- import           "Miso.Canvas"
+-- import qualified "Miso.CSS"       as CSS
+-- import qualified "Miso.CSS.Color" as Color
+-- import qualified "Miso.Html.Property" as HP
+--
+-- view :: Model -> 'Miso.Types.View' Model Action
+-- view m =
+--   'canvas'
+--     [ HP.'Miso.Html.Property.width_' \"800\", HP.'Miso.Html.Property.height_' \"480\" ]
+--     (\\_ -> pure ())          -- init: no canvas-level state needed
+--     (\\() -> drawScene m)    -- draw: closure over current model
+--
+-- drawScene :: Model -> 'Canvas' ()
+-- drawScene m = do
+--   'clearRect' (0, 0, 800, 480)
+--   'fillStyle' ('color' Color.'Miso.CSS.Color.cornflowerblue')
+--   'fillRect'  (0, 0, 800, 480)
+--   'fillStyle' ('color' Color.'Miso.CSS.Color.white')
+--   'font'      \"24px sans-serif\"
+--   'fillText'  (\"Hello, miso!\", 32, 48)
+-- @
+--
+-- = canvas vs canvas_
+--
+-- Two element constructors are provided:
+--
+-- * 'canvas' — the standard variant. Acquires a @\"2d\"@
+--   'CanvasContext2D' automatically and runs @init@ \/ @draw@ inside
+--   the 'Canvas' monad.
+--
+-- * 'canvas_' — the escape hatch. @init@ and @draw@ receive raw 'IO'
+--   callbacks and a 'Miso.DSL.DOMRef', letting you hand the element off to
+--   a third-party JavaScript library (e.g. Three.js, WebGL) that manages
+--   its own context.
+--
+-- = Styling
+--
+-- 'fillStyle' and 'strokeStyle' accept a 'StyleArg', which can be a plain
+-- 'Miso.CSS.Color.Color' (via 'color'), a t'Gradient' (via 'gradient'), or a
+-- t'Pattern' (via 'pattern_'):
+--
+-- @
+-- 'fillStyle' ('color' Color.'Miso.CSS.Color.red')
+-- 'fillStyle' ('gradient' myGradient)
+-- 'fillStyle' ('pattern_' myPattern)
+-- @
+--
+-- Note: @'Miso.Canvas.color'@ and @'Miso.CSS.color'@ have the same name but
+-- different types. Import "Miso.CSS" qualified to avoid ambiguity when using
+-- both in the same file.
+--
+-- = See also
+--
+-- * "Miso.CSS.Color" — 'Miso.CSS.Color.Color' type and named colors
+-- * "Miso.CSS" — CSS property DSL for non-canvas styling
+-- * "Miso.FFI" — lower-level JS interop used internally
+-----------------------------------------------------------------------------
+module Miso.Canvas
+  ( -- * Types
+    Canvas
+  , CanvasContext2D
+  , Pattern            (..)
+  , Gradient           (..)
+  , ImageData          (..)
+  , LineCapType        (..)
+  , PatternType        (..)
+  , LineJoinType       (..)
+  , DirectionType      (..)
+  , TextAlignType      (..)
+  , TextBaselineType   (..)
+  , CompositeOperation (..)
+  , StyleArg           (..)
+  , Coord
+   -- * Property
+  , canvas
+  , canvas_
+    -- * API
+  , set
+  , globalCompositeOperation
+  , clearRect
+  , fillRect
+  , strokeRect
+  , beginPath
+  , closePath
+  , moveTo
+  , lineTo
+  , fill
+  , rect
+  , stroke
+  , bezierCurveTo
+  , arc
+  , arcTo
+  , quadraticCurveTo
+  , direction
+  , fillText
+  , font
+  , strokeText
+  , textAlign
+  , textBaseline
+  , addColorStop
+  , createLinearGradient
+  , createPattern
+  , createRadialGradient
+  , fillStyle
+  , lineCap
+  , lineJoin
+  , lineWidth
+  , miterLimit
+  , shadowBlur
+  , shadowColor
+  , shadowOffsetX
+  , shadowOffsetY
+  , strokeStyle
+  , scale
+  , rotate
+  , translate
+  , transform
+  , setTransform
+  , drawImage
+  , drawImage'
+  , createImageData
+  , getImageData
+  , setImageData
+  , height
+  , width
+  , putImageData
+  , globalAlpha
+  , clip
+  , save
+  , restore
+  -- * Smart constructors
+  , gradient
+  , pattern_
+  , color
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad.IO.Class (liftIO)
+import           Control.Monad.Reader (ReaderT, runReaderT, ask)
+-----------------------------------------------------------------------------
+import           Miso.DSL hiding (call)
+import qualified Miso.FFI as FFI
+import           Miso.FFI (Image)
+import           Miso.Types
+import           Miso.CSS (Color, renderColor)
+-----------------------------------------------------------------------------
+-- | Another variant of canvas, this is not specialized to 'ReaderT'. This is
+-- useful when building applications with three.js, or other libraries where
+-- explicit context is not necessary.
+canvas_
+  :: forall context model action canvasState
+   . (FromJSVal canvasState, ToJSVal canvasState)
+  => [ Attribute model action ]
+  -> (DOMRef -> IO canvasState)
+  -- ^ Init function, takes @DOMRef@ as arg, returns canvas init. state.
+  -> (canvasState -> IO ())
+  -- ^ Callback to render graphics using this canvas' context, takes init state as arg.
+  -> View context model action
+canvas_ attributes initialize_ draw_ = node HTML "canvas" attrs []
+  where
+    attrs :: [ Attribute model action ]
+    attrs = On initCallback : On drawCallack : attributes
+
+    initCallback _ _ (VTree vtree) _ _ =
+      flip (FFI.set "onCreated") vtree =<< do
+        FFI.syncCallback1 $ \domRef -> do
+          initialState <- initialize_ domRef
+          FFI.set "state" initialState (Object domRef)
+
+    drawCallack _ _ (VTree vtree) _ _ =
+      flip (FFI.set "draw") vtree =<< do
+        FFI.syncCallback1 $ \domRef -> do
+          state <- fromJSValUnchecked =<< domRef ! ("state" :: MisoString)
+          draw_ state
+-----------------------------------------------------------------------------
+-- | Element for drawing on a [\<canvas\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/canvas).
+-- This function abstracts over the context and interpret callback,
+-- including dimension ("2d" or "3d") canvas.
+canvas
+  :: forall context model action canvasState
+   . (FromJSVal canvasState, ToJSVal canvasState)
+  => [ Attribute model action ]
+  -> (DOMRef -> Canvas canvasState)
+  -- ^ Init function, takes @DOMRef@ as arg, returns canvas init. state.
+  -> (canvasState -> Canvas ())
+  -- ^ Callback to render graphics using this canvas' context, takes init state as arg.
+  -> View context model action
+canvas attributes initialize draw = node HTML "canvas" attrs []
+  where
+    attrs :: [ Attribute model action ]
+    attrs = On initCallback : On drawCallack : attributes
+
+    initCallback _ _ (VTree vtree) _ _ =
+      flip (FFI.set "onCreated") vtree =<< do
+        FFI.syncCallback1 $ \domRef -> do
+          ctx <- domRef # ("getContext" :: MisoString) $ ["2d" :: MisoString]
+          initialState <- runReaderT (initialize domRef) ctx
+          FFI.set "state" initialState (Object domRef)
+
+    drawCallack _ _ (VTree vtree) _ _ =
+      flip (FFI.set "draw") vtree =<< do
+        FFI.syncCallback1 $ \domRef -> do
+          jval <- domRef ! ("state" :: MisoString)
+          initialState <- fromJSValUnchecked jval
+          ctx <- domRef # ("getContext" :: MisoString) $ ["2d" :: MisoString]
+          runReaderT (draw initialState) ctx
+-----------------------------------------------------------------------------
+-- | Various patterns used in the canvas API
+data PatternType = Repeat | RepeatX | RepeatY | NoRepeat
+-----------------------------------------------------------------------------
+instance ToJSVal PatternType where
+  toJSVal = toJSVal . renderPattern
+-----------------------------------------------------------------------------
+instance FromJSVal PatternType where
+  fromJSVal pat =
+    fromJSValUnchecked @MisoString pat >>= \case
+      "repeat" -> pure (Just Repeat)
+      "repeat-x" -> pure (Just RepeatX)
+      "repeat-y" -> pure (Just RepeatY)
+      "no-repeat" -> pure (Just NoRepeat)
+      _ -> pure Nothing
+-----------------------------------------------------------------------------
+-- | Color, Gradient or Pattern styling
+data StyleArg
+  = ColorArg Color
+  | GradientArg Gradient
+  | PatternArg Pattern
+-----------------------------------------------------------------------------
+-- | Smart constructor for 'Color' when using 'StyleArg'
+color :: Color -> StyleArg
+color = ColorArg
+-----------------------------------------------------------------------------
+-- | Smart constructor for t'Gradient' when using t'StyleArg'
+gradient :: Gradient -> StyleArg
+gradient = GradientArg
+-----------------------------------------------------------------------------
+-- | Smart constructor for t'Pattern' when using t'StyleArg'
+pattern_ :: Pattern -> StyleArg
+pattern_ = PatternArg
+-----------------------------------------------------------------------------
+-- | Renders a t'StyleArg' to a 'JSVal'
+renderStyleArg :: StyleArg -> IO JSVal
+renderStyleArg = \case
+  ColorArg c -> toJSVal (renderColor c)
+  GradientArg g -> toJSVal g
+  PatternArg p -> toJSVal p
+-----------------------------------------------------------------------------
+instance ToArgs StyleArg where
+  toArgs arg = (:[]) <$> toJSVal arg
+-----------------------------------------------------------------------------
+instance ToJSVal StyleArg where
+  toJSVal = renderStyleArg
+-----------------------------------------------------------------------------
+-- | Pretty-prints a t'PatternType' as 'Miso.String.MisoString'
+renderPattern :: PatternType -> MisoString
+renderPattern = \case
+  Repeat -> "repeat"
+  RepeatX -> "repeat-x"
+  RepeatY -> "repeat-y"
+  NoRepeat -> "no-repeat"
+-----------------------------------------------------------------------------
+-- | [LineCap](https://www.w3schools.com/tags/canvas_linecap.asp)
+data LineCapType
+  = LineCapButt
+  | LineCapRound
+  | LineCapSquare
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToArgs LineCapType where
+  toArgs arg = (:[]) <$> toJSVal arg
+-----------------------------------------------------------------------------
+instance ToJSVal LineCapType where
+  toJSVal = toJSVal . renderLineCapType
+-----------------------------------------------------------------------------
+-- | Pretty-printing for 'LineCapType'
+renderLineCapType :: LineCapType -> MisoString
+renderLineCapType = \case
+  LineCapButt -> "butt"
+  LineCapRound -> "round"
+  LineCapSquare -> "square"
+-----------------------------------------------------------------------------
+-- | [LineJoin](https://www.w3schools.com/tags/canvas_linejoin.asp)
+data LineJoinType
+  = LineJoinBevel
+  | LineJoinRound
+  | LineJoinMiter
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToArgs LineJoinType where
+  toArgs arg = (:[]) <$> toJSVal arg
+-----------------------------------------------------------------------------
+instance ToJSVal LineJoinType where
+  toJSVal = toJSVal . renderLineJoinType
+-----------------------------------------------------------------------------
+-- | Pretty-print a 'LineJoinType'
+renderLineJoinType :: LineJoinType -> MisoString
+renderLineJoinType = \case
+ LineJoinBevel -> "bevel"
+ LineJoinRound -> "round"
+ LineJoinMiter -> "miter"
+-----------------------------------------------------------------------------
+-- | Left-to-right, right-to-left, or inherit direction type.
+data DirectionType
+  = LTR
+  | RTL
+  | Inherit
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToArgs DirectionType where
+  toArgs arg = (:[]) <$> toJSVal arg
+-----------------------------------------------------------------------------
+instance ToJSVal DirectionType where
+  toJSVal = toJSVal . renderDirectionType
+-----------------------------------------------------------------------------
+-- | Pretty-printing for 'DirectionType'
+renderDirectionType :: DirectionType -> MisoString
+renderDirectionType = \case
+  LTR -> "ltr"
+  RTL -> "rtl"
+  Inherit -> "inherit"
+-----------------------------------------------------------------------------
+-- | Text alignment type
+data TextAlignType
+  = TextAlignCenter
+  | TextAlignEnd
+  | TextAlignLeft
+  | TextAlignRight
+  | TextAlignStart
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToArgs TextAlignType where
+  toArgs arg = (:[]) <$> toJSVal arg
+-----------------------------------------------------------------------------
+instance ToJSVal TextAlignType where
+  toJSVal = toJSVal . renderTextAlignType
+-----------------------------------------------------------------------------
+-- | Pretty-print 'TextAlignType'
+renderTextAlignType :: TextAlignType -> MisoString
+renderTextAlignType = \case
+  TextAlignCenter -> "center"
+  TextAlignEnd -> "end"
+  TextAlignLeft -> "left"
+  TextAlignRight -> "right"
+  TextAlignStart -> "start"
+-----------------------------------------------------------------------------
+-- | TextBaselineType
+data TextBaselineType
+  = TextBaselineAlphabetic
+  | TextBaselineTop
+  | TextBaselineHanging
+  | TextBaselineMiddle
+  | TextBaselineIdeographic
+  | TextBaselineBottom
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToArgs TextBaselineType where
+  toArgs arg = (:[]) <$> toJSVal arg
+-----------------------------------------------------------------------------
+instance ToJSVal TextBaselineType where
+  toJSVal = toJSVal . renderTextBaselineType
+-----------------------------------------------------------------------------
+-- | Pretty-printing for 'TextBaselineType'
+renderTextBaselineType :: TextBaselineType -> MisoString
+renderTextBaselineType = \case
+  TextBaselineAlphabetic -> "alphabetic"
+  TextBaselineTop -> "top"
+  TextBaselineHanging -> "hanging"
+  TextBaselineMiddle -> "middle"
+  TextBaselineIdeographic -> "ideographic"
+  TextBaselineBottom -> "bottom"
+-----------------------------------------------------------------------------
+-- | CompositeOperation
+data CompositeOperation
+  = SourceOver
+  | SourceAtop
+  | SourceIn
+  | SourceOut
+  | DestinationOver
+  | DestinationAtop
+  | DestinationIn
+  | DestinationOut
+  | Lighter
+  | Copy
+  | Xor
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToArgs CompositeOperation where
+  toArgs arg = (:[]) <$> toJSVal arg
+-----------------------------------------------------------------------------
+instance ToJSVal CompositeOperation where
+  toJSVal = toJSVal . renderCompositeOperation
+-----------------------------------------------------------------------------
+-- | Pretty-print a 'CompositeOperation'
+renderCompositeOperation :: CompositeOperation -> MisoString
+renderCompositeOperation = \case
+  SourceOver -> "source-over"
+  SourceAtop -> "source-atop"
+  SourceIn -> "source-in"
+  SourceOut -> "source-out"
+  DestinationOver -> "destination-over"
+  DestinationAtop -> "destination-atop"
+  DestinationIn -> "destination-in"
+  DestinationOut -> "destination-out"
+  Lighter -> "lighter"
+  Copy -> "copy"
+  Xor -> "xor"
+-----------------------------------------------------------------------------
+-- | Type used to hold a canvas Pattern
+newtype Pattern = Pattern JSVal deriving (ToJSVal)
+-----------------------------------------------------------------------------
+instance FromJSVal Pattern where
+  fromJSVal = pure . pure . Pattern
+-----------------------------------------------------------------------------
+-- | Type used to hold a Gradient
+newtype Gradient = Gradient JSVal deriving (ToJSVal, ToArgs)
+-----------------------------------------------------------------------------
+instance FromJSVal Gradient where
+  fromJSVal = pure . pure . Gradient
+-----------------------------------------------------------------------------
+-- | Type used to hold t'ImageData'
+newtype ImageData = ImageData JSVal deriving (ToJSVal, ToObject)
+-----------------------------------------------------------------------------
+instance ToArgs ImageData where
+  toArgs args = (:[]) <$> toJSVal args
+-----------------------------------------------------------------------------
+instance FromJSVal ImageData where
+  fromJSVal = pure . pure . ImageData
+-----------------------------------------------------------------------------
+-- | An (x,y) coordinate.
+type Coord = (Double, Double)
+-----------------------------------------------------------------------------
+-- | The canvas t'CanvasContext2D'
+type CanvasContext2D = JSVal
+-----------------------------------------------------------------------------
+call :: (FromJSVal a, ToArgs args) => MisoString -> args -> Canvas a
+call name arg = do
+  ctx <- ask
+  liftIO $ fromJSValUnchecked =<< do
+    ctx # name $ arg
+-----------------------------------------------------------------------------
+-- | Property setter specialized to t'Canvas'.
+--
+-- @
+-- globalCompositeOperation :: CompositeOperation -> Canvas ()
+-- globalCompositeOperation = set "globalCompositeOperation"
+-- @
+--
+set :: ToArgs args => MisoString -> args -> Canvas ()
+set name args = do
+  ctx <- ask
+  liftIO $ setField ctx name (toArgs args)
+-----------------------------------------------------------------------------
+-- | DSL for expressing operations on 'canvas_'
+type Canvas a = ReaderT CanvasContext2D IO a
+-----------------------------------------------------------------------------
+-- | [ctx.globalCompositeOperation = "source-over"](https://www.w3schools.com/tags/canvas_globalcompositeoperation.asp)
+globalCompositeOperation :: CompositeOperation -> Canvas ()
+globalCompositeOperation = set "globalCompositeOperation"
+-----------------------------------------------------------------------------
+-- | [ctx.clearRect(x,y,width,height)](https://www.w3schools.com/tags/canvas_clearrect.asp)
+clearRect :: (Double, Double, Double, Double) -> Canvas ()
+clearRect = call "clearRect"
+-----------------------------------------------------------------------------
+-- | [ctx.fillRect(x,y,width,height)](https://www.w3schools.com/tags/canvas_fillrect.asp)
+fillRect :: (Double, Double, Double, Double) -> Canvas ()
+fillRect = call "fillRect"
+-----------------------------------------------------------------------------
+-- | [ctx.strokeRect(x,y,width,height)](https://www.w3schools.com/tags/canvas_strokerect.asp)
+strokeRect :: (Double, Double, Double, Double) -> Canvas ()
+strokeRect = call "strokeRect"
+-----------------------------------------------------------------------------
+-- | [ctx.beginPath()](https://www.w3schools.com/tags/canvas_beginpath.asp)
+beginPath :: () -> Canvas ()
+beginPath = call "beginPath"
+-----------------------------------------------------------------------------
+-- | [ctx.closePath()](https://www.w3schools.com/tags/canvas_closepath.asp)
+closePath :: () -> Canvas ()
+closePath = call "closePath"
+-----------------------------------------------------------------------------
+-- | [ctx.moveTo(x,y)](https://www.w3schools.com/tags/canvas_moveto.asp)
+moveTo :: Coord -> Canvas ()
+moveTo = call "moveTo"
+-----------------------------------------------------------------------------
+-- | [ctx.lineTo(x,y)](https://www.w3schools.com/tags/canvas_lineto.asp)
+lineTo :: Coord -> Canvas ()
+lineTo = call "lineTo"
+-----------------------------------------------------------------------------
+-- | [ctx.fill()](https://www.w3schools.com/tags/canvas_fill.asp)
+fill :: () -> Canvas ()
+fill = call "fill"
+-----------------------------------------------------------------------------
+-- | [ctx.rect(x,y,width,height)](https://www.w3schools.com/tags/canvas_rect.asp)
+rect :: (Double, Double, Double, Double) -> Canvas ()
+rect = call "rect"
+-----------------------------------------------------------------------------
+-- | [ctx.stroke()](https://www.w3schools.com/tags/canvas_stroke.asp)
+stroke :: () -> Canvas ()
+stroke = call "stroke"
+-----------------------------------------------------------------------------
+-- | [ctx.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)](https://www.w3schools.com/tags/canvas_beziercurveto.asp)
+bezierCurveTo :: (Double, Double, Double, Double, Double, Double) -> Canvas ()
+bezierCurveTo = call "bezierCurveTo"
+-----------------------------------------------------------------------------
+-- | [context.arc(x, y, r, sAngle, eAngle, counterclockwise)](https://www.w3schools.com/tags/canvas_arc.asp)
+arc :: (Double, Double, Double, Double, Double) -> Canvas ()
+arc = call "arc"
+-----------------------------------------------------------------------------
+-- | [context.arcTo(x1, y1, x2, y2, r)](https://www.w3schools.com/tags/canvas_arcto.asp)
+arcTo :: (Double, Double, Double, Double, Double) -> Canvas ()
+arcTo = call "arcTo"
+-----------------------------------------------------------------------------
+-- | [context.quadraticCurveTo(cpx,cpy,x,y)](https://www.w3schools.com/tags/canvas_quadraticcurveto.asp)
+quadraticCurveTo :: (Double, Double, Double, Double) -> Canvas ()
+quadraticCurveTo = call "quadraticCurveTo"
+-----------------------------------------------------------------------------
+-- | [context.direction = "ltr"](https://www.w3schools.com/tags/canvas_direction.asp)
+direction :: DirectionType -> Canvas ()
+direction = set "direction"
+-----------------------------------------------------------------------------
+-- | [context.fillText(text,x,y)](https://www.w3schools.com/tags/canvas_filltext.asp)
+fillText :: (MisoString, Double, Double) -> Canvas ()
+fillText = call "fillText"
+-----------------------------------------------------------------------------
+-- | [context.font = "italic small-caps bold 12px arial"](https://www.w3schools.com/tags/canvas_font.asp)
+font :: MisoString -> Canvas ()
+font = set "font"
+-----------------------------------------------------------------------------
+-- | [ctx.strokeText()](https://www.w3schools.com/tags/canvas_stroketext.asp)
+strokeText :: (MisoString, Double, Double) -> Canvas ()
+strokeText = call "strokeText"
+-----------------------------------------------------------------------------
+-- | [ctx.textAlign = "start"](https://www.w3schools.com/tags/canvas_textalign.asp)
+textAlign :: TextAlignType -> Canvas ()
+textAlign = set "textAlign"
+-----------------------------------------------------------------------------
+-- | [ctx.textBaseline = "top"](https://www.w3schools.com/tags/canvas_textBaseLine.asp)
+textBaseline :: TextBaselineType -> Canvas ()
+textBaseline = set "textBaseline"
+-----------------------------------------------------------------------------
+-- | [gradient.addColorStop(stop,color)](https://www.w3schools.com/tags/canvas_addcolorstop.asp)
+addColorStop
+  :: (Double, Color)
+  -- ^ @(stop, color)@ — position along the gradient (0.0–1.0) and the colour at that stop
+  -> Gradient
+  -- ^ The gradient object to add the colour stop to
+  -> Canvas ()
+addColorStop args (Gradient g) = do
+  _ <- liftIO $ g # ("addColorStop" :: MisoString) $ args
+  pure ()
+-----------------------------------------------------------------------------
+-- | [ctx.createLinearGradient(x0,y0,x1,y1)](https://www.w3schools.com/tags/canvas_createlineargradient.asp)
+createLinearGradient :: (Double, Double, Double, Double) -> Canvas Gradient
+createLinearGradient = call "createLinearGradient"
+-----------------------------------------------------------------------------
+-- | [ctx.createPattern(image, "repeat")](https://www.w3schools.com/tags/canvas_createpattern.asp)
+createPattern :: (Image, PatternType) -> Canvas Pattern
+createPattern = call "createPattern"
+-----------------------------------------------------------------------------
+-- | [ctx.createRadialGradient(x0,y0,r0,x1,y1,r1)](https://www.w3schools.com/tags/canvas_createradialgradient.asp)
+createRadialGradient :: (Double,Double,Double,Double,Double,Double) -> Canvas Gradient
+createRadialGradient = call "createRadialGradient"
+-----------------------------------------------------------------------------
+-- | [ctx.fillStyle = "red"](https://www.w3schools.com/tags/canvas_fillstyle.asp)
+fillStyle :: StyleArg -> Canvas ()
+fillStyle = set "fillStyle"
+-----------------------------------------------------------------------------
+-- | [ctx.lineCap = "butt"](https://www.w3schools.com/tags/canvas_lineCap.asp)
+lineCap :: LineCapType -> Canvas ()
+lineCap = set "lineCap"
+-----------------------------------------------------------------------------
+-- | [ctx.lineJoin = "bevel"](https://www.w3schools.com/tags/canvas_lineJoin.asp)
+lineJoin :: LineJoinType -> Canvas ()
+lineJoin = set "lineJoin"
+-----------------------------------------------------------------------------
+-- | [ctx.lineWidth = 10](https://www.w3schools.com/tags/canvas_lineWidth.asp)
+lineWidth :: Double -> Canvas ()
+lineWidth = set "lineWidth"
+-----------------------------------------------------------------------------
+-- | [ctx.miterLimit = 10](https://www.w3schools.com/tags/canvas_miterLimit.asp)
+miterLimit :: Double -> Canvas ()
+miterLimit = set "miterLimit"
+-----------------------------------------------------------------------------
+-- | [ctx.shadowBlur = 10](https://www.w3schools.com/tags/canvas_shadowBlur.asp)
+shadowBlur :: Double -> Canvas ()
+shadowBlur = set "shadowBlur"
+-----------------------------------------------------------------------------
+-- | [ctx.shadowColor = "red"](https://www.w3schools.com/tags/canvas_shadowColor.asp)
+shadowColor :: Color -> Canvas ()
+shadowColor = set "shadowColor"
+-----------------------------------------------------------------------------
+-- | [ctx.shadowOffsetX = 20](https://www.w3schools.com/tags/canvas_shadowOffsetX.asp)
+shadowOffsetX :: Double -> Canvas ()
+shadowOffsetX = set "shadowOffsetX"
+-----------------------------------------------------------------------------
+-- | [ctx.shadowOffsetY = 20](https://www.w3schools.com/tags/canvas_shadowOffsetY.asp)
+shadowOffsetY :: Double -> Canvas ()
+shadowOffsetY = set "shadowOffsetY"
+-----------------------------------------------------------------------------
+-- | [ctx.strokeStyle = "red"](https://www.w3schools.com/tags/canvas_strokeStyle.asp)
+strokeStyle :: StyleArg -> Canvas ()
+strokeStyle = set "strokeStyle"
+-----------------------------------------------------------------------------
+-- | [ctx.scale(width,height)](https://www.w3schools.com/tags/canvas_scale.asp)
+scale :: (Double, Double) -> Canvas ()
+scale = call "scale"
+-----------------------------------------------------------------------------
+-- | [ctx.rotate(angle)](https://www.w3schools.com/tags/canvas_rotate.asp)
+rotate :: Double -> Canvas ()
+rotate = call "rotate"
+-----------------------------------------------------------------------------
+-- | [ctx.translate(angle)](https://www.w3schools.com/tags/canvas_translate.asp)
+translate :: Coord -> Canvas ()
+translate = call "translate"
+-----------------------------------------------------------------------------
+-- | [ctx.transform(a,b,c,d,e,f)](https://www.w3schools.com/tags/canvas_transform.asp)
+transform :: (Double, Double, Double, Double, Double, Double) -> Canvas ()
+transform = call "transform"
+-----------------------------------------------------------------------------
+-- | [ctx.setTransform(a,b,c,d,e,f)](https://www.w3schools.com/tags/canvas_setTransform.asp)
+setTransform :: (Double, Double, Double, Double, Double, Double) -> Canvas ()
+setTransform = call "setTransform"
+----------------------------------------------------------------------------
+-- | [ctx.drawImage(image,x,y)](https://www.w3schools.com/tags/canvas_drawImage.asp)
+drawImage :: (Image, Double, Double) -> Canvas ()
+drawImage = call "drawImage"
+-----------------------------------------------------------------------------
+-- | [ctx.drawImage(image,x,y)](https://www.w3schools.com/tags/canvas_drawImage.asp)
+drawImage' :: (Image, Double, Double, Double, Double) -> Canvas ()
+drawImage' = call "drawImage"
+-----------------------------------------------------------------------------
+-- | [ctx.createImageData(width,height)](https://www.w3schools.com/tags/canvas_createImageData.asp)
+createImageData :: (Double, Double) -> Canvas ImageData
+createImageData = call "createImageData"
+-----------------------------------------------------------------------------
+-- | [ctx.getImageData(w,x,y,z)](https://www.w3schools.com/tags/canvas_getImageData.asp)
+getImageData :: (Double, Double, Double, Double) -> Canvas ImageData
+getImageData = call "getImageData"
+-----------------------------------------------------------------------------
+-- | [imageData.data\[index\] = 255](https://www.w3schools.com/tags/canvas_imagedata_data.asp)
+setImageData :: (ImageData, Int, Double) -> Canvas ()
+setImageData (imgData, index, value) = liftIO $ do
+   o <- imgData ! ("data" :: MisoString)
+   (o <## index) value
+-----------------------------------------------------------------------------
+-- | [imageData.height](https://www.w3schools.com/tags/canvas_imagedata_height.asp)
+height :: ImageData -> Canvas Double
+height (ImageData imgData) = liftIO $ do
+  fromJSValUnchecked =<< imgData ! ("height" :: MisoString)
+-----------------------------------------------------------------------------
+-- | [imageData.width](https://www.w3schools.com/tags/canvas_imagedata_width.asp)
+width :: ImageData -> Canvas Double
+width (ImageData imgData) = liftIO $
+  fromJSValUnchecked =<< imgData ! ("width" :: MisoString)
+-----------------------------------------------------------------------------
+-- | [ctx.putImageData(imageData,x,y)](https://www.w3schools.com/tags/canvas_putImageData.asp)
+putImageData :: (ImageData, Double, Double) -> Canvas ()
+putImageData = call "putImageData"
+-----------------------------------------------------------------------------
+-- | [ctx.globalAlpha = 0.2](https://www.w3schools.com/tags/canvas_globalAlpha.asp)
+globalAlpha :: Double -> Canvas ()
+globalAlpha = set "globalAlpha"
+-----------------------------------------------------------------------------
+-- | [ctx.clip()](https://www.w3schools.com/tags/canvas_clip.asp)
+clip :: () -> Canvas ()
+clip = call "clip"
+-----------------------------------------------------------------------------
+-- | [ctx.save()](https://www.w3schools.com/tags/canvas_save.asp)
+save :: () -> Canvas ()
+save = call "save"
+-----------------------------------------------------------------------------
+-- | [ctx.restore()](https://www.w3schools.com/tags/canvas_restore.asp)
+restore :: () -> Canvas ()
+restore = call "restore"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Concurrent.hs b/src/Miso/Concurrent.hs
--- a/src/Miso/Concurrent.hs
+++ b/src/Miso/Concurrent.hs
@@ -1,30 +1,82 @@
+-----------------------------------------------------------------------------
 {-# LANGUAGE ScopedTypeVariables #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Concurrent
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Concurrent (
-    Notify (..)
-  , newNotify
+--
+-- = Overview
+--
+-- "Miso.Concurrent" provides t'Waiter', a lightweight synchronization
+-- primitive built on 'Control.Concurrent.MVar.MVar' that the miso runtime
+-- uses to coordinate its event loop with subscription threads.
+--
+-- Two constructors are available with different wakeup semantics:
+--
+-- * 'waiter' — __many-to-one__. Multiple threads may call 'notify'
+--   concurrently; only one pending notification is retained at a time
+--   ('Control.Concurrent.MVar.tryPutMVar' is used, so rapid notifications
+--   coalesce). The single consumer calls 'wait' to block until at least one
+--   notification arrives.
+--
+-- * 'oneshot' — __one-to-many__. One thread calls 'notify' to permanently
+--   unblock /all/ threads currently (or subsequently) calling 'wait'.
+--   Implemented with 'Control.Concurrent.MVar.readMVar', so the stored value
+--   is never consumed.
+--
+-- = See also
+--
+-- * "Miso.Effect" — 'Miso.Effect.Sub' subscriptions that use 'notify' to
+--   wake the event loop
+-- * "Miso.Runtime" — the event loop that calls 'wait'
+-----------------------------------------------------------------------------
+module Miso.Concurrent
+  ( -- ** Synchronization primitives
+    Waiter (..)
+  , waiter
+  , oneshot
   ) where
-
+-----------------------------------------------------------------------------
 import Control.Concurrent
-
--- | Concurrent API for `SkipChan` implementation
-data Notify = Notify {
-    wait :: IO ()
+-----------------------------------------------------------------------------
+-- | Synchronization primitive for event loop
+data Waiter
+  = Waiter
+  { wait :: IO ()
+    -- ^ Blocks on MVar
   , notify :: IO ()
+    -- ^ Unblocks threads waiting on MVar
   }
-
--- | Create a new `Notify`
-newNotify :: IO Notify
-newNotify = do
-  mvar <- newMVar ()
-  pure $ Notify
-   (takeMVar mvar)
-   (() <$ do tryPutMVar mvar $! ())
+-----------------------------------------------------------------------------
+-- | Creates a new @Waiter@
+--
+-- Useful for multiple threads to wake-up / notify a single thread running in an
+-- infinite loop, waiting for work (e.g. to process an event queue).
+--
+waiter :: IO Waiter
+waiter = do
+  mvar <- newEmptyMVar
+  pure Waiter
+    { wait = takeMVar mvar
+    , notify = do
+        _ <- tryPutMVar mvar ()
+        pure ()
+    }
+-----------------------------------------------------------------------------
+-- | Creates a new @Waiter@
+--
+-- Useful for a single thread to wake-up multiple threads that are waiting 
+-- to run a oneshot task (e.g. like forking a thread).
+--
+oneshot :: IO Waiter
+oneshot = do
+  mvar <- newEmptyMVar
+  pure Waiter
+    { wait = readMVar mvar
+    , notify = putMVar mvar ()
+    }
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Cookie.hs b/src/Miso/Cookie.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Cookie.hs
@@ -0,0 +1,405 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE RecordWildCards     #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Cookie
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Cookie" wraps the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>
+-- as 'Miso.Effect.Effect' combinators that integrate directly into the
+-- Model-View-Update loop.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Cookie"
+--
+-- data Action
+--   = LoadSession
+--   | GotSession (Maybe t'Cookie')
+--   | SessionError 'Miso.String.MisoString'
+--   | SaveTheme
+--   | ThemeSaved
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update LoadSession =
+--   'cookieGet' \"session\" GotSession SessionError
+-- update SaveTheme =
+--   'cookieSet' \"theme\" \"dark\" ThemeSaved SessionError
+-- update _ = pure ()
+-- @
+--
+-- = Types
+--
+-- * t'Cookie' — a single cookie with all standard fields
+-- * t'CookieChangeEvent' — payload for 'Miso.Subscription.Cookie.cookieChangeSub'
+--
+-- = API groups
+--
+-- * __Read__: 'cookieGet', 'cookieGetAll'
+-- * __Write__: 'cookieSet'
+-- * __Delete__: 'cookieDelete'
+--
+-- = Availability
+--
+-- The CookieStore API requires a
+-- <https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts secure context>
+-- (HTTPS or @localhost@) and is not yet universally supported. Operations
+-- silently call the error callback when the API is unavailable.
+--
+-- = See also
+--
+-- * "Miso.Subscription.Cookie" — 'Miso.Subscription.Cookie.cookieChangeSub'
+--   for subscribing to cookie change events
+-- * "Miso.FFI" — raw FFI primitives ('Miso.FFI.cookieGet' etc.) for
+--   advanced use-cases
+-----------------------------------------------------------------------------
+module Miso.Cookie
+  ( -- ** Types
+    Cookie (..)
+  , CookieChangeEvent (..)
+    -- ** Read
+  , cookieGet
+  , cookieGetAll
+    -- ** Write
+  , cookieSet
+    -- ** Delete
+  , cookieDelete
+  , cookieDeleteWith
+    -- ** Construction
+  , defaultCookie
+    -- ** Synchronous API variants
+  , cookieSet_
+  , cookieGet_
+  , cookieDelete_
+  , cookieDeleteWith_
+  , cookieGetAll_
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Concurrent (MVar, newEmptyMVar, putMVar, takeMVar)
+import           Control.Monad ((<=<), forM_, join)
+import           Prelude hiding ((!!))
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.Effect
+import           Miso.String (MisoString)
+import qualified Miso.FFI.Internal as FFI
+-----------------------------------------------------------------------------
+-- | A cookie from the
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>.
+--
+-- Fields map directly to the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/get#return_value CookieListItem>.
+--
+-- @since 1.13.0.0
+data Cookie = Cookie
+  { cookieName        :: MisoString
+  -- ^ Cookie name (empty string for nameless cookies)
+  , cookieValue       :: Maybe MisoString
+  -- ^ Cookie value
+  , cookieDomain      :: Maybe MisoString
+  -- ^ Cookie domain (@Nothing@ when unset — host-only cookie)
+  , cookiePath        :: MisoString
+  -- ^ Cookie path
+  , cookieExpires     :: Maybe Double
+  -- ^ Expiry as Unix milliseconds (@Nothing@ for session cookies)
+  , cookieSecure      :: Bool
+  -- ^ @Secure@ flag
+  , cookieSameSite    :: MisoString
+  -- ^ @SameSite@ value: @\"strict\"@, @\"lax\"@, or @\"none\"@
+  , cookiePartitioned :: Bool
+  -- ^ @Partitioned@ flag (CHIPS — Cookies Having Independent Partitioned State)
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal Cookie where
+  toJSVal Cookie {..} = do
+    o <- create
+    FFI.set "name"        cookieName        o
+    FFI.set "value"       cookieValue       o
+    FFI.set "path"        cookiePath        o
+    FFI.set "secure"      cookieSecure      o
+    FFI.set "sameSite"    cookieSameSite    o
+    FFI.set "partitioned" cookiePartitioned o
+    forM_ cookieDomain  $ \d -> FFI.set "domain"  d o
+    forM_ cookieExpires $ \e -> FFI.set "expires" e o
+    toJSVal o
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Cookie where
+  fromJSVal v = do
+    name_        <- fromJSVal =<< v ! "name"
+    value_       <- fromJSVal =<< v ! "value"
+    domain_      <- fromJSVal =<< v ! "domain"
+    path_        <- fromJSVal =<< v ! "path"
+    expires_     <- fromJSVal =<< v ! "expires"
+    secure_      <- fromJSVal =<< v ! "secure"
+    sameSite_    <- fromJSVal =<< v ! "sameSite"
+    partitioned_ <- fromJSVal =<< v ! "partitioned"
+    pure $ do
+      n   <- name_
+      vl  <- value_
+      p   <- path_
+      sec <- secure_
+      ss  <- sameSite_
+      par <- partitioned_
+      pure Cookie
+        { cookieName        = n
+        , cookieValue       = vl
+        , cookieDomain      = join domain_
+        , cookiePath        = p
+        , cookieExpires     = join expires_
+        , cookieSecure      = sec
+        , cookieSameSite    = ss
+        , cookiePartitioned = par
+        }
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | The event payload delivered to
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/change_event cookieStore change>
+-- listeners. Consumed by 'Miso.Subscription.Cookie.cookieChangeSub'.
+--
+-- @since 1.13.0.0
+data CookieChangeEvent = CookieChangeEvent
+  { cookiesChanged :: [Cookie]
+  -- ^ Cookies that were added or updated
+  , cookiesDeleted :: [Cookie]
+  -- ^ Cookies that were deleted
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal CookieChangeEvent where
+  fromJSVal ev = do
+    changed_ <- fromJSValUnchecked =<< ev ! "changed"
+    deleted_ <- fromJSValUnchecked =<< ev ! "deleted"
+    pure (CookieChangeEvent <$> changed_ <*> deleted_)
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal CookieChangeEvent where
+  toJSVal CookieChangeEvent {..} = do
+    o <- create
+    FFI.set "changed" cookiesChanged o
+    FFI.set "deleted" cookiesDeleted o
+    toJSVal o
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToArgs CookieChangeEvent where
+  toArgs ev = (:[]) <$> toJSVal ev
+  {-# INLINE toArgs #-}
+-----------------------------------------------------------------------------
+-- | Retrieve a cookie value by name.
+--
+-- Calls @successful@ with @'Just' value@ when found, @'Nothing'@ when
+-- absent, or @errorful@ with the error message if the operation fails.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/get>
+--
+-- @since 1.13.0.0
+cookieGet
+  :: MisoString
+  -- ^ Cookie name
+  -> (Maybe MisoString -> action)
+  -- ^ Successful callback (@Nothing@ when the cookie is absent)
+  -> (MisoString -> action)
+  -- ^ Errorful callback
+  -> Effect context props model action
+cookieGet name successful errorful = withSink $ \sink ->
+  FFI.cookieGet name
+    (sink . successful <=< fromJSVal)
+    (sink . errorful)
+-----------------------------------------------------------------------------
+-- | Retrieve all cookies visible to the current document.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/getAll>
+--
+-- @since 1.13.0.0
+cookieGetAll
+  :: ([Cookie] -> action)
+  -- ^ Successful callback
+  -> (MisoString -> action)
+  -- ^ Errorful callback
+  -> Effect context props model action
+cookieGetAll successful errorful = withSink $ \sink -> do
+  FFI.cookieGetAll
+    (sink . successful <=< fromJSValUnchecked)
+    (sink . errorful)
+-----------------------------------------------------------------------------
+-- | A t'Cookie' with sensible defaults: @path = "/"@, session expiry,
+-- @SameSite = "lax"@, not secure, not partitioned, no domain restriction.
+--
+-- @since 1.13.0.0
+defaultCookie :: MisoString -> MisoString -> Cookie
+defaultCookie name value = Cookie
+  { cookieName        = name
+  , cookieValue       = Just value
+  , cookieDomain      = Nothing
+  , cookiePath        = "/"
+  , cookieExpires     = Nothing
+  , cookieSecure      = False
+  , cookieSameSite    = "lax"
+  , cookiePartitioned = False
+  }
+-----------------------------------------------------------------------------
+-- | Set a cookie via the
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>.
+--
+-- Use 'defaultCookie' to construct a t'Cookie' with sensible defaults, or
+-- supply a fully specified t'Cookie' record for custom path, domain, expiry etc.
+--
+-- __Important:__ You cannot use both @expires@ and @maxAge@ in the same call.
+-- If you do, the @set()@ method will fail with a @TypeError@.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/set>
+--
+-- @since 1.13.0.0
+cookieSet
+  :: Cookie
+  -- ^ Cookie to set (use 'defaultCookie' for the common case)
+  -> action
+  -- ^ Successful callback
+  -> (MisoString -> action)
+  -- ^ Errorful callback
+  -> Effect context props model action
+cookieSet cookie successful errorful = withSink $ \sink -> do
+  c_ <- toJSVal cookie
+  FFI.cookieSet c_ (sink successful) (sink . errorful)
+-----------------------------------------------------------------------------
+-- | Delete a cookie by name.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/delete>
+--
+-- @since 1.13.0.0
+cookieDelete
+  :: MisoString
+  -- ^ Cookie name
+  -> action
+  -- ^ Successful callback
+  -> (MisoString -> action)
+  -- ^ Errorful callback
+  -> Effect context props model action
+cookieDelete name successful errorful = withSink $ \sink ->
+  FFI.cookieDelete name (sink successful) (sink . errorful)
+-----------------------------------------------------------------------------
+-- | Delete a cookie by matching on name, path, domain, and\/or partitioned
+-- flag — useful when multiple cookies share the same name across different
+-- paths or domains.
+--
+-- Use 'defaultCookie' to build the argument and override only the fields
+-- you need:
+--
+-- @
+-- 'cookieDeleteWith' ('defaultCookie' \"session\" \"\") { 'cookiePath' = \"\/admin\" }
+--   Deleted
+--   SessionError
+-- @
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/delete>
+--
+-- @since 1.13.0.0
+cookieDeleteWith
+  :: Cookie
+  -- ^ Cookie whose name, path, domain and partitioned fields are used for matching
+  -> action
+  -- ^ Successful callback
+  -> (MisoString -> action)
+  -- ^ Errorful callback
+  -> Effect context props model action
+cookieDeleteWith cookie successful errorful = withSink $ \sink -> do
+  c_ <- toJSVal cookie
+  FFI.cookieDeleteWith c_ (sink successful) (sink . errorful)
+-----------------------------------------------------------------------------
+-- | Synchronous API variant of 'cookieSet'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' ()@ on success or @'Left' err@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+cookieSet_ :: Cookie -> IO (Either MisoString ())
+cookieSet_ cookie = do
+  mvar <- newEmptyMVar :: IO (MVar (Either MisoString ()))
+  c_ <- toJSVal cookie
+  FFI.cookieSet c_
+    (putMVar mvar (Right ()))
+    (\e -> putMVar mvar (Left e))
+  takeMVar mvar
+{-# INLINE cookieSet_ #-}
+-----------------------------------------------------------------------------
+-- | Synchronous API variant of 'cookieGet'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' ('Just' value)@ when the cookie exists, @'Right' 'Nothing'@
+-- when absent, or @'Left' err@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+cookieGet_ :: MisoString -> IO (Either MisoString (Maybe MisoString))
+cookieGet_ name = do
+  mvar <- newEmptyMVar :: IO (MVar (Either MisoString (Maybe MisoString)))
+  FFI.cookieGet name
+    (\v -> fromJSValUnchecked v >>= putMVar mvar . Right)
+    (\e -> putMVar mvar (Left e))
+  takeMVar mvar
+{-# INLINE cookieGet_ #-}
+-----------------------------------------------------------------------------
+-- | Synchronous API variant of 'cookieDelete'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' ()@ on success or @'Left' err@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+cookieDelete_ :: MisoString -> IO (Either MisoString ())
+cookieDelete_ name = do
+  mvar <- newEmptyMVar :: IO (MVar (Either MisoString ()))
+  FFI.cookieDelete name
+    (putMVar mvar (Right ()))
+    (\e -> putMVar mvar (Left e))
+  takeMVar mvar
+{-# INLINE cookieDelete_ #-}
+-----------------------------------------------------------------------------
+-- | Synchronous API variant of 'cookieDeleteWith'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' ()@ on success or @'Left' err@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+cookieDeleteWith_ :: Cookie -> IO (Either MisoString ())
+cookieDeleteWith_ cookie = do
+  mvar <- newEmptyMVar :: IO (MVar (Either MisoString ()))
+  c_ <- toJSVal cookie
+  FFI.cookieDeleteWith c_
+    (putMVar mvar (Right ()))
+    (\e -> putMVar mvar (Left e))
+  takeMVar mvar
+{-# INLINE cookieDeleteWith_ #-}
+-----------------------------------------------------------------------------
+-- | Synchronous API variant of 'cookieGetAll'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' cookies@ on success or @'Left' err@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+cookieGetAll_ :: IO (Either MisoString [Cookie])
+cookieGetAll_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either MisoString [Cookie]))
+  FFI.cookieGetAll
+    (\v -> fromJSValUnchecked v >>= putMVar mvar . Right)
+    (\e -> putMVar mvar (Left e))
+  takeMVar mvar
+{-# INLINE cookieGetAll_ #-}
+-----------------------------------------------------------------------------
diff --git a/src/Miso/DSL.hs b/src/Miso/DSL.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/DSL.hs
@@ -0,0 +1,978 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE ScopedTypeVariables  #-}
+{-# LANGUAGE DerivingStrategies   #-}
+{-# LANGUAGE DefaultSignatures    #-}
+{-# LANGUAGE OverloadedStrings    #-}
+{-# LANGUAGE FlexibleInstances    #-}
+{-# LANGUAGE FlexibleContexts     #-}
+{-# LANGUAGE KindSignatures       #-}
+{-# LANGUAGE TypeOperators        #-}
+{-# LANGUAGE LambdaCase           #-}
+{-# LANGUAGE DataKinds            #-}
+{-# LANGUAGE CPP                  #-}
+#if __GLASGOW_HASKELL__ <= 865
+{-# LANGUAGE UndecidableInstances #-}
+#endif
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.DSL
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.DSL" is the low-level JavaScript interop layer for miso. It provides
+-- the marshaling typeclasses, JS value types, and combinators needed to call
+-- browser APIs and exchange data with JavaScript from Haskell.
+--
+-- Most miso users never import this module directly — higher-level modules
+-- ("Miso.FFI", "Miso.Canvas", "Miso.Fetch", etc.) build on top of it.
+-- Import it directly when writing custom FFI bindings or inline JS.
+--
+-- = Marshaling
+--
+-- Two typeclasses handle the Haskell ↔ JavaScript boundary:
+--
+-- * 'ToJSVal' — converts a Haskell value into a t'JSVal'. Instances exist
+--   for all primitive types, lists, tuples (up to 6), 'Maybe', and
+--   'Data.Map.Strict.Map' 'Miso.String.MisoString'. Product record types can
+--   derive 'ToJSVal' via @GHC.Generics@ (sum types are not supported).
+--
+-- * 'FromJSVal' — parses a t'JSVal' back into Haskell, returning
+--   @'Maybe' a@ ('Nothing' on type mismatch or missing field).
+--   Use 'fromJSValUnchecked' when the shape is guaranteed by the caller.
+--   Product record types can derive 'FromJSVal' via @GHC.Generics@.
+--
+-- Two auxiliary classes support the calling convention:
+--
+-- * 'ToArgs' — marshals a Haskell value to a @['JSVal']@ argument list.
+--   Tuples up to arity 6 automatically produce the correct positional list.
+--
+-- * 'ToObject' — promotes a value to a JS t'Object' for use as the @this@
+--   receiver in method calls.
+--
+-- = Accessing the global scope
+--
+-- @
+-- -- Read a global variable
+-- x <- 'jsg' \"innerWidth\"          -- globalThis.innerWidth
+--
+-- -- Call a global function
+-- 'jsg0' \"requestAnimationFrame\"   -- no args
+-- 'jsg1' \"parseInt\" (\"42\" :: 'Miso.String.MisoString')  -- one arg
+-- 'jsgf' \"encodeURIComponent\" args -- arbitrary ToArgs
+-- @
+--
+-- = Property access and method calls
+--
+-- @
+-- obj '!' \"name\"          -- get obj.name   :: IO JSVal
+-- obj '!!' 3            -- get obj[3]     :: IO JSVal
+-- obj '#' \"push\" [val]   -- call obj.push(val) :: IO JSVal
+-- 'setField' obj \"x\" 10  -- obj.x = 10
+-- 'getProp' \"x\" obj      -- obj.x
+-- 'setProp' \"x\" 10 obj   -- obj.x = 10
+-- @
+--
+-- = Object creation
+--
+-- @
+-- o <- 'create'                            -- new empty object  {}
+-- o <- 'createWith' [(\"x\", 1), (\"y\", 2)]  -- { x: 1, y: 2 }
+-- v <- 'new' constructor args              -- new Constructor(...args)
+-- @
+--
+-- = Callbacks
+--
+-- Wrap a Haskell @IO@ action as a JS function. Variants ending in @\'@
+-- return the t'JSVal' of the callback's return value.
+--
+-- @
+-- cb  <- 'syncCallback'  action         -- () -> ()
+-- cb1 <- 'syncCallback1' (\\x -> …)     -- (x) -> ()
+-- cb2 <- 'syncCallback2' (\\x y -> …)   -- (x, y) -> ()
+-- @
+--
+-- Always free callbacks when they are no longer needed to avoid leaks:
+--
+-- @
+-- 'freeFunction' cb
+-- @
+--
+-- = See also
+--
+-- * "Miso.FFI" — higher-level browser API wrappers built on this module
+-- * "Miso.FFI.QQ" — the @[js| … |]@ quasi-quoter for inline JavaScript
+-- * "Miso.Canvas" — canvas 2D API using 'ToArgs' and 'ToJSVal'
+-----------------------------------------------------------------------------
+module Miso.DSL
+  ( -- * Classes
+    ToJSVal (..)
+  , GToJSVal (..)
+  , FromJSVal (..)
+  , GFromJSVal (..)
+  , ToArgs (..)
+  , ToObject (..)
+    -- * Types
+  , JSVal
+  , Object (..)
+  , Function (..)
+    -- * Utils
+  , jsg
+  , jsg0
+  , jsg1
+  , jsg2
+  , jsg3
+  , jsg4
+  , jsg5
+  , jsgf
+  , global
+  , (#)
+  , setField
+  , (<##)
+  , (!)
+  , listProps
+  , call
+  , new
+  , create
+  , createWith
+  , setProp
+  , getProp
+  , eval
+  , now_ffi
+  , requestAnimationFrame
+  , cancelAnimationFrame
+  , freeFunction
+  , freeJSVal
+  , (!!)
+  , isUndefined
+  , isNull
+  , jsNull
+  , syncCallback
+  , syncCallback1
+  , syncCallback2
+  , syncCallback3
+  , syncCallback'
+  , syncCallback1'
+  , syncCallback2'
+  , syncCallback3'
+  , await
+  , asyncCallback
+  , asyncCallback1
+  , asyncCallback2
+  , asyncCallback3
+  , apply
+  , JSException
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Applicative
+#ifndef VANILLA
+import           Data.Text (Text)
+#endif
+import           Control.Monad
+import           Control.Monad.Trans.Maybe
+import qualified Data.Map.Strict as M
+import           Data.Map.Strict (Map)
+import           GHC.Generics
+import           GHC.TypeLits
+import           Data.Kind
+import           Prelude hiding ((!!))
+-----------------------------------------------------------------------------
+import           Miso.DSL.FFI
+import           Miso.JSON (Value, fromJSVal_Value, toJSVal_Value)
+import           Miso.String
+-----------------------------------------------------------------------------
+-- | A class for marshaling Haskell values into JS
+class ToJSVal a where
+  toJSVal :: a -> IO JSVal
+  default toJSVal :: (Generic a, GToJSVal (Rep a)) => a -> IO JSVal
+  toJSVal x = do
+    o <- create
+    gToJSVal (from x) o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | Internal: writes a t'GHC.Generics.Generic' representation into a JS object
+-- field by field. Backs the default 'ToJSVal' implementation; you should not
+-- need to write instances.
+class GToJSVal (f :: Type -> Type) where
+  gToJSVal :: f a -> Object -> IO ()
+-----------------------------------------------------------------------------
+instance GToJSVal a => GToJSVal (D1 i a) where
+  gToJSVal (M1 x) = gToJSVal x
+  {-# INLINE gToJSVal #-}
+-----------------------------------------------------------------------------
+instance GToJSVal a => GToJSVal (C1 i a) where
+  gToJSVal (M1 x) = gToJSVal x
+  {-# INLINE gToJSVal #-}
+-----------------------------------------------------------------------------
+instance (GToJSVal a, GToJSVal b) => GToJSVal (a :*: b) where
+  gToJSVal (x :*: y) o = gToJSVal x o >> gToJSVal y o
+  {-# INLINE gToJSVal #-}
+-----------------------------------------------------------------------------
+instance (TypeError ('Text "Sum types unsupported"), GToJSVal a, GToJSVal b) => GToJSVal (a :+: b) where
+  gToJSVal = \case
+    L1 x -> gToJSVal x
+    R1 x -> gToJSVal x
+  {-# INLINE gToJSVal #-}
+-----------------------------------------------------------------------------
+instance (ToJSVal a, Selector s) => GToJSVal (S1 s (K1 i a)) where
+  gToJSVal (M1 (K1 x)) o =
+    setField o fieldName =<< toJSVal x
+      where
+        fieldName = ms $ selName (undefined :: S1 s (K1 i a) ())
+  {-# INLINE gToJSVal #-}
+-----------------------------------------------------------------------------
+instance GToJSVal U1 where
+  gToJSVal U1 _ = pure ()
+  {-# INLINE gToJSVal #-}
+-----------------------------------------------------------------------------
+instance GToJSVal V1 where
+  gToJSVal _ _ = pure ()
+  {-# INLINE gToJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal Bool where
+  toJSVal = toJSVal_Bool
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal Double where
+  toJSVal = toJSVal_Double
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal Float where
+  toJSVal = toJSVal_Float
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal a => ToJSVal (IO a) where
+  toJSVal action = toJSVal =<< action
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal () where
+  toJSVal () = pure jsNull
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal Char where
+  toJSVal = toJSVal_Char
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal Int where
+  toJSVal = toJSVal_Int
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal a => ToJSVal (Map MisoString a) where
+  toJSVal map_ = do
+    o <- create
+    forM_ (M.toList map_) $ \(k,v) ->
+      setField o k =<< toJSVal v
+    toJSVal o
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal a => FromJSVal (Map MisoString a) where
+  fromJSVal o = pure <$> do foldM populate M.empty =<< listProps (Object o)
+    where
+      populate m k = do
+        v <- fromJSValUnchecked =<< getProp k (Object o)
+        pure (M.insert k v m)
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal a => ToObject (Map MisoString a) where
+  toObject x = Object <$> toJSVal x
+  {-# INLINE toObject #-}
+-----------------------------------------------------------------------------
+instance ToJSVal a => ToJSVal (Maybe a) where
+  toJSVal = \case
+    Nothing -> pure jsNull
+    Just x -> toJSVal x
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance {-# OVERLAPPABLE #-} FromJSVal a => FromJSVal [a] where
+  fromJSVal jsval_ = do
+    fromJSVal_List jsval_ >>= \case
+      Nothing -> pure Nothing
+      Just xs -> sequence <$> mapM fromJSVal xs
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal [Char] where
+  fromJSVal jsval_ = fmap unpack <$> fromJSVal jsval_
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal [Char] where
+  toJSVal = toJSVal . toMisoString
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance {-# OVERLAPPABLE #-} ToJSVal a => ToJSVal [a] where
+  toJSVal = toJSVal_List <=< mapM toJSVal
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal JSVal where
+  toJSVal = pure
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Value where
+  fromJSVal = fromJSVal_Value
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | A class for marshaling JS values into Haskell
+class FromJSVal a where
+  fromJSVal :: JSVal -> IO (Maybe a)
+  default fromJSVal :: (Generic a, GFromJSVal (Rep a)) => JSVal -> IO (Maybe a)
+  fromJSVal x = fmap to <$> gFromJSVal (Object x)
+  fromJSValUnchecked :: JSVal -> IO a
+  fromJSValUnchecked x = do
+    fromJSVal x >>= \case
+      Nothing -> error "fromJSValUnchecked: failure"
+      Just y -> pure y
+-----------------------------------------------------------------------------
+-- | Internal: rebuilds a t'GHC.Generics.Generic' representation from a JS
+-- object, yielding 'Nothing' when a field is missing or ill-typed. Backs the
+-- default 'FromJSVal' implementation.
+class GFromJSVal (f :: Type -> Type) where
+  gFromJSVal :: Object -> IO (Maybe (f a))
+-----------------------------------------------------------------------------
+instance GFromJSVal a => GFromJSVal (D1 i a) where
+  gFromJSVal o = fmap M1 <$> gFromJSVal o
+  {-# INLINE gFromJSVal #-}
+-----------------------------------------------------------------------------
+instance GFromJSVal a => GFromJSVal (C1 i a) where
+  gFromJSVal o = fmap M1 <$> gFromJSVal o
+  {-# INLINE gFromJSVal #-}
+-----------------------------------------------------------------------------
+instance GFromJSVal U1 where
+  gFromJSVal _ = pure (Just U1)
+  {-# INLINE gFromJSVal #-}
+-----------------------------------------------------------------------------
+instance GFromJSVal V1 where
+  gFromJSVal _ = pure Nothing
+  {-# INLINE gFromJSVal #-}
+-----------------------------------------------------------------------------
+instance (GFromJSVal a, GFromJSVal b) => GFromJSVal (a :*: b) where
+  gFromJSVal o = runMaybeT $ (:*:) <$> MaybeT (gFromJSVal o) <*> MaybeT (gFromJSVal o)
+  {-# INLINE gFromJSVal #-}
+-----------------------------------------------------------------------------
+instance (TypeError ('Text "Sum types unsupported"), GFromJSVal a, GFromJSVal b) => GFromJSVal (a :+: b) where
+  gFromJSVal o = do
+    x <- fmap L1 <$> gFromJSVal o
+    case x of
+      Nothing -> fmap R1 <$> gFromJSVal o
+      Just y -> pure (Just y)
+  {-# INLINE gFromJSVal #-}
+-----------------------------------------------------------------------------
+instance (FromJSVal a, Selector s) => GFromJSVal (S1 s (K1 i a)) where
+  gFromJSVal o = fmap (M1 . K1) <$> do fromJSVal =<< getProp (ms name) o
+    where
+      name = selName (undefined :: S1 s (K1 i a) ())
+  {-# INLINE gFromJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Int where
+  fromJSVal = fromJSVal_Int
+  fromJSValUnchecked = fromJSValUnchecked_Int
+  {-# INLINE fromJSVal #-}
+  {-# INLINE fromJSValUnchecked #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Char where
+  fromJSVal = fromJSVal_Char
+  fromJSValUnchecked = fromJSValUnchecked_Char
+  {-# INLINE fromJSVal #-}
+  {-# INLINE fromJSValUnchecked #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Float where
+  fromJSVal = fromJSVal_Float
+  fromJSValUnchecked = fromJSValUnchecked_Float
+  {-# INLINE fromJSVal #-}
+  {-# INLINE fromJSValUnchecked #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Double where
+  fromJSVal = fromJSVal_Double
+  fromJSValUnchecked = fromJSValUnchecked_Double
+  {-# INLINE fromJSVal #-}
+  {-# INLINE fromJSValUnchecked #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Text where
+  fromJSVal = fromJSVal_Text
+  fromJSValUnchecked = fromJSValUnchecked_Text
+  {-# INLINE fromJSVal #-}
+  {-# INLINE fromJSValUnchecked #-}
+-----------------------------------------------------------------------------
+instance ToObject Object where
+  toObject = pure
+  {-# INLINE toObject #-}
+-----------------------------------------------------------------------------
+instance ToJSVal Value where
+  toJSVal = toJSVal_Value
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance ToJSVal Text where
+  toJSVal = toJSVal_Text
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal () where
+  fromJSVal _ = pure (Just ())
+    -- if isUndefined_ffi x || isNull_ffi x
+    --   then pure (Just ())
+    --   else pure Nothing
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+instance (ToJSVal a, ToJSVal b) => ToJSVal (a,b) where
+  toJSVal (y,z) = do
+    y_ <- toJSVal y
+    z_ <- toJSVal z
+    toJSVal_List [ y_, z_ ]
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance (ToJSVal a, ToJSVal b, ToJSVal c) => ToJSVal (a,b,c) where
+  toJSVal (x,y,z) = do
+    x_ <- toJSVal x
+    y_ <- toJSVal y
+    z_ <- toJSVal z
+    toJSVal_List [ x_, y_, z_ ]
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance (ToJSVal a, ToJSVal b, ToJSVal c, ToJSVal d) => ToJSVal (a,b,c,d) where
+  toJSVal (w,x,y,z) = do
+    w_ <- toJSVal w
+    x_ <- toJSVal x
+    y_ <- toJSVal y
+    z_ <- toJSVal z
+    toJSVal_List [ w_, x_, y_, z_ ]
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance (ToJSVal a, ToJSVal b, ToJSVal c, ToJSVal d, ToJSVal e) => ToJSVal (a,b,c,d,e) where
+  toJSVal (v,w,x,y,z) = do
+    v_ <- toJSVal v
+    w_ <- toJSVal w
+    x_ <- toJSVal x
+    y_ <- toJSVal y
+    z_ <- toJSVal z
+    toJSVal_List [ v_, w_, x_, y_, z_ ]
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance (ToJSVal a, ToJSVal b, ToJSVal c, ToJSVal d, ToJSVal e, ToJSVal f) => ToJSVal (a,b,c,d,e,f) where
+  toJSVal (u,v,w,x,y,z) = do
+    u_ <- toJSVal u
+    v_ <- toJSVal v
+    w_ <- toJSVal w
+    x_ <- toJSVal x
+    y_ <- toJSVal y
+    z_ <- toJSVal z
+    toJSVal_List [ u_, v_, w_, x_, y_, z_ ]
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+-- | Retrieves a field from globalThis
+jsg :: MisoString -> IO JSVal
+jsg key = global ! key
+{-# INLINABLE jsg #-}
+-----------------------------------------------------------------------------
+-- | Invokes a function with a specified argument list
+jsgf
+  :: ToArgs args
+  => MisoString
+  -- ^ Global function name on @globalThis@
+  -> args
+  -- ^ Arguments to pass to the function
+  -> IO JSVal
+jsgf name = global # name
+{-# INLINABLE jsgf #-}
+-----------------------------------------------------------------------------
+-- | Invokes a function with no argument
+jsg0 :: MisoString -> IO JSVal
+jsg0 name = jsgf name ([] :: [JSVal])
+{-# INLINABLE jsg0 #-}
+-----------------------------------------------------------------------------
+-- | Invokes a function with 1 argument
+jsg1 :: ToJSVal arg => MisoString -> arg -> IO JSVal
+jsg1 name arg = jsgf name [arg]
+{-# INLINABLE jsg1 #-}
+-----------------------------------------------------------------------------
+-- | Invokes a function with 2 arguments
+jsg2
+  :: (ToJSVal arg1, ToJSVal arg2)
+  => MisoString
+  -- ^ Global function name on @globalThis@
+  -> arg1 -- ^ First argument
+  -> arg2 -- ^ Second argument
+  -> IO JSVal
+jsg2 name arg1 arg2 = do
+  arg1_ <- toJSVal arg1
+  arg2_ <- toJSVal arg2
+  jsgf name [arg1_, arg2_]
+{-# INLINABLE jsg2 #-}
+-----------------------------------------------------------------------------
+-- | Invokes a function with 3 arguments
+jsg3
+  :: (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3)
+  => MisoString
+  -- ^ Global function name on @globalThis@
+  -> arg1 -- ^ First argument
+  -> arg2 -- ^ Second argument
+  -> arg3 -- ^ Third argument
+  -> IO JSVal
+jsg3 name arg1 arg2 arg3 = do
+  arg1_ <- toJSVal arg1
+  arg2_ <- toJSVal arg2
+  arg3_ <- toJSVal arg3
+  jsgf name [arg1_, arg2_, arg3_]
+{-# INLINABLE jsg3 #-}
+-----------------------------------------------------------------------------
+-- | Invokes a function with 4 arguments
+jsg4 :: (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4)
+     => MisoString
+     -> arg1
+     -> arg2
+     -> arg3
+     -> arg4
+     -> IO JSVal
+jsg4 name arg1 arg2 arg3 arg4 = do
+  arg1_ <- toJSVal arg1
+  arg2_ <- toJSVal arg2
+  arg3_ <- toJSVal arg3
+  arg4_ <- toJSVal arg4
+  jsgf name [arg1_, arg2_, arg3_, arg4_]
+{-# INLINABLE jsg4 #-}
+-----------------------------------------------------------------------------
+-- | Invokes a function with 5 arguments
+jsg5 :: (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4, ToJSVal arg5)
+     => MisoString
+     -> arg1
+     -> arg2
+     -> arg3
+     -> arg4
+     -> arg5
+     -> IO JSVal
+jsg5 name arg1 arg2 arg3 arg4 arg5 = do
+  arg1_ <- toJSVal arg1
+  arg2_ <- toJSVal arg2
+  arg3_ <- toJSVal arg3
+  arg4_ <- toJSVal arg4
+  arg5_ <- toJSVal arg5
+  jsgf name [arg1_, arg2_, arg3_, arg4_, arg5_]
+{-# INLINABLE jsg5 #-}
+-----------------------------------------------------------------------------
+-- | Sets a field on an Object at a specified field
+setField
+  :: (ToObject o, ToJSVal v)
+  => o
+  -- ^ JavaScript object to mutate
+  -> MisoString
+  -- ^ Field name to set
+  -> v
+  -- ^ Value to assign
+  -> IO ()
+setField o k v = do
+  o' <- toJSVal =<< toObject o
+  v' <- toJSVal v
+  setProp_ffi
+#ifdef MISO_TEXT
+    (textToJSString k)
+#else
+    k
+#endif
+    v' o'
+{-# INLINABLE setField #-}
+-----------------------------------------------------------------------------
+-- | Sets a field on an Object at a specified index
+infixr 1 <##
+(<##) :: (ToObject o, ToJSVal v) => o -> Int -> v -> IO ()
+(<##) o k v = do
+  o' <- toJSVal =<< toObject o
+  v' <- toJSVal v
+  setPropIndex_ffi k v' o'
+{-# INLINABLE (<##) #-}
+-----------------------------------------------------------------------------
+-- | Retrieves a property from an Object
+(!) :: ToObject o => o -> MisoString -> IO JSVal
+(!) = flip getProp
+{-# INLINABLE (!) #-}
+-----------------------------------------------------------------------------
+-- | Lists the properties on a JS Object.
+listProps :: Object -> IO [MisoString]
+listProps (Object jsval) = do
+  keys <- fromJSValUnchecked =<< listProps_ffi jsval
+  forM keys fromJSValUnchecked
+{-# INLINABLE listProps #-}
+-----------------------------------------------------------------------------
+-- | Calls a JS function on an t'Object' at a field with specified arguments.
+call
+  :: (ToObject obj, ToObject this, ToArgs args)
+  => obj
+  -- ^ The function object to call
+  -> this
+  -- ^ The @this@ context to bind for the call
+  -> args
+  -- ^ Arguments to pass to the function
+  -> IO JSVal
+call o this args = do
+  o' <- toJSVal =<< toObject o
+  this' <- toJSVal =<< toObject this
+  args' <- toJSVal =<< toArgs args
+  result <- invokeFunction o' this' args'
+  freeJSVal args'
+  pure result
+{-# INLINABLE call #-}
+-----------------------------------------------------------------------------
+-- | Calls a JS function on an t'Object' at a field with specified arguments.
+infixr 2 #
+(#) :: (ToObject object, ToArgs args) => object -> MisoString -> args -> IO JSVal
+(#) o k args = do
+  o' <- toJSVal =<< toObject o
+  func <- getProp_ffi
+#ifdef MISO_TEXT
+    (textToJSString k)
+#else
+    k
+#endif
+    o'
+  args' <- toJSVal =<< toArgs args
+  result <- invokeFunction func o' args'
+  -- @func@ and the argument array are temporaries nobody else can reach;
+  -- release them eagerly (see 'freeJSVal'). The argument elements may be the
+  -- caller's handles, so only the array itself is freed.
+  freeJSVal func
+  freeJSVal args'
+  pure result
+{-# INLINABLE (#) #-}
+-----------------------------------------------------------------------------
+-- | Calls a JavaScript t'Function' with the given arguments and marshals
+-- the result back into Haskell.
+--
+-- @since 1.13.0.0
+apply
+  :: (FromJSVal a, ToArgs args)
+  => Function
+  -- ^ JavaScript function to invoke
+  -> args
+  -- ^ Arguments to pass to the function
+  -> IO a
+apply (Function func) args = do
+  o <- toJSVal global
+  fromJSValUnchecked =<< do
+    invokeFunction func o =<<
+      toJSVal (toArgs args)
+{-# INLINABLE apply #-}
+-----------------------------------------------------------------------------
+-- | Instantiates a new JS t'Object'.
+new
+  :: (ToObject constructor, ToArgs args)
+  => constructor
+  -- ^ JavaScript constructor function (e.g. @jsg \"Array\"@)
+  -> args
+  -- ^ Constructor arguments
+  -> IO JSVal
+new constr args = do
+  obj <- toJSVal =<< toObject constr
+  argv <- toJSVal =<< toArgs args
+  result <- new_ffi obj argv
+  freeJSVal argv
+  pure result
+{-# INLINABLE new #-}
+-----------------------------------------------------------------------------
+-- | Creates a new JS t'Object'
+create :: IO Object
+create = Object <$> create_ffi
+{-# INLINABLE create #-}
+-----------------------------------------------------------------------------
+-- | Creates a new JS t'Object' populated with key-value pairs specified
+-- in the list. Meant for use with 'Miso.FFI.inline' JS functionality.
+--
+-- @
+-- update = \case
+--  Highlight domRef -> do
+--    3 <- inline "hljs.highlight(domRef); return 3;" =<<
+--      createWith [ "domRef" =: domRef ]
+--    pure ()
+-- @
+--
+createWith :: ToJSVal val => [(MisoString, val)] -> IO Object
+createWith kvs = do
+  o <- create
+  forM_ kvs $ \(k,v) ->
+    flip (setProp k) o =<< toJSVal v
+  pure o
+{-# INLINABLE createWith #-}
+-----------------------------------------------------------------------------
+-- | Sets a property on a JS t'Object'
+setProp
+  :: ToJSVal val
+  => MisoString
+  -- ^ Property name to set
+  -> val
+  -- ^ Value to assign
+  -> Object
+  -- ^ Target JavaScript object
+  -> IO ()
+setProp k v (Object o) = flip (setProp_ffi
+#ifdef MISO_TEXT
+    (textToJSString k)
+#else
+    k
+#endif
+    ) o =<< toJSVal v
+{-# INLINABLE setProp #-}
+-----------------------------------------------------------------------------
+-- | Retrieves a property from a JS t'Object'
+getProp
+  :: ToObject o
+  => MisoString
+  -- ^ Property name to read
+  -> o
+  -- ^ JavaScript object to read from
+  -> IO JSVal
+getProp k v = getProp_ffi
+#ifdef MISO_TEXT
+    (textToJSString k)
+#else
+    k
+#endif
+    =<< toJSVal (toObject v)
+{-# INLINABLE getProp #-}
+-----------------------------------------------------------------------------
+-- | Dynamically evaluates a JS string. See [eval](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)
+--
+-- `eval()` is slower (not subject to JS engine optimizations) and also
+-- has security vulnerabilities (can alter other local variables).
+--
+-- Consider using the more performant and secure (isolated) `inline` function.
+--
+eval :: MisoString -> IO JSVal
+eval =
+#ifdef MISO_TEXT
+  eval_ffi . textToJSString
+#else
+  eval_ffi
+#endif
+{-# INLINABLE eval #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Bool where
+  fromJSVal = fromJSVal_Bool
+  fromJSValUnchecked = fromJSValUnchecked_Bool
+  {-# INLINE fromJSVal #-}
+  {-# INLINE fromJSValUnchecked #-}
+-----------------------------------------------------------------------------
+instance FromJSVal JSVal where
+  fromJSVal = pure . Just
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal a => FromJSVal (Maybe a) where
+  fromJSVal x = fromJSVal_Maybe x >>= \case
+    Nothing -> pure Nothing
+    Just Nothing -> pure (Just Nothing)
+    Just (Just y) -> fmap Just <$> fromJSVal y
+  fromJSValUnchecked x = fromJSValUnchecked_Maybe x >>= \case
+    Nothing -> pure Nothing
+    Just y -> Just <$> fromJSValUnchecked y
+  {-# INLINE fromJSVal #-}
+  {-# INLINE fromJSValUnchecked #-}
+-----------------------------------------------------------------------------
+-- | A class for creating arguments to a JS function
+class ToArgs args where
+  toArgs :: args -> IO [JSVal]
+-----------------------------------------------------------------------------
+instance ToArgs Double where
+  toArgs x = (:[]) <$> toJSVal x
+  {-# INLINE toArgs #-}
+-----------------------------------------------------------------------------
+instance ToArgs JSVal where
+  toArgs val = pure [val]
+  {-# INLINE toArgs #-}
+-----------------------------------------------------------------------------
+instance ToObject JSVal where
+  toObject = pure . Object
+  {-# INLINE toObject #-}
+-----------------------------------------------------------------------------
+-- | A class for creating JS objects.
+class ToObject a where
+  toObject :: a -> IO Object
+  default toObject :: (Generic a, GToJSVal (Rep a)) => a -> IO Object
+  toObject x = do
+    o <- create
+    gToJSVal (from x) o
+    pure o
+-----------------------------------------------------------------------------
+instance ToJSVal a => ToObject (IO a) where
+  toObject action = Object <$> (toJSVal =<< action)
+  {-# INLINE toObject #-}
+-----------------------------------------------------------------------------
+instance ToArgs MisoString where
+  toArgs arg = (:[]) <$> toJSVal arg
+  {-# INLINE toArgs #-}
+----------------------------------------------------------------------------
+#if !defined(VANILLA) && !defined(MISO_TEXT)
+----------------------------------------------------------------------------
+instance ToJSVal MisoString where
+  toJSVal = toJSVal_JSString
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal MisoString where
+  fromJSVal = fromJSVal_JSString
+  {-# INLINE fromJSVal #-}
+----------------------------------------------------------------------------
+#endif
+----------------------------------------------------------------------------
+instance ToJSVal arg => ToArgs [arg] where
+    toArgs = mapM toJSVal
+    {-# INLINE toArgs #-}
+----------------------------------------------------------------------------
+instance ToArgs () where
+  toArgs _ = pure []
+  {-# INLINE toArgs #-}
+----------------------------------------------------------------------------
+instance ToArgs Int where
+  toArgs k = (:[]) <$> toJSVal k
+  {-# INLINE toArgs #-}
+-----------------------------------------------------------------------------
+instance ToArgs Function where
+  toArgs k = (:[]) <$> toJSVal k
+  {-# INLINE toArgs #-}
+-----------------------------------------------------------------------------
+instance ToArgs Bool where
+  toArgs k = (:[]) <$> toJSVal k
+  {-# INLINE toArgs #-}
+-----------------------------------------------------------------------------
+instance ToArgs Object where
+  toArgs k = (:[]) <$> toJSVal k
+  {-# INLINE toArgs #-}
+-----------------------------------------------------------------------------
+instance ToArgs args => ToArgs (Maybe args) where
+  toArgs (Just args) = toArgs args
+  toArgs Nothing     = pure []
+  {-# INLINE toArgs #-}
+----------------------------------------------------------------------------
+instance (ToJSVal arg1, ToJSVal arg2) => ToArgs (arg1, arg2) where
+  toArgs (arg1, arg2) = do
+    rarg1 <- toJSVal arg1
+    rarg2 <- toJSVal arg2
+    return [rarg1, rarg2]
+  {-# INLINE toArgs #-}
+----------------------------------------------------------------------------
+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3) => ToArgs (arg1, arg2, arg3) where
+  toArgs (arg1, arg2, arg3) = do
+    rarg1 <- toJSVal arg1
+    rarg2 <- toJSVal arg2
+    rarg3 <- toJSVal arg3
+    return [rarg1, rarg2, rarg3]
+  {-# INLINE toArgs #-}
+----------------------------------------------------------------------------
+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4) => ToArgs (arg1, arg2, arg3, arg4) where
+  toArgs (arg1, arg2, arg3, arg4) = do
+    rarg1 <- toJSVal arg1
+    rarg2 <- toJSVal arg2
+    rarg3 <- toJSVal arg3
+    rarg4 <- toJSVal arg4
+    return [rarg1, rarg2, rarg3, rarg4]
+  {-# INLINE toArgs #-}
+----------------------------------------------------------------------------
+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4, ToJSVal arg5) => ToArgs (arg1, arg2, arg3, arg4, arg5) where
+  toArgs (arg1, arg2, arg3, arg4, arg5) = do
+    rarg1 <- toJSVal arg1
+    rarg2 <- toJSVal arg2
+    rarg3 <- toJSVal arg3
+    rarg4 <- toJSVal arg4
+    rarg5 <- toJSVal arg5
+    return [rarg1, rarg2, rarg3, rarg4, rarg5]
+  {-# INLINE toArgs #-}
+----------------------------------------------------------------------------
+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4, ToJSVal arg5, ToJSVal arg6) => ToArgs (arg1, arg2, arg3, arg4, arg5, arg6) where
+  toArgs (arg1, arg2, arg3, arg4, arg5, arg6) = do
+    rarg1 <- toJSVal arg1
+    rarg2 <- toJSVal arg2
+    rarg3 <- toJSVal arg3
+    rarg4 <- toJSVal arg4
+    rarg5 <- toJSVal arg5
+    rarg6 <- toJSVal arg6
+    return [rarg1, rarg2, rarg3, rarg4, rarg5, rarg6]
+  {-# INLINE toArgs #-}
+----------------------------------------------------------------------------
+-- | Frees references to a callback
+freeFunction :: Function -> IO ()
+freeFunction (Function x) = freeFunction_ffi x
+{-# INLINABLE freeFunction #-}
+-----------------------------------------------------------------------------
+-- | Eagerly release a 'JSVal' handle.
+--
+-- On the WASM backend every 'JSVal' carries a weak pointer and a C finalizer
+-- so that the JavaScript value can be released once the handle is garbage
+-- collected. The RTS must evacuate every such weak pointer on every GC (dead
+-- or alive) before it can run the finalizer, so short-lived handles created
+-- in bulk (e.g. while building a virtual DOM) make each GC pause scale with
+-- the number of handles allocated since the last one. 'freeJSVal' unlinks
+-- the weak pointer and releases the JavaScript side immediately, so the
+-- handle costs the GC nothing.
+--
+-- Only the Haskell handle is released: the JavaScript value itself stays
+-- alive for as long as something on the JavaScript side references it.
+--
+-- Using a 'JSVal' after it has been freed is undefined behaviour, so only
+-- free handles that no other Haskell code (including callbacks that close
+-- over them) can reach. Note that on WASM a 'JSString' /is/ a 'JSVal', so
+-- never free a handle obtained from 'toJSVal' on a string you do not own.
+--
+-- No-op on the GHCJS and native backends.
+freeJSVal :: JSVal -> IO ()
+freeJSVal = freeJSVal_ffi
+{-# INLINABLE freeJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Function where
+  fromJSVal x = do
+    missing <- (||) <$> isUndefined x <*> isNull x
+    pure $ if missing then Nothing else Just (Function x)
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal Object where
+  fromJSVal x = do
+    missing <- (||) <$> isUndefined x <*> isNull x
+    pure $ if missing then Nothing else Just (Object x)
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | Lookup a property based on its index
+(!!) :: ToObject object => object -> Int -> IO JSVal
+(!!) o k = getPropIndex_ffi k =<< toJSVal =<< toObject o
+{-# INLINABLE (!!) #-}
+-----------------------------------------------------------------------------
+-- | Checks if a t'JSVal' is undefined
+isUndefined :: ToJSVal val => val -> IO Bool
+isUndefined val = isUndefined_ffi <$> toJSVal val
+{-# INLINABLE isUndefined #-}
+-----------------------------------------------------------------------------
+-- | Checks if a t'JSVal' is null
+isNull :: ToJSVal val => val -> IO Bool
+isNull val = isNull_ffi <$> toJSVal val
+{-# INLINABLE isNull #-}
+-----------------------------------------------------------------------------
+-- | A JS Object
+newtype Object = Object { unObject :: JSVal } deriving newtype (ToJSVal, Eq)
+-----------------------------------------------------------------------------
+-- | A JS Functionn
+newtype Function = Function { unFunction :: JSVal } deriving newtype (ToJSVal, Eq)
+-----------------------------------------------------------------------------
+instance (FromJSVal a, FromJSVal b) => FromJSVal (a,b) where
+    fromJSVal r = runMaybeT $ (,) <$> jf r 0 <*> jf r 1
+    {-# INLINE fromJSVal #-}
+instance (FromJSVal a, FromJSVal b, FromJSVal c) => FromJSVal (a,b,c) where
+    fromJSVal r = runMaybeT $ (,,) <$> jf r 0 <*> jf r 1 <*> jf r 2
+    {-# INLINE fromJSVal #-}
+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d) => FromJSVal (a,b,c,d) where
+    fromJSVal r = runMaybeT $ (,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3
+    {-# INLINE fromJSVal #-}
+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d, FromJSVal e) => FromJSVal (a,b,c,d,e) where
+    fromJSVal r = runMaybeT $ (,,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3 <*> jf r 4
+    {-# INLINE fromJSVal #-}
+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d, FromJSVal e, FromJSVal f) => FromJSVal (a,b,c,d,e,f) where
+    fromJSVal r = runMaybeT $ (,,,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3 <*> jf r 4 <*> jf r 5
+    {-# INLINE fromJSVal #-}
+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d, FromJSVal e, FromJSVal f, FromJSVal g) => FromJSVal (a,b,c,d,e,f,g) where
+    fromJSVal r = runMaybeT $ (,,,,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3 <*> jf r 4 <*> jf r 5 <*> jf r 6
+    {-# INLINE fromJSVal #-}
+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d, FromJSVal e, FromJSVal f, FromJSVal g, FromJSVal h) => FromJSVal (a,b,c,d,e,f,g,h) where
+    fromJSVal r = runMaybeT $ (,,,,,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3 <*> jf r 4 <*> jf r 5 <*> jf r 6 <*> jf r 7
+    {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+jf :: FromJSVal a => JSVal -> Int -> MaybeT IO a
+{-# INLINE jf #-}
+jf r n = MaybeT $ do
+  x <- getPropIndex_ffi n r
+  if isUndefined_ffi r
+    then return Nothing
+    else fromJSVal x
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Data/Array.hs b/src/Miso/Data/Array.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Data/Array.hs
@@ -0,0 +1,242 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Data.Array
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Data.Array" is a Haskell wrapper around the JavaScript
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array Array>
+-- object. Values of type @'Array' a@ live in JavaScript memory; all
+-- operations run in 'IO' and mutate the underlying JS array in place.
+--
+-- Use this module when you need to pass a JS-native array to a browser API
+-- or a third-party JavaScript library. For pure Haskell data processing,
+-- prefer ordinary lists or 'Data.Map.Strict.Map'.
+--
+-- Import qualified to avoid clashing with "Prelude":
+--
+-- @
+-- import qualified "Miso.Data.Array" as A
+-- @
+--
+-- = Quick start
+--
+-- @
+-- import qualified "Miso.Data.Array" as A
+--
+-- example :: IO ()
+-- example = do
+--   arr <- A.'fromList' [10, 20, 30 :: Int]
+--   A.'push' 40 arr
+--   v   <- A.'lookup' 2 arr    -- Just 30
+--   n   <- A.'size' arr        -- 4
+--   xs  <- A.'toList' arr      -- [10, 20, 30, 40]
+--   pure ()
+-- @
+--
+-- = Operations
+--
+-- * __Construction__: 'new', 'fromList', 'singleton'
+-- * __Deconstruction__: 'toList'
+-- * __Access__: 'lookup', '(!?)', 'member', 'size', 'null'
+-- * __Mutation__: 'insert', 'push', 'pop', 'shift', 'unshift', 'splice', 'reverse'
+--
+-- = See also
+--
+-- * "Miso.Data.Map" — mutable JS 'Miso.Data.Map.Map'
+-- * "Miso.Data.Set" — mutable JS 'Miso.Data.Set.Set'
+-- * "Miso.DSL" — 'Miso.DSL.ToJSVal' \/ 'Miso.DSL.FromJSVal' used by element types
+-----------------------------------------------------------------------------
+module Miso.Data.Array
+  ( -- * Type
+    Array
+    -- * Construction
+  , new
+  , fromList
+    -- * Deconstruction
+  , toList
+    -- * Operations
+  , insert
+  , push
+  , member
+  , size
+  , splice
+  , singleton
+  , pop
+  , shift
+  , unshift
+  , null
+  , lookup
+  , (!?)
+  , reverse
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad (void, forM, forM_)
+import           Prelude hiding (lookup, null, reverse)
+-----------------------------------------------------------------------------
+import           Miso.DSL (jsg, JSVal, ToObject, ToJSVal, FromJSVal, (!))
+import qualified Miso.DSL as DSL
+import           Miso.FFI (callFunction)
+import           Miso.String (ms, unpack)
+-----------------------------------------------------------------------------
+-- | A JS [Array](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array),
+-- wrapped so it can be passed across the FFI without copying. Operations live
+-- in t'IO' because the underlying object is mutable.
+newtype Array value = Array JSVal deriving (FromJSVal, ToJSVal, ToObject)
+-----------------------------------------------------------------------------
+-- | Constructs a new JS [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) in t'IO'.
+--
+new :: IO (Array value)
+new = Array <$> DSL.new (jsg "Array") ([] :: [JSVal])
+-----------------------------------------------------------------------------
+-- | Inserts a value into the t'Array' by value.
+insert
+  :: ToJSVal value
+  => Int
+  -- ^ Index at which to insert the value (0-based)
+  -> value
+  -- ^ Value to store at that index
+  -> Array value
+  -- ^ Array to mutate
+  -> IO ()
+insert key value (Array m) = do
+  _ <- DSL.Object m DSL.<## key $ value
+  pure ()
+-----------------------------------------------------------------------------
+-- | Appends a value to the end of the t'Array'.
+push
+  :: ToJSVal value
+  => value
+  -- ^ Value to append
+  -> Array value
+  -- ^ Array to mutate
+  -> IO ()
+push value (Array m) = do
+  _ <- callFunction m "push" [value]
+  pure ()
+-----------------------------------------------------------------------------
+-- | Look up a value in the array by key.
+lookup
+  :: FromJSVal value
+  => Int
+  -- ^ 0-based index to look up
+  -> Array value
+  -- ^ Array to query
+  -> IO (Maybe value)
+lookup key m = DSL.fromJSValUnchecked =<< m DSL.!! key
+-----------------------------------------------------------------------------
+-- | Look up a value in the array by index, throwing if out of bounds.
+(!?)
+  :: FromJSVal value
+  => Int
+  -- ^ 0-based index to look up
+  -> Array value
+  -- ^ Array to query
+  -> IO value
+(!?) key m =
+  lookup key m >>= \case
+    Nothing ->
+      error ("(!?) index out of bounds: " <> unpack (ms key))
+    Just value ->
+      pure value
+-----------------------------------------------------------------------------
+-- | Return the size of t'Array'.
+size :: Array value -> IO Int
+size (Array m) = DSL.fromJSValUnchecked =<< m ! "length"
+-----------------------------------------------------------------------------
+-- | Return the null of t'Array'.
+null :: Array value -> IO Bool
+null m = (== 0) <$> size m
+-----------------------------------------------------------------------------
+-- | Checks existence of @value@ in t'Array', returns t'Bool.
+member
+  :: ToJSVal value
+  => value
+  -- ^ Value to search for (uses JavaScript @SameValueZero@ equality)
+  -> Array value
+  -- ^ Array to search
+  -> IO Bool
+member value (Array m) = DSL.fromJSValUnchecked =<< callFunction m "includes" =<< DSL.toJSVal value
+-----------------------------------------------------------------------------
+-- | Splices an array. See [splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice).
+splice
+  :: ToJSVal value
+  => Int
+  -- ^ Start index (0-based) at which to begin the splice
+  -> Int
+  -- ^ Number of elements to remove starting at @start@
+  -> [value]
+  -- ^ Elements to insert at @start@ after the removal
+  -> Array value
+  -- ^ Array to mutate in place
+  -> IO (Array value)
+splice start deleteCount xs (Array m) = do
+  s <- DSL.toJSVal start
+  d <- DSL.toJSVal deleteCount
+  args <- mapM DSL.toJSVal xs
+  Array <$> do callFunction m "splice" $ [s,d] ++ args
+-----------------------------------------------------------------------------
+-- | Construct a t'Array' from a list of values.
+fromList
+  :: ToJSVal value
+  => [value]
+  -- ^ Elements to populate the new array with (in order)
+  -> IO (Array value)
+fromList xs = do
+  m <- new
+  forM_ (zip [0..] xs) $ \(k,v) ->
+    insert k v m
+  pure m
+-----------------------------------------------------------------------------
+-- | Converts an t'Array' to a list.
+toList :: FromJSVal value => Array value -> IO [value]
+toList m = do
+  len <- subtract 1 <$> size m
+  forM [0..len] (!? m)
+-----------------------------------------------------------------------------
+-- | Creates a new Array with a single element.
+--
+singleton
+  :: ToJSVal a
+  => a
+  -- ^ The single element for the new array
+  -> IO (Array a)
+singleton x = fromList [x]
+-----------------------------------------------------------------------------
+-- | Removes the last element from an array and returns it.
+--
+-- Returns 'Nothing' if the t'Array' is empty.
+--
+pop :: FromJSVal a => Array a -> IO (Maybe a)
+pop (Array arr) = DSL.fromJSValUnchecked =<< callFunction arr "pop" ([] :: [JSVal])
+-----------------------------------------------------------------------------
+-- | Removes the first element from an array and returns it.
+--
+shift :: FromJSVal a => Array a -> IO (Maybe a)
+shift (Array arr) = DSL.fromJSValUnchecked =<< callFunction arr "shift" ([] :: [JSVal])
+-----------------------------------------------------------------------------
+-- | Adds one or more elements to the beginning of an array.
+--
+unshift
+  :: ToJSVal a
+  => a
+  -- ^ Element to prepend at index 0
+  -> Array a
+  -- ^ Array to mutate
+  -> IO Int
+unshift x (Array arr) = DSL.fromJSValUnchecked =<< callFunction arr "unshift" [x]
+-----------------------------------------------------------------------------
+-- | Reverses an array in-place.
+--
+reverse :: Array a -> IO ()
+reverse (Array arr) = void $ callFunction arr "reverse" ([] :: [JSVal])
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Data/Map.hs b/src/Miso/Data/Map.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Data/Map.hs
@@ -0,0 +1,156 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Data.Map
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Data.Map" is a Haskell wrapper around the JavaScript
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map Map>
+-- object. Values of type @'Map' k v@ live in JavaScript memory; all
+-- operations run in 'IO' and mutate the underlying JS map in place.
+--
+-- Unlike 'Data.Map.Strict.Map', keys do not require an 'Ord' instance —
+-- any type with a 'Miso.DSL.ToJSVal' instance can serve as a key, including
+-- JS objects and numeric values that compare by identity.
+--
+-- Use this module when you need to share a key-value structure with a browser
+-- API or a third-party JavaScript library. For pure Haskell processing,
+-- prefer 'Data.Map.Strict.Map'.
+--
+-- Import qualified to avoid clashing with "Prelude":
+--
+-- @
+-- import qualified "Miso.Data.Map" as M
+-- @
+--
+-- = Quick start
+--
+-- @
+-- import qualified "Miso.Data.Map" as M
+--
+-- example :: IO ()
+-- example = do
+--   m <- M.'fromList' [(\"a\", 1), (\"b\", 2 :: Int)]
+--   M.'insert' \"c\" 3 m
+--   v <- M.'lookup' \"b\" m   -- Just 2
+--   n <- M.'size' m          -- 3
+--   M.'delete' \"a\" m
+--   pure ()
+-- @
+--
+-- = Operations
+--
+-- * __Construction__: 'new', 'fromList'
+-- * __Access__: 'lookup', 'has', 'size'
+-- * __Mutation__: 'insert', 'delete', 'clear'
+--
+-- = See also
+--
+-- * "Miso.Data.Array" — mutable JS 'Miso.Data.Array.Array'
+-- * "Miso.Data.Set" — mutable JS 'Miso.Data.Set.Set'
+-- * "Miso.DSL" — 'Miso.DSL.ToJSVal' \/ 'Miso.DSL.FromJSVal' used by key and value types
+-----------------------------------------------------------------------------
+module Miso.Data.Map
+  ( -- * Type
+    Map
+    -- * Construction
+  , new
+  , fromList
+    -- * Operations
+  , insert
+  , lookup
+  , clear
+  , size
+  , has
+  , delete
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad (void, forM_)
+import           Prelude hiding (lookup)
+-----------------------------------------------------------------------------
+import           Miso.DSL (jsg, JSVal, ToJSVal, FromJSVal, (!))
+import qualified Miso.DSL as DSL
+import           Miso.FFI (callFunction)
+-----------------------------------------------------------------------------
+-- | A JS [Map](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Map),
+-- wrapped so it can be passed across the FFI without copying. Operations live
+-- in t'IO' because the underlying object is mutable.
+newtype Map key value = Map JSVal deriving (FromJSVal, ToJSVal)
+-----------------------------------------------------------------------------
+-- | Constructs a new JS [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) in t'IO'.
+--
+new :: IO (Map key value)
+new = Map <$> DSL.new (jsg "Map") ([] :: [JSVal])
+-----------------------------------------------------------------------------
+-- | Inserts a value into the t'Map' by key.
+insert
+  :: (ToJSVal key, ToJSVal value)
+  => key
+  -- ^ Key to associate the value with
+  -> value
+  -- ^ Value to store
+  -> Map key value
+  -- ^ Map to mutate
+  -> IO ()
+insert key value (Map m) = do
+  _ <- callFunction m "set" (key, value)
+  pure ()
+-----------------------------------------------------------------------------
+-- | Finds a value in the t'Map' by key.
+lookup
+  :: (ToJSVal key, FromJSVal value)
+  => key
+  -- ^ Key to look up
+  -> Map key value
+  -- ^ Map to query
+  -> IO (Maybe value)
+lookup key (Map m) = DSL.fromJSValUnchecked =<< callFunction m "get" =<< DSL.toJSVal key
+-----------------------------------------------------------------------------
+-- | Empties the t'Map'.
+clear :: Map key value -> IO ()
+clear (Map m) = void (callFunction m "clear" ())
+-----------------------------------------------------------------------------
+-- | Return the size of t'Map'.
+size :: Map key value -> IO Int
+size (Map m) = DSL.fromJSValUnchecked =<< m ! "size"
+-----------------------------------------------------------------------------
+-- | Checks existence of a value by @key@, returns t'Bool.
+has
+  :: ToJSVal key
+  => key
+  -- ^ Key to test for membership
+  -> Map key value
+  -- ^ Map to query
+  -> IO Bool
+has key (Map m) = DSL.fromJSValUnchecked =<< callFunction m "has" =<< DSL.toJSVal key
+-----------------------------------------------------------------------------
+-- | Removes an entry from the t'Map', returns 'True' if the key existed.
+delete
+  :: ToJSVal key
+  => key
+  -- ^ Key to remove
+  -> Map key value
+  -- ^ Map to mutate
+  -> IO Bool
+delete key (Map m) = DSL.fromJSValUnchecked =<< callFunction m "delete" =<< DSL.toJSVal key
+-----------------------------------------------------------------------------
+-- | Construct a t'Map' from a list of key value pairs.
+fromList
+  :: (ToJSVal key, ToJSVal value)
+  => [(key, value)]
+  -- ^ Key-value pairs to populate the new map with
+  -> IO (Map key value)
+fromList xs = do
+  m <- new
+  forM_ xs $ \(k,v) ->
+    insert k v m
+  pure m
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Data/Set.hs b/src/Miso/Data/Set.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Data/Set.hs
@@ -0,0 +1,203 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Data.Set
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Data.Set" is a Haskell wrapper around the JavaScript
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set Set>
+-- object. Values of type @'Set' a@ live in JavaScript memory; all
+-- operations run in 'IO' and mutate the underlying JS set in place.
+--
+-- Unlike 'Data.Set.Set', elements do not require an 'Ord' instance —
+-- any type with a 'Miso.DSL.ToJSVal' instance can be stored, and equality
+-- is determined by JavaScript's
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness SameValueZero>
+-- algorithm.
+--
+-- Use this module when you need to share a set with a browser API or a
+-- third-party JavaScript library. For pure Haskell processing, prefer
+-- 'Data.Set.Set'.
+--
+-- Import qualified to avoid clashing with "Prelude":
+--
+-- @
+-- import qualified "Miso.Data.Set" as S
+-- @
+--
+-- = Quick start
+--
+-- @
+-- import qualified "Miso.Data.Set" as S
+--
+-- example :: IO ()
+-- example = do
+--   s  <- S.'fromList' [1, 2, 3 :: Int]
+--   S.'insert' 4 s
+--   b  <- S.'member' 2 s   -- True
+--   n  <- S.'size' s       -- 4
+--   S.'delete' 1 s
+--   pure ()
+-- @
+--
+-- = Operations
+--
+-- * __Construction__: 'new', 'fromList'
+-- * __Access__: 'member', 'size'
+-- * __Mutation__: 'insert', 'delete', 'clear'
+-- * __Set algebra__: 'union', 'intersection', 'difference', 'isSubset', 'isSuperset', 'isDisjoint'
+--
+-- = See also
+--
+-- * "Miso.Data.Array" — mutable JS 'Miso.Data.Array.Array'
+-- * "Miso.Data.Map" — mutable JS 'Miso.Data.Map.Map'
+-- * "Miso.DSL" — 'Miso.DSL.ToJSVal' \/ 'Miso.DSL.FromJSVal' used by element types
+-----------------------------------------------------------------------------
+module Miso.Data.Set
+  ( -- * Type
+    Set
+    -- * Construction
+  , new
+  , fromList
+    -- * Operations
+  , insert
+  , member
+  , clear
+  , size
+  , delete
+  , union
+  , intersection
+  , difference
+  , isSubset
+  , isSuperset
+  , isDisjoint
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad (void, forM_)
+import           Prelude hiding (lookup)
+-----------------------------------------------------------------------------
+import           Miso.DSL (jsg, JSVal, ToJSVal, FromJSVal, (!))
+import qualified Miso.DSL as DSL
+import           Miso.FFI (callFunction)
+-----------------------------------------------------------------------------
+-- | A JS [Set](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Set),
+-- wrapped so it can be passed across the FFI without copying. Operations live
+-- in t'IO' because the underlying object is mutable.
+newtype Set key = Set JSVal deriving (FromJSVal, ToJSVal)
+-----------------------------------------------------------------------------
+-- | Constructs a new JS [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) in t'IO'.
+--
+new :: IO (Set key)
+new = Set <$> DSL.new (jsg "Set") ([] :: [JSVal])
+-----------------------------------------------------------------------------
+-- | Inserts a value into the t'Set'.
+insert
+  :: ToJSVal key
+  => key
+  -- ^ Element to add
+  -> Set key
+  -- ^ Set to mutate
+  -> IO ()
+insert key (Set m) = do
+  _ <- callFunction m "add" [key]
+  pure ()
+-----------------------------------------------------------------------------
+-- | Empties the t'Set'.
+clear :: Set key -> IO ()
+clear (Set m) = void (callFunction m "clear" ())
+-----------------------------------------------------------------------------
+-- | Return the size of t'Set'.
+size :: Set key -> IO Int
+size (Set m) = DSL.fromJSValUnchecked =<< m ! "size"
+-----------------------------------------------------------------------------
+-- | Checks existence of @key@ in t'Set', returns t'Bool.
+member
+  :: ToJSVal key
+  => key
+  -- ^ Element to test for membership
+  -> Set key
+  -- ^ Set to query
+  -> IO Bool
+member key (Set m) = DSL.fromJSValUnchecked =<< callFunction m "has" =<< DSL.toJSVal key
+-----------------------------------------------------------------------------
+-- | Removes an element from the t'Set', returns 'True' if it existed.
+delete
+  :: ToJSVal key
+  => key
+  -- ^ Element to remove
+  -> Set key
+  -- ^ Set to mutate
+  -> IO Bool
+delete key (Set m) = DSL.fromJSValUnchecked =<< callFunction m "delete" =<< DSL.toJSVal key
+-----------------------------------------------------------------------------
+-- | Construct a t'Set' from a list of elements.
+fromList
+  :: ToJSVal key
+  => [key]
+  -- ^ Elements to populate the new set with
+  -> IO (Set key)
+fromList xs = do
+  m <- new
+  forM_ xs $ \k ->
+    insert k m
+  pure m
+-----------------------------------------------------------------------------
+-- | The union of two t'Set'
+union
+  :: ToJSVal key
+  => Set key -- ^ First set
+  -> Set key -- ^ Second set
+  -> IO (Set key)
+union (Set x) (Set y) = Set <$> callFunction x "union" [y]
+-----------------------------------------------------------------------------
+-- | The intersection of two t'Set'
+intersection
+  :: ToJSVal key
+  => Set key -- ^ First set
+  -> Set key -- ^ Second set
+  -> IO (Set key)
+intersection (Set x) (Set y) = Set <$> callFunction x "intersection" [y]
+-----------------------------------------------------------------------------
+-- | The symmetric difference of two t'Set'
+difference
+  :: ToJSVal key
+  => Set key -- ^ First set
+  -> Set key -- ^ Second set
+  -> IO (Set key)
+difference (Set x) (Set y) = Set <$> callFunction x "symmetricDifference" [y]
+-----------------------------------------------------------------------------
+-- | Checks if one t'Set' is a subset of another t'Set'
+isSubset
+  :: ToJSVal key
+  => Set key -- ^ Candidate subset
+  -> Set key -- ^ Potential superset
+  -> IO Bool
+isSubset (Set x) (Set y) = DSL.fromJSValUnchecked =<<
+  callFunction x "isSubsetOf" [y]
+-----------------------------------------------------------------------------
+-- | Checks if one t'Set' is a superset of another t'Set'
+isSuperset
+  :: ToJSVal key
+  => Set key -- ^ Candidate superset
+  -> Set key -- ^ Potential subset
+  -> IO Bool
+isSuperset (Set x) (Set y) = DSL.fromJSValUnchecked =<<
+  callFunction x "isSupersetOf" [y]
+-----------------------------------------------------------------------------
+-- | Checks if one t'Set' is disjoint from another t'Set'
+isDisjoint
+  :: ToJSVal key
+  => Set key -- ^ First set
+  -> Set key -- ^ Second set (disjoint means they share no elements)
+  -> IO Bool
+isDisjoint (Set x) (Set y) = DSL.fromJSValUnchecked =<<
+  callFunction x "isDisjointFrom" [y]
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Date.hs b/src/Miso/Date.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Date.hs
@@ -0,0 +1,526 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Date
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Date" is a Haskell wrapper around the JavaScript
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date Date>
+-- object. A t'Date' value lives in JavaScript memory and represents a single
+-- point in time. All operations run in 'IO' and call through to the
+-- underlying JS object.
+--
+-- Import qualified to avoid clashing with @Prelude@:
+--
+-- @
+-- import qualified "Miso.Date" as D
+-- @
+--
+-- = Quick start
+--
+-- @
+-- import qualified "Miso.Date" as D
+--
+-- example :: IO ()
+-- example = do
+--   now  <- D.'new'
+--   iso  <- D.'toISOString' now     -- e.g. \"2026-06-23T12:00:00.000Z\"
+--   year <- D.'getFullYear' now     -- e.g. 2026
+--   ms   <- D.'valueOf' now         -- milliseconds since Unix epoch
+--   pure ()
+-- @
+--
+-- = API groups
+--
+-- * __Construction__: 'new'
+-- * __Conversion__ (strings): 'toDateString', 'toISOString', 'toJSON',
+--   'toLocaleDateString', 'toLocaleString', 'toLocaleTimeString',
+--   'toString', 'toTimeString', 'toUTCString'
+-- * __Conversion__ (numeric): 'valueOf' (ms since epoch)
+-- * __Local getters__: 'getDate', 'getDay', 'getFullYear', 'getHours',
+--   'getMilliseconds', 'getMinutes', 'getMonth', 'getSeconds',
+--   'getTime', 'getTimezoneOffset'
+-- * __UTC getters__: 'getUTCDate', 'getUTCDay', 'getUTCFullYear',
+--   'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes',
+--   'getUTCMonth', 'getUTCSeconds'
+-- * __Local setters__: 'setDate', 'setFullYear', 'setHours',
+--   'setMilliseconds', 'setMinutes', 'setMonth', 'setSeconds', 'setTime'
+-- * __UTC setters__: 'setUTCDate', 'setUTCFullYear', 'setUTCHours',
+--   'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds'
+--
+-- __Note__: JavaScript months are __0-indexed__ (January = 0, December = 11).
+-- All getter and setter functions in this module follow that convention.
+-- Setter functions return the new timestamp as milliseconds since the Unix
+-- epoch (a 'Double'), mirroring the JavaScript return value.
+--
+-- = See also
+--
+-- * "Miso.DSL" — 'Miso.DSL.JSVal' and marshaling used internally
+-----------------------------------------------------------------------------
+module Miso.Date
+  ( -- * Type
+    Date
+    -- * Construction
+  , new
+    -- * Conversion
+  , toDateString
+  , toISOString
+  , toJSON
+  , toLocaleDateString
+  , toLocaleString
+  , toLocaleTimeString
+  , toString
+  , toTimeString
+  , toUTCString
+  , valueOf
+    -- * Getters
+  , getDate
+  , getDay
+  , getFullYear
+  , getHours
+  , getMilliseconds
+  , getMinutes
+  , getMonth
+  , getSeconds
+  , getTime
+  , getTimezoneOffset
+  , getUTCDate
+  , getUTCDay
+  , getUTCFullYear
+  , getUTCHours
+  , getUTCMilliseconds
+  , getUTCMinutes
+  , getUTCMonth
+  , getUTCSeconds
+    -- * Setters
+  , setDate
+  , setFullYear
+  , setHours
+  , setMilliseconds
+  , setMinutes
+  , setMonth
+  , setSeconds
+  , setTime
+  , setUTCDate
+  , setUTCFullYear
+  , setUTCHours
+  , setUTCMilliseconds
+  , setUTCMinutes
+  , setUTCMonth
+  , setUTCSeconds
+  ) where
+-----------------------------------------------------------------------------
+import           Data.Maybe (catMaybes)
+-----------------------------------------------------------------------------
+import           Miso.DSL (jsg, JSVal, ToJSVal, FromJSVal, ToObject)
+import qualified Miso.DSL as DSL
+import           Miso.FFI (callFunction)
+import           Miso.String (MisoString)
+-----------------------------------------------------------------------------
+-- | A JS [Date](https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Date),
+-- wrapped so it can be passed across the FFI without copying.
+newtype Date = Date JSVal deriving (FromJSVal, ToJSVal, ToObject, Eq)
+-----------------------------------------------------------------------------
+-- | Constructs a new JS [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) in t'IO'.
+--
+new :: IO Date
+new = Date <$> DSL.new (jsg "Date") ([] :: [JSVal])
+-----------------------------------------------------------------------------
+call0 :: FromJSVal a => Date -> MisoString -> IO a
+call0 (Date d) name = DSL.fromJSValUnchecked =<< callFunction d name ([] :: [JSVal])
+-----------------------------------------------------------------------------
+callArgs :: FromJSVal a => Date -> MisoString -> [JSVal] -> IO a
+callArgs (Date d) name args = DSL.fromJSValUnchecked =<< callFunction d name args
+-----------------------------------------------------------------------------
+-- | Returns a human-readable date string.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toDateString>
+--
+toDateString :: Date -> IO MisoString
+toDateString date = call0 date "toDateString"
+-----------------------------------------------------------------------------
+-- | Returns an ISO 8601 string.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString>
+--
+toISOString :: Date -> IO MisoString
+toISOString date = call0 date "toISOString"
+-----------------------------------------------------------------------------
+-- | Returns the JSON representation of the date.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toJSON>
+--
+toJSON :: Date -> IO MisoString
+toJSON date = call0 date "toJSON"
+-----------------------------------------------------------------------------
+-- | Returns a locale-sensitive date string.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString>
+--
+toLocaleDateString :: Date -> IO MisoString
+toLocaleDateString date = call0 date "toLocaleDateString"
+-----------------------------------------------------------------------------
+-- | Returns a locale-sensitive date and time string.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString>
+--
+toLocaleString :: Date -> IO MisoString
+toLocaleString date = call0 date "toLocaleString"
+-----------------------------------------------------------------------------
+-- | Returns a locale-sensitive time string.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString>
+--
+toLocaleTimeString :: Date -> IO MisoString
+toLocaleTimeString date = call0 date "toLocaleTimeString"
+-----------------------------------------------------------------------------
+-- | Returns the full date string.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toString>
+--
+toString :: Date -> IO MisoString
+toString date = call0 date "toString"
+-----------------------------------------------------------------------------
+-- | Returns a time string.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toTimeString>
+--
+toTimeString :: Date -> IO MisoString
+toTimeString date = call0 date "toTimeString"
+-----------------------------------------------------------------------------
+-- | Returns a UTC string.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString>
+--
+toUTCString :: Date -> IO MisoString
+toUTCString date = call0 date "toUTCString"
+-----------------------------------------------------------------------------
+-- | Returns the primitive value (milliseconds since epoch).
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/valueOf>
+--
+valueOf :: Date -> IO Double
+valueOf date = call0 date "valueOf"
+-----------------------------------------------------------------------------
+-- | Returns the day of the month.
+--
+getDate :: Date -> IO Int
+getDate date = call0 date "getDate"
+-----------------------------------------------------------------------------
+-- | Returns the day of the week.
+--
+getDay :: Date -> IO Int
+getDay date = call0 date "getDay"
+-----------------------------------------------------------------------------
+-- | Returns the full year.
+--
+getFullYear :: Date -> IO Int
+getFullYear date = call0 date "getFullYear"
+-----------------------------------------------------------------------------
+-- | Returns the hour.
+--
+getHours :: Date -> IO Int
+getHours date = call0 date "getHours"
+-----------------------------------------------------------------------------
+-- | Returns the milliseconds.
+--
+getMilliseconds :: Date -> IO Int
+getMilliseconds date = call0 date "getMilliseconds"
+-----------------------------------------------------------------------------
+-- | Returns the minutes.
+--
+getMinutes :: Date -> IO Int
+getMinutes date = call0 date "getMinutes"
+-----------------------------------------------------------------------------
+-- | Returns the month (0-11).
+--
+getMonth :: Date -> IO Int
+getMonth date = call0 date "getMonth"
+-----------------------------------------------------------------------------
+-- | Returns the seconds.
+--
+getSeconds :: Date -> IO Int
+getSeconds date = call0 date "getSeconds"
+-----------------------------------------------------------------------------
+-- | Returns milliseconds since epoch.
+--
+getTime :: Date -> IO Double
+getTime date = call0 date "getTime"
+-----------------------------------------------------------------------------
+-- | Returns the time zone offset in minutes.
+--
+getTimezoneOffset :: Date -> IO Int
+getTimezoneOffset date = call0 date "getTimezoneOffset"
+-----------------------------------------------------------------------------
+-- | Returns the UTC day of the month.
+--
+getUTCDate :: Date -> IO Int
+getUTCDate date = call0 date "getUTCDate"
+-----------------------------------------------------------------------------
+-- | Returns the UTC day of the week.
+--
+getUTCDay :: Date -> IO Int
+getUTCDay date = call0 date "getUTCDay"
+-----------------------------------------------------------------------------
+-- | Returns the UTC full year.
+--
+getUTCFullYear :: Date -> IO Int
+getUTCFullYear date = call0 date "getUTCFullYear"
+-----------------------------------------------------------------------------
+-- | Returns the UTC hour.
+--
+getUTCHours :: Date -> IO Int
+getUTCHours date = call0 date "getUTCHours"
+-----------------------------------------------------------------------------
+-- | Returns the UTC milliseconds.
+--
+getUTCMilliseconds :: Date -> IO Int
+getUTCMilliseconds date = call0 date "getUTCMilliseconds"
+-----------------------------------------------------------------------------
+-- | Returns the UTC minutes.
+--
+getUTCMinutes :: Date -> IO Int
+getUTCMinutes date = call0 date "getUTCMinutes"
+-----------------------------------------------------------------------------
+-- | Returns the UTC month (0-11).
+--
+getUTCMonth :: Date -> IO Int
+getUTCMonth date = call0 date "getUTCMonth"
+-----------------------------------------------------------------------------
+-- | Returns the UTC seconds.
+--
+getUTCSeconds :: Date -> IO Int
+getUTCSeconds date = call0 date "getUTCSeconds"
+-----------------------------------------------------------------------------
+-- | Sets the day of the month.
+--
+setDate
+  :: Int
+  -- ^ Day of the month (1–31)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setDate day (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setDate" [day]
+-----------------------------------------------------------------------------
+-- | Sets the full year, with optional month and day.
+--
+setFullYear
+  :: Int
+  -- ^ Full year (e.g. 2026)
+  -> Maybe Int
+  -- ^ Optional month (0-indexed: 0 = January)
+  -> Maybe Int
+  -- ^ Optional day of the month (1–31)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setFullYear year month day (Date d) = do
+  y <- DSL.toJSVal year
+  m <- traverse DSL.toJSVal month
+  d' <- traverse DSL.toJSVal day
+  callArgs (Date d) "setFullYear" (catMaybes [Just y, m, d'])
+-----------------------------------------------------------------------------
+-- | Sets the hour, with optional minutes, seconds, and milliseconds.
+--
+setHours
+  :: Int
+  -- ^ Hour (0–23)
+  -> Maybe Int
+  -- ^ Optional minutes (0–59)
+  -> Maybe Int
+  -- ^ Optional seconds (0–59)
+  -> Maybe Int
+  -- ^ Optional milliseconds (0–999)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setHours hours minutes seconds millis (Date d) = do
+  h <- DSL.toJSVal hours
+  m <- traverse DSL.toJSVal minutes
+  s <- traverse DSL.toJSVal seconds
+  ms <- traverse DSL.toJSVal millis
+  callArgs (Date d) "setHours" (catMaybes [Just h, m, s, ms])
+-----------------------------------------------------------------------------
+-- | Sets the milliseconds.
+--
+setMilliseconds
+  :: Int
+  -- ^ Milliseconds (0–999)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setMilliseconds ms (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setMilliseconds" [ms]
+-----------------------------------------------------------------------------
+-- | Sets the minutes, with optional seconds and milliseconds.
+--
+setMinutes
+  :: Int
+  -- ^ Minutes (0–59)
+  -> Maybe Int
+  -- ^ Optional seconds (0–59)
+  -> Maybe Int
+  -- ^ Optional milliseconds (0–999)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setMinutes minutes seconds millis (Date d) = do
+  m <- DSL.toJSVal minutes
+  s <- traverse DSL.toJSVal seconds
+  ms <- traverse DSL.toJSVal millis
+  callArgs (Date d) "setMinutes" (catMaybes [Just m, s, ms])
+-----------------------------------------------------------------------------
+-- | Sets the month, with optional day of the month.
+--
+setMonth
+  :: Int
+  -- ^ Month (0-indexed: 0 = January, 11 = December)
+  -> Maybe Int
+  -- ^ Optional day of the month (1–31)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setMonth month day (Date d) = do
+  m <- DSL.toJSVal month
+  d' <- traverse DSL.toJSVal day
+  callArgs (Date d) "setMonth" (catMaybes [Just m, d'])
+-----------------------------------------------------------------------------
+-- | Sets the seconds, with optional milliseconds.
+--
+setSeconds
+  :: Int
+  -- ^ Seconds (0–59)
+  -> Maybe Int
+  -- ^ Optional milliseconds (0–999)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setSeconds seconds millis (Date d) = do
+  s <- DSL.toJSVal seconds
+  ms <- traverse DSL.toJSVal millis
+  callArgs (Date d) "setSeconds" (catMaybes [Just s, ms])
+-----------------------------------------------------------------------------
+-- | Sets the time in milliseconds since epoch.
+--
+setTime
+  :: Double
+  -- ^ Milliseconds since the Unix epoch (1 January 1970 00:00:00 UTC)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setTime time (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setTime" [time]
+-----------------------------------------------------------------------------
+-- | Sets the UTC day of the month.
+--
+setUTCDate
+  :: Int
+  -- ^ Day of the month in UTC (1–31)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setUTCDate day (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setUTCDate" [day]
+-----------------------------------------------------------------------------
+-- | Sets the UTC full year, with optional month and day.
+--
+setUTCFullYear
+  :: Int
+  -- ^ Full year in UTC (e.g. 2026)
+  -> Maybe Int
+  -- ^ Optional month in UTC (0-indexed)
+  -> Maybe Int
+  -- ^ Optional day in UTC (1–31)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setUTCFullYear year month day (Date d) = do
+  y <- DSL.toJSVal year
+  m <- traverse DSL.toJSVal month
+  d' <- traverse DSL.toJSVal day
+  callArgs (Date d) "setUTCFullYear" (catMaybes [Just y, m, d'])
+-----------------------------------------------------------------------------
+-- | Sets the UTC hour, with optional minutes, seconds, and milliseconds.
+--
+setUTCHours
+  :: Int
+  -- ^ Hour in UTC (0–23)
+  -> Maybe Int
+  -- ^ Optional minutes (0–59)
+  -> Maybe Int
+  -- ^ Optional seconds (0–59)
+  -> Maybe Int
+  -- ^ Optional milliseconds (0–999)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setUTCHours hours minutes seconds millis (Date d) = do
+  h <- DSL.toJSVal hours
+  m <- traverse DSL.toJSVal minutes
+  s <- traverse DSL.toJSVal seconds
+  ms <- traverse DSL.toJSVal millis
+  callArgs (Date d) "setUTCHours" (catMaybes [Just h, m, s, ms])
+-----------------------------------------------------------------------------
+-- | Sets the UTC milliseconds.
+--
+setUTCMilliseconds
+  :: Int
+  -- ^ Milliseconds in UTC (0–999)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setUTCMilliseconds ms (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setUTCMilliseconds" [ms]
+-----------------------------------------------------------------------------
+-- | Sets the UTC minutes, with optional seconds and milliseconds.
+--
+setUTCMinutes
+  :: Int
+  -- ^ Minutes in UTC (0–59)
+  -> Maybe Int
+  -- ^ Optional seconds (0–59)
+  -> Maybe Int
+  -- ^ Optional milliseconds (0–999)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setUTCMinutes minutes seconds millis (Date d) = do
+  m <- DSL.toJSVal minutes
+  s <- traverse DSL.toJSVal seconds
+  ms <- traverse DSL.toJSVal millis
+  callArgs (Date d) "setUTCMinutes" (catMaybes [Just m, s, ms])
+-----------------------------------------------------------------------------
+-- | Sets the UTC month, with optional day of the month.
+--
+setUTCMonth
+  :: Int
+  -- ^ Month in UTC (0-indexed: 0 = January)
+  -> Maybe Int
+  -- ^ Optional day in UTC (1–31)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setUTCMonth month day (Date d) = do
+  m <- DSL.toJSVal month
+  d' <- traverse DSL.toJSVal day
+  callArgs (Date d) "setUTCMonth" (catMaybes [Just m, d'])
+-----------------------------------------------------------------------------
+-- | Sets the UTC seconds, with optional milliseconds.
+--
+setUTCSeconds
+  :: Int
+  -- ^ Seconds in UTC (0–59)
+  -> Maybe Int
+  -- ^ Optional milliseconds (0–999)
+  -> Date
+  -- ^ Date object to modify
+  -> IO Double
+setUTCSeconds seconds millis (Date d) = do
+  s <- DSL.toJSVal seconds
+  ms <- traverse DSL.toJSVal millis
+  callArgs (Date d) "setUTCSeconds" (catMaybes [Just s, ms])
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Delegate.hs b/src/Miso/Delegate.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Delegate.hs
@@ -0,0 +1,57 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Delegate
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- Types and functions related to [event delegation](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling#event_delegation)
+--
+----------------------------------------------------------------------------
+module Miso.Delegate
+  ( delegator
+  ) where
+-----------------------------------------------------------------------------
+import           Data.IORef (IORef, readIORef)
+import qualified Data.Map.Strict as M
+-----------------------------------------------------------------------------
+import           Miso.DSL (create, JSVal, Object(..), ToJSVal(toJSVal))
+import           Miso.Types (VTree(..), Events, Phase)
+import           Miso.String (MisoString)
+import qualified Miso.FFI.Internal as FFI
+-----------------------------------------------------------------------------
+-- | Local Event type, used to create field names for a delegated event
+data Event
+  = Event
+  { name :: MisoString
+  -- ^ Event name
+  , capture :: Phase
+  -- ^ Capture settings for event
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Instance used to initialize event delegation
+instance ToJSVal Event where
+  toJSVal Event {..} = do
+    o <- create
+    flip (FFI.set "name") o =<< toJSVal name
+    flip (FFI.set "capture") o =<< toJSVal capture
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | Entry point for event delegation
+delegator
+  :: JSVal
+  -> IORef VTree
+  -> Events
+  -> Bool
+  -> IO ()
+delegator mountPointElement vtreeRef es debug = do
+  evts <- toJSVal (uncurry Event <$> M.toList es)
+  FFI.delegator mountPointElement evts debug $ do
+    VTree (Object vtree) <- readIORef vtreeRef
+    pure vtree
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Diff.hs b/src/Miso/Diff.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Diff.hs
@@ -0,0 +1,45 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Diff
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- Functions and helpers for Virtual DOM diffing.
+--
+----------------------------------------------------------------------------
+module Miso.Diff
+  ( diff
+  , mountElement
+  ) where
+-----------------------------------------------------------------------------
+import qualified Miso.FFI.Internal as FFI
+import           Miso.Types
+import           Miso.DSL
+-----------------------------------------------------------------------------
+-- | diffing / patching a given element
+diff :: Maybe VTree -> Maybe VTree -> JSVal -> IO ()
+diff current new_ mountEl =
+  case (current, new_) of
+    (Nothing, Nothing) -> pure ()
+    (Just (VTree current'), Just (VTree new')) -> do
+      FFI.diff current' new' mountEl
+      FFI.flush
+    (Nothing, Just (VTree new')) -> do
+      FFI.diff (Object jsNull) new' mountEl
+      FFI.flush
+    (Just (VTree current'), Nothing) -> do
+      FFI.diff current' (Object jsNull) mountEl
+      FFI.flush
+-----------------------------------------------------------------------------
+-- | return the configured mountPoint element or the body
+mountElement :: MisoString -> IO JSVal
+mountElement = \case
+  "body" -> FFI.getBody
+  e -> FFI.getElementById e
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Effect.hs b/src/Miso/Effect.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Effect.hs
@@ -0,0 +1,704 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -fno-warn-orphans       #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Effect
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Effect" defines the three core abstractions used in the
+-- Model-View-Update loop:
+--
+-- * 'Effect' — the monad returned by every 'Miso.Types.update' handler.
+--   Combines a state update on @model@ with a list of 'IO' actions to
+--   schedule.
+--
+-- * 'Sub' — a long-running subscription (@'Sink' action -> IO ()@) that
+--   feeds actions into the event queue from threads, timers, WebSockets, etc.
+--
+-- * 'Sink' — a function (@action -> IO ()@) that enqueues a single action
+--   for processing by 'Miso.Types.update'.
+--
+-- = The Effect monad
+--
+-- @
+-- type 'Effect' context props model action
+--      = RWS ('ComponentInfo' context props) ['Schedule' context action] model ()
+-- @
+--
+-- The @RWS@ decomposition:
+--
+-- * __Reader__ — t'ComponentInfo': component metadata ('componentInfoId',
+--   'componentInfoDOMRef', 'componentInfoProps') accessible via 'Control.Monad.Reader.ask'
+--   or the convenience lenses.
+-- * __Writer__ — accumulated list of t'Schedule'd 'IO' actions to run after
+--   the model update.
+-- * __State__ — the @model@, updated via 'Control.Monad.State.put',
+--   'Control.Monad.State.modify', or the lens operators from "Miso.Lens".
+--
+-- = Scheduling IO
+--
+-- By default all 'IO' runs asynchronously in a separate thread after the
+-- VDOM has been patched. Use 'sync' \/ 'sync_' to block the render thread:
+--
+-- @
+-- update = \\case
+--   Fetch    -> 'io'   (fetchData >>= pure . GotData)  -- async
+--   LogIt    -> 'io_'  (consoleLog \"hi\")               -- async, no action
+--   Urgent   -> 'sync' (pure SomeSyncAction)           -- blocks render
+--   Many     -> 'batch' [a1, a2, a3]                   -- multiple async
+--   Opt      -> 'for'  (fetchMaybe >>= pure)           -- Maybe\/Foldable
+-- @
+--
+-- = Subscriptions
+--
+-- A 'Sub' is a function that receives a 'Sink' and an @IO model@ (a snapshot
+-- of the owning component's current model) and runs forever (typically on a
+-- forked thread). Register subscriptions in 'Miso.Types.subs':
+--
+-- @
+-- tickSub :: 'Sub' Model Action
+-- tickSub sink _getModel = forever $ do
+--   threadDelay 16667
+--   sink Tick
+--
+-- myComponent = ('Miso.component' model update view) { 'Miso.Types.subs' = [tickSub] }
+-- @
+--
+-- Use 'mapSub' to adapt a @Sub model a@ into a @Sub model b@ with a mapping function.
+--
+-- = Component metadata
+--
+-- Within @update@, access the current component's runtime info through
+-- 'Control.Monad.Reader.ask' or the provided lenses:
+--
+-- @
+-- update = \\case
+--   Init -> do
+--     domRef <- 'Miso.Lens.view' 'componentInfoDOMRef'
+--     compId <- 'Miso.Lens.view' 'componentInfoId'
+--     myProps <- 'getProps'
+--     io_ (initThirdParty domRef)
+-- @
+--
+-- = See also
+--
+-- * "Miso.Types" — t'Miso.Types.Component', 'Miso.Types.update', 'Miso.Types.subs'
+-- * "Miso.Lens" — lens operators (@.=@, @+=@, @%=@) for model updates
+-- * "Miso.Subscription" — pre-built subscriptions (mouse, keyboard, history, …)
+-----------------------------------------------------------------------------
+module Miso.Effect
+  ( -- ** Effect
+    -- *** Types
+    Effect
+  , Sub
+  , Sink
+  , DOMRef
+  , ComponentInfo (..)
+  , ComponentId
+  , Thread (..)
+  , mkComponentInfo
+  -- ** 'IO'
+  , Schedule (..)
+  , Synchronicity (..)
+    -- *** Combinators
+  , (<#)
+  , (#>)
+  , batch
+  , batch_
+  , io
+  , io_
+  , sync
+  , sync_
+  , for
+  , issue
+  , withSink
+  , modifyContext
+  , modifyContext_
+  , putContext
+  , mapSub
+  , noop
+  , beforeAll
+  , afterAll
+  , modifyAllIO
+  -- *** Lens
+  , componentInfoDOMRef
+  , componentInfoParentId
+  , componentInfoId
+  -- *** Internal
+  , runEffect
+  -- *** Props
+  , componentInfoProps
+  , props
+  , getProps
+  -- *** Context
+  , componentInfoContext
+  , context
+  , getContext
+  -- *** Dual-thread
+  , runOnBG
+  , runOnMain
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad (void)
+import           Data.Foldable (traverse_)
+import           Control.Monad.RWS (RWS, put, tell, execRWS, censor, MonadReader)
+import           Control.Monad.State (State, execState)
+-----------------------------------------------------------------------------
+import           Miso.DSL.FFI
+import           Miso.Lens
+-----------------------------------------------------------------------------
+-- | Smart constructor for t'ComponentInfo'
+mkComponentInfo
+  :: ComponentId
+  -- ^ 'ComponentId'
+  -> ComponentId
+  -- ^ @parent@ 'ComponentId'
+  -> DOMRef
+  -- ^ 'DOMRef'
+  -> props
+  -- ^ props
+  -> context
+  -- ^ context
+  -> ComponentInfo context props
+mkComponentInfo = ComponentInfo
+-----------------------------------------------------------------------------
+-- | This is the 'Reader r' in t'Miso.Effect'. Accessible via 'Control.Monad.Reader.ask'. It holds
+-- a phantom type for @context@ (the app-global React-style context, which is
+-- write-only from within @update@). It gives access to t'Miso.Types.Component' metadata such
+-- as the 'DOMRef' the t'Miso.Types.Component' was mounted on and the 'ComponentId' associated
+-- with it.
+data ComponentInfo context props
+  = ComponentInfo
+  { _componentInfoId :: ComponentId
+  -- ^ Unique identifier for this component instance
+  , _componentInfoParentId :: ComponentId
+  -- ^ Unique identifier of the parent component (same as '_componentInfoId' for root components)
+  , _componentInfoDOMRef :: DOMRef
+  -- ^ The DOM node this component is mounted on
+  , _componentInfoProps :: props
+  -- ^ The current @props@ value passed into this component
+  , _componentInfoContext :: context
+  -- ^ The current @context@ value passed into this component
+  }
+-----------------------------------------------------------------------------
+-- | Lens for accessing the t'ComponentId' from t'ComponentInfo'.
+--
+-- @
+--   update = \case
+--     SomeAction -> do
+--       compId <- view componentInfoId
+--       someAction compId
+-- @
+--
+-- @since 1.9.0.0
+componentInfoId :: Lens (ComponentInfo context props) ComponentId
+componentInfoId = lens _componentInfoId $ \r x -> r { _componentInfoId = x }
+-----------------------------------------------------------------------------
+-- | Lens for accessing the parents's  t'ComponentId' from t'ComponentInfo'.
+--
+-- @
+--
+-- update = \case
+--   SomeAction -> do
+--     compParentId <- view componentParentId
+--     someAction compParentId
+-- @
+--
+-- @since 1.9.0.0
+componentInfoParentId :: Lens (ComponentInfo context props) ComponentId
+componentInfoParentId = lens _componentInfoParentId $ \r x -> r { _componentInfoParentId = x }
+-----------------------------------------------------------------------------
+-- | Lens for accessing the underlying t'Miso.Types.Component' t'DOMRef'.
+--
+-- @
+--   update = \case
+--     SomeAction -> do
+--       domRef <- view componentDOMRef
+--       someAction domRef
+-- @
+--
+-- @since 1.9.0.0
+componentInfoDOMRef :: Lens (ComponentInfo context props) DOMRef
+componentInfoDOMRef = lens _componentInfoDOMRef $ \r x -> r { _componentInfoDOMRef = x }
+-----------------------------------------------------------------------------
+-- | Lens for accessing the underlying t'Miso.Types.Component' @props@.
+--
+-- @
+--   update = \case
+--     SomeAction -> do
+--       props <- view componentInfoProps
+--       someAction props
+-- @
+--
+-- @since 1.9.0.0
+componentInfoProps :: Lens (ComponentInfo context props) props
+componentInfoProps = lens _componentInfoProps $ \r x -> r { _componentInfoProps = x }
+-----------------------------------------------------------------------------
+-- | Lens for accessing the underlying t'Miso.Types.Component' @context@.
+--
+-- @
+--   update = \case
+--     SomeAction -> do
+--       ctx <- view componentInfoContext
+--       someAction ctx
+-- @
+--
+-- @since 1.13.0.0
+componentInfoContext :: Lens (ComponentInfo context props) context
+componentInfoContext = lens _componentInfoContext $ \r x -> r { _componentInfoContext = x }
+-----------------------------------------------------------------------------
+-- | Lens for accessing the underlying t'Miso.Types.Component' @context@.
+--
+-- This is a shorter convenience lens that is a synonynm for 'componentInfoContext'.
+-- See 'getContext' for usage in the 'Effect' monad.
+--
+-- @
+--   update = \case
+--     SomeAction ->
+--       someAction =<< view context
+-- @
+--
+-- __Note:__ this lens is __read-only__ within 'Effect'. It targets the
+-- t'ComponentInfo' reader environment, so setting through it (e.g. with
+-- 'Miso.Lens.set' \/ 'Miso.Lens..=') has no observable effect. To change the
+-- global @context@ from 'Miso.Types.update', use 'Miso.Effect.modifyContext',
+-- 'Miso.Effect.putContext', or 'Miso.Effect.modifyContext_' (the 'State'-monad
+-- variant, which supports lens operators like @'Miso.Lens..='@) instead.
+--
+-- @since 1.13.0.0
+context :: Lens (ComponentInfo context props) context
+context = componentInfoContext
+-----------------------------------------------------------------------------
+-- | Lens for accessing the underlying t'Miso.Types.Component' @props@.
+--
+-- This is a shorter convenience lens that is a synonynm for 'componentInfoProps'.
+-- See 'getProps' for usage in the 'Effect' monad.
+--
+-- @
+--   update = \case
+--     SomeAction ->
+--       someAction =<< view props
+-- @
+--
+props :: Lens (ComponentInfo context props) props
+props = componentInfoProps
+-----------------------------------------------------------------------------
+-- | @props@ retrieval from within the 'Effect' monad.
+--
+-- @
+--   update = \case
+--     SomeAction -> do
+--       props <- getProps
+--       someAction props
+-- @
+--
+getProps :: MonadReader (ComponentInfo context props) m => m props
+getProps = Miso.Lens.view props
+-----------------------------------------------------------------------------
+-- | Read-only @context@ retrieval from within the 'Effect' monad.
+--
+-- @
+--   update = \case
+--     SomeAction -> do
+--       ctx <- getContext
+--       someAction ctx
+-- @
+--
+-- @since 1.13.0.0
+getContext :: MonadReader (ComponentInfo context props) m => m context
+getContext = Miso.Lens.view context
+-----------------------------------------------------------------------------
+-- | 'ComponentId' of the current t'Miso.Types.Component'
+type ComponentId = Int
+-----------------------------------------------------------------------------
+-- | Type synonym for constructing subscriptions.
+--
+-- For example usage see "Miso.Subscription"
+--
+-- The 'Sink' function is used to write to the global event queue.
+--
+-- The @IO model@ action returns a snapshot of the owning
+-- t'Miso.Types.Component'\'s current model, and is safe to call for the
+-- lifetime of the 'Sub'. Subscriptions that don't need the model can
+-- simply ignore it.
+type Sub model action = Sink action -> IO model -> IO ()
+-----------------------------------------------------------------------------
+-- | Function to write to the global event queue for processing by the scheduler.
+type Sink action = action -> IO ()
+-----------------------------------------------------------------------------
+-- | Smart constructor for an 'Effect' with exactly one action.
+infixl 0 <#
+(<#) :: model -> IO action -> Effect context props model action
+(<#) m action = put m >> tell [ async $ \f -> f =<< action ]
+-----------------------------------------------------------------------------
+async :: (Sink action -> IO ()) -> Schedule context action
+async = Schedule Async
+-----------------------------------------------------------------------------
+-- | Run @action@'s 'Miso.Types.update' on the __background__ thread (BTS).
+--
+-- On the Lynx dual-thread runtime the shared @model@ is owned solely by the
+-- background thread. A main-thread ('Miso.Event.Types.MTS') event handler that
+-- needs to change shared state cannot do so directly — it dispatches the state
+-- change here, and @action@'s 'Miso.Types.update' runs (exactly once) on the
+-- BTS, where the model write commits. Off the native runtime (or when already
+-- on the BTS) this is just an ordinary local dispatch, equivalent to 'issue'.
+--
+-- Unlike a plain 'issue', @action@ is /not/ handled on the current thread: it
+-- crosses to the BTS. It carries no other effects with it — only @action@ is
+-- sent, so sibling effects in the current 'Miso.Types.update' are unaffected.
+--
+-- @since 1.13.0.0
+runOnBG :: action -> Effect context props model action
+runOnBG action = tell [ CrossThread BTS action ]
+-----------------------------------------------------------------------------
+-- | Run @action@'s 'Miso.Types.update' on the __main__ thread (MTS).
+--
+-- The dual of 'runOnBG': a background-thread ('Miso.Event.Types.MTS') effect
+-- that needs an imperative main-thread operation (see "Miso.Native.MainThread")
+-- dispatches @action@ here, and its 'Miso.Types.update' runs (exactly once) on
+-- the MTS. Off the native runtime (or when already on the MTS) this is an
+-- ordinary local dispatch, equivalent to 'issue'.
+--
+-- @since 1.13.0.0
+runOnMain :: action -> Effect context props model action
+runOnMain action = tell [ CrossThread MTS action ]
+-----------------------------------------------------------------------------
+-- | `Effect` smart constructor, flipped
+infixr 0 #>
+(#>) :: IO action -> model -> Effect context props model action
+(#>) = flip (<#)
+-----------------------------------------------------------------------------
+-- | Smart constructor for an 'Effect' with multiple 'IO' actions.
+--
+-- @since 1.9.0.0
+batch
+  :: [IO action]
+  -- ^ Batch of 'IO' actions to execute
+  -> Effect context props model action
+batch actions = sequence_
+  [ tell [ async $ \f -> f =<< action ]
+  | action <- actions
+  ]
+-----------------------------------------------------------------------------
+-- | Like @batch@ but actions are discarded
+--
+-- @since 1.9.0.0
+batch_ :: [IO ()] -> Effect context props model action
+batch_ actions = sequence_
+  [ tell [ async (const action) ]
+  | action <- actions
+  ]
+-----------------------------------------------------------------------------
+-- | A monad for succinctly expressing model transitions in the @update@ function.
+--
+-- t'Effect' is a @RWS@, where the @State@ allows modification to @model@.
+-- It's also a @Writer@ @Monad@, where the accumulator is a list of scheduled
+-- @IO@ actions. Multiple actions can be scheduled using 'Control.Monad.Writer.Class.tell'
+-- from the @mtl@ library and a single asynchronous action can be scheduled using 'io_'.
+--
+-- An t'Effect' represents the results of an @update@ action.
+--
+-- It consists of the updated model and a list of subscriptions. Each t'Sub' is
+-- run in a new thread so there is no risk of accidentally blocking the
+-- application.
+--
+-- Tip: use the t'Effect' monad in combination with the stateful "Miso.Lens"
+-- operators (all operators ending in "@=@"). The following example assumes
+-- the lenses @field1@, @counter@ and @field2@ are in scope and that the
+-- @LambdaCase@ language extension is enabled:
+--
+-- @
+-- myComponent = Component
+--   { update = \\case
+--       MyAction1 -> do
+--         field1 @.=@ value1
+--         counter @+=@ 1
+--       MyAction2 -> do
+--         field2 @%=@ f
+--         'io_' $ do
+--           'Miso.FFI.consoleLog' \"Hello\"
+--           'Miso.FFI.consoleLog' \"World!\"
+--   , ...
+--   }
+-- @
+type Effect context props model action = RWS (ComponentInfo context props) [Schedule context action] model ()
+-----------------------------------------------------------------------------
+-- | Represents a scheduled 'Effect' that is executed either synchronously
+-- or asynchronously.
+--
+-- All t'IO' is by default asynchronous, use the 'sync' function for synchronous
+-- execution. Beware 'sync' can block the render thread for a specific
+-- t'Miso.Types.Component'.
+--
+-- N.B. During t'Miso.Types.Component' unmounting, all effects are evaluated
+-- synchronously.
+--
+-- The 'ContextModify' constructor carries a pending mutation to the app-global
+-- React-style @context@. It is emitted by 'modifyContext' \/ 'putContext' and
+-- applied to the global context during the scheduler's commit phase, triggering
+-- a re-render of every t'Miso.Types.Component' with @useContext@ enabled.
+--
+-- The 'CrossThread' constructor carries an @action@ to be handled on a specific
+-- Lynx 'Thread'. Emitted by 'runOnBG' \/ 'runOnMain', it is dispatched locally
+-- when already on the target thread, otherwise forwarded to the peer thread
+-- (where the @action@'s 'Miso.Types.update' runs). A plain t'Schedule' always
+-- runs on the thread that produced it.
+--
+-- @since 1.9.0.0
+data Schedule context action
+  = Schedule Synchronicity (Sink action -> IO ())
+  | CrossThread Thread action
+  | ContextModify (context -> context)
+-----------------------------------------------------------------------------
+-- | Type to represent a DOM reference
+type DOMRef = JSVal
+-----------------------------------------------------------------------------
+-- | Internal function used to unwrap an @Effect@
+runEffect
+    :: Effect context props model action
+    -> ComponentInfo context props
+    -> model
+    -> (model, [Schedule context action])
+runEffect = execRWS
+-----------------------------------------------------------------------------
+-- | Turn a 'Sub' that consumes actions of type @a@ into a 'Sub' that consumes
+-- actions of type @b@ using the supplied function of type @a -> b@.
+mapSub
+  :: (a -> b)
+  -- ^ Function to map actions produced by the subscription
+  -> Sub m a
+  -- ^ Source subscription delivering @a@ actions
+  -> Sub m b
+mapSub f sub = \g m -> sub (g . f) m
+-----------------------------------------------------------------------------
+-- | Schedule a single 'IO' action, executed synchronously. For asynchronous
+-- execution, see 'io'.
+--
+-- Please use this with caution because it will block the render thread.
+--
+-- @since 1.9.0.0
+sync
+  :: IO action
+  -- ^ 'IO' action to execute synchronously
+  -> Effect context props model action
+sync action = tell [ Schedule Sync $ \f -> f =<< action ]
+-----------------------------------------------------------------------------
+-- | Like 'sync', except discards the result.
+--
+-- @since 1.9.0.0
+sync_
+  :: IO ()
+  -- ^ 'IO' action to execute synchronously
+  -> Effect context props model action
+sync_ action = tell [ Schedule Sync $ \_ -> action ]
+-----------------------------------------------------------------------------
+-- | Schedule a single 'IO' action for later execution.
+--
+-- Note that multiple 'IO' action can be scheduled using
+-- 'Control.Monad.Writer.Class.tell' from the @mtl@ library.
+--
+-- @since 1.9.0.0
+io
+  :: IO action
+  -- ^ 'IO' action to execute asynchronously
+  -> Effect context props model action
+io action = withSink (action >>=)
+-----------------------------------------------------------------------------
+-- | Like 'io' but doesn't cause an action to be dispatched to
+-- the @update@ function.
+--
+-- This is handy for scheduling @IO@ computations where you don't care
+-- about their results or when they complete.
+--
+-- Note: The result of @IO a@ is discarded.
+--
+-- @since 1.9.0.0
+io_
+  :: IO ()
+  -- ^ 'IO' action to execute asynchronously
+  -> Effect context props model action
+io_ action = withSink (\_ -> void action)
+-----------------------------------------------------------------------------
+-- | Like 'io' but generalized to any instance of 'Foldable'
+--
+-- This is handy for scheduling @IO@ computations that return a @Maybe@ value
+--
+-- @since 1.9.0.0
+for
+  :: Foldable f
+  => IO (f action)
+  -- ^ @actions@ executed in batch.
+  -> Effect context props model action
+for actions = withSink $ \sink -> actions >>= traverse_ sink
+-----------------------------------------------------------------------------
+-- | Performs the given 'IO' action before all IO actions collected by the given
+-- effect.
+--
+-- @
+-- -- delays connecting a websocket by 100000 microseconds
+-- beforeAll (liftIO $ threadDelay 100000) $ websocketConnectJSON OnConnect OnClose OnOpen OnError
+-- @
+--
+-- @since 1.9.0.0
+beforeAll
+  :: IO ()
+  -- ^ 'IO' action to prepend before all scheduled effects
+  -> Effect context props model action
+  -- ^ Effect whose IO actions are modified
+  -> Effect context props model action
+beforeAll = modifyAllIO . (*>)
+-----------------------------------------------------------------------------
+-- | Performs the given 'IO' action after all IO actions collected by the given
+-- effect.
+--
+-- Example usage:
+--
+-- > -- log that running the a websocket Effect completed
+-- > afterAll (consoleLog "Done running websocket effect") $ websocketConnectJSON OnConnect OnClose OnOpen OnError
+afterAll
+  :: IO ()
+  -- ^ 'IO' action to append after all scheduled effects
+  -> Effect context props model action
+  -- ^ Effect whose IO actions are modified
+  -> Effect context props model action
+afterAll = modifyAllIO . (<*)
+-----------------------------------------------------------------------------
+-- | Modifies all 'IO' collected by the given Effect.
+--
+-- All 'IO' expressions collected by 'Effect' can be evaluated either
+-- synchronously or asynchronously (the default).
+--
+-- This function can be used to adjoin additional actions to all 'IO'
+-- expressions in an 'Effect'. For examples see 'beforeAll' and 'afterAll'.
+modifyAllIO
+  :: (IO () -> IO ())
+  -- ^ Transform to apply to every scheduled 'IO' action in the effect
+  -> Effect context props model action
+  -- ^ Effect whose IO actions are modified
+  -> Effect context props model action
+modifyAllIO f = censor (map go)
+  where
+    go (Schedule x action) = Schedule x (f <$> action)
+    go s                   = s  -- 'CrossThread' / 'ContextModify' carry no IO
+-----------------------------------------------------------------------------
+-- | @withSink@ allows users to write to the global event queue. This is useful for introducing 'IO' into the system.
+-- A synonym for 'Control.Monad.Writer.tell', specialized to 'Effect'.
+--
+-- A use-case is scheduling an 'IO' computation which creates a 3rd-party JS
+-- widget which has an associated callback. The callback can then call the sink
+-- to turn events into actions.
+--
+-- @
+-- @update@ FetchJSON = 'withSink' $ \\sink -> getJSON (sink . ReceivedJSON) (sink . HandleError)
+-- @
+--
+-- @since 1.9.0.0
+withSink
+  :: (Sink action -> IO ())
+  -- ^ Callback function that provides access to the underlying 'Sink'.
+  -> Effect context props model action
+withSink f = tell [ async f ]
+-----------------------------------------------------------------------------
+-- | Mutate the app-global React-style @context@ from within @update@.
+--
+-- The supplied function is scheduled as a 'ContextModify' and folded over the
+-- current global context during the scheduler's commit phase. If the context
+-- value changes (per its 'Eq' instance), every t'Miso.Types.Component' with @useContext@
+-- enabled is re-rendered.
+--
+-- Note that @context@ is __write-only__ inside @update@; to read it, use the
+-- @context@ argument threaded into the 'Miso.Types.view' function.
+--
+-- @
+-- @update@ Toggle = 'modifyContext' (\\theme -> if theme == Light then Dark else Light)
+-- @
+--
+-- @since 1.13.0.0
+modifyContext
+  :: (context -> context)
+  -- ^ Transformation to apply to the global @context@
+  -> Effect context props model action
+modifyContext f = tell [ ContextModify f ]
+-----------------------------------------------------------------------------
+-- | Replace the app-global React-style @context@ with a new value.
+--
+-- A convenience wrapper around 'modifyContext'. See 'modifyContext' for details
+-- of when re-renders are triggered.
+--
+-- @since 1.13.0.0
+putContext
+  :: context
+  -- ^ New global @context@ value
+  -> Effect context props model action
+putContext = modifyContext . const
+-----------------------------------------------------------------------------
+-- | Mutate the app-global React-style @context@ using a 'State' computation.
+--
+-- A convenience wrapper around 'modifyContext' that runs the supplied
+-- @'State' context@ action over the current global context (via 'execState'),
+-- scheduling the resulting @context -> context@ transformation as a
+-- 'ContextModify'. This lets you use @put@ \/ @modify@ and the lens operators
+-- from "Miso.Lens" to update @context@, mirroring how @model@ is updated.
+--
+-- @
+-- @update@ Toggle = 'modifyContext_' $ theme @.=@ Dark
+-- @
+--
+-- @since 1.13.0.0
+modifyContext_
+  :: State context ()
+  -- ^ 'State' computation describing the @context@ mutation
+  -> Effect context props model action
+modifyContext_ = modifyContext . execState
+-----------------------------------------------------------------------------
+-- | Issue a new @action@ to be processed by 'Miso.Types.update'.
+--
+-- @
+-- data Action = HelloWorld
+-- type Model  = Int
+--
+-- @update@ :: Action -> 'Effect' context props Model Action
+-- @update@ = \\case
+--   Click -> 'issue' HelloWorld
+-- @
+--
+-- @since 1.9.0.0
+issue
+  :: action
+  -- ^ @action@ to raise
+  -> Effect context props model action
+issue action = tell [ async $ \f -> f action ]
+-----------------------------------------------------------------------------
+-- | Helper for t'Miso.Types.Component' construction, when you want to ignore the 'Miso.Types.update'
+-- function temporarily, or permanently.
+--
+-- @since 1.9.0.0
+noop :: action -> Effect context props model action
+noop = const (pure ())
+-----------------------------------------------------------------------------
+-- | Type to indicate if effects should be handled asynchronously
+-- or synchronously.
+--
+data Synchronicity
+  = Async
+  | Sync
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Type to indicate where the 'Effect' should execute.
+--
+-- @since 1.13.0.0
+data Thread
+  = MTS
+  | BTS
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Event.hs b/src/Miso/Event.hs
--- a/src/Miso/Event.hs
+++ b/src/Miso/Event.hs
@@ -1,17 +1,334 @@
 -----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+-----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Event
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
+--
+-- DOM event handlers and component lifecycle hooks for 'Miso.Types.View'.
+--
+-- There are two axes of event handling:
+--
+-- * __DOM events__ — 'on', 'onCapture', 'onWithOptions': attach JavaScript
+--   event listeners to VDOM nodes. Decoded event payloads are dispatched as
+--   @action@ values through the MVU loop.
+--
+-- * __Lifecycle hooks__ — 'onCreated', 'onDestroyed', etc.: fire Haskell
+--   callbacks at specific points in a DOM element's mount\/unmount lifecycle.
+--
+-- See "Miso.Event.Decoder" for building custom t'Decoder' values and
+-- "Miso.Event.Types" for structured payload types (@KeyboardEvent@,
+-- t'PointerEvent', etc.).
+--
 ----------------------------------------------------------------------------
 module Miso.Event
-   ( module Miso.Event.Decoder
+   ( -- *** Smart constructors
+     on
+   , onMain
+   , onCapture
+   , onWithOptions
+   , onMainWithOptions
+   , Phase (..)
+   -- *** Lifecycle events
+   , onCreated
+   , onCreatedWith
+   , onBeforeCreated
+   , onDestroyed
+   , onBeforeDestroyed
+   , onBeforeDestroyedWith
+    -- *** Exports
+   , module Miso.Event.Decoder
    , module Miso.Event.Types
    ) where
-
-import Miso.Event.Decoder
-import Miso.Event.Types
-
+-----------------------------------------------------------------------------
+import           Control.Monad (when)
+import qualified Data.Map.Strict as M
+import qualified Data.IntMap.Strict as IM
+import           Data.IORef
+import           Miso.JSON (parseEither)
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.Event.Decoder
+import           Miso.Event.Types
+import qualified Miso.FFI.Internal as FFI
+import           Miso.Types (LogLevel(..), DOMRef, VTree(..), EventHandler(..), Attribute(..))
+import           Miso.Runtime
+import           Miso.String (MisoString, ms)
+-----------------------------------------------------------------------------
+-- | Like 'on' but meant to used with the "Miso.Native" namespace.
+--
+-- @
+-- view_ [ event $ static ('onMain' "tap" emptyDecoder ) ] [ text_ \"+\" ]
+-- @
+--
+-- @since 1.13.0.0
+onMain :: MisoString
+   -- ^ DOM event name (e.g. @\"click\"@, @\"input\"@)
+   -> Decoder result
+   -- ^ How to extract a Haskell value from the browser event object
+   -> (result -> model -> DOMRef -> action)
+   -- ^ Converts the decoded payload and the element's DOM reference to an @action@
+   -> EventHandler model action
+onMain = onMainWithOptions BUBBLE defaultOptions
+-----------------------------------------------------------------------------
+-- | Attach a bubble-phase event handler to a VDOM node.
+-- Convenience wrapper for @'onWithOptions' 'BUBBLE' 'defaultOptions'@.
+--
+-- The decoded event payload is converted to an @action@ by @toAction@ and
+-- dispatched into the component's @update@ function.
+--
+-- @
+-- let clickHandler = on \"click\" emptyDecoder $ \\() _ -> MyAction
+-- in button_ [ clickHandler, class_ \"add\" ] [ text_ \"+\" ]
+-- @
+--
+on :: MisoString
+   -- ^ DOM event name (e.g. @\"click\"@, @\"input\"@)
+   -> Decoder result
+   -- ^ How to extract a Haskell value from the browser event object
+   -> (result -> model -> DOMRef -> action)
+   -- ^ Converts the decoded payload and the element's DOM reference to an @action@
+   -> Attribute model action
+on = onWithOptions BUBBLE defaultOptions
+-----------------------------------------------------------------------------
+-- | Attach a capture-phase event handler to a VDOM node.
+-- Convenience wrapper for @'onWithOptions' 'CAPTURE' 'defaultOptions'@.
+--
+-- Events in the capture phase propagate from the document root down to the
+-- target element, before any bubble-phase handlers run.
+--
+-- @
+-- let captureClick = onCapture \"click\" emptyDecoder $ \\() _ -> MyAction
+-- in button_ [ captureClick ] [ text_ \"capture me\" ]
+-- @
+--
+onCapture
+   :: MisoString
+   -- ^ DOM event name (e.g. @\"click\"@)
+   -> Decoder result
+   -- ^ How to extract a Haskell value from the browser event object
+   -> (result -> model -> DOMRef -> action)
+   -- ^ Converts the decoded payload and the element's DOM reference to an @action@
+   -> Attribute model action
+onCapture = onWithOptions CAPTURE defaultOptions
+-----------------------------------------------------------------------------
+-- | Mark an event handler to be dispatched on the Lynx __main thread__ (@MTS@)
+-- rather than the background thread. This is the analog of Lynx's
+-- @main-thread:bind@ prefix, and is decided __per handler__ — so @tap@ can be a
+-- main-thread handler on one element and a background handler on another.
+--
+-- A main-thread handler runs imperatively on the MTS (no VDOM diff, no repaint);
+-- pair it with a @*With@ combinator to receive the target 'DOMRef' and mutate it
+-- via "Miso.Native.MainThread". No-op on the browser\/WASM runtime.
+--
+-- @
+-- view_ [ event (static (mainThread (onTapWith Grow))) ] children
+-- @
+--
+-- @since 1.13.0.0
+onMainWithOptions
+  :: Phase
+  -- ^ Event propagation phase: 'BUBBLE' (default) or 'CAPTURE'
+  -> Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> MisoString
+  -- ^ DOM event name (e.g. @\"click\"@, @\"keydown\"@)
+  -> Decoder result
+  -- ^ How to extract a Haskell value from the browser event object
+  -> (result -> model -> DOMRef -> action)
+  -- ^ Converts the decoded payload and the element's DOM reference to an @action@
+  -> EventHandler model action
+onMainWithOptions phase opts name decoder conversion =
+  EventHandler
+    { eventHandlerInstall = \m snk tree ll events ->
+        case onWithOptions phase opts name decoder conversion of
+          On cb -> do
+            FFI.set "pendingMainThread" True =<< toObject tree
+            cb m snk tree ll events
+          _ ->
+            error "onMainWithOptions: impossible"
+    , eventHandlerDecoder = decoder
+    , eventHandlerConvert = conversion
+    }
+-----------------------------------------------------------------------------
+-- | Attach an event handler with explicit phase and propagation options.
+--
+-- * @phase@    — 'BUBBLE' (default) or 'CAPTURE': which DOM propagation phase
+--   the listener is registered on.
+-- * @options@  — 'defaultOptions' or a custom t'Options' value: controls
+--   @preventDefault@ and @stopPropagation@ behaviour.
+-- * @eventName@ — the DOM event name, e.g. @\"click\"@, @\"keydown\"@.
+-- * @decoder@  — a t'Decoder' that extracts relevant fields from the JS event object.
+-- * @toAction@ — maps the decoded payload and the element's 'DOMRef' to an @action@.
+--
+-- @
+-- let clickHandler = onWithOptions BUBBLE defaultOptions \"click\" emptyDecoder $ \\() _ -> Action
+-- in button_ [ clickHandler, class_ \"add\" ] [ text_ \"+\" ]
+-- @
+--
+onWithOptions
+  :: Phase
+  -- ^ Event propagation phase: 'BUBBLE' (default) or 'CAPTURE'
+  -> Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> MisoString
+  -- ^ DOM event name (e.g. @\"click\"@, @\"keydown\"@)
+  -> Decoder result
+  -- ^ How to extract a Haskell value from the browser event object
+  -> (result -> model -> DOMRef -> action)
+  -- ^ Converts the decoded payload and the element's DOM reference to an @action@
+  -> Attribute model action
+onWithOptions phase options eventName Decoder{..} toAction =
+  On $ \_model sink (VTree n) logLevel events -> do
+    when (logLevel == DebugAll || logLevel == DebugEvents) $
+      case M.lookup eventName events of
+        Nothing ->
+            FFI.consoleError $ mconcat
+              [ "Event \""
+              , eventName
+              , "\" is not being listened on. To use this event, "
+              , "add to the 'events' Map in Component"
+              ]
+        _ -> pure ()
+    eventsVal <-
+      getProp "events" n
+    eventObj <-
+      case phase of
+        CAPTURE -> getProp "captures" (Object eventsVal)
+        BUBBLE -> getProp "bubbles" (Object eventsVal)
+    eventHandlerObject@(Object eo) <- create
+    jsOptions <- toJSVal options
+    decodeAtVal <- toJSVal decodeAt
+    cb <- FFI.asyncCallback2 $ \e domRef -> do
+        Just v <- fromJSVal =<< FFI.eventJSON decodeAtVal e
+        case parseEither decoder v of
+          Left msg -> FFI.consoleError ("[EVENT DECODE ERROR]: " <> ms msg)
+          Right event -> do
+            vcompId <- fromJSValUnchecked =<< getProp "pendingComponentId" n
+            IM.lookup vcompId <$> readIORef components >>= \case
+              Nothing ->
+                FFI.consoleError ("[COMPONENT]: No component found at ID: " <> ms vcompId)
+              Just ComponentState {..} ->
+                sink (toAction event _componentModel domRef)
+    -- The runtime frees this callback when the vtree that owns it is
+    -- replaced; see Note [Freeing event handler callbacks] in "Miso.Runtime".
+    registerEventHandler cb
+    FFI.set "runEvent" cb eventHandlerObject
+    FFI.set "options" jsOptions eventHandlerObject
+    -- Only 'mainThread'-marked handlers carry their 'StaticKey' \/ @ComponentId@
+    -- (stashed on the node by 'setAttrs') onto the per-event object. That is what
+    -- puts them in the node's @eventKeys@, telling the native delegator to
+    -- dispatch this handler on the main thread. Unmarked handlers (and the
+    -- browser\/WASM runtime) leave these off and delegate to the background.
+    pendingMT <- getProp "pendingMainThread" n
+    isMainThread <- fromJSVal pendingMT :: IO (Maybe Bool)
+    when (isMainThread == Just True) $ do
+      pendingKey <- getProp "pendingStaticKey" n
+      mKey <- fromJSVal pendingKey :: IO (Maybe MisoString)
+      maybe (pure ()) (\k -> FFI.set "staticKey" (k :: MisoString) eventHandlerObject) mKey
+      pendingCid <- getProp "pendingComponentId" n
+      mCid <- fromJSVal pendingCid :: IO (Maybe Int)
+      maybe (pure ()) (\c -> FFI.set "componentId" (c :: Int) eventHandlerObject) mCid
+    FFI.set eventName eo (Object eventObj)
+    -- The handler object is now reachable from the node; release the scratch
+    -- handles. @decodeAtVal@, @cb@ and @n@ are captured by the callback and
+    -- must stay alive. See Note [Freeing VTree handles] in "Miso.Runtime".
+    mapM_ freeJSVal [eventsVal, eventObj, eo, jsOptions, pendingMT]
+-----------------------------------------------------------------------------
+-- | Fire an action immediately after the DOM element is inserted into the document.
+--
+-- Use this to trigger imperative setup (focus, measurements, third-party widget
+-- initialisation) that requires the element to be live in the page.
+--
+-- @since 1.9.0.0
+--
+onCreated
+  :: action
+  -- ^ Action to dispatch after the element is inserted into the DOM
+  -> Attribute model action
+onCreated action =
+  On $ \_model sink (VTree object) _ _ -> do
+    callback <- FFI.syncCallback (sink action)
+    FFI.set "onCreated" callback object
+-----------------------------------------------------------------------------
+-- | Like 'onCreated' but also receives the element's 'DOMRef'.
+--
+-- Useful when you need to store or forward the raw DOM node to a JS library.
+--
+-- @since 1.9.0.0
+--
+onCreatedWith
+  :: (DOMRef -> action)
+  -- ^ Callback receiving the element's 'DOMRef' after it is inserted into the DOM
+  -> Attribute model action
+onCreatedWith action =
+  On $ \_model sink (VTree object) _ _ -> do
+    callback <- FFI.syncCallback1 (sink . action)
+    FFI.set "onCreated" callback object
+-----------------------------------------------------------------------------
+-- | Fire an action immediately after the DOM element is removed from the document.
+--
+-- The element has already been detached from the DOM when this fires.
+--
+-- @since 1.9.0.0
+--
+onDestroyed
+  :: action
+  -- ^ Action to dispatch after the element is removed from the DOM
+  -> Attribute model action
+onDestroyed action =
+  On $ \_model sink (VTree object) _ _ -> do
+    callback <- FFI.syncCallback (sink action)
+    FFI.set "onDestroyed" callback object
+-----------------------------------------------------------------------------
+-- | Fire an action just before the DOM element is removed from the document.
+--
+-- The element is still present in the DOM when this fires, making it suitable
+-- for teardown logic (cancel animations, disconnect observers, etc.).
+--
+-- @since 1.9.0.0
+--
+onBeforeDestroyed
+  :: action
+  -- ^ Action to dispatch just before the element is removed from the DOM
+  -> Attribute model action
+onBeforeDestroyed action =
+  On $ \_model sink (VTree object) _ _ -> do
+    callback <- FFI.syncCallback (sink action)
+    FFI.set "onBeforeDestroyed" callback object
+-----------------------------------------------------------------------------
+-- | Like 'onBeforeDestroyed' but also receives the element's 'DOMRef'.
+--
+-- @since 1.9.0.0
+--
+onBeforeDestroyedWith
+  :: (DOMRef -> action)
+  -- ^ Callback receiving the element's 'DOMRef' just before it is removed from the DOM
+  -> Attribute model action
+onBeforeDestroyedWith action =
+  On $ \_model sink (VTree object) _ _ -> do
+    callback <- FFI.syncCallback1 (sink . action)
+    FFI.set "onBeforeDestroyed" callback object
+-----------------------------------------------------------------------------
+-- | Fire an action just before the DOM element is inserted into the document.
+--
+-- The element has been constructed but is not yet attached to the live DOM when
+-- this fires.
+--
+-- @since 1.9.0.0
+--
+onBeforeCreated
+  :: action
+  -- ^ Action to dispatch just before the element is inserted into the DOM
+  -> Attribute model action
+onBeforeCreated action =
+  On $ \_model sink (VTree object) _ _ -> do
+    callback <- FFI.syncCallback (sink action)
+    FFI.set "onBeforeCreated" callback object
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Event/Decoder.hs b/src/Miso/Event/Decoder.hs
--- a/src/Miso/Event/Decoder.hs
+++ b/src/Miso/Event/Decoder.hs
@@ -1,74 +1,189 @@
-{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE LambdaCase        #-}
 {-# LANGUAGE RecordWildCards   #-}
+{-# LANGUAGE OverloadedStrings #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Event.Decoder
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
-----------------------------------------------------------------------------
+--
+-- = Overview
+--
+-- "Miso.Event.Decoder" provides t'Decoder', the type that tells miso how to
+-- extract a Haskell value from a browser
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Event DOM Event> object.
+-- It pairs a target path ('DecodeTarget') into the event with a
+-- JSON-style parser ('Miso.JSON.Value' @->@ 'Miso.JSON.Parser' @a@).
+--
+-- Decoders are consumed by 'Miso.Html.Event.on' from "Miso.Html.Event":
+--
+-- @
+-- on :: 'Miso.String.MisoString'   -- event name (e.g. \"click\")
+--    -> t'Decoder' a      -- how to extract @a@ from the event object
+--    -> (a -> action)   -- turn the extracted value into an action
+--    -> 'Miso.Types.Attribute' action
+-- @
+--
+-- = DecodeTarget
+--
+-- A t'DecodeTarget' selects the sub-object of the event to decode:
+--
+-- * @'DecodeTarget' []@ — the event object itself (e.g. for keyboard events).
+-- * @'DecodeTarget' [\"target\"]@ — @event.target@ (e.g. for input values).
+-- * @'DecodeTargets' [[\"a\"], [\"b\"]]@ — tries @event.a@ first, then
+--   @event.b@; the first successful decode wins.
+--
+-- = Built-in decoders
+--
+-- ['emptyDecoder'] @()@ — @click@, @submit@, stateless events
+-- ['keycodeDecoder'] 'Miso.Event.Types.KeyCode' — @keydown@ \/ @keyup@ key code
+-- ['keyInfoDecoder'] 'Miso.Event.Types.KeyInfo' — key code + modifier keys
+-- ['valueDecoder'] 'Miso.String.MisoString' — @input@ \/ @change@ (@event.target.value@)
+-- ['checkedDecoder'] 'Miso.Event.Types.Checked' — checkbox @change@ (@event.target.checked@)
+-- ['pointerDecoder'] 'Miso.Event.Types.PointerEvent' — pointer\/mouse position and metadata
+--
+-- = Custom decoders
+--
+-- Build a custom decoder with 'at' or by constructing t'Decoder' directly:
+--
+-- @
+-- -- Extract (offsetX, offsetY) from a click event
+-- clickXY :: t'Decoder' (Int, Int)
+-- clickXY = t'Decoder'
+--   { 'decodeAt' = t'DecodeTarget' []
+--   , 'decoder'  = 'Miso.JSON.withObject' \"click\" $ \\o ->
+--       (,) \<$\> o 'Miso.JSON..:' \"offsetX\"
+--           \<*\> o 'Miso.JSON..:' \"offsetY\"
+--   }
+-- @
+--
+-- = See also
+--
+-- * "Miso.Html.Event" — @on@ and the pre-wired event handlers (@onClick@, @onInput@, …)
+-- * "Miso.Event.Types" — payload types ('Miso.Event.Types.KeyCode', 'Miso.Event.Types.PointerEvent', …)
+-- * "Miso.JSON" — 'Miso.JSON.Value', 'Miso.JSON.Parser', 'Miso.JSON.withObject', @('Miso.JSON..:')@
+-----------------------------------------------------------------------------
 module Miso.Event.Decoder
-  ( -- * Decoder
+  ( -- ** Types
     Decoder (..)
   , DecodeTarget (..)
+    -- ** Combinators
   , at
-  -- * Decoders
+    -- ** Decoders
   , emptyDecoder
   , keycodeDecoder
+  , keyInfoDecoder
   , checkedDecoder
   , valueDecoder
-  )
-  where
-
-import Data.Aeson.Types
+  , pointerDecoder
+  ) where
+-----------------------------------------------------------------------------
 import Control.Applicative
-
+-----------------------------------------------------------------------------
+import Miso.DSL (ToJSVal(toJSVal))
 import Miso.Event.Types
+import Miso.JSON
 import Miso.String
-
--- | Data type for storing the target when parsing events
+-----------------------------------------------------------------------------
+-- | Data type representing path (consisting of field names) within event object
+-- where a decoder should be applied.
 data DecodeTarget
-  = DecodeTarget [MisoString] -- ^ Decode a single object
-  | DecodeTargets [[MisoString]] -- ^ Decode multiple objecjects
-
--- | Decoder data type for parsing events
-data Decoder a = Decoder {
-  decoder :: Value -> Parser a -- ^ FromJSON-based Event decoder
-, decodeAt :: DecodeTarget -- ^ Location in DOM of where to decode
-}
-
--- | Smart constructor for building
-at :: [MisoString] -> (Value -> Parser a) -> Decoder a
+  = DecodeTarget [MisoString]
+  -- ^ Specify single path within Event object, where a decoder should be applied.
+  | DecodeTargets [[MisoString]]
+  -- ^ Specify multiple paths withing Event object, where decoding should be attempted. The first path where decoding suceeds is the one taken.
+-----------------------------------------------------------------------------
+-- | `ToJSVal` instance for t'DecodeTarget'.
+instance ToJSVal DecodeTarget where
+  toJSVal = \case
+    DecodeTarget xs -> toJSVal xs
+    DecodeTargets xs -> toJSVal xs
+-----------------------------------------------------------------------------
+-- | t'Decoder' data type for parsing events
+data Decoder a
+  = Decoder
+  { decoder :: Value -> Parser a
+    -- ^ FromJSON-based Event decoder
+  , decodeAt :: DecodeTarget
+    -- ^ Location in DOM of where to decode
+  }
+-----------------------------------------------------------------------------
+-- | Smart constructor for building a t'Decoder'.
+at
+  :: [MisoString]
+  -- ^ Path into the event object (e.g. @[\"target\"]@ for @event.target@, @[]@ for the event itself)
+  -> (Value -> Parser a)
+  -- ^ JSON-style decoder applied at the given path
+  -> Decoder a
 at decodeAt decoder = Decoder {decodeAt = DecodeTarget decodeAt, ..}
-
--- | Empty decoder for use with events like "click" that do not
+-----------------------------------------------------------------------------
+-- | Empty t'Decoder' for use with events like "click" that do not
 -- return any meaningful values
 emptyDecoder :: Decoder ()
 emptyDecoder = mempty `at` go
   where
     go = withObject "emptyDecoder" $ \_ -> pure ()
-
--- | Retrieves either "keyCode", "which" or "charCode" field in `Decoder`
+-----------------------------------------------------------------------------
+-- | Retrieves either "keyCode", "which" or "charCode" field in t'Decoder'
 keycodeDecoder :: Decoder KeyCode
 keycodeDecoder = Decoder {..}
   where
     decodeAt = DecodeTarget mempty
     decoder = withObject "event" $ \o ->
        KeyCode <$> (o .: "keyCode" <|> o .: "which" <|> o .: "charCode")
-
--- | Retrieves "value" field in `Decoder`
+-----------------------------------------------------------------------------
+-- | Retrieves either "keyCode", "which" or "charCode" field in t'Decoder',
+-- along with shift, ctrl, meta and alt.
+keyInfoDecoder :: Decoder KeyInfo
+keyInfoDecoder = Decoder {..}
+  where
+    decodeAt =
+      DecodeTarget mempty
+    decoder =
+      withObject "event" $ \o ->
+        KeyInfo
+          <$> (o .: "keyCode" <|> o .: "which" <|> o .: "charCode")
+          <*> o .: "shiftKey"
+          <*> o .: "metaKey"
+          <*> o .: "ctrlKey"
+          <*> o .: "altKey"
+-----------------------------------------------------------------------------
+-- | Retrieves "value" field in t'Decoder'
 valueDecoder :: Decoder MisoString
 valueDecoder = Decoder {..}
   where
     decodeAt = DecodeTarget ["target"]
     decoder = withObject "target" $ \o -> o .: "value"
-
--- | Retrieves "checked" field in Decoder
+-----------------------------------------------------------------------------
+-- | Retrieves "checked" field in t'Decoder'
 checkedDecoder :: Decoder Checked
 checkedDecoder = Decoder {..}
   where
     decodeAt = DecodeTarget ["target"]
     decoder = withObject "target" $ \o ->
-       Checked <$> (o .: "checked")
+      Checked <$> (o .: "checked")
+-----------------------------------------------------------------------------
+-- | Pointer t'Decoder' for use with events like "onpointerover"
+pointerDecoder :: Decoder PointerEvent
+pointerDecoder = Decoder {..}
+  where
+    pair o x y = liftA2 (,) (o .: x) (o .: y)
+    decodeAt = DecodeTarget mempty
+    decoder = withObject "pointerDecoder" $ \o ->
+      PointerEvent
+        <$> o .: "pointerType"
+        <*> o .: "pointerId"
+        <*> o .: "isPrimary"
+        <*> pair o "clientX" "clientY"
+        <*> pair o "screenX" "screenY"
+        <*> pair o "offsetX" "offsetY"
+        <*> pair o "pageX" "pageY"
+        <*> pair o "tiltX" "tiltY"
+        <*> o .: "pressure"
+        <*> o .: "button"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Event/Types.hs b/src/Miso/Event/Types.hs
--- a/src/Miso/Event/Types.hs
+++ b/src/Miso/Event/Types.hs
@@ -1,72 +1,336 @@
-{-# LANGUAGE DeriveGeneric     #-}
-{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase                 #-}
+{-# LANGUAGE RecordWildCards            #-}
+{-# LANGUAGE OverloadedStrings          #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Event.Types
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
-----------------------------------------------------------------------------
-module Miso.Event.Types where
-
-import qualified Data.Map as M
-import           GHC.Generics
-import           Miso.String
-import           Data.Aeson (FromJSON)
-
+--
+-- = Overview
+--
+-- "Miso.Event.Types" defines the payload types for browser DOM events and
+-- the 'Events' map that controls which events are delegated to the miso
+-- runtime and at which 'Phase' of the event lifecycle.
+--
+-- = Event delegation
+--
+-- Miso uses
+-- <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling event delegation>:
+-- a single listener is attached at the root of the component's DOM subtree
+-- and catches all matching events as they bubble or capture past it.
+-- The 'Events' map (@'Data.Map.Strict.Map' 'Miso.String.MisoString' 'Phase'@)
+-- declares which event names participate and their phase.
+--
+-- The default set ('defaultEvents') covers the most common interactions.
+-- Additional event groups can be merged in when constructing a component:
+--
+-- @
+-- myComponent = ('Miso.component' model update view)
+--   { 'Miso.Types.events' = 'defaultEvents'
+--       \<\> 'keyboardEvents'
+--       \<\> 'pointerEvents'
+--   }
+-- @
+--
+-- = Event groups
+--
+-- ['defaultEvents'] blur, change, click, contextmenu, dblclick, focus, input, select, submit
+-- ['keyboardEvents'] keydown, keypress, keyup
+-- ['mouseEvents'] mouseup, mousedown, mouseenter, mouseleave, mouseover, mouseout, contextmenu
+-- ['dragEvents'] drag, dragstart, dragend, dragenter, dragleave, dragover, drop
+-- ['pointerEvents'] pointerup, pointerdown, pointerenter, pointerleave, pointerover, pointerout, pointercancel, contextmenu
+-- ['mediaEvents'] play, pause, ended, timeupdate, volumechange, …
+-- ['clipboardEvents'] cut, copy, paste
+-- ['touchEvents'] touchstart, touchend, touchmove, touchcancel
+--
+-- = Payload types
+--
+-- * t'KeyCode' \/ t'KeyInfo' — keyboard event key code and modifier state.
+-- * t'Checked' — checkbox @checked@ boolean.
+-- * t'PointerEvent' \/ 'PointerType' — pointer position, pressure, tilt, and device type.
+-- * t'Options' — per-handler flags: 'preventDefault', 'stopPropagation'.
+--
+-- = See also
+--
+-- * "Miso.Event.Decoder" — 'Miso.Event.Decoder.Decoder' and pre-built decoders for these types
+-- * "Miso.Html.Event" — @onClick@, @onInput@, @onKeyDown@, … combinators
+-----------------------------------------------------------------------------
+module Miso.Event.Types
+  ( -- ** Types
+    Events
+  , Phase (..)
+    -- *** KeyboardEvent
+  , KeyInfo (..)
+  , KeyCode (..)
+    -- *** CheckedEvent
+  , Checked (..)
+    -- *** PointerEvent
+  , PointerEvent (..)
+  , PointerType (..)
+    -- *** Options
+  , Options (..)
+  , defaultOptions
+  , preventDefault
+  , stopPropagation
+    -- *** Events
+  , defaultEvents
+  , keyboardEvents
+  , mouseEvents
+  , dragEvents
+  , pointerEvents
+  , mediaEvents
+  , clipboardEvents
+  , touchEvents
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON (FromJSON(..), withText)
+import qualified Data.Map.Strict as M
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.String (MisoString, ms)
+-----------------------------------------------------------------------------
+-- | Type useful for both KeyCode and additional key press information.
+data KeyInfo
+  = KeyInfo
+  { keyCode :: !KeyCode
+  -- ^ Numeric key code of the pressed key (see t'KeyCode')
+  , shiftKey :: !Bool
+  -- ^ 'True' if the Shift key was held when the event fired
+  , metaKey :: !Bool
+  -- ^ 'True' if the Meta (Command on macOS, Windows key on PC) key was held
+  , ctrlKey :: !Bool
+  -- ^ 'True' if the Control key was held
+  , altKey :: !Bool
+  -- ^ 'True' if the Alt (Option on macOS) key was held
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
 -- | Type used for Keyboard events.
 --
 -- See <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#Browser_compatibility>
 newtype KeyCode = KeyCode Int
-  deriving (Show, Eq, Ord, FromJSON)
-
+  deriving (Show, Eq, Ord, FromJSON, Num)
+-----------------------------------------------------------------------------
 -- | Type used for Checkbox events.
 newtype Checked = Checked Bool
   deriving (Show, Eq, Ord, FromJSON)
-
--- | Options for handling event propagation.
-data Options = Options {
-    preventDefault :: Bool
-  , stopPropagation :: Bool
-  } deriving (Show, Eq, Generic)
-
--- | Default value for 'Options'.
+-----------------------------------------------------------------------------
+-- | Type used for Pointer events.
+-- <https://w3c.github.io/pointerevents>
+data PointerEvent
+  = PointerEvent
+  { pointerType :: PointerType
+  -- ^ Device kind: 'MousePointerType', 'PenPointerType', 'TouchPointerType', or 'UnknownPointerType'
+  , pointerId :: Int
+  -- ^ Unique identifier for this pointer, stable across move\/up\/cancel events
+  , isPrimary :: Bool
+  -- ^ 'True' for the primary pointer in a multi-touch sequence
+  , client :: (Double, Double)
+  -- ^ @(clientX, clientY)@ — position relative to the viewport
+  , screen :: (Double, Double)
+  -- ^ @(screenX, screenY)@ — position relative to the screen
+  , offset :: (Double, Double)
+  -- ^ @(offsetX, offsetY)@ — position relative to the target element
+  , page :: (Double,Double)
+  -- ^ @(pageX, pageY)@ — position relative to the full document
+  , tilt :: (Double,Double)
+  -- ^ @(tiltX, tiltY)@ — pen tilt angle in degrees from the surface plane
+  , pressure :: Double
+  -- ^ Normalised pressure in @[0, 1]@; @0.5@ for mouse buttons that lack pressure sensitivity
+  , button :: Int
+  -- ^ Which button changed state; @-1@ during move with no button change.
+  -- See <https://w3c.github.io/pointerevents/#the-button-property PointerEvent.button>
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Pointer type
+-- <https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pointerType>
+data PointerType
+  = MousePointerType
+  | PenPointerType
+  | TouchPointerType
+  | UnknownPointerType MisoString
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSON PointerType where
+  parseJSON = withText "PointerType" $ \case
+    "mouse" -> pure MousePointerType
+    "touch" -> pure TouchPointerType
+    "pen"   -> pure PenPointerType
+    x       -> pure (UnknownPointerType (ms x))
+-----------------------------------------------------------------------------
+-- | t'Options' for handling event propagation.
+data Options
+  = Options
+  { _preventDefault :: Bool
+  -- ^ If 'True', calls @event.preventDefault()@ to suppress the browser's default behaviour
+  , _stopPropagation :: Bool
+  -- ^ If 'True', calls @event.stopPropagation()@ to halt event bubbling\/capturing
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance Monoid Options where
+  mempty = defaultOptions
+-----------------------------------------------------------------------------
+instance Semigroup Options where
+  Options p1 s1 <> Options p2 s2 = Options (p1 || p2) (s1 || s2)
+-----------------------------------------------------------------------------
+-- | Smart constructor for specifying 'preventDefault'
 --
+-- @since 1.9.0.0
+preventDefault :: Options
+preventDefault = defaultOptions { _preventDefault = True }
+-----------------------------------------------------------------------------
+-- | Smart constructor for specifying 'stopPropagation'
+--
+-- @since 1.9.0.0
+stopPropagation :: Options
+stopPropagation = defaultOptions { _stopPropagation = True }
+-----------------------------------------------------------------------------
+instance ToJSVal Options where
+  toJSVal Options {..} = do
+    o <- create
+    flip (setProp "preventDefault") o =<< toJSVal _preventDefault
+    flip (setProp "stopPropagation") o =<< toJSVal _stopPropagation
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | Default value for @Options@.
+--
 -- > defaultOptions = Options { preventDefault = False, stopPropagation = False }
 defaultOptions :: Options
-defaultOptions = Options False False
-
--- | Related to using drop-related events
-newtype AllowDrop = AllowDrop Bool
-  deriving (Show, Eq, FromJSON)
-
+defaultOptions
+  = Options
+  { _preventDefault = False
+  , _stopPropagation = False
+  }
+-----------------------------------------------------------------------------
+-- | Convenience type for Events
+--
+-- The map declares which DOM events are delegated and at which 'Phase'. Whether
+-- an individual handler runs on the Lynx main thread (@MTS@) or background
+-- thread (@BTS@) is decided __per handler__ (see @Miso.Event.mainThread@), not
+-- per event name — mirroring Lynx's @main-thread:bind@ vs @bind@ prefix.
+type Events = M.Map MisoString Phase
+-----------------------------------------------------------------------------
 -- | Default delegated events
-defaultEvents :: M.Map MisoString Bool
-defaultEvents = M.fromList [
-    ("blur", True)
-  , ("change", False)
-  , ("click", False)
-  , ("dblclick", False)
-  , ("focus", False)
-  , ("input", False)
-  , ("keydown", False)
-  , ("keypress", False)
-  , ("keyup", False)
-  , ("mouseup", False)
-  , ("mousedown", False)
-  , ("mouseenter", False)
-  , ("mouseleave", False)
-  , ("mouseover", False)
-  , ("mouseout", False)
-  , ("dragstart", False)
-  , ("dragover", False)
-  , ("dragend", False)
-  , ("dragenter", False)
-  , ("dragleave", False)
-  , ("drag", False)
-  , ("drop", False)
-  , ("submit", False)
+defaultEvents :: Events
+defaultEvents = M.fromList
+  [ ("blur", CAPTURE)
+  , ("change", BUBBLE)
+  , ("click", BUBBLE)
+  , ("contextmenu", BUBBLE)
+  , ("dblclick", BUBBLE)
+  , ("focus", CAPTURE)
+  , ("input", BUBBLE)
+  , ("select", BUBBLE)
+  , ("submit", BUBBLE)
   ]
+-----------------------------------------------------------------------------
+-- | Keyboard events
+keyboardEvents :: Events
+keyboardEvents = M.fromList
+  [ ("keydown", BUBBLE)
+  , ("keypress", BUBBLE)
+  , ("keyup", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Mouse events
+mouseEvents :: Events
+mouseEvents = M.fromList
+  [ ("mouseup", BUBBLE)
+  , ("mousedown", BUBBLE)
+  , ("mouseenter", CAPTURE)
+  , ("mouseleave", CAPTURE)
+  , ("mouseover", BUBBLE)
+  , ("mouseout", BUBBLE)
+  , ("contextmenu", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Drag events
+dragEvents :: Events
+dragEvents = M.fromList
+  [ ("dragstart", BUBBLE)
+  , ("dragover", BUBBLE)
+  , ("dragend", BUBBLE)
+  , ("dragenter", BUBBLE)
+  , ("dragleave", BUBBLE)
+  , ("drag", BUBBLE)
+  , ("drop", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Pointer events
+pointerEvents :: Events
+pointerEvents = M.fromList
+  [ ("pointerup", BUBBLE)
+  , ("pointerdown", BUBBLE)
+  , ("pointerenter", CAPTURE)
+  , ("pointercancel", BUBBLE)
+  , ("pointerleave", CAPTURE)
+  , ("pointerover", BUBBLE)
+  , ("pointerout", BUBBLE)
+  , ("contextmenu", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Audio video events
+-- For use with the @<audio>@ and @<video>@ tags.
+--
+-- @
+-- myApp :: 'Miso.Types.App' Model Action
+-- myApp = ('Miso.Types.component' model update view){ events = 'defaultEvents' <> 'mediaEvents' }
+-- @
+mediaEvents :: Events
+mediaEvents = M.fromList
+  [ ("abort", CAPTURE)
+  , ("canplay", CAPTURE)
+  , ("canplaythrough", CAPTURE)
+  , ("durationchange", CAPTURE)
+  , ("emptied", CAPTURE)
+  , ("ended", CAPTURE)
+  , ("error", CAPTURE)
+  , ("loadeddata", CAPTURE)
+  , ("loadedmetadata", CAPTURE)
+  , ("loadstart", CAPTURE)
+  , ("pause", CAPTURE)
+  , ("play", CAPTURE)
+  , ("playing", CAPTURE)
+  , ("progress", CAPTURE)
+  , ("ratechange", CAPTURE)
+  , ("seeked", CAPTURE)
+  , ("seeking", CAPTURE)
+  , ("stalled", CAPTURE)
+  , ("suspend", CAPTURE)
+  , ("timeupdate", CAPTURE)
+  , ("volumechange", CAPTURE)
+  , ("waiting", CAPTURE)
+  ]
+-----------------------------------------------------------------------------
+-- | Clipboard events
+clipboardEvents :: Events
+clipboardEvents = M.fromList
+  [ ("cut", BUBBLE)
+  , ("copy", BUBBLE)
+  , ("paste", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Touch events
+touchEvents :: Events
+touchEvents = M.fromList
+  [ ("touchstart", BUBBLE)
+  , ("touchcancel", BUBBLE)
+  , ("touchmove", BUBBLE)
+  , ("touchend", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Phase during which event listener is invoked.
+--
+-- @since 1.9.0.0
+data Phase = CAPTURE | BUBBLE deriving (Eq, Show)
+-----------------------------------------------------------------------------
+instance ToJSVal Phase where
+  toJSVal = \case
+    CAPTURE -> toJSVal True
+    BUBBLE -> toJSVal False
+-----------------------------------------------------------------------------
diff --git a/src/Miso/EventSource.hs b/src/Miso/EventSource.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/EventSource.hs
@@ -0,0 +1,106 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP                        #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.EventSource
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- Interface to the browser's
+-- [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
+-- API, which provides a persistent, unidirectional stream of text or JSON
+-- messages pushed from a server to the browser client.
+--
+-- Typical usage inside an @update@ function:
+--
+-- @
+-- update FetchStream =
+--   connectText "\/events" StreamOpened GotMessage StreamError
+-- update (GotMessage msg) =
+--   modify (\\m -> m { messages = msg : messages m })
+-- @
+--
+-- 'close' shuts down an open t'EventSource' connection. 'socketState' reads
+-- the current ready-state, and 'emptyEventSource' provides a zero-value for
+-- use in the model before a connection is established.
+--
+----------------------------------------------------------------------------
+module Miso.EventSource
+  ( -- *** EventSource
+    connectText
+  , connectJSON
+  , close
+  , socketState
+  -- *** Defaults
+  , emptyEventSource
+  -- *** Types
+  , EventSource (..)
+  , URL
+  -- *** Re-exports
+  , Payload (..)
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON
+-----------------------------------------------------------------------------
+import           Miso.Effect
+import           Miso.Runtime
+import           Miso.String
+-----------------------------------------------------------------------------
+-- | Open a Server-Sent Events connection that delivers raw 'MisoString' messages.
+--
+-- The three callbacks map browser events to @action@ values dispatched into
+-- the MVU loop:
+--
+-- * @onOpen@    — receives the live t'EventSource' handle (store it in the model
+--   to 'close' it later)
+-- * @onMessage@ — called with each message payload as a plain string
+-- * @onError@   — called with a description of the connection error
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/EventSource>
+connectText
+  :: URL
+  -- ^ URL endpoint for the Server-Sent Events stream
+  -> (EventSource -> action)
+  -- ^ @onOpen@ callback; receives the live t'EventSource' handle
+  -> (MisoString -> action)
+  -- ^ @onMessage@ callback; receives each raw text message
+  -> (MisoString -> action)
+  -- ^ @onError@ callback; receives an error description
+  -> Effect context props model action
+connectText = eventSourceConnectText
+-----------------------------------------------------------------------------
+-- | Open a Server-Sent Events connection that decodes each message as JSON.
+--
+-- Identical to 'connectText' but the @onMessage@ callback receives a parsed
+-- Haskell value of type @value@ (via 'FromJSON') rather than a raw string.
+-- JSON decode failures are silently dropped; use 'connectText' and decode
+-- manually if you need error recovery.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/EventSource>
+connectJSON
+  :: FromJSON value
+  => URL
+  -- ^ URL endpoint for the Server-Sent Events stream
+  -> (EventSource -> action)
+  -- ^ @onOpen@ callback; receives the live t'EventSource' handle
+  -> (value -> action)
+  -- ^ @onMessage@ callback; receives each JSON-decoded message
+  -> (MisoString -> action)
+  -- ^ @onError@ callback; receives an error description
+  -> Effect context props model action
+connectJSON = eventSourceConnectJSON
+-----------------------------------------------------------------------------
+-- | Close an open t'EventSource' connection.
+--
+-- After calling 'close', no further @onMessage@ or @onError@ callbacks will
+-- fire. Corresponds to
+-- <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/close EventSource.close()>.
+close
+  :: EventSource
+  -- ^ The t'EventSource' handle to close
+  -> Effect context props model action
+close = eventSourceClose
+-----------------------------------------------------------------------------
diff --git a/src/Miso/FFI.hs b/src/Miso/FFI.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/FFI.hs
@@ -0,0 +1,132 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.FFI
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- Public re-export surface for Miso's JavaScript FFI layer.
+--
+-- This module re-exports the stable public API from "Miso.FFI.Internal".
+-- Prefer importing this module over @Internal@ in application code and
+-- library extensions.
+--
+-- Exports are grouped by concern:
+--
+-- * __DOM manipulation__: 'getElementById', 'focus', 'blur', 'removeChild', …
+-- * __Logging__: 'Miso.FFI.consoleLog', 'consoleError', 'consoleWarn'
+-- * __Callbacks__: 'syncCallback', 'asyncCallback', 'asyncCallback2', …
+-- * __Canvas\/Drawing__: 'flush', 'setDrawingContext'
+-- * __Browser APIs__: 'fetch', 'addEventListener', 'dispatchEvent', …
+-- * __JS types__: t'ArrayBuffer', t'Blob', t'FormData', t'Uint8Array', t'File', …
+--
+-- For inline JavaScript via quasi-quotation, see "Miso.FFI.QQ".
+--
+----------------------------------------------------------------------------
+module Miso.FFI
+  ( -- ** Object
+    set
+    -- ** Performance
+  , now
+    -- ** Logging
+  , consoleLog
+  , consoleLog'
+  , consoleError
+  , consoleWarn
+    -- ** DOM
+  , getElementById
+  , focus
+  , blur
+  , select
+  , setSelectionRange
+  , alert
+  , getProperty
+  , callFunction
+  , castJSVal
+  , removeChild
+    -- ** Styles
+  , addStyle
+  , addStyleSheet
+    -- * JS
+  , addSrc
+  , addScript
+  , addScriptImportMap
+    -- ** Callbacks
+  , syncCallback
+  , syncCallback1
+  , asyncCallback
+  , asyncCallback1
+  , asyncCallback2
+    -- ** Drawing
+  , flush
+  , setDrawingContext
+    -- ** Window
+  , windowInnerWidth
+  , windowInnerHeight
+  , locationReload
+    -- ** Image
+  , Image (..)
+  , newImage
+    -- ** Date
+  , Date (..)
+  , newDate
+  , toLocaleString
+  , getSeconds
+  , getMilliseconds
+    -- ** DOM Traversal
+  , nextSibling
+  , previousSibling
+    -- ** Element
+  , click
+  , setValue
+    -- ** File Input
+  , files
+    -- ** Navigator
+  , isOnLine
+    -- ** Lynx
+  , onBTS
+  , onMTS
+  , getThreads
+    -- ** ArrayBuffer
+  , ArrayBuffer (..)
+    -- ** Blob
+  , Blob (..)
+    -- ** Uint8Array
+  , Uint8Array (..)
+    -- ** FormData
+  , FormData (..)
+    -- ** File
+  , File (..)
+    -- ** URLSearchParams
+  , URLSearchParams (..)
+    -- ** FileReader
+  , FileReader (..)
+  , newFileReader
+    -- ** Fetch API
+  , fetch
+  , Response (..)
+    -- ** Event
+  , addEventListener
+  , removeEventListener
+  , dispatchEvent
+  , newEvent
+  , newCustomEvent
+  , Event (..)
+  , eventPreventDefault
+  , eventStopPropagation
+    -- ** Inline JS
+  , inline
+    -- ** Scroll
+  , scrollIntoView
+    -- ** Fullscreen
+  , requestFullscreen
+    -- ** SplitMix32
+  , splitmix32
+    -- ** Math.random()
+  , mathRandom
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.FFI.Internal
+-----------------------------------------------------------------------------
diff --git a/src/Miso/FFI/Internal.hs b/src/Miso/FFI/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/FFI/Internal.hs
@@ -0,0 +1,1448 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE NamedFieldPuns             #-}
+{-# LANGUAGE LambdaCase                 #-}
+{-# LANGUAGE CPP                        #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -fno-warn-orphans       #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.FFI.Internal
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.FFI.Internal" contains the low-level browser bindings that back the
+-- miso runtime. It is exposed for advanced use-cases and custom renderer
+-- authors; most application code should import "Miso.FFI" instead, which
+-- re-exports a curated subset of this module.
+--
+-- = Drawing context abstraction
+--
+-- Miso routes all DOM mutations through a /drawing context/ object stored at
+-- @globalThis.miso.drawingContext@. This indirection lets the same Haskell
+-- runtime target different rendering backends (browser DOM, native mobile via
+-- <https://github.com/haskell-miso/miso-lynx miso-lynx>, etc.) without
+-- changing application code. Use 'setDrawingContext' to switch renderers at
+-- startup:
+--
+-- @
+-- setDrawingContext \"lynx\"   -- switch to the Lynx native renderer
+-- @
+--
+-- = Inline JavaScript
+--
+-- 'inline' provides a safe, scoped alternative to 'Miso.DSL.eval'. It
+-- wraps a JS snippet in a function, passes the supplied 'Miso.DSL.Object'
+-- fields as named parameters, and returns the result:
+--
+-- @
+-- {-\# LANGUAGE DeriveGeneric, DeriveAnyClass \#-}
+--
+-- data Person = Person { name :: MisoString, age :: Int }
+--   deriving (Generic, ToJSVal, ToObject)
+--
+-- logNameGetAge :: Person -> IO Int
+-- logNameGetAge person = inline
+--   \"console.log(name); return age;\"
+--   person
+-- @
+--
+-- Prefer 'inline' (or the @[js| … |]@ quasi-quoter from "Miso.FFI.QQ")
+-- over 'Miso.DSL.eval' — 'inline' is isolated and not subject to the
+-- security concerns or optimisation barriers of @eval@.
+--
+-- = API groups
+--
+-- * __Callbacks__: 'syncCallback', 'asyncCallback' (and 1\/2-arg variants)
+-- * __Events__: 'addEventListener', 'removeEventListener',
+--   'eventPreventDefault', 'eventStopPropagation',
+--   'delegator', 'dispatchEvent', 'newEvent', 'newCustomEvent'
+-- * __Window__: 'windowAddEventListener', 'windowRemoveEventListener',
+--   'windowInnerHeight', 'windowInnerWidth'
+-- * __DOM__: 'getBody', 'getDocument', 'getElementById', 'getHead',
+--   'removeChild', 'nextSibling', 'previousSibling', 'diff', 'hydrate'
+-- * __Console__: 'consoleLog', 'consoleWarn', 'consoleError', 'consoleLog''
+-- * __Performance__: 'now'
+-- * __Element actions__: 'focus', 'blur', 'select', 'setSelectionRange',
+--   'scrollIntoView', 'requestFullscreen', 'click', 'files', 'setValue'
+-- * __CSS \/ JS injection__: 'addStyle', 'addStyleSheet', 'addScript',
+--   'addSrc', 'addScriptImportMap'
+-- * __Network__: 'fetch' \/ t'Response' \/ 'CONTENT_TYPE',
+--   'websocketConnect', 'websocketSend', 'websocketClose',
+--   'eventSourceConnect', 'eventSourceClose'
+-- * __Navigator__: 'getUserMedia', 'copyClipboard', 'geolocation', 'isOnLine'
+-- * __Types__: t'Image', t'Date', t'Blob', t'File', t'FormData',
+--   t'ArrayBuffer', t'Uint8Array', t'FileReader', t'URLSearchParams', t'Event'
+-- * __Randomness__: 'splitmix32', 'mathRandom', 'getRandomValue'
+--
+-- = See also
+--
+-- * "Miso.FFI" — public re-export surface for application code
+-- * "Miso.FFI.QQ" — @[js| … |]@ quasi-quoter for inline JavaScript
+-- * "Miso.DSL" — 'Miso.DSL.JSVal', 'Miso.DSL.ToJSVal', 'Miso.DSL.FromJSVal'
+-----------------------------------------------------------------------------
+module Miso.FFI.Internal
+   ( -- * Callbacks
+     syncCallback
+   , syncCallback1
+   , syncCallback2
+   , asyncCallback
+   , asyncCallback1
+   , asyncCallback2
+   -- * Events
+   , addEventListener
+   , removeEventListener
+   , eventPreventDefault
+   , eventStopPropagation
+   -- * Window
+   , windowAddEventListener
+   , windowRemoveEventListener
+   , windowInnerHeight
+   , windowInnerWidth
+   -- * Performance
+   , now
+   -- * Console
+   , consoleWarn
+   , consoleLog
+   , consoleError
+   , consoleLog'
+   -- * JSON
+   , eventJSON
+   -- * Object
+   , set
+   , setValue
+   -- * DOM
+   , getBody
+   , getDocument
+   , getDrawingContext
+   , getHydrationContext
+   , getEventContext
+   , getElementById
+   , removeChild
+   , getHead
+   , diff
+   , nextSibling
+   , previousSibling
+   , getProperty
+   , callFunction
+   , castJSVal
+   -- * Events
+   , delegator
+   , dispatchEvent
+   , newEvent
+   , newCustomEvent
+   -- * Isomorphic
+   , hydrate
+   -- * Misc.
+   , focus
+   , blur
+   , select
+   , setSelectionRange
+   , scrollIntoView
+   , requestFullscreen
+   , alert
+   , locationReload
+   -- * CSS
+   , addStyle
+   , addStyleSheet
+   -- * JS
+   , addSrc
+   , addScript
+   , addScriptImportMap
+   -- * XHR
+   , fetch
+   , CONTENT_TYPE(..)
+   -- * Drawing
+   , setDrawingContext
+   , flush
+   -- * Image
+   , Image (..)
+   , newImage
+   -- * Date
+   , Date (..)
+   , newDate
+   , toLocaleString
+   -- * Utils
+   , getMilliseconds
+   , getSeconds
+   -- * Element
+   , files
+   , click
+   -- * WebSocket
+   , websocketConnect
+   , websocketClose
+   , websocketSend
+   -- * SSE
+   , eventSourceConnect
+   , eventSourceClose
+   -- * Blob
+   , Blob (..)
+   -- * FormData
+   , FormData (..)
+   -- * URLSearchParams
+   , URLSearchParams (..)
+   -- * File
+   , File (..)
+   -- * Uint8Array
+   , Uint8Array (..)
+   -- * ArrayBuffer
+   , ArrayBuffer (..)
+   -- * Navigator
+   , geolocation
+   , copyClipboard
+   , getUserMedia
+   , isOnLine
+   , onBTS
+   , onMTS
+   , getThreads
+   -- * Cookie Store
+   , cookieGet
+   , cookieGetAll
+   , cookieSet
+   , cookieDelete
+   , cookieDeleteWith
+   , cookieStoreAddEventListener
+   , cookieStoreRemoveEventListener
+   -- * FileReader
+   , FileReader (..)
+   , newFileReader
+   -- * Fetch API
+   , Response (..)
+   -- * Event
+   , Event (..)
+   -- * Class
+   , populateClass
+   , updateRef
+   -- * Inline JS
+   , inline
+   -- * Randomness
+   , splitmix32
+   -- * Math
+   , mathRandom
+   -- * Crypto
+   , getRandomValue
+   ) where
+-----------------------------------------------------------------------------
+import           Control.Monad (void, forM_, (<=<), when, unless)
+import           Data.Map.Strict (Map)
+import           Data.Maybe
+import           Prelude hiding ((!!))
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.String
+-----------------------------------------------------------------------------
+-- | Set property on object
+set
+  :: ToJSVal v
+  => MisoString
+  -- ^ Property name to set
+  -> v
+  -- ^ Value to assign
+  -> Object
+  -- ^ JavaScript object to mutate
+  -> IO ()
+{-# INLINABLE set #-}
+set k v o = do
+  v' <- toJSVal v
+  setProp (fromMisoString k) v' o
+-----------------------------------------------------------------------------
+-- | Get a property of a 'JSVal'
+--
+-- Example usage:
+--
+-- > Just (value :: String) <- fromJSVal =<< getProperty domRef "value"
+getProperty
+  :: JSVal
+  -- ^ JavaScript object to read from
+  -> MisoString
+  -- ^ Property name to retrieve
+  -> IO JSVal
+{-# INLINABLE getProperty #-}
+getProperty = (!)
+-----------------------------------------------------------------------------
+-- | Calls a function on a 'JSVal'
+--
+-- Example usage:
+--
+-- > callFunction domRef "focus" ()
+-- > callFunction domRef "setSelectionRange" (0, 3, "none")
+callFunction :: (ToArgs args) => JSVal -> MisoString -> args -> IO JSVal
+{-# INLINABLE callFunction #-}
+callFunction = (#)
+-----------------------------------------------------------------------------
+-- | Marshalling of 'JSVal', useful for 'getProperty'
+castJSVal :: (FromJSVal a) => JSVal -> IO (Maybe a)
+{-# INLINABLE castJSVal #-}
+castJSVal = fromJSVal
+-----------------------------------------------------------------------------
+-- | Register an event listener on given target.
+addEventListener
+  :: JSVal
+  -- ^ Event target on which we want to register event listener
+  -> MisoString
+  -- ^ Type of event to listen to (e.g. "click")
+  -> (JSVal -> IO ())
+  -- ^ Callback which will be called when the event occurs,
+  -- the event will be passed to it as a parameter.
+  -> IO Function
+{-# INLINABLE addEventListener #-}
+addEventListener self name cb = do
+#ifdef GHCJS_BOTH
+  cb_ <- Function <$> syncCallback1 cb
+#else
+  cb_ <- Function <$> asyncCallback1 cb
+#endif
+  void $ self # "addEventListener" $ (name, cb_)
+  pure cb_
+-----------------------------------------------------------------------------
+-- | Removes an event listener from given target.
+removeEventListener
+  :: JSVal
+  -- ^ Event target from which we want to remove event listener
+  -> MisoString
+  -- ^ Type of event to listen to (e.g. "click")
+  -> Function
+  -- ^ Callback which will be called when the event occurs,
+  -- the event will be passed to it as a parameter.
+  -> IO ()
+{-# INLINABLE removeEventListener #-}
+removeEventListener self name cb =
+  void $ self # "removeEventListener" $ (name, cb)
+-----------------------------------------------------------------------------
+-- | Removes an event listener from window
+windowRemoveEventListener
+  :: MisoString
+  -- ^ Type of event to listen to (e.g. "click")
+  -> Function
+  -- ^ Callback which will be called when the event occurs,
+  -- the event will be passed to it as a parameter.
+  -> IO ()
+{-# INLINABLE windowRemoveEventListener #-}
+windowRemoveEventListener name cb = do
+  win <- jsg "window"
+  removeEventListener win name cb
+-----------------------------------------------------------------------------
+-- | Registers an event listener on window
+windowAddEventListener
+  :: MisoString
+  -- ^ Type of event to listen to (e.g. "click")
+  -> (JSVal -> IO ())
+  -- ^ Callback which will be called when the event occurs,
+  -- the event will be passed to it as a parameter.
+  -> IO Function
+{-# INLINABLE windowAddEventListener #-}
+windowAddEventListener name cb = do
+  win <- jsg "window"
+  addEventListener win name cb
+-----------------------------------------------------------------------------
+-- | Stop propagation of events
+eventStopPropagation :: JSVal -> IO ()
+{-# INLINABLE eventStopPropagation #-}
+eventStopPropagation e = do
+  _ <- e # "stopPropagation" $ ()
+  pure ()
+-----------------------------------------------------------------------------
+-- | Prevent default event behavior
+eventPreventDefault :: JSVal -> IO ()
+{-# INLINABLE eventPreventDefault #-}
+eventPreventDefault e = do
+  _ <- e # "preventDefault" $ ()
+  pure ()
+-----------------------------------------------------------------------------
+-- | Retrieves the height (in pixels) of the browser window viewport including,
+-- if rendered, the horizontal scrollbar.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight>
+windowInnerHeight :: IO Int
+{-# INLINABLE windowInnerHeight #-}
+windowInnerHeight = fromJSValUnchecked =<< jsg "window" ! "innerHeight"
+-----------------------------------------------------------------------------
+-- | Retrieves the width (in pixels) of the browser window viewport including
+-- if rendered, the vertical scrollbar.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth>
+windowInnerWidth :: IO Int
+{-# INLINABLE windowInnerWidth #-}
+windowInnerWidth =
+  fromJSValUnchecked =<< jsg "window" ! "innerWidth"
+-----------------------------------------------------------------------------
+-- | Retrieve high resolution time stamp
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Performance/now>
+-- Lynx's *background* thread realm has no @performance@ global at all - only
+-- the main thread does - so the obvious @performance.now()@ throws
+-- @cannot read property 'now' of undefined@ there. Everything that timestamps
+-- from the BTS goes through here, including gesture handling like
+-- double-tap detection, so that throw took real features down rather than
+-- merely losing precision. Falls back to @Date.now()@, which every realm has.
+now :: IO Double
+{-# INLINABLE now #-}
+now = now_ffi
+-----------------------------------------------------------------------------
+-- | Outputs a message to the web console
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Console/log>
+--
+-- Console logging of JavaScript strings.
+consoleLog :: MisoString -> IO ()
+{-# INLINABLE consoleLog #-}
+consoleLog v = do
+  _ <- jsg "console" # "log" $ [ms v]
+  pure ()
+-----------------------------------------------------------------------------
+-- | Outputs a warning message to the web console
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Console/warn>
+--
+-- Console logging of JavaScript strings.
+consoleWarn :: MisoString -> IO ()
+{-# INLINABLE consoleWarn #-}
+consoleWarn v = do
+  _ <- jsg "console" # "warn" $ [ms v]
+  pure ()
+-----------------------------------------------------------------------------
+-- | Outputs an error message to the web console
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Console/error>
+--
+-- Console logging of JavaScript strings.
+consoleError :: MisoString -> IO ()
+{-# INLINABLE consoleError #-}
+consoleError v = do
+  _ <- jsg "console" # "error" $ [ms v]
+  pure ()
+-----------------------------------------------------------------------------
+-- | Console-logging of JSVal
+consoleLog' :: ToArgs a => a -> IO ()
+{-# INLINABLE consoleLog' #-}
+consoleLog' args' = do
+  args <- toArgs args'
+  _ <- jsg "console" # "log" $ args
+  pure ()
+-----------------------------------------------------------------------------
+-- | Convert a JavaScript object to JSON
+-- JSONified representation of events
+eventJSON
+    :: JSVal -- ^ decodeAt :: [JSString]
+    -> JSVal -- ^ object with impure references to the DOM
+    -> IO JSVal
+{-# INLINABLE eventJSON #-}
+eventJSON x y = do
+  moduleMiso <- jsg "miso"
+  moduleMiso # "eventJSON" $ [x,y]
+-----------------------------------------------------------------------------
+-- | Used to update the JavaScript reference post-diff.
+updateRef
+    :: ToJSVal val
+    => val
+    -> val
+    -> IO ()
+{-# INLINABLE updateRef #-}
+updateRef jsval1 jsval2 = do
+  moduleMiso <- jsg "miso"
+  freeJSVal =<< (moduleMiso # "updateRef" $ (jsval1, jsval2))
+  freeJSVal moduleMiso
+-----------------------------------------------------------------------------
+-- | Convenience function to write inline javascript.
+--
+-- Prefer this function over the use of `eval`.
+--
+-- This function takes as arguments a JavaScript object and makes the
+-- keys available in the function body.
+--
+-- @
+--
+-- data Person = Person { name :: MisoString, age :: Int }
+--   deriving stock (Generic)
+--   deriving anyclass (ToJSVal, ToObject)
+--
+-- logNameGetAge :: Person -> IO Int
+-- logNameGetAge = inline
+--   """
+--   console.log(@name@, name);
+--   return age;
+--   """
+--
+-- @
+--
+inline
+    :: (FromJSVal return, ToObject object)
+    => MisoString
+    -> object
+    -> IO return
+{-# INLINABLE inline #-}
+inline code o = do
+  moduleMiso <- jsg "miso"
+  Object obj <- toObject o
+  fromJSValUnchecked =<< do
+    moduleMiso # "inline" $ (code, obj)
+-----------------------------------------------------------------------------
+-- | Populate the 'Miso.Html.Property.classList' Set on the virtual DOM.
+populateClass
+    :: JSVal
+    -- ^ Node
+    -> [MisoString]
+    -- ^ classes
+    -> IO ()
+{-# INLINABLE populateClass #-}
+populateClass domRef classes = do
+  moduleMiso <- jsg "miso"
+  freeJSVal =<< (moduleMiso # "populateClass" $ (domRef, classes))
+  freeJSVal moduleMiso
+-----------------------------------------------------------------------------
+-- | Retrieves a reference to document body.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Document/body>
+getBody :: IO JSVal
+{-# INLINABLE getBody #-}
+getBody = do
+  ctx <- getDrawingContext
+  ctx # "getRoot" $ ()
+-----------------------------------------------------------------------------
+-- | Retrieves a reference to the document.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Document>
+getDocument :: IO JSVal
+{-# INLINABLE getDocument #-}
+getDocument = jsg "document"
+-----------------------------------------------------------------------------
+-- | Retrieves a reference to the drawing context.
+--
+-- This is a miso specific construct used to provide an identical interface
+-- for both native (iOS / Android, etc.) and browser environments.
+--
+getDrawingContext :: IO JSVal
+{-# INLINABLE getDrawingContext #-}
+getDrawingContext = do
+  moduleMiso <- jsg "miso"
+  context <- moduleMiso ! "drawingContext"
+  freeJSVal moduleMiso
+  pure context
+-----------------------------------------------------------------------------
+-- | Retrieves a reference to the event context.
+--
+-- This is a miso specific construct used to provide an identical interface
+-- for both native (iOS / Android, etc.) and browser environments.
+--
+getEventContext :: IO JSVal
+{-# INLINABLE getEventContext #-}
+getEventContext = jsg "miso" ! "eventContext"
+-----------------------------------------------------------------------------
+-- | Retrieves a reference to the hydration context.
+--
+-- This is a miso specific construct used to provide an identical interface
+-- for both native (iOS / Android, etc.) and browser environments.
+--
+getHydrationContext :: IO JSVal
+{-# INLINABLE getHydrationContext #-}
+getHydrationContext = jsg "miso" ! "hydrationContext"
+-----------------------------------------------------------------------------
+-- | Returns an Element object representing the element whose id property matches
+-- the specified string.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById>
+getElementById :: MisoString -> IO JSVal
+{-# INLINABLE getElementById #-}
+getElementById e = getDocument # "getElementById" $ [e]
+-----------------------------------------------------------------------------
+-- | Retrieves a reference to the renderer's "head" mount.
+--
+-- Calls @miso.drawingContext.getHead()@.
+--
+-- Note: custom renderers should implement this method.
+--
+-- @since 1.9.0.0
+getHead :: IO JSVal
+{-# INLINABLE getHead #-}
+getHead = do
+  context <- getDrawingContext
+  context # "getHead" $ ()
+-----------------------------------------------------------------------------
+-- | Removes a child node from a parent node.
+--
+-- Calls @miso.drawingContext.removeChild(parent, child)@.
+--
+-- @since 1.9.0.0
+removeChild :: JSVal -> JSVal -> IO ()
+{-# INLINABLE removeChild #-}
+removeChild parent child = do
+  context <- getDrawingContext
+  void $ context # "removeChild" $ (parent, child)
+-----------------------------------------------------------------------------
+-- | Diff two virtual DOMs
+diff
+  :: Object
+  -- ^ current object
+  -> Object
+  -- ^ new object
+  -> JSVal
+  -- ^ parent node
+  -> IO ()
+{-# INLINABLE diff #-}
+diff (Object a) (Object b) c = do
+  moduleMiso <- jsg "miso"
+  context <- getDrawingContext
+  freeJSVal =<< (moduleMiso # "diff" $ [a,b,c,context])
+  freeJSVal moduleMiso
+  freeJSVal context
+-----------------------------------------------------------------------------
+-- | Initialize event delegation from a mount point.
+delegator :: JSVal -> JSVal -> Bool -> IO JSVal -> IO ()
+{-# INLINABLE delegator #-}
+delegator mountPoint events debug getVTree = do
+  ctx <- getEventContext
+#ifdef WASM
+  cb <- asyncCallback1 $ \continuation -> void (call continuation global =<< getVTree)
+#else
+  cb <- syncCallback1 $ \continuation -> void (call continuation global =<< getVTree)
+#endif
+  d <- toJSVal debug
+  eventContext <- getEventContext
+  void $ eventContext # "delegator" $ [mountPoint,events,cb,d,ctx]
+-----------------------------------------------------------------------------
+-- | Copies DOM pointers into virtual dom entry point into isomorphic javascript
+--
+-- See [hydration](https://en.wikipedia.org/wiki/Hydration_(web_development))
+--
+hydrate :: Bool -> JSVal -> JSVal -> IO JSVal
+{-# INLINABLE hydrate #-}
+hydrate logLevel mountPoint vtree = do
+  ll <- toJSVal logLevel
+  drawingContext <- getDrawingContext
+  hydrationContext <- getHydrationContext
+  moduleMiso <- jsg "miso"
+  moduleMiso # "hydrate" $ (ll, mountPoint, vtree, hydrationContext, drawingContext)
+-----------------------------------------------------------------------------
+-- | Fails silently if the element is not found.
+--
+-- Analogous to @document.getElementById(id).focus()@.
+focus :: MisoString -> IO ()
+{-# INLINABLE focus #-}
+focus x = void $ jsg "miso" # "callFocus" $ (x, 50 :: Int)
+-----------------------------------------------------------------------------
+-- | Fails silently if the element is not found.
+--
+-- Analogous to @document.getElementById(id).blur()@
+blur :: MisoString -> IO ()
+{-# INLINABLE blur #-}
+blur x = void $ jsg "miso" # "callBlur" $ (x, 50 :: Int)
+-----------------------------------------------------------------------------
+-- | Fails silently if the element is not found.
+--
+-- Analogous to @document.querySelector('#' + id).select()@.
+select :: MisoString -> IO ()
+{-# INLINABLE select #-}
+select x = void $ jsg "miso" # "callSelect" $ (x, 50 :: Int)
+-----------------------------------------------------------------------------
+-- | Fails silently if the element is not found.
+--
+-- Analogous to @document.querySelector('#' + id).setSelectionRange(start, end, \'none\')@.
+setSelectionRange
+  :: MisoString
+  -- ^ DOM element @id@ (without the @#@ prefix) to call @setSelectionRange@ on
+  -> Int
+  -- ^ Selection start index (inclusive)
+  -> Int
+  -- ^ Selection end index (exclusive)
+  -> IO ()
+{-# INLINABLE setSelectionRange #-}
+setSelectionRange x start end = void $ jsg "miso" # "callSetSelectionRange" $ (x, start, end, 50 :: Int)
+-----------------------------------------------------------------------------
+-- | Calls @document.getElementById(id).scrollIntoView()@
+scrollIntoView :: MisoString -> IO ()
+{-# INLINABLE scrollIntoView #-}
+scrollIntoView elId = do
+  el <- jsg "document" # "getElementById" $ [elId]
+  _ <- el # "scrollIntoView" $ ()
+  pure ()
+-----------------------------------------------------------------------------
+-- | Calls @document.documentElement.requestFullscreen()@, falling back to
+-- @webkitRequestFullscreen@ for Safari.
+requestFullscreen :: IO ()
+{-# INLINABLE requestFullscreen #-}
+requestFullscreen = do
+  doc   <- jsg "document"
+  docEl <- doc ! "documentElement"
+  rfs   <- docEl ! "requestFullscreen"
+  undef <- isUndefined rfs
+  if undef
+    then do
+      wrfs   <- docEl ! "webkitRequestFullscreen"
+      wundef <- isUndefined wrfs
+      unless wundef $ void $ docEl # "webkitRequestFullscreen" $ ()
+    else void $ docEl # "requestFullscreen" $ ()
+-----------------------------------------------------------------------------
+-- | Calls the @alert()@ function.
+alert :: MisoString -> IO ()
+{-# INLINABLE alert #-}
+alert a = () <$ jsg1 "alert" a
+-----------------------------------------------------------------------------
+-- | Calls the @location.reload()@ function.
+locationReload :: IO ()
+{-# INLINABLE locationReload #-}
+locationReload = void $ jsg "location" # "reload" $ ([] :: [MisoString])
+-----------------------------------------------------------------------------
+-- | Appends a 'Miso.Html.Element.style_' element containing CSS to 'Miso.Html.Element.head_'
+--
+-- > addStyle "body { background-color: green; }"
+--
+-- > <head><style>body { background-color: green; }</style></head>
+--
+addStyle :: MisoString -> IO JSVal
+{-# INLINABLE addStyle #-}
+addStyle css = do
+  context <- getDrawingContext
+  head_ <- getHead
+  style <- context # "createElement" $ ["style" :: MisoString]
+  setField style "innerHTML" css
+  void $ context # "appendChild" $ (head_, style)
+  pure style
+-----------------------------------------------------------------------------
+-- | Appends a 'Miso.Html.Element.script_' element containing JS to 'Miso.Html.Element.head_'
+--
+-- > addScript False "function () { alert('hi'); }"
+--
+addScript :: Bool -> MisoString -> IO JSVal
+{-# INLINABLE addScript #-}
+addScript useModule js_ = do
+  context <- getDrawingContext
+  head_ <- getHead
+  script <- context # "createElement" $ ["script" :: MisoString]
+  when useModule $ setField script "type" ("module" :: MisoString)
+  setField script "innerHTML" js_
+  void $ context # "appendChild" $ (head_, script)
+  pure script
+-----------------------------------------------------------------------------
+-- | Sets the @.value@ property on a @DOMRef@.
+--
+-- Useful for resetting the @value@ property on an input element.
+--
+-- @
+--   setValue domRef ("" :: MisoString)
+-- @
+--
+setValue :: JSVal -> MisoString -> IO ()
+{-# INLINABLE setValue #-}
+setValue domRef value = setField domRef "value" value
+-----------------------------------------------------------------------------
+-- | Appends a 'Miso.Html.Element.script_' element containing a JS import map.
+--
+-- > addScript "{ \"import\" : { \"three\" : \"url\" } }"
+--
+addScriptImportMap :: MisoString -> IO JSVal
+{-# INLINABLE addScriptImportMap #-}
+addScriptImportMap impMap = do
+  context <- getDrawingContext
+  head_ <- getHead
+  script <- context # "createElement" $ ["script" :: MisoString]
+  setField script "type" ("importmap" :: MisoString)
+  setField script "innerHTML" impMap
+  void $ context # "appendChild" $ (head_, script)
+  pure script
+-----------------------------------------------------------------------------
+-- | Appends a \<script\> element to 'Miso.Html.Element.head_'
+--
+-- > addSrc "https://example.com/script.js"
+--
+addSrc :: MisoString -> Bool -> IO JSVal
+{-# INLINABLE addSrc #-}
+addSrc url cacheBust = do
+  context <- getDrawingContext
+  head_ <- getHead
+  link <- context # "createElement" $ ["script" :: MisoString]
+  url_ <- appendTimestamp url cacheBust
+  _ <- link # "setAttribute" $ ["src", url_ ]
+  void $ context # "appendChild" $ (head_, link)
+  pure link
+-----------------------------------------------------------------------------
+-- | Appends a StyleSheet 'Miso.Html.Element.link_' element to 'Miso.Html.Element.head_'
+-- The 'Miso.Html.Element.link_' tag will contain a URL to a CSS file.
+--
+-- > addStyleSheet "https://cdn.jsdelivr.net/npm/todomvc-common@1.0.5/base.min.css"
+--
+-- > <head><link href="https://cdn.jsdelivr.net/npm/todomvc-common@1.0.5/base.min.css" ref="stylesheet"></head>
+--
+addStyleSheet :: MisoString -> Bool -> IO JSVal
+{-# INLINABLE addStyleSheet #-}
+addStyleSheet url cacheBust  = do
+  context <- getDrawingContext
+  head_ <- getHead
+  link <- context # "createElement" $ ["link" :: MisoString]
+  _ <- link # "setAttribute" $ ["rel","stylesheet" :: MisoString]
+  url_ <- appendTimestamp url cacheBust
+  _ <- link # "setAttribute" $ ["href", url_ ]
+  void $ context # "appendChild" $ (head_, link)
+  pure link
+-----------------------------------------------------------------------------
+-- | Helper for cache busting
+appendTimestamp
+  :: MisoString
+  -- ^ Base URL to optionally append a timestamp query parameter to
+  -> Bool
+  -- ^ When 'True', appends @?v=\<timestamp\>@ to force cache invalidation
+  -> IO MisoString
+{-# INLINABLE appendTimestamp #-}
+appendTimestamp url = \case
+  True -> do
+    ts <- fromJSValUnchecked =<< do jsg "Date" # "now" $ ()
+    pure (url <> "?v=" <> ms (ts :: Double))
+  False ->
+    pure url
+-----------------------------------------------------------------------------
+-- | Retrieve JSON via Fetch API
+--
+-- Basic GET of JSON using Fetch API, will be expanded upon.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API>
+--
+fetch
+  :: (FromJSVal success, FromJSVal error)
+  => MisoString
+  -- ^ url
+  -> MisoString
+  -- ^ method
+  -> Maybe JSVal
+  -- ^ body
+  -> [(MisoString, MisoString)]
+  -- ^ headers
+  -> (Response success -> IO ())
+  -- ^ successful callback
+  -> (Response error -> IO ())
+  -- ^ errorful callback
+  -> CONTENT_TYPE
+  -- ^ content type
+  -> IO ()
+{-# INLINABLE fetch #-}
+fetch url method maybeBody requestHeaders successful errorful type_ = do
+  successful_ <- toJSVal =<< asyncCallback1 (successful <=< fromJSValUnchecked)
+  errorful_ <- toJSVal =<< asyncCallback1 (errorful <=< fromJSValUnchecked)
+  moduleMiso <- jsg "miso"
+  url_ <- toJSVal url
+  method_ <- toJSVal method
+  body_ <- toJSVal maybeBody
+  Object headers_ <- do
+    o <- create
+    forM_ requestHeaders $ \(k,v) -> set k v o
+    pure o
+  typ <- toJSVal type_
+  void $ moduleMiso # "fetchCore" $
+    [ url_
+    , method_
+    , body_
+    , headers_
+    , successful_
+    , errorful_
+    , typ
+    ]
+-----------------------------------------------------------------------------
+-- | List of possible content types that are available for use with the fetch API
+data CONTENT_TYPE
+  = JSON
+  | ARRAY_BUFFER
+  | TEXT
+  | BLOB
+  | BYTES
+  | FORM_DATA
+  | NONE
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal CONTENT_TYPE where
+  toJSVal = \case
+    JSON ->
+      toJSVal ("json" :: MisoString)
+    ARRAY_BUFFER ->
+      toJSVal ("arrayBuffer" :: MisoString)
+    TEXT ->
+      toJSVal ("text" :: MisoString)
+    BLOB ->
+      toJSVal ("blob" :: MisoString)
+    BYTES ->
+      toJSVal ("bytes" :: MisoString)
+    FORM_DATA ->
+      toJSVal ("formData" :: MisoString)
+    NONE ->
+      toJSVal ("none" :: MisoString)
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+-- | Flush is used to force a draw of the render tree. This is currently
+-- only used when targeting platforms other than the browser (like mobile).
+flush :: IO ()
+{-# INLINABLE flush #-}
+flush = do
+  context <- getDrawingContext
+  freeJSVal =<< (context # "flush" $ ([] :: [JSVal]))
+  freeJSVal context
+-----------------------------------------------------------------------------
+-- | Type that holds an [Image](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img).
+newtype Image = Image JSVal
+  deriving (ToJSVal, ToObject)
+-----------------------------------------------------------------------------
+instance FromJSVal Image where
+  fromJSVal = pure . pure . Image
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | Smart constructor for building a t'Image' w/ 'Miso.Html.Property.src_' 'Miso.Types.Attribute'.
+newImage :: MisoString -> IO Image
+{-# INLINABLE newImage #-}
+newImage url = do
+  img <- new (jsg "Image") ([] :: [MisoString])
+  setField img "src" url
+  pure (Image img)
+-----------------------------------------------------------------------------
+-- | Used to select a drawing context. Users can override the default DOM renderer
+-- by implementing their own Context, and exporting it to the global scope. This
+-- opens the door to different rendering engines, ala [miso-lynx](https://github.com/haskell-miso/miso-lynx).
+setDrawingContext :: MisoString -> IO ()
+{-# INLINABLE setDrawingContext #-}
+setDrawingContext rendererName =
+  void $ jsg "miso" # "setDrawingContext" $ [rendererName]
+-----------------------------------------------------------------------------
+-- | The [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) type
+newtype Date = Date JSVal
+  deriving (ToJSVal, ToObject, Eq)
+-----------------------------------------------------------------------------
+-- | Smart constructor for a t'Date'
+newDate :: IO Date
+{-# INLINABLE newDate #-}
+newDate = Date <$> new (jsg "Date") ([] :: [MisoString])
+-----------------------------------------------------------------------------
+-- | Date conversion function to produce a locale
+toLocaleString :: Date -> IO MisoString
+{-# INLINABLE toLocaleString #-}
+toLocaleString date = fromJSValUnchecked =<< do
+  date # "toLocaleString" $ ()
+-----------------------------------------------------------------------------
+-- | Retrieves current milliseconds from t'Date'
+getMilliseconds :: Date -> IO Double
+{-# INLINABLE getMilliseconds #-}
+getMilliseconds date =
+  fromJSValUnchecked =<< do
+    date # "getMilliseconds" $ ([] :: [MisoString])
+-----------------------------------------------------------------------------
+-- | Retrieves current seconds from t'Date'
+getSeconds :: Date -> IO Double
+{-# INLINABLE getSeconds #-}
+getSeconds date =
+  fromJSValUnchecked =<< do
+    date # "getSeconds" $ ([] :: [MisoString])
+-----------------------------------------------------------------------------
+-- | Fetch next sibling DOM node
+--
+-- @since 1.9.0.0
+nextSibling :: JSVal -> IO JSVal
+{-# INLINABLE nextSibling #-}
+nextSibling domRef = domRef ! "nextSibling"
+-----------------------------------------------------------------------------
+-- | Fetch previous sibling DOM node
+--
+-- @since 1.9.0.0
+previousSibling :: JSVal -> IO JSVal
+{-# INLINABLE previousSibling #-}
+previousSibling domRef = domRef ! "previousSibling"
+-----------------------------------------------------------------------------
+-- | When working with @\<input type="file"\>@, this is useful for
+-- extracting out the selected files.
+--
+-- @
+--   update (InputClicked inputElement) = withSink $ \\sink -> do
+--      files_ <- files inputElement
+--      forM_ files_ $ \\file -> sink (Upload file)
+--   update (Upload file) = do
+--      fetch \"https://localhost:8080\/upload\" \"POST\" (Just file) []
+--        Successful Errorful
+-- @
+--
+-- @since 1.9.0.0
+files :: JSVal -> IO [JSVal]
+{-# INLINABLE files #-}
+files domRef = fromJSValUnchecked =<< domRef ! "files"
+-----------------------------------------------------------------------------
+-- | Simulates a click event
+--
+-- > button & click ()
+--
+-- @since 1.9.0.0
+click :: () -> JSVal -> IO ()
+{-# INLINABLE click #-}
+click () domRef = void $ domRef # "click" $ ([] :: [MisoString])
+-----------------------------------------------------------------------------
+-- | Get Camera on user's device
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia>
+--
+getUserMedia
+  :: Bool
+  -- ^ video
+  -> Bool
+  -- ^ audio
+  -> (JSVal -> IO ())
+  -- ^ successful
+  -> (JSVal -> IO ())
+  -- ^ errorful
+  -> IO ()
+{-# INLINABLE getUserMedia #-}
+getUserMedia video audio successful errorful = do
+  params <- create
+  set "video" video params
+  set "audio" audio params
+  devices <- jsg "navigator" ! "mediaDevices"
+  promise <- devices # "getUserMedia" $ [params]
+  successfulCallback <- asyncCallback1 successful
+  void $ promise # "then" $ [successfulCallback]
+  errorfulCallback <- asyncCallback1 errorful
+  void $ promise # "catch" $ [errorfulCallback]
+-----------------------------------------------------------------------------
+-- | Copy clipboard
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia>
+--
+copyClipboard
+  :: MisoString
+  -- ^ Text to copy
+  -> IO ()
+  -- ^ successful
+  -> (JSVal -> IO ())
+  -- ^ errorful
+  -> IO ()
+{-# INLINABLE copyClipboard #-}
+copyClipboard txt successful errorful = do
+  clipboard <- jsg "navigator" ! "clipboard"
+  promise <- clipboard # "writeText" $ [txt]
+  successfulCallback <- asyncCallback successful
+  void $ promise # "then" $ [successfulCallback]
+  errorfulCallback <- asyncCallback1 errorful
+  void $ promise # "catch" $ [errorfulCallback]
+-----------------------------------------------------------------------------
+-- | Establishes a @WebSocket@ connection
+websocketConnect
+  :: MisoString
+  -> IO ()
+  -> (JSVal -> IO ())
+  -> Maybe (JSVal -> IO ())
+  -> Maybe (JSVal -> IO ())
+  -> Maybe (JSVal -> IO ())
+  -> Maybe (JSVal -> IO ())
+  -> (JSVal -> IO ())
+  -> Bool
+  -> IO JSVal
+{-# INLINABLE websocketConnect #-}
+websocketConnect
+  url onOpen onClose
+  onMessageText onMessageJSON
+  onMessageBLOB onMessageArrayBuffer
+  onError textOnly = do
+    url_ <- toJSVal url
+    onOpen_ <- toJSVal =<< asyncCallback onOpen
+    onClose_ <- toJSVal =<< asyncCallback1 onClose
+    onMessageText_ <- withMaybe onMessageText
+    onMessageJSON_ <- withMaybe onMessageJSON
+    onMessageBLOB_ <- withMaybe onMessageBLOB
+    onMessageArrayBuffer_ <- withMaybe onMessageArrayBuffer
+    onError_ <- toJSVal =<< asyncCallback1 onError
+    textOnly_ <- toJSVal textOnly
+    jsg "miso" # "websocketConnect" $
+      [ url_
+      , onOpen_
+      , onClose_
+      , onMessageText_
+      , onMessageJSON_
+      , onMessageBLOB_
+      , onMessageArrayBuffer_
+      , onError_
+      , textOnly_
+      ]
+  where
+    withMaybe Nothing = pure jsNull
+    withMaybe (Just f) = asyncCallback1 f
+-----------------------------------------------------------------------------
+-- | Closes an open WebSocket.
+--
+-- @since 1.13.0.0
+websocketClose :: JSVal -> IO ()
+{-# INLINABLE websocketClose #-}
+websocketClose websocket = void $ do
+  jsg "miso" # "websocketClose" $ [websocket]
+-----------------------------------------------------------------------------
+-- | Sends a payload over an open WebSocket.
+--
+-- @since 1.13.0.0
+websocketSend :: JSVal -> JSVal -> IO ()
+{-# INLINABLE websocketSend #-}
+websocketSend websocket message = void $ do
+  jsg "miso" # "websocketSend" $ [websocket, message]
+-----------------------------------------------------------------------------
+-- | Opens a @Server-Sent Events@ connection and wires up its callbacks.
+--
+-- @since 1.13.0.0
+eventSourceConnect
+  :: MisoString
+  -> IO ()
+  -> Maybe (JSVal -> IO ())
+  -> Maybe (JSVal -> IO ())
+  -> (JSVal -> IO ())
+  -> Bool
+  -> IO JSVal
+{-# INLINABLE eventSourceConnect #-}
+eventSourceConnect url onOpen onMessageText onMessageJSON onError textOnly = do
+  onOpen_ <- asyncCallback onOpen
+  onMessageText_ <- withMaybe onMessageText
+  onMessageJSON_ <- withMaybe onMessageJSON
+  onError_ <- asyncCallback1 onError
+  textOnly_ <- toJSVal textOnly
+  jsg "miso" # "eventSourceConnect" $
+    (url, onOpen_, onMessageText_, onMessageJSON_, onError_, textOnly_)
+    where
+      withMaybe Nothing = pure jsNull
+      withMaybe (Just f) = toJSVal =<< asyncCallback1 f
+-----------------------------------------------------------------------------
+-- | Closes an open @Server-Sent Events@ connection.
+--
+-- @since 1.13.0.0
+eventSourceClose :: JSVal -> IO ()
+{-# INLINABLE eventSourceClose #-}
+eventSourceClose eventSource = void $ do
+  jsg "miso" # "eventSourceClose" $ [eventSource]
+-----------------------------------------------------------------------------
+-- | Navigator function to query the current online status of the user's computer
+--
+-- See [navigator.onLine](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine)
+--
+isOnLine :: IO Bool
+{-# INLINABLE isOnLine #-}
+isOnLine = fromJSValUnchecked =<< jsg "navigator" ! "onLine"
+-----------------------------------------------------------------------------
+-- | Returns 'True' when executing on the Lynx background thread (BTS),
+-- @False@ on the main thread or in a web build.
+--
+-- Backed by @miso.onBTS()@, which uses the @__BACKGROUND__@ compile-time
+-- define injected by rspeedy. In web builds where @__BACKGROUND__@ is
+-- undefined the function safely returns @false@.
+--
+-- @since 1.13.0.0
+onBTS :: IO Bool
+{-# INLINABLE onBTS #-}
+onBTS = fromJSValUnchecked =<< do jsg "miso" # "onBTS" $ ()
+-----------------------------------------------------------------------------
+-- | Returns 'True' when executing on the Lynx main thread (MTS),
+-- @False@ on the background thread and in web builds.
+--
+-- @since 1.13.0.0
+onMTS :: IO Bool
+{-# INLINABLE onMTS #-}
+onMTS = fromJSValUnchecked =<< do jsg "miso" # "onMTS" $ ()
+-----------------------------------------------------------------------------
+-- | Returns @(mts, bts, web)@: whether the current execution context is the
+-- Lynx main thread, Lynx background thread, or a plain web build.
+--
+-- @since 1.13.0.0
+getThreads :: IO (Bool, Bool, Bool)
+getThreads = do
+  mts <- onMTS
+  bts <- onBTS
+  pure (mts, bts, not mts && not bts)
+-----------------------------------------------------------------------------
+-- | [Blob](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
+newtype Blob = Blob JSVal
+  deriving (ToJSVal, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal Blob where
+  fromJSVal = pure . pure . Blob
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
+newtype FormData = FormData JSVal
+  deriving (ToJSVal, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal FormData where
+  fromJSVal = pure . pure . FormData
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal ArrayBuffer where
+  fromJSVal = pure . pure . ArrayBuffer
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/API/ArrayBuffer)
+newtype ArrayBuffer = ArrayBuffer JSVal
+  deriving (Eq, ToJSVal)
+-----------------------------------------------------------------------------
+-- | Reads the device position via @navigator.geolocation.getCurrentPosition@.
+--
+-- @since 1.13.0.0
+geolocation :: (JSVal -> IO ()) -> (JSVal -> IO ()) -> IO ()
+{-# INLINABLE geolocation #-}
+geolocation successful errorful = do
+  geo <- jsg "navigator" ! "geolocation"
+  cb1 <- asyncCallback1 successful
+  cb2 <- asyncCallback1 errorful
+  void $ geo # "getCurrentPosition" $ (cb1, cb2)
+-----------------------------------------------------------------------------
+-- | [File](https://developer.mozilla.org/en-US/docs/Web/API/File)
+newtype File = File JSVal
+  deriving (ToJSVal, ToObject, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal File where
+  fromJSVal = pure . pure . File
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/API/Uint8Array)
+newtype Uint8Array = Uint8Array JSVal
+  deriving ToJSVal
+-----------------------------------------------------------------------------
+instance FromJSVal Uint8Array where
+  fromJSVal = pure . pure . Uint8Array
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | [FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader)
+newtype FileReader = FileReader JSVal
+  deriving (ToJSVal, ToObject, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal FileReader where
+  fromJSVal = pure . pure . FileReader
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)
+newtype URLSearchParams = URLSearchParams JSVal
+  deriving (ToJSVal, ToObject, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal URLSearchParams where
+  fromJSVal = pure . pure . URLSearchParams
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | Smart constructor for building a t'FileReader'
+newFileReader :: IO FileReader
+{-# INLINABLE newFileReader #-}
+newFileReader = do
+  reader <- new (jsg "FileReader") ([] :: [MisoString])
+  pure (FileReader reader)
+-----------------------------------------------------------------------------
+-- | Type returned from a 'fetch' request
+data Response body
+  = Response
+  { status :: Maybe Int
+    -- ^ HTTP status code
+  , headers :: Map MisoString MisoString
+    -- ^ Response headers
+  , errorMessage :: Maybe MisoString
+    -- ^ Optional error message
+  , body :: body
+    -- ^ Response body
+  }
+-----------------------------------------------------------------------------
+instance Functor Response where
+  fmap f response@Response { body } = response { body = f body }
+  {-# INLINE fmap #-}
+-----------------------------------------------------------------------------
+instance FromJSVal body => FromJSVal (Response body) where
+  fromJSVal o = do
+    status_ <- fromJSVal =<< getProp "status" (Object o)
+    headers_ <- fromJSVal =<< getProp "headers" (Object o)
+    errorMessage_ <- fromJSVal =<< getProp "error" (Object o)
+    body_ <- fromJSVal =<< getProp "body" (Object o)
+    pure (Response <$> status_ <*> headers_ <*> errorMessage_ <*> body_)
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event)
+newtype Event = Event JSVal
+  deriving (ToJSVal, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal Event where
+  fromJSVal = pure . Just . Event
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | Invokes [document.dispatchEvent](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent)
+--
+-- @
+--   update ChangeTheme = io_ $ do
+--     themeEvent <- newEvent "basecoat:theme"
+--     dispatchEvent themeEvent
+-- @
+--
+dispatchEvent :: Event -> IO ()
+{-# INLINABLE dispatchEvent #-}
+dispatchEvent event = do
+  doc <- getDocument
+  _ <- doc # "dispatchEvent" $ [event]
+  pure ()
+-----------------------------------------------------------------------------
+-- | Creates a new [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event)
+--
+-- @
+--   update ChangeTheme = io_ $ do
+--     themeEvent <- newEvent "basecoat:theme"
+--     dispatchEvent themeEvent
+-- @
+--
+newEvent :: ToArgs args => args -> IO Event
+{-# INLINABLE newEvent #-}
+newEvent args = Event <$> new (jsg "Event") args
+-----------------------------------------------------------------------------
+-- | Creates a new [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/CustomEvent)
+--
+-- @
+--   update ToggleSidebar = io_ $ do
+--     themeEvent <- newCustomEvent "basecoat:sidebar"
+--     dispatchEvent themeEvent
+-- @
+--
+newCustomEvent :: ToArgs args => args -> IO Event
+{-# INLINABLE newCustomEvent #-}
+newCustomEvent args = Event <$> new (jsg "CustomEvent") args
+-----------------------------------------------------------------------------
+-- | Uses the @splitmix@ function to generate a PRNG.
+--
+splitmix32 :: Double -> IO JSVal
+{-# INLINABLE splitmix32 #-}
+splitmix32 x = jsg "miso" # "splitmix32" $ [x]
+-----------------------------------------------------------------------------
+-- | Uses the 'Math.random()' function.
+--
+mathRandom :: IO Double
+{-# INLINABLE mathRandom #-}
+mathRandom = fromJSValUnchecked =<< do
+  jsg "miso" # "mathRandom" $ ()
+-----------------------------------------------------------------------------
+-- | Uses the first element of 'crypto.getRandomValues()'.
+--
+getRandomValue :: IO Double
+{-# INLINABLE getRandomValue #-}
+getRandomValue = fromJSValUnchecked =<< do
+  jsg "miso" # "getRandomValues" $ ()
+-----------------------------------------------------------------------------
+-- | Retrieve a single cookie by name from the
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>.
+--
+-- The successful callback receives a @null@ 'JSVal' when no cookie with
+-- that name exists. The errorful callback receives the error message string.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/get>
+--
+-- @since 1.13.0.0
+cookieGet
+  :: MisoString
+  -- ^ Cookie name
+  -> (JSVal -> IO ())
+  -- ^ Successful callback
+  -> (MisoString -> IO ())
+  -- ^ Errorful callback
+  -> IO ()
+{-# INLINABLE cookieGet #-}
+cookieGet name successful errorful = do
+  s_ <- toJSVal =<< asyncCallback1 successful
+  e_ <- toJSVal =<< asyncCallback1 (errorful <=< fromJSValUnchecked)
+  n_ <- toJSVal name
+  void $ jsg "miso" # "cookieGet" $ [n_, e_, s_]
+-----------------------------------------------------------------------------
+-- | Retrieve all cookies from the
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/getAll>
+--
+-- @since 1.13.0.0
+cookieGetAll
+  :: (JSVal -> IO ())
+  -- ^ Successful callback (receives a JS array of cookie objects)
+  -> (MisoString -> IO ())
+  -- ^ Errorful callback
+  -> IO ()
+{-# INLINABLE cookieGetAll #-}
+cookieGetAll successful errorful = do
+  s_ <- toJSVal =<< asyncCallback1 successful
+  e_ <- toJSVal =<< asyncCallback1 (errorful <=< fromJSValUnchecked)
+  void $ jsg "miso" # "cookieGetAll" $ [e_, s_]
+-----------------------------------------------------------------------------
+-- | Set a cookie via the
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/set>
+--
+-- @since 1.13.0.0
+cookieSet
+  :: JSVal
+  -- ^ Cookie options object (serialised 'Miso.Cookie.Cookie')
+  -> IO ()
+  -- ^ Successful callback
+  -> (MisoString -> IO ())
+  -- ^ Errorful callback
+  -> IO ()
+{-# INLINABLE cookieSet #-}
+cookieSet cookie successful errorful = do
+  s_ <- toJSVal =<< asyncCallback successful
+  e_ <- toJSVal =<< asyncCallback1 (errorful <=< fromJSValUnchecked)
+  void $ jsg "miso" # "cookieSet" $ [cookie, e_, s_]
+-----------------------------------------------------------------------------
+-- | Delete a cookie by name via the
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/delete>
+--
+-- @since 1.13.0.0
+cookieDelete
+  :: MisoString
+  -- ^ Cookie name
+  -> IO ()
+  -- ^ Successful callback
+  -> (MisoString -> IO ())
+  -- ^ Errorful callback
+  -> IO ()
+{-# INLINABLE cookieDelete #-}
+cookieDelete name successful errorful = do
+  s_ <- toJSVal =<< asyncCallback successful
+  e_ <- toJSVal =<< asyncCallback1 (errorful <=< fromJSValUnchecked)
+  n_ <- toJSVal name
+  void $ jsg "miso" # "cookieDelete" $ [n_, e_, s_]
+-----------------------------------------------------------------------------
+-- | Delete a cookie by options object via the
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore CookieStore API>.
+--
+-- See <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/delete>
+--
+-- @since 1.13.0.0
+cookieDeleteWith
+  :: JSVal
+  -- ^ Cookie options object (name, path, domain, partitioned)
+  -> IO ()
+  -- ^ Successful callback
+  -> (MisoString -> IO ())
+  -- ^ Errorful callback
+  -> IO ()
+{-# INLINABLE cookieDeleteWith #-}
+cookieDeleteWith opts successful errorful = do
+  s_ <- toJSVal =<< asyncCallback successful
+  e_ <- toJSVal =<< asyncCallback1 (errorful <=< fromJSValUnchecked)
+  void $ jsg "miso" # "cookieDeleteWith" $ [opts, e_, s_]
+-----------------------------------------------------------------------------
+-- | Register a listener for
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/change_event cookieStore change>
+-- events. Returns the t'Function' handle needed to remove the listener later.
+--
+-- When the CookieStore API is unavailable (e.g. Firefox, insecure contexts)
+-- no listener is registered and an inert t'Function' handle is returned.
+cookieStoreAddEventListener :: (JSVal -> IO ()) -> IO Function
+{-# INLINABLE cookieStoreAddEventListener #-}
+cookieStoreAddEventListener cb = do
+  cs <- jsg "cookieStore"
+  undef <- isUndefined cs
+  if undef
+    then pure (Function cs)
+    else addEventListener cs "change" cb
+-----------------------------------------------------------------------------
+-- | Remove a previously registered
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/change_event cookieStore change>
+-- listener.
+--
+-- When the CookieStore API is unavailable this is a no-op.
+cookieStoreRemoveEventListener :: Function -> IO ()
+{-# INLINABLE cookieStoreRemoveEventListener #-}
+cookieStoreRemoveEventListener cb = do
+  cs <- jsg "cookieStore"
+  undef <- isUndefined cs
+  unless undef $
+    removeEventListener cs "change" cb
+-----------------------------------------------------------------------------
diff --git a/src/Miso/FFI/QQ.hs b/src/Miso/FFI/QQ.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/FFI/QQ.hs
@@ -0,0 +1,187 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE DeriveLift            #-}
+{-# LANGUAGE LambdaCase            #-}
+{-# LANGUAGE QuasiQuotes           #-}
+{-# LANGUAGE ViewPatterns          #-}
+{-# LANGUAGE BlockArguments        #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE DeriveDataTypeable    #-}
+{-# LANGUAGE StandaloneDeriving    #-}
+{-# LANGUAGE TypeSynonymInstances  #-}
+{-# LANGUAGE TemplateHaskellQuotes #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -Wno-duplicate-exports #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.FFI.QQ
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.FFI.QQ" provides the @'js'@ quasi-quoter, which lets you embed
+-- JavaScript snippets directly in Haskell source. In-scope Haskell
+-- variables are spliced into the JS body with @${varName}@ interpolation
+-- syntax, and their types are checked at compile time via
+-- 'Miso.DSL.ToJSVal'.
+--
+-- Enable the extension and import the quoter:
+--
+-- @
+-- {-\# LANGUAGE QuasiQuotes \#-}
+-- import "Miso.FFI.QQ" ('js')
+-- @
+--
+-- = Quick start
+--
+-- @
+-- -- Compute a factorial entirely in JavaScript
+-- fac :: Int -> IO Int
+-- fac n = ['js'|
+--   let x = 1;
+--   for (let i = 1; i \<= ${n}; i++) {
+--     x *= i;
+--   }
+--   return x;
+-- |]
+--
+-- -- Call a third-party JS library with a DOM reference and a string
+-- highlight :: 'Miso.DSL.JSVal' -> 'Miso.String.MisoString' -> IO ()
+-- highlight domRef lang = ['js'|
+--   hljs.highlightElement(${domRef}, { language: ${lang} });
+-- |]
+-- @
+--
+-- = How it works
+--
+-- At compile time the quasi-quoter:
+--
+-- 1. Lexes the JS body to find all @${varName}@ interpolations.
+-- 2. Looks up each @varName@ in the Haskell scope (compile error if not found).
+-- 3. Builds a 'Miso.DSL.Object' mapping short generated keys to the
+--    marshalled values (via 'Miso.FFI.Internal.inline' \/ 'Miso.DSL.createWith').
+-- 4. Rewrites the JS body, replacing each @${varName}@ with its generated
+--    key, and wraps the whole thing in a JS function so the keys are visible
+--    as named parameters.
+--
+-- The result is semantically equivalent to:
+--
+-- @
+-- do o <- 'Miso.DSL.createWith' [(\"a0\", toJSVal n)]
+--    'Miso.FFI.Internal.inline' \"… body with a0 instead of n …\" o
+-- @
+--
+-- = Differences from eval
+--
+-- Unlike 'Miso.DSL.eval', the generated code runs in a fresh function scope —
+-- it cannot read or write surrounding local variables other than those
+-- explicitly interpolated. This makes it both safer and faster (JS engines
+-- can optimise closed-over functions that don't reference @eval@).
+--
+-- = See also
+--
+-- * 'Miso.FFI.Internal.inline' — the runtime primitive this expands to
+-- * "Miso.DSL" — 'Miso.DSL.ToJSVal', 'Miso.DSL.createWith'
+-- * "Miso.FFI" — higher-level browser API wrappers
+-----------------------------------------------------------------------------
+module Miso.FFI.QQ
+  ( js
+  ) where
+----------------------------------------------------------------------------
+import           Control.Applicative
+import           Data.Data
+import           Control.Monad
+import           System.IO.Unsafe (unsafePerformIO)
+import           Language.Haskell.TH.Lib
+import           Language.Haskell.TH.Quote
+import           Language.Haskell.TH.Syntax
+----------------------------------------------------------------------------
+import           Miso.String (MisoString)
+import           Miso.Util.Lexer
+import           Miso.DSL
+import qualified Miso.String as MS
+import qualified Miso.FFI as FFI
+----------------------------------------------------------------------------
+-- | QuasiQuoter for specifying inline JavaScript.
+--
+js :: QuasiQuoter
+js = QuasiQuoter
+  { quoteExp  = \s -> dataToExpQ (withString `extQ` inlineJS) s
+  , quotePat  = \_ -> fail "quotePat: not implemented"
+  , quoteType = \_ -> fail "quoteType: not implemented"
+  , quoteDec  = \_ -> fail "quoteDec: not implemented"
+  }
+----------------------------------------------------------------------------
+inlineJS :: String -> Maybe (Q Exp)
+inlineJS jsString = pure $ do
+  found <- typeCheck vars
+  kvs <- forM found $ \(var, key) -> do
+    k <- [| MS.pack $(stringE (MS.unpack key)) |]
+    let v = mkName (MS.unpack var)
+    val <- [| unsafePerformIO (toJSVal $(varE v)) :: JSVal |]
+    pure $ tupE [ pure k, pure val ]
+  [| do o <- createWith ($(listE kvs) :: [(MisoString, JSVal)])
+        FFI.inline $(stringE (MS.unpack (formatVars (MS.pack jsString) found)))
+          o
+   |] where
+        vars = getVariables (MS.pack jsString)
+----------------------------------------------------------------------------
+extQ :: (Typeable a, Typeable b) => (a -> c) -> (b -> c) -> a -> c
+extQ f g a = maybe (f a) g (cast a)
+----------------------------------------------------------------------------
+withString :: (Quote m, Typeable a) => a -> Maybe (m Exp)
+withString a = liftString <$> cast a
+----------------------------------------------------------------------------
+-- | Use @isPrefixOf@ as you traverse the string in lex order and do a replace
+formatVars :: MisoString -> [(MisoString, MisoString)] -> MisoString
+formatVars s [] = s
+formatVars s table@((var,key):xs) =
+  case MS.uncons s of
+    Nothing ->
+      mempty
+    Just ('$', cs) -> do
+      let needle = "{" <> var <> "}"
+      if needle `MS.isPrefixOf` cs
+        then
+          formatVars (key <> MS.drop (MS.length needle) cs) xs
+        else
+          formatVars cs table
+    Just (c,cs) ->
+      MS.cons c (formatVars cs table)
+----------------------------------------------------------------------------
+keys :: [MisoString]
+keys = do
+  (x,y) <- (,) <$> ['a'..'z'] <*> ['0'..'9']
+  pure (MS.pack [x,y])
+----------------------------------------------------------------------------
+typeCheck :: [MisoString] -> Q [(MisoString, MisoString)]
+typeCheck vars = do
+  forM (Prelude.zip vars keys) $ \(var, key) ->
+    lookupValueName (MS.unpack var) >>= \case
+      Nothing -> fail (MS.unpack var <> " is not in scope")
+      Just _ -> pure (var, key)
+---------------------------------------------------------------------------
+getVariables :: MisoString -> [MisoString]
+getVariables s =
+  case runLexer lexer (mkStream s) of
+    Left _ -> mempty
+    Right (xs,_) -> xs
+  where
+    varLexer :: Lexer MisoString
+    varLexer = do
+      void (string "${")
+      xs <- some $ satisfy (/= '}')
+      void (char '}')
+      pure (MS.pack xs)
+
+    anything :: Lexer MisoString
+    anything = mempty <$ satisfy (const True)
+
+    lexer :: Lexer [MisoString]
+    lexer = Prelude.filter (/="") <$>
+      many (varLexer <|> anything)
+----------------------------------------------------------------------------
diff --git a/src/Miso/Fetch.hs b/src/Miso/Fetch.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Fetch.hs
@@ -0,0 +1,1356 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase          #-}
+{-# LANGUAGE RecordWildCards     #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Fetch
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- Interface to the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API Fetch API>
+-- for making HTTP requests inside Miso's 'Effect' monad.
+--
+-- Each function accepts a URL, optional request headers, a success callback,
+-- and an error callback of the form @'Response' x -> action@. The resulting
+-- 'Effect' dispatches the appropriate action into the MVU loop when the
+-- response arrives.
+--
+-- Functions are grouped by HTTP method and body\/response type:
+--
+-- * __JSON__        — 'getJSON', 'postJSON', 'postJSON'', 'putJSON'
+-- * __Text__        — 'getText', 'postText', 'putText'
+-- * __Blob__        — 'getBlob', 'postBlob', 'putBlob'
+-- * __FormData__    — 'getFormData', 'postFormData', 'putFormData'
+-- * __Uint8Array__  — 'getUint8Array', 'postUint8Array', 'putUint8Array'
+-- * __ArrayBuffer__ — 'getArrayBuffer', 'postArrayBuffer', 'putArrayBuffer'
+-- * __Image__       — 'postImage', 'putImage'
+--
+-- Use 'getJSON' or 'postJSON' for typical REST calls; use 'postJSON'' when
+-- the server also returns a JSON response body.
+--
+-- Every function above has a synchronous counterpart suffixed with @_@
+-- (e.g. 'getJSON_', 'postJSON_') that blocks the calling thread until the
+-- browser resolves the underlying promise, returning @'Right' response@ on
+-- success or @'Left' response@ on failure instead of dispatching an action.
+-- These are best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid
+-- blocking the scheduler thread.
+--
+-- For Servant-style typed client generation, see the miso README.
+--
+----------------------------------------------------------------------------
+module Miso.Fetch
+  ( -- ** JSON
+    getJSON
+  , postJSON
+  , postJSON'
+  , putJSON
+  -- ** Text
+  , getText
+  , postText
+  , putText
+  -- ** Blob
+  , getBlob
+  , postBlob
+  , putBlob
+  -- ** FormData
+  , getFormData
+  , postFormData
+  , putFormData
+  -- ** Uint8Array
+  , getUint8Array
+  , postUint8Array
+  , putUint8Array
+  -- ** Image
+  , postImage
+  , putImage
+  -- ** ArrayBuffer
+  , getArrayBuffer
+  , postArrayBuffer
+  , putArrayBuffer
+    -- ** Header helpers
+  , accept
+  , contentType
+  , applicationJSON
+  , textPlain
+  , formData
+    -- ** Types
+  , Body
+  , Response (..)
+  , CONTENT_TYPE (..)
+    -- ** Synchronous API variants
+  , getJSON_
+  , postJSON_
+  , postJSON'_
+  , putJSON_
+  , getText_
+  , postText_
+  , putText_
+  , getBlob_
+  , postBlob_
+  , putBlob_
+  , getFormData_
+  , postFormData_
+  , putFormData_
+  , getUint8Array_
+  , postUint8Array_
+  , putUint8Array_
+  , postImage_
+  , putImage_
+  , getArrayBuffer_
+  , postArrayBuffer_
+  , putArrayBuffer_
+    -- ** Internal
+  , fetch
+  ) where
+----------------------------------------------------------------------------
+import           Control.Concurrent (MVar, newEmptyMVar, putMVar, takeMVar)
+import           Miso.JSON
+import qualified Data.Map.Strict as M
+----------------------------------------------------------------------------
+import           Miso.DSL (toJSVal, FromJSVal(..), JSVal)
+import qualified Miso.FFI.Internal as FFI
+import           Miso.Effect (Effect, withSink)
+import           Miso.String (MisoString, ms)
+import           Miso.Util ((=:))
+import           Miso.FFI.Internal (Response(..), Blob, FormData, ArrayBuffer, Uint8Array, Image, fetch, CONTENT_TYPE(..))
+----------------------------------------------------------------------------
+-- | Retrieve a JSON resource via GET.
+--
+-- @
+-- data Action
+--  = FetchGitHub
+--  | SetGitHub GitHub
+--  | ErrorHandler MisoString
+--  deriving (Show, Eq)
+--
+-- updateModel :: Action -> Effect Model Action
+-- updateModel = \case
+--   FetchGitHub -> getJSON "https://api.github.com" [] SetGitHub ErrorHandler
+--   SetGitHub apiInfo -> info ?= apiInfo
+--   ErrorHandler msg -> io_ (consoleError msg)
+-- @
+--
+getJSON
+  :: (FromJSON body, FromJSVal error)
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers
+  -> (Response body -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+getJSON url headers_ successful errorful =
+  withSink $ \sink ->
+    FFI.fetch url "GET" Nothing jsonHeaders
+      (handleJSON sink)
+      (sink . errorful)
+      JSON -- dmj: expected return type
+  where
+    jsonHeaders = biasHeaders headers_ [accept =: applicationJSON]
+    handleJSON sink resp@Response {..} =
+      fmap fromJSON <$> fromJSVal body >>= \case
+        Nothing -> do
+          err <- fromJSValUnchecked body
+          sink $ errorful $ Response
+            { body = err
+            , errorMessage = Just "Not a valid JSON object"
+            , ..
+            }
+        Just (Success result) ->
+          sink $ successful resp { body = result }
+        Just (Error msg) -> do
+          err <- fromJSValUnchecked body
+          sink $ errorful $ Response
+            { body = err
+            , errorMessage = Just (ms msg)
+            , ..
+            }
+----------------------------------------------------------------------------
+-- | Send a POST request with a JSON-encoded body; ignores the response body.
+--
+-- Sets @Content-Type: application\/json@ automatically. Use 'postJSON'' when
+-- you also need to parse a JSON response body.
+postJSON
+  :: (FromJSVal error, ToJSON body)
+  => MisoString
+  -- ^ url
+  -> body
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+postJSON url body_ headers_ successful errorful =
+  withSink $ \sink -> do
+    bodyVal <- toJSVal (encode body_)
+    FFI.fetch url "POST" (Just bodyVal) jsonHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    jsonHeaders_ = biasHeaders headers_ [contentType =: applicationJSON]
+----------------------------------------------------------------------------
+-- | Send a POST request with a JSON-encoded body and parse a JSON response.
+--
+-- Sets both @Content-Type: application\/json@ and @Accept: application\/json@
+-- automatically. Use 'postJSON' when the response body is not needed.
+postJSON'
+  :: (FromJSVal error, ToJSON body, FromJSON return)
+  => MisoString
+  -- ^ url
+  -> body
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response return -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+postJSON' url body_ headers_ successful errorful =
+  withSink $ \sink -> do
+    bodyVal <- toJSVal (encode body_)
+    FFI.fetch url "POST" (Just bodyVal) jsonHeaders_
+      (handleJSON sink)
+      (sink . errorful)
+      JSON
+  where
+    jsonHeaders_ = biasHeaders headers_ [contentType =: applicationJSON, accept =: applicationJSON]
+    handleJSON sink resp@Response {..} =
+      fmap fromJSON <$> fromJSVal body >>= \case
+        Nothing -> do
+          err <- fromJSValUnchecked body
+          sink $ errorful $ Response
+            { body = err
+            , errorMessage = Just "Not a valid JSON object"
+            , ..
+            }
+        Just (Success result) ->
+          sink $ successful resp { body = result }
+        Just (Error msg) -> do
+          err <- fromJSValUnchecked body
+          sink $ errorful $ Response
+            { body = err
+            , errorMessage = Just (ms msg)
+            , ..
+            }
+----------------------------------------------------------------------------
+-- | Send a PUT request with a JSON-encoded body; ignores the response body.
+--
+-- Sets @Content-Type: application\/json@ automatically.
+putJSON
+  :: (FromJSVal error, ToJSON body)
+  => MisoString
+  -- ^ url
+  -> body
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+putJSON url body_ headers_ successful errorful =
+  withSink $ \sink -> do
+    bodyVal <- toJSVal (encode body_)
+    FFI.fetch url "PUT" (Just bodyVal) jsonHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    jsonHeaders_ = biasHeaders headers_ [contentType =: applicationJSON]
+----------------------------------------------------------------------------
+-- | Retrieve a plain-text resource via GET.
+--
+-- Sets @Accept: text\/plain@ automatically. The response body is delivered as
+-- a 'MisoString'.
+getText
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response MisoString -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+getText url headers_ successful errorful =
+  withSink $ \sink ->
+    FFI.fetch url "GET" Nothing textHeaders_
+      (sink . successful)
+      (sink . errorful)
+      TEXT -- dmj: expected return type
+  where
+    textHeaders_ = biasHeaders headers_ [accept =: textPlain]
+----------------------------------------------------------------------------
+-- | Send a POST request with a plain-text body; ignores the response body.
+--
+-- Sets @Content-Type: text\/plain@ automatically.
+postText
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> MisoString
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+postText url body_ headers_ successful errorful =
+  withSink $ \sink -> do
+    bodyVal <- toJSVal (encode body_)
+    FFI.fetch url "POST" (Just bodyVal) textHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    textHeaders_ = biasHeaders headers_ [contentType =: textPlain]
+----------------------------------------------------------------------------
+-- | Send a PUT request with a plain-text body; ignores the response body.
+--
+-- Sets @Content-Type: text\/plain@ automatically.
+putText
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> MisoString
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+putText url imageBody headers_ successful errorful =
+  withSink $ \sink -> do
+    body_ <- toJSVal imageBody
+    FFI.fetch url "PUT" (Just body_) textHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    textHeaders_ = biasHeaders headers_ [contentType =: textPlain]
+----------------------------------------------------------------------------
+-- | Retrieve a binary resource as a t'Blob' via GET.
+--
+-- Sets @Accept: application\/octet-stream@ automatically.
+getBlob
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response Blob -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+getBlob url headers_ successful errorful =
+  withSink $ \sink ->
+    FFI.fetch url "GET" Nothing blobHeaders_
+      (sink . successful)
+      (sink . errorful)
+      BLOB -- dmj: expected return type
+  where
+    blobHeaders_ = biasHeaders headers_ [accept =: octetStream]
+----------------------------------------------------------------------------
+-- | Send a POST request with a t'Blob' body; ignores the response body.
+--
+-- Sets @Content-Type: application\/octet-stream@ automatically.
+postBlob
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Blob
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+postBlob url body_ headers_ successful errorful =
+  withSink $ \sink -> do
+    bodyVal <- toJSVal body_
+    FFI.fetch url "POST" (Just bodyVal) blobHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    blobHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+----------------------------------------------------------------------------
+-- | Send a PUT request with a t'Blob' body; ignores the response body.
+--
+-- Sets @Content-Type: application\/octet-stream@ automatically.
+putBlob
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Blob
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+putBlob url imageBody headers_ successful errorful =
+  withSink $ \sink -> do
+    body_ <- toJSVal imageBody
+    FFI.fetch url "PUT" (Just body_) blobHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    blobHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+----------------------------------------------------------------------------
+-- | Retrieve a multipart resource as t'FormData' via GET.
+--
+-- Sets @Accept: multipart\/form-data@ automatically.
+getFormData
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response FormData -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+getFormData url headers_ successful errorful =
+  withSink $ \sink ->
+    FFI.fetch url "GET" Nothing formDataHeaders_
+      (sink . successful)
+      (sink . errorful)
+      FORM_DATA -- dmj: expected return type
+  where
+    formDataHeaders_ = biasHeaders headers_ [accept =: formData]
+----------------------------------------------------------------------------
+-- | Send a POST request with a t'FormData' body; ignores the response body.
+--
+-- Sets @Content-Type: multipart\/form-data@ automatically.
+postFormData
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> FormData
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action 
+postFormData url body_ headers_ successful errorful =
+  withSink $ \sink -> do
+    bodyVal <- toJSVal body_
+    FFI.fetch url "POST" (Just bodyVal) formDataHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    formDataHeaders_ = biasHeaders headers_ [contentType =: formData]
+----------------------------------------------------------------------------
+-- | Send a PUT request with a t'FormData' body; ignores the response body.
+--
+-- Sets @Content-Type: multipart\/form-data@ automatically.
+putFormData
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> FormData
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error  -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+putFormData url imageBody headers_ successful errorful =
+  withSink $ \sink -> do
+    body_ <- toJSVal imageBody
+    FFI.fetch url "PUT" (Just body_) formDataHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    formDataHeaders_ = biasHeaders headers_ [contentType =: formData]
+----------------------------------------------------------------------------
+-- | Retrieve a binary resource as an t'ArrayBuffer' via GET.
+--
+-- Sets @Accept: application\/octet-stream@ automatically.
+getArrayBuffer
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response ArrayBuffer -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+getArrayBuffer url headers_ successful errorful =
+  withSink $ \sink ->
+    FFI.fetch url "GET" Nothing arrayBufferHeaders_
+      (sink . successful)
+      (sink . errorful)
+      ARRAY_BUFFER -- dmj: expected return type
+  where
+    arrayBufferHeaders_ = biasHeaders headers_ [accept =: octetStream]
+----------------------------------------------------------------------------
+-- | Send a POST request with an t'ArrayBuffer' body; ignores the response body.
+--
+-- Sets @Content-Type: application\/octet-stream@ automatically.
+postArrayBuffer
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> ArrayBuffer
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+postArrayBuffer url body_ headers_ successful errorful =
+  withSink $ \sink -> do
+    bodyVal <- toJSVal body_
+    FFI.fetch url "POST" (Just bodyVal) arrayBufferHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    arrayBufferHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+----------------------------------------------------------------------------
+-- | Send a PUT request with an t'ArrayBuffer' body; ignores the response body.
+--
+-- Sets @Content-Type: application\/octet-stream@ automatically.
+putArrayBuffer
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> ArrayBuffer
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+putArrayBuffer url arrayBuffer_ headers_ successful errorful =
+  withSink $ \sink -> do
+    body_ <- toJSVal arrayBuffer_
+    FFI.fetch url "PUT" (Just body_) arrayBufferHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    arrayBufferHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+----------------------------------------------------------------------------
+-- | Retrieve a binary resource as a t'Uint8Array' via GET.
+--
+-- Sets @Accept: application\/octet-stream@ automatically.
+getUint8Array
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response Uint8Array -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+getUint8Array url headers_ successful errorful =
+  withSink $ \sink ->
+    FFI.fetch url "GET" Nothing uint8ArrayHeaders_
+      (sink . successful)
+      (sink . errorful)
+      BYTES -- expected return type
+  where
+    uint8ArrayHeaders_ = biasHeaders headers_ [accept =: octetStream]
+----------------------------------------------------------------------------
+-- | Send a POST request with a t'Uint8Array' body; ignores the response body.
+--
+-- Sets @Content-Type: application\/octet-stream@ automatically.
+postUint8Array
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Uint8Array
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+postUint8Array url body_ headers_ successful errorful =
+  withSink $ \sink -> do
+    bodyVal <- toJSVal body_
+    FFI.fetch url "POST" (Just bodyVal) uint8ArrayHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    uint8ArrayHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+----------------------------------------------------------------------------
+-- | Send a PUT request with a t'Uint8Array' body; ignores the response body.
+--
+-- Sets @Content-Type: application\/octet-stream@ automatically.
+putUint8Array
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Uint8Array
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+putUint8Array url uint8Array_ headers_ successful errorful =
+  withSink $ \sink -> do
+    body_ <- toJSVal uint8Array_
+    FFI.fetch url "PUT" (Just body_) uint8ArrayHeaders_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+  where
+    uint8ArrayHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+----------------------------------------------------------------------------
+-- | Send a POST request with an t'Image' body; ignores the response body.
+postImage
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Image
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+postImage url body_ headers_ successful errorful =
+  withSink $ \sink -> do
+    bodyVal <- toJSVal body_
+    FFI.fetch url "POST" (Just bodyVal) headers_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+----------------------------------------------------------------------------
+-- | Send a PUT request with an t'Image' body; ignores the response body.
+putImage
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Image
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> (Response () -> action)
+  -- ^ successful callback
+  -> (Response error -> action)
+  -- ^ errorful callback
+  -> Effect context props model action
+putImage url imageBody headers_ successful errorful =
+  withSink $ \sink -> do
+    body_ <- toJSVal imageBody
+    FFI.fetch url "PUT" (Just body_) headers_
+      (sink . successful)
+      (sink . errorful)
+      NONE
+----------------------------------------------------------------------------
+-- | Type synonym for a raw JavaScript request body.
+type Body = JSVal
+----------------------------------------------------------------------------
+-- | HTTP header name @\"Accept\"@.
+-- Use with @=:@ to build request headers, e.g. @accept =: applicationJSON@.
+accept :: MisoString
+accept = "Accept"
+----------------------------------------------------------------------------
+-- | HTTP header name @\"Content-Type\"@.
+-- Use with @=:@ to build request headers, e.g. @contentType =: textPlain@.
+contentType :: MisoString
+contentType = "Content-Type"
+----------------------------------------------------------------------------
+-- | MIME type @\"application\/json\"@.
+applicationJSON :: MisoString
+applicationJSON = "application/json"
+----------------------------------------------------------------------------
+-- | MIME type @\"text\/plain\"@.
+textPlain :: MisoString
+textPlain = "text/plain"
+----------------------------------------------------------------------------
+-- | MIME type @\"application\/octet-stream\"@. Used for binary payloads.
+octetStream :: MisoString
+octetStream = "application/octet-stream"
+----------------------------------------------------------------------------
+-- | MIME type @\"multipart\/form-data\"@.
+formData :: MisoString
+formData = "multipart/form-data"
+----------------------------------------------------------------------------
+-- | Merge two header lists, giving precedence to the first (user-supplied) list.
+--
+-- Duplicate keys in @contentSpecific@ are dropped when the same key already
+-- appears in @userDefined@, allowing callers to override the library's default
+-- @Content-Type@ and @Accept@ headers.
+biasHeaders :: Ord k => [(k, a)] -> [(k, a)] -> [(k, a)]
+biasHeaders userDefined contentSpecific
+  = M.toList
+  $ M.fromList userDefined <> M.fromList contentSpecific
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'getJSON'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+getJSON_
+  :: (FromJSON body, FromJSVal error)
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers
+  -> IO (Either (Response error) (Response body))
+getJSON_ url headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response body)))
+  FFI.fetch url "GET" Nothing jsonHeaders
+    (handleJSON mvar)
+    (putMVar mvar . Left)
+    JSON
+  takeMVar mvar
+  where
+    jsonHeaders = biasHeaders headers_ [accept =: applicationJSON]
+    handleJSON mvar resp@Response {..} =
+      fmap fromJSON <$> fromJSVal body >>= \case
+        Nothing -> do
+          err <- fromJSValUnchecked body
+          putMVar mvar $ Left $ Response
+            { body = err
+            , errorMessage = Just "Not a valid JSON object"
+            , ..
+            }
+        Just (Success result) ->
+          putMVar mvar $ Right resp { body = result }
+        Just (Error msg) -> do
+          err <- fromJSValUnchecked body
+          putMVar mvar $ Left $ Response
+            { body = err
+            , errorMessage = Just (ms msg)
+            , ..
+            }
+{-# INLINE getJSON_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'postJSON'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+postJSON_
+  :: (FromJSVal error, ToJSON body)
+  => MisoString
+  -- ^ url
+  -> body
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+postJSON_ url body_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  bodyVal <- toJSVal (encode body_)
+  FFI.fetch url "POST" (Just bodyVal) jsonHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    jsonHeaders_ = biasHeaders headers_ [contentType =: applicationJSON]
+{-# INLINE postJSON_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'postJSON''.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+postJSON'_
+  :: (FromJSVal error, ToJSON body, FromJSON return)
+  => MisoString
+  -- ^ url
+  -> body
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response return))
+postJSON'_ url body_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response return)))
+  bodyVal <- toJSVal (encode body_)
+  FFI.fetch url "POST" (Just bodyVal) jsonHeaders_
+    (handleJSON mvar)
+    (putMVar mvar . Left)
+    JSON
+  takeMVar mvar
+  where
+    jsonHeaders_ = biasHeaders headers_ [contentType =: applicationJSON, accept =: applicationJSON]
+    handleJSON mvar resp@Response {..} =
+      fmap fromJSON <$> fromJSVal body >>= \case
+        Nothing -> do
+          err <- fromJSValUnchecked body
+          putMVar mvar $ Left $ Response
+            { body = err
+            , errorMessage = Just "Not a valid JSON object"
+            , ..
+            }
+        Just (Success result) ->
+          putMVar mvar $ Right resp { body = result }
+        Just (Error msg) -> do
+          err <- fromJSValUnchecked body
+          putMVar mvar $ Left $ Response
+            { body = err
+            , errorMessage = Just (ms msg)
+            , ..
+            }
+{-# INLINE postJSON'_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'putJSON'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+putJSON_
+  :: (FromJSVal error, ToJSON body)
+  => MisoString
+  -- ^ url
+  -> body
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+putJSON_ url body_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  bodyVal <- toJSVal (encode body_)
+  FFI.fetch url "PUT" (Just bodyVal) jsonHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    jsonHeaders_ = biasHeaders headers_ [contentType =: applicationJSON]
+{-# INLINE putJSON_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'getText'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+getText_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response MisoString))
+getText_ url headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response MisoString)))
+  FFI.fetch url "GET" Nothing textHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    TEXT
+  takeMVar mvar
+  where
+    textHeaders_ = biasHeaders headers_ [accept =: textPlain]
+{-# INLINE getText_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'postText'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+postText_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> MisoString
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+postText_ url body_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  bodyVal <- toJSVal (encode body_)
+  FFI.fetch url "POST" (Just bodyVal) textHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    textHeaders_ = biasHeaders headers_ [contentType =: textPlain]
+{-# INLINE postText_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'putText'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+putText_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> MisoString
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+putText_ url imageBody headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  body_ <- toJSVal imageBody
+  FFI.fetch url "PUT" (Just body_) textHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    textHeaders_ = biasHeaders headers_ [contentType =: textPlain]
+{-# INLINE putText_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'getBlob'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+getBlob_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response Blob))
+getBlob_ url headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response Blob)))
+  FFI.fetch url "GET" Nothing blobHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    BLOB
+  takeMVar mvar
+  where
+    blobHeaders_ = biasHeaders headers_ [accept =: octetStream]
+{-# INLINE getBlob_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'postBlob'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+postBlob_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Blob
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+postBlob_ url body_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  bodyVal <- toJSVal body_
+  FFI.fetch url "POST" (Just bodyVal) blobHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    blobHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+{-# INLINE postBlob_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'putBlob'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+putBlob_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Blob
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+putBlob_ url imageBody headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  body_ <- toJSVal imageBody
+  FFI.fetch url "PUT" (Just body_) blobHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    blobHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+{-# INLINE putBlob_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'getFormData'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+getFormData_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response FormData))
+getFormData_ url headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response FormData)))
+  FFI.fetch url "GET" Nothing formDataHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    FORM_DATA
+  takeMVar mvar
+  where
+    formDataHeaders_ = biasHeaders headers_ [accept =: formData]
+{-# INLINE getFormData_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'postFormData'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+postFormData_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> FormData
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+postFormData_ url body_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  bodyVal <- toJSVal body_
+  FFI.fetch url "POST" (Just bodyVal) formDataHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    formDataHeaders_ = biasHeaders headers_ [contentType =: formData]
+{-# INLINE postFormData_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'putFormData'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+putFormData_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> FormData
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+putFormData_ url imageBody headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  body_ <- toJSVal imageBody
+  FFI.fetch url "PUT" (Just body_) formDataHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    formDataHeaders_ = biasHeaders headers_ [contentType =: formData]
+{-# INLINE putFormData_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'getArrayBuffer'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+getArrayBuffer_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ArrayBuffer))
+getArrayBuffer_ url headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ArrayBuffer)))
+  FFI.fetch url "GET" Nothing arrayBufferHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    ARRAY_BUFFER
+  takeMVar mvar
+  where
+    arrayBufferHeaders_ = biasHeaders headers_ [accept =: octetStream]
+{-# INLINE getArrayBuffer_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'postArrayBuffer'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+postArrayBuffer_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> ArrayBuffer
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+postArrayBuffer_ url body_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  bodyVal <- toJSVal body_
+  FFI.fetch url "POST" (Just bodyVal) arrayBufferHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    arrayBufferHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+{-# INLINE postArrayBuffer_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'putArrayBuffer'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+putArrayBuffer_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> ArrayBuffer
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+putArrayBuffer_ url arrayBuffer_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  body_ <- toJSVal arrayBuffer_
+  FFI.fetch url "PUT" (Just body_) arrayBufferHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    arrayBufferHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+{-# INLINE putArrayBuffer_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'getUint8Array'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+getUint8Array_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response Uint8Array))
+getUint8Array_ url headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response Uint8Array)))
+  FFI.fetch url "GET" Nothing uint8ArrayHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    BYTES
+  takeMVar mvar
+  where
+    uint8ArrayHeaders_ = biasHeaders headers_ [accept =: octetStream]
+{-# INLINE getUint8Array_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'postUint8Array'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+postUint8Array_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Uint8Array
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+postUint8Array_ url body_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  bodyVal <- toJSVal body_
+  FFI.fetch url "POST" (Just bodyVal) uint8ArrayHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    uint8ArrayHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+{-# INLINE postUint8Array_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'putUint8Array'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+putUint8Array_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Uint8Array
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+putUint8Array_ url uint8Array_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  body_ <- toJSVal uint8Array_
+  FFI.fetch url "PUT" (Just body_) uint8ArrayHeaders_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+  where
+    uint8ArrayHeaders_ = biasHeaders headers_ [contentType =: octetStream]
+{-# INLINE putUint8Array_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'postImage'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+postImage_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Image
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+postImage_ url body_ headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  bodyVal <- toJSVal body_
+  FFI.fetch url "POST" (Just bodyVal) headers_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+{-# INLINE postImage_ #-}
+----------------------------------------------------------------------------
+-- | Synchronous API variant of 'putImage'.
+--
+-- Blocks the calling thread until the browser resolves the promise, returning
+-- @'Right' response@ on success or @'Left' response@ on failure.
+--
+-- __Note:__ best used with 'Miso.Effect.io' or 'Miso.Effect.io_', to avoid blocking the scheduler thread.
+--
+-- @since 1.13.0.0
+putImage_
+  :: FromJSVal error
+  => MisoString
+  -- ^ url
+  -> Image
+  -- ^ Body
+  -> [(MisoString, MisoString)]
+  -- ^ headers_
+  -> IO (Either (Response error) (Response ()))
+putImage_ url imageBody headers_ = do
+  mvar <- newEmptyMVar :: IO (MVar (Either (Response error) (Response ())))
+  body_ <- toJSVal imageBody
+  FFI.fetch url "PUT" (Just body_) headers_
+    (putMVar mvar . Right)
+    (putMVar mvar . Left)
+    NONE
+  takeMVar mvar
+{-# INLINE putImage_ #-}
+----------------------------------------------------------------------------
diff --git a/src/Miso/Html.hs b/src/Miso/Html.hs
--- a/src/Miso/Html.hs
+++ b/src/Miso/Html.hs
@@ -1,40 +1,89 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Html
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
 --
--- Example usage:
+-- = Overview
 --
+-- "Miso.Html" is the HTML DSL re-export hub. It collects element smart
+-- constructors, pre-wired event handlers, and the server-side rendering
+-- typeclass into a single convenient import.
+--
+-- The top-level "Miso" module already re-exports everything from
+-- "Miso.Html", so applications that @import Miso@ have the entire HTML
+-- layer in scope without an additional import.  Import "Miso.Html"
+-- directly only when you want the HTML DSL in isolation — for example,
+-- in a view-only library that should not depend on the miso runtime.
+--
+-- __Note:__ "Miso.Html.Property" (@'Miso.Html.Property.id_'@,
+-- @'Miso.Html.Property.class_'@, @'Miso.Html.Property.href_'@, …) is
+-- /not/ re-exported here.  Import it separately, or use the top-level
+-- "Miso" import which includes everything.
+--
+-- = Quick start
+--
 -- @
--- import Miso
+-- import "Miso"
+-- import "Miso.Html.Property" ('Miso.Html.Property.class_')
 --
--- data IntAction = Add | Subtract
+-- data Action = Increment | Decrement | Reset
 --
--- intView :: Int -> View IntAction
--- intView n = div_ [ class_ "main" ] [
---    btn_ [ onClick Add ] [ text_ "+" ]
---  , text_ $ pack (show n)
---  , btn_ [ onClick Subtract ] [ text_ "-" ]
---  ]
+-- view :: Int -> 'Miso.Types.View' Int Action
+-- view n =
+--   'Miso.Html.Element.div_' [ 'Miso.Html.Property.class_' \"counter\" ]
+--     [ 'h1_' [] [ 'Miso.text' \"Counter\" ]
+--     , 'Miso.Html.Element.p_'  [] [ 'Miso.text' ('Miso.String.ms' n) ]
+--     , 'button_' [ @onClick@ Increment ] [ 'Miso.text' \"+\" ]
+--     , 'button_' [ @onClick@ Decrement ] [ 'Miso.text' \"-\" ]
+--     , 'button_' [ @onClick@ Reset ]     [ 'Miso.text' \"Reset\" ]
+--     ]
 -- @
 --
--- More information on how to use `miso` is available on GitHub
+-- = Re-exported modules
 --
--- <http://github.com/dmjio/miso>
+-- ["Miso.Html.Element"]
+--   Smart constructors for every standard HTML element (@'Miso.Html.Element.div_'@,
+--   @'button_'@, @'input_'@, @'table_'@, …).  All names are suffixed
+--   with @_@ to avoid clashing with @Prelude@ identifiers.
 --
+-- ["Miso.Html.Event"]
+--   Pre-wired event-handler attributes (@'onClick'@, @'onInput'@,
+--   @'onKeyDown'@, @'onDrop'@, …).  Covers mouse, keyboard, form, focus,
+--   pointer, drag, touch, media, and lifecycle events.
+--
+-- ["Miso.Html.Render"]
+--   The 'Miso.Html.Render.ToHtml' typeclass for serialising a
+--   'Miso.Types.View' tree to a lazy @ByteString@ of UTF-8 HTML
+--   (server-side rendering \/ SSR).
+--
+-- = See also
+--
+-- * "Miso.Html.Element" — full element reference with groupings
+-- * "Miso.Html.Event" — full event-handler reference with naming conventions
+-- * "Miso.Html.Property" — DOM properties and attributes (@'Miso.Html.Property.id_'@,
+--   @'Miso.Html.Property.class_'@, @'Miso.Html.Property.src_'@, …)
+-- * "Miso.Html.Render" — SSR rendering rules and @-fssr@ flag details
+-- * "Miso.Svg" — SVG element, event, and property combinators
+-- * "Miso.CSS" — structured CSS property DSL
+-- * "Miso" — complete miso API including runtime, routing, and FFI
+--
+-- More information and examples are available at <http://github.com/dmjio/miso>.
+--
 ----------------------------------------------------------------------------
 module Miso.Html
-   ( module Miso.Html.Element
+   ( -- * Elements
+     module Miso.Html.Element
+     -- * Events
    , module Miso.Html.Event
-   , module Miso.Html.Internal
-   , module Miso.Html.Property
+     -- * Rendering
+   , module Miso.Html.Render
    ) where
-
+-----------------------------------------------------------------------------
 import Miso.Html.Element
 import Miso.Html.Event
-import Miso.Html.Internal
-import Miso.Html.Property hiding (form_)
+import Miso.Html.Render
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Html/Element.hs b/src/Miso/Html/Element.hs
--- a/src/Miso/Html/Element.hs
+++ b/src/Miso/Html/Element.hs
@@ -1,492 +1,756 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE LambdaCase        #-}
 {-# LANGUAGE OverloadedStrings #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Html.Element
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
-----------------------------------------------------------------------------
+--
+-- = Overview
+--
+-- "Miso.Html.Element" provides smart constructors for every
+-- <https://developer.mozilla.org/en-US/docs/Web/HTML/Element HTML element>.
+-- Each constructor has the signature:
+--
+-- @
+-- tagName_ :: ['Miso.Types.Attribute' action] -> ['Miso.Types.View' model action] -> 'Miso.Types.View' model action
+-- @
+--
+-- All names are suffixed with @_@ to avoid clashing with Haskell
+-- @Prelude@ names (e.g. 'div_', 'head_', 'map_').
+-- This module is re-exported in its entirety by "Miso.Html" and "Miso".
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+--
+-- view :: Model -> 'Miso.Types.View' Model Action
+-- view m =
+--   'div_' []
+--     [ 'h1_' [] [ 'Miso.text' \"Hello, miso!\" ]
+--     , 'p_'  [ 'Miso.Html.Property.class_' \"intro\" ]
+--              [ 'Miso.text' \"Counter: \", 'Miso.text' ('Miso.String.ms' m) ]
+--     , 'button_' [ 'Miso.Html.Event.onClick' Increment ] [ 'Miso.text' \"+\" ]
+--     ]
+-- @
+--
+-- = Element groups
+--
+-- * __Document metadata__: 'html_', 'head_', 'base_', 'link_', 'meta_',
+--   'style_', 'title_', 'doctype_'
+-- * __Sectioning__: 'body_', 'address_', 'article_', 'aside_', 'footer_',
+--   'header_', 'h1_'–'h6_', 'hgroup_', 'main_', 'nav_', 'section_', 'search_'
+-- * __Text content__: 'blockquote_', 'dd_', 'div_', 'dl_', 'dt_',
+--   'figcaption_', 'figure_', 'hr_', 'li_', 'menu_', 'ol_', 'p_', 'pre_',
+--   'ul_'
+-- * __Inline semantics__: 'a_', 'abbr_', 'b_', 'bdi_', 'bdo_', 'br_',
+--   'cite_', 'code_', 'data_', 'dfn_', 'em_', 'i_', 'kbd_', 'mark_',
+--   'q_', 'rp_', 'rt_', 'ruby_', 's_', 'samp_', 'small_', 'span_',
+--   'strong_', 'sub_', 'sup_', 'time_', 'u_', 'var_', 'wbr_'
+-- * __Embedded content__: 'audio_', 'canvas_', 'embed_', 'iframe_',
+--   'img_', 'map_', 'object_', 'picture_', @portal_@, 'source_',
+--   'track_', 'video_'
+-- * __Scripting__: 'noscript_', 'script_'
+-- * __Edits__: 'del_', 'ins_'
+-- * __Table__: 'caption_', 'col_', 'colgroup_', 'table_', 'tbody_',
+--   'td_', 'tfoot_', 'th_', 'thead_', 'tr_'
+-- * __Forms__: 'button_', 'datalist_', 'fieldset_', 'form_', 'input_',
+--   'label_', 'legend_', 'meter_', 'optgroup_', 'option_', 'output_',
+--   'progress_', 'select_', 'textarea_'
+-- * __Interactive__: 'details_', 'dialog_', 'summary_'
+-- * __Custom__: 'nodeHtml' for any tag name not listed above
+--
+-- = See also
+--
+-- * "Miso.Html.Property" — 'Miso.Html.Property.id_', 'Miso.Html.Property.class_', 'Miso.Html.Property.src_', …
+-- * "Miso.Html.Event" — 'Miso.Html.Event.onClick', 'Miso.Html.Event.onInput', …
+-- * "Miso.Html.Render" — server-side HTML rendering via 'Miso.Html.Render.ToHtml'
+-- * "Miso.Svg.Element" — SVG element constructors
+-----------------------------------------------------------------------------
 module Miso.Html.Element
-  ( -- * Construct an Element
+  ( -- ** Smart constructors
       nodeHtml
-    , nodeHtmlKeyed
-    -- * Headers
+    -- ** Document metadata
+    , html_
+    , doctype_
+    , base_
+    , head_
+    , link_
+    , meta_
+    , style_
+    , title_
+    -- ** Sectioning root
+    , body_
+    -- ** Content sectioning
+    , address_
+    , article_
+    , aside_
+    , footer_
+    , header_
     , h1_
     , h2_
     , h3_
     , h4_
     , h5_
     , h6_
-    -- * Grouping Content
+    , hgroup_
+    , main_
+    , nav_
+    , section_
+    , search_
+    -- ** Text content
+    , blockquote_
+    , dd_
     , div_
-    , p_
+    , dl_
+    , dt_
+    , figcaption_
+    , figure_
     , hr_
+    , li_
+    , menu_
+    , ol_
+    , p_
     , pre_
-    , blockquote_
-    -- * Text
+    , ul_
+    -- ** Inline text semantics
+    , a_
+    , abbr_
+    , b_
+    , bdi_
+    , bdo_
+    , br_
+    , cite_
     , code_
+    , data_
+    , dfn_
     , em_
+    , i_
+    , kbd_
+    , mark_
+    , q_
+    , rp_
+    , rt_
+    , ruby_
+    , s_
+    , samp_
+    , small_
     , span_
-    , a_
     , strong_
-    , i_
-    , b_
-    , u_
     , sub_
     , sup_
-    , br_
-    -- * Lists
-    , ol_
-    , ul_
-    , li_
-    , liKeyed_
-    , dl_
-    , dt_
-    , dd_
-    -- * Embedded Content
+    , time_
+    , u_
+    , var_
+    , wbr_
+    -- ** Image and multimedia
+    , area_
+    , audio_
     , img_
+    , map_
+    , track_
+    , video_
+    -- ** Embedded content
+    , embed_
+    , fencedframe_
     , iframe_
+    , object_
+    , picture_
+    , source_
+    -- ** Scripting
     , canvas_
-    , math_
+    , noscript_
     , script_
-    , link_
-    -- * Inputs
-    , select_
-    , option_
-    , textarea_
-    , form_
-    , input_
-    , button_
-    -- * Sections
-    , section_
-    , header_
-    , footer_
-    , nav_
-    , article_
-    , aside_
-    , address_
-    , main_
-    , body_
-    -- * Figures
-    , figure_
-    , figcaption_
-    -- * Tables
-    , table_
+    -- ** Demarcating edits
+    , del_
+    , ins_
+    -- ** Table content
     , caption_
-    , colgroup_
     , col_
+    , colgroup_
+    , table_
     , tbody_
-    , thead_
-    , tfoot_
-    , tr_
-    , trKeyed_
     , td_
+    , tfoot_
     , th_
-    -- * Less common elements
-    , label_
+    , thead_
+    , tr_
+    -- ** Forms
+    , button_
+    , datalist_
     , fieldset_
+    , form_
+    , input_
+    , label_
     , legend_
-    , datalist_
+    , meter_
     , optgroup_
-    , keygen_
+    , option_
     , output_
     , progress_
-    , meter_
-    , center_
-    -- * Audio and Video
-    , audio_
-    , video_
-    , source_
-    , track_
-    -- * Embedded objects
-    , embed_
-    , object_
-    , param_
-    -- * Text edits
-    , ins_
-    , del_
-    -- * Semantic text
-    , small_
-    , cite_
-    , dfn_
-    , abbr_
-    , time_
-    , var_
-    , samp_
-    , kbd_
-    , q_
-    , s_
-    -- * Less common tags
-    , mark_
-    , ruby_
-    , rt_
-    , rp_
-    , bdi_
-    , bdo_
-    , wbr_
-    -- * Interactive elemnts
+    , select_
+    , textarea_
+    -- ** Interactive elements
     , details_
+    , dialog_
     , summary_
-    , menuitem_
-    , menu_
+    -- ** Web components
+    , slot_
+    , template_
+    -- * SVG
+    , svg_
     ) where
-
-import           Miso.Html.Internal
-import           Miso.String (MisoString)
-
--- | Used to construct `VNode`'s in `View`
-nodeHtml :: MisoString -> [Attribute action] -> [View action] -> View action
-nodeHtml = flip (node HTML) Nothing
-
--- | Construct a node with a `Key`
-nodeHtmlKeyed :: MisoString -> Key -> [Attribute action] -> [View action] -> View action
-nodeHtmlKeyed name = node HTML name . pure
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div
-div_ :: [Attribute action] -> [View action] -> View action
-div_  = nodeHtml "div"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table
-table_ :: [Attribute action] -> [View action] -> View action
-table_  = nodeHtml "table"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/thead
-thead_ :: [Attribute action] -> [View action] -> View action
-thead_  = nodeHtml "thead"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tbody
-tbody_ :: [Attribute action] -> [View action] -> View action
-tbody_  = nodeHtml "tbody"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr
-tr_ :: [Attribute action] -> [View action] -> View action
-tr_  = nodeHtml "tr"
-
--- | Contains `Key`, inteded to be used for child replacement patch
---
--- <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr>
-
-trKeyed_ :: Key -> [Attribute action] -> [View action] -> View action
-trKeyed_ = node HTML "tr" . pure
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/th
-th_ :: [Attribute action] -> [View action] -> View action
-th_  = nodeHtml "th"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td
-td_ :: [Attribute action] -> [View action] -> View action
-td_  = nodeHtml "td"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tfoot
-tfoot_ :: [Attribute action] -> [View action] -> View action
-tfoot_  = nodeHtml "tfoot"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/section
-section_ :: [Attribute action] -> [View action] -> View action
-section_  = nodeHtml "section"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/header
-header_ :: [Attribute action] -> [View action] -> View action
-header_  = nodeHtml "header"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/footer
-footer_ :: [Attribute action] -> [View action] -> View action
-footer_  = nodeHtml "footer"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button
-button_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+#ifdef VANILLA
+import           Miso.JSON (Value(String))
+#endif
+import           Miso.Types
+-----------------------------------------------------------------------------
+import           Miso.Svg.Element (svg_)
+-----------------------------------------------------------------------------
+-- | Low-level helper used to construct 'HTML' 'node' in 'Miso.Types.View'.
+-- Almost all functions in this module, like 'div_', 'table_' etc. are defined in terms of it.
+nodeHtml :: MisoString -> [Attribute model action] -> [View context model action] -> View context model action
+nodeHtml nodeName = node HTML nodeName
+-----------------------------------------------------------------------------
+-- | [\<div\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/div)
+div_ :: [Attribute model action] -> [View context model action] -> View context model action
+div_ = nodeHtml "div"
+-----------------------------------------------------------------------------
+-- | [\<table\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/table)
+table_ :: [Attribute model action] -> [View context model action] -> View context model action
+table_ = nodeHtml "table"
+-----------------------------------------------------------------------------
+-- | [\<thead\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/thead)
+thead_ :: [Attribute model action] -> [View context model action] -> View context model action
+thead_ = nodeHtml "thead"
+-----------------------------------------------------------------------------
+-- | [\<tbody\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/tbody)
+tbody_ :: [Attribute model action] -> [View context model action] -> View context model action
+tbody_ = nodeHtml "tbody"
+-----------------------------------------------------------------------------
+-- | [\<tr\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/tr)
+tr_ :: [Attribute model action] -> [View context model action] -> View context model action
+tr_ = nodeHtml "tr"
+-----------------------------------------------------------------------------
+-- | [\<th\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/th)
+th_ :: [Attribute model action] -> [View context model action] -> View context model action
+th_ = nodeHtml "th"
+-----------------------------------------------------------------------------
+-- | [\<td\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/td)
+td_ :: [Attribute model action] -> [View context model action] -> View context model action
+td_ = nodeHtml "td"
+-----------------------------------------------------------------------------
+-- | [\<tfoot\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/tfoot)
+tfoot_ :: [Attribute model action] -> [View context model action] -> View context model action
+tfoot_ = nodeHtml "tfoot"
+-----------------------------------------------------------------------------
+-- | [\<section\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/section)
+section_ :: [Attribute model action] -> [View context model action] -> View context model action
+section_ = nodeHtml "section"
+-----------------------------------------------------------------------------
+-- | [\<header\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/header)
+header_ :: [Attribute model action] -> [View context model action] -> View context model action
+header_ = nodeHtml "header"
+-----------------------------------------------------------------------------
+-- | [\<footer\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/footer)
+footer_ :: [Attribute model action] -> [View context model action] -> View context model action
+footer_ = nodeHtml "footer"
+-----------------------------------------------------------------------------
+-- | [\<button\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button)
+button_ :: [Attribute model action] -> [View context model action] -> View context model action
 button_ = nodeHtml "button"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form
-form_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<form\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form)
+--
+-- For usage in a real-world application with the @onSubmit@ event.
+--
+-- > view :: Model -> View context model action
+-- > view model = form_ [ onSubmit NoOp ] [ input [ type_ "submit" ] ]
+--
+-- Note: @onSubmit@ will use @preventDefault = True@. This will keep
+-- the form from submitting to the server.
+--
+form_ :: [Attribute model action] -> [View context model action] -> View context model action
 form_ = nodeHtml "form"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p
-p_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<p\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/p)
+p_ :: [Attribute model action] -> [View context model action] -> View context model action
 p_ = nodeHtml "p"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/s
-s_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<s\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/s)
+s_ :: [Attribute model action] -> [View context model action] -> View context model action
 s_ = nodeHtml "s"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul
-ul_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<ul\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ul)
+ul_ :: [Attribute model action] -> [View context model action] -> View context model action
 ul_ = nodeHtml "ul"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span
-span_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<span\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/span)
+span_ :: [Attribute model action] -> [View context model action] -> View context model action
 span_ = nodeHtml "span"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong
-strong_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<strong\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/strong)
+strong_ :: [Attribute model action] -> [View context model action] -> View context model action
 strong_ = nodeHtml "strong"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li
-li_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<li\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/li)
+li_ :: [Attribute model action] -> [View context model action] -> View context model action
 li_ = nodeHtml "li"
-
--- | Contains `Key`, inteded to be used for child replacement patch
---
--- <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li>
---
-liKeyed_ :: Key -> [Attribute action] -> [View action] -> View action
-liKeyed_ = node HTML "li" . pure
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1
-h1_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<h1\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)
+h1_ :: [Attribute model action] -> [View context model action] -> View context model action
 h1_ = nodeHtml "h1"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2
-h2_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<h2\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)
+h2_ :: [Attribute model action] -> [View context model action] -> View context model action
 h2_ = nodeHtml "h2"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h3
-h3_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<h3\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)
+h3_ :: [Attribute model action] -> [View context model action] -> View context model action
 h3_ = nodeHtml "h3"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h4
-h4_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<h4\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)
+h4_ :: [Attribute model action] -> [View context model action] -> View context model action
 h4_ = nodeHtml "h4"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h5
-h5_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<h5\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)
+h5_ :: [Attribute model action] -> [View context model action] -> View context model action
 h5_ = nodeHtml "h5"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h6
-h6_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<h6\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)
+h6_ :: [Attribute model action] -> [View context model action] -> View context model action
 h6_ = nodeHtml "h6"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hr
-hr_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<hr\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/hr)
+hr_ :: [Attribute model action] -> View context model action
 hr_ = flip (nodeHtml "hr") []
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre
-pre_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<pre\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/pre)
+pre_ :: [Attribute model action] -> [View context model action] -> View context model action
 pre_ = nodeHtml "pre"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
-input_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<input\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input)
+input_ :: [Attribute model action] -> View context model action
 input_ = flip (nodeHtml "input") []
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label
-label_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<label\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/label)
+label_ :: [Attribute model action] -> [View context model action] -> View context model action
 label_ = nodeHtml "label"
-
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a
-a_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<a\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a)
+a_ :: [Attribute model action] -> [View context model action] -> View context model action
 a_ = nodeHtml "a"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark
-mark_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<mark\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/mark)
+mark_ :: [Attribute model action] -> [View context model action] -> View context model action
 mark_ = nodeHtml "mark"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ruby
-ruby_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<ruby\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ruby)
+ruby_ :: [Attribute model action] -> [View context model action] -> View context model action
 ruby_ = nodeHtml "ruby"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rt
-rt_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<rt\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/rt)
+rt_ :: [Attribute model action] -> [View context model action] -> View context model action
 rt_ = nodeHtml "rt"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rp
-rp_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<rp\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/rp)
+rp_ :: [Attribute model action] -> [View context model action] -> View context model action
 rp_ = nodeHtml "rp"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdi
-bdi_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<bdi\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/bdi)
+bdi_ :: [Attribute model action] -> [View context model action] -> View context model action
 bdi_ = nodeHtml "bdi"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdo
-bdo_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<bdo\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/bdo)
+bdo_ :: [Attribute model action] -> [View context model action] -> View context model action
 bdo_ = nodeHtml "bdo"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr
-wbr_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<wbr\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/wbr)
+wbr_ :: [Attribute model action] -> View context model action
 wbr_ = flip (nodeHtml "wbr") []
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details
-details_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<details\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details)
+details_ :: [Attribute model action] -> [View context model action] -> View context model action
 details_ = nodeHtml "details"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary
-summary_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<summary\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/summary)
+summary_ :: [Attribute model action] -> [View context model action] -> View context model action
 summary_ = nodeHtml "summary"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem
-menuitem_ :: [Attribute action] -> [View action] -> View action
-menuitem_ = nodeHtml "menuitem"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu
-menu_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<menu\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/menu)
+menu_ :: [Attribute model action] -> [View context model action] -> View context model action
 menu_ = nodeHtml "menu"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset
-fieldset_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<fieldset\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/fieldset)
+fieldset_ :: [Attribute model action] -> [View context model action] -> View context model action
 fieldset_ = nodeHtml "fieldset"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/legend
-legend_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<legend\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/legend)
+legend_ :: [Attribute model action] -> [View context model action] -> View context model action
 legend_ = nodeHtml "legend"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist
-datalist_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<datalist\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/datalist)
+datalist_ :: [Attribute model action] -> [View context model action] -> View context model action
 datalist_ = nodeHtml "datalist"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup
-optgroup_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<optgroup\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/optgroup)
+optgroup_ :: [Attribute model action] -> [View context model action] -> View context model action
 optgroup_ = nodeHtml "optgroup"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen
-keygen_ :: [Attribute action] -> [View action] -> View action
-keygen_ = nodeHtml "keygen"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/output
-output_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<output\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/output)
+output_ :: [Attribute model action] -> [View context model action] -> View context model action
 output_ = nodeHtml "output"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress
-progress_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<progress\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/progress)
+progress_ :: [Attribute model action] -> [View context model action] -> View context model action
 progress_ = nodeHtml "progress"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meter
-meter_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<meter\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meter)
+meter_ :: [Attribute model action] -> [View context model action] -> View context model action
 meter_ = nodeHtml "meter"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/center
-center_ :: [Attribute action] -> [View action] -> View action
-center_ = nodeHtml "center"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio
-audio_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<audio\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/audio)
+audio_ :: [Attribute model action] -> [View context model action] -> View context model action
 audio_ = nodeHtml "audio"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video
-video_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<video\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/video)
+video_ :: [Attribute model action] -> [View context model action] -> View context model action
 video_ = nodeHtml "video"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source
-source_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<source\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/source)
+source_ :: [Attribute model action] -> View context model action
 source_ = flip (nodeHtml "source") []
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track
-track_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<track\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/track)
+track_ :: [Attribute model action] -> View context model action
 track_ = flip (nodeHtml "track") []
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/embed
-embed_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<embed\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/embed)
+embed_ :: [Attribute model action] -> View context model action
 embed_ = flip (nodeHtml "embed") []
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object
-object_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<object\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/object)
+object_ :: [Attribute model action] -> [View context model action] -> View context model action
 object_ = nodeHtml "object"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/param
-param_ :: [Attribute action] -> View action
-param_ = flip (nodeHtml "param") []
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ins
-ins_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<ins\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ins)
+ins_ :: [Attribute model action] -> [View context model action] -> View context model action
 ins_ = nodeHtml "ins"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/del
-del_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<del\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/del)
+del_ :: [Attribute model action] -> [View context model action] -> View context model action
 del_ = nodeHtml "del"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/small
-small_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<small\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/small)
+small_ :: [Attribute model action] -> [View context model action] -> View context model action
 small_ = nodeHtml "small"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite
-cite_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<cite\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/cite)
+cite_ :: [Attribute model action] -> [View context model action] -> View context model action
 cite_ = nodeHtml "cite"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dfn
-dfn_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<dfn\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dfn)
+dfn_ :: [Attribute model action] -> [View context model action] -> View context model action
 dfn_ = nodeHtml "dfn"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/abbr
-abbr_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<abbr\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/abbr)
+abbr_ :: [Attribute model action] -> [View context model action] -> View context model action
 abbr_ = nodeHtml "abbr"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time
-time_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<time\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/time)
+time_ :: [Attribute model action] -> [View context model action] -> View context model action
 time_ = nodeHtml "time"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/var
-var_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<var\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/var)
+var_ :: [Attribute model action] -> [View context model action] -> View context model action
 var_ = nodeHtml "var"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/samp
-samp_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<samp\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/samp)
+samp_ :: [Attribute model action] -> [View context model action] -> View context model action
 samp_ = nodeHtml "samp"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd
-kbd_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<kbd\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/kbd)
+kbd_ :: [Attribute model action] -> [View context model action] -> View context model action
 kbd_ = nodeHtml "kbd"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/caption
-caption_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<caption\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/caption)
+caption_ :: [Attribute model action] -> [View context model action] -> View context model action
 caption_ = nodeHtml "caption"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/colgroup
-colgroup_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<colgroup\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/colgroup)
+colgroup_ :: [Attribute model action] -> [View context model action] -> View context model action
 colgroup_ = nodeHtml "colgroup"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/col
-col_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<col\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/col)
+col_ :: [Attribute model action] -> View context model action
 col_ = flip (nodeHtml "col") []
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav
-nav_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<nav\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/nav)
+nav_ :: [Attribute model action] -> [View context model action] -> View context model action
 nav_ = nodeHtml "nav"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article
-article_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<article\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/article)
+article_ :: [Attribute model action] -> [View context model action] -> View context model action
 article_ = nodeHtml "article"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside
-aside_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<aside\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/aside)
+aside_ :: [Attribute model action] -> [View context model action] -> View context model action
 aside_ = nodeHtml "aside"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/address
-address_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<address\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/address)
+address_ :: [Attribute model action] -> [View context model action] -> View context model action
 address_ = nodeHtml "address"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main
-main_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<main\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/main)
+main_ :: [Attribute model action] -> [View context model action] -> View context model action
 main_ = nodeHtml "main"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body
-body_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<body\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/body)
+body_ :: [Attribute model action] -> [View context model action] -> View context model action
 body_ = nodeHtml "body"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure
-figure_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<figure\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/figure)
+figure_ :: [Attribute model action] -> [View context model action] -> View context model action
 figure_ = nodeHtml "figure"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figcaption
-figcaption_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<figcaption\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/figcaption)
+figcaption_ :: [Attribute model action] -> [View context model action] -> View context model action
 figcaption_ = nodeHtml "figcaption"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl
-dl_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<dl\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dl)
+dl_ :: [Attribute model action] -> [View context model action] -> View context model action
 dl_ = nodeHtml "dl"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt
-dt_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<dt\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dt)
+dt_ :: [Attribute model action] -> [View context model action] -> View context model action
 dt_ = nodeHtml "dt"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd
-dd_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<dd\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dd)
+dd_ :: [Attribute model action] -> [View context model action] -> View context model action
 dd_ = nodeHtml "dd"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img
-img_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<img\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img)
+img_ :: [Attribute model action] -> View context model action
 img_ = flip (nodeHtml "img") []
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe
-iframe_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<iframe\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/iframe)
+iframe_ :: [Attribute model action] -> [View context model action] -> View context model action
 iframe_ = nodeHtml "iframe"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas
-canvas_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<canvas\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/canvas)
+--
+-- Note this just renders a canvas element.
+-- See also 'Miso.Canvas.canvas_' which supports canvas drawing DSL.
+canvas_ :: [Attribute model action] -> [View context model action] -> View context model action
 canvas_ = nodeHtml "canvas"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/math
-math_ :: [Attribute action] -> [View action] -> View action
-math_ = nodeHtml "math"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select
-select_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<select\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select)
+select_ :: [Attribute model action] -> [View context model action] -> View context model action
 select_ = nodeHtml "select"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option
-option_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<option\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/option)
+option_ :: [Attribute model action] -> [View context model action] -> View context model action
 option_ = nodeHtml "option"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
-textarea_ :: [Attribute action] -> [View action] -> View action
-textarea_ = nodeHtml "textarea"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sub
-sub_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<textarea\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/textarea)
+--
+-- @
+-- textarea_ [ id_ "txt", P.value_ (model ^. txt) ]
+-- @
+--
+-- When compiling on the server, this combinator will render HTML as \<textarea\>text\<\/textarea\>.
+--
+-- @since 1.9.0.0
+textarea_ :: [Attribute model action] -> View context model action
+#ifdef VANILLA
+textarea_ attrs = nodeHtml "textarea" newAttrs
+  [ text x
+  | Property "value" (String x) <- attrs
+  ] where
+      newAttrs = flip filter attrs $ \case
+        Property "value" _ -> False
+        _ -> True
+#else
+textarea_ = flip (nodeHtml "textarea") []
+#endif
+-----------------------------------------------------------------------------
+-- | [\<sub\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/sub)
+sub_ :: [Attribute model action] -> [View context model action] -> View context model action
 sub_ = nodeHtml "sub"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sup
-sup_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<sup\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/sup)
+sup_ :: [Attribute model action] -> [View context model action] -> View context model action
 sup_ = nodeHtml "sup"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/br
-br_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<br\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/br)
+br_ :: [Attribute model action] -> View context model action
 br_ = flip (nodeHtml "br") []
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol
-ol_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<ol\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ol)
+ol_ :: [Attribute model action] -> [View context model action] -> View context model action
 ol_ = nodeHtml "ol"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote
-blockquote_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<blockquote\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/blockquote)
+blockquote_ :: [Attribute model action] -> [View context model action] -> View context model action
 blockquote_ = nodeHtml "blockquote"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code
-code_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<code\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/code)
+code_ :: [Attribute model action] -> [View context model action] -> View context model action
 code_ = nodeHtml "code"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em
-em_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<em\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/em)
+em_ :: [Attribute model action] -> [View context model action] -> View context model action
 em_ = nodeHtml "em"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/i
-i_ :: [Attribute action] -> [View action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<i\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/i)
+i_ :: [Attribute model action] -> [View context model action] -> View context model action
 i_ = nodeHtml "i"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/b
-b_ :: [Attribute actbon] -> [View actbon] -> View actbon
+-----------------------------------------------------------------------------
+-- | [\<b\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/b)
+b_ :: [Attribute model action] -> [View context model action] -> View context model action
 b_ = nodeHtml "b"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u
-u_ :: [Attribute actuon] -> [View actuon] -> View actuon
+-----------------------------------------------------------------------------
+-- | [\<u\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/u)
+u_ :: [Attribute model action] -> [View context model action] -> View context model action
 u_ = nodeHtml "u"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q
-q_ :: [Attribute actqon] -> [View actqon] -> View actqon
+-----------------------------------------------------------------------------
+-- | [\<q\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/q)
+q_ :: [Attribute model action] -> [View context model action] -> View context model action
 q_ = nodeHtml "q"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
-script_ :: [Attribute action] -> [View action] -> View action
-script_ = nodeHtml "script"
--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link
-link_ :: [Attribute action] -> View action
+-----------------------------------------------------------------------------
+-- | [\<link\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/link)
+link_ :: [Attribute model action] -> View context model action
 link_ = flip (nodeHtml "link") []
+-----------------------------------------------------------------------------
+-- | [\<style\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/style)
+--
+-- This takes the raw text to be put in the style tag.
+--
+-- That means that if any part of the text is not trusted there's
+-- a potential [CSS injection](https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/11-Client-side_Testing/05-Testing_for_CSS_Injection).
+--
+-- You can also easily shoot yourself in the foot with something like:
+--
+-- @
+-- style_ [] "\</style\>"
+-- @
+--
+-- You can use 'Miso.CSS.style_' as a safer anternative.
+style_ :: [Attribute model action] -> MisoString -> View context model action
+style_ attrs rawText = node HTML "style" attrs [text rawText]
+-----------------------------------------------------------------------------
+-- | [\<script\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script)
+--
+-- This takes the raw text to be put in the script tag.
+--
+-- That means that if any part of the text is not trusted there's
+-- a potential JavaScript injection. Read more at
+-- https://owasp.org/www-community/attacks/xss/
+--
+-- You can also easily shoot yourself in the foot with something like:
+--
+-- @'script_' [] "\</script\>"@
+script_ :: [Attribute model action] -> MisoString -> View context model action
+script_ attrs rawText = node HTML "script" attrs [textRaw rawText]
+-----------------------------------------------------------------------------
+-- | [\<doctype\>](https://developer.mozilla.org/en-US/docs/Glossary/Doctype)
+doctype_ :: View context model action
+doctype_ = nodeHtml "doctype" [] []
+-----------------------------------------------------------------------------
+-- | [\<html\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/html)
+html_ :: [Attribute model action] -> [View context model action] -> View context model action
+html_ = nodeHtml "html"
+-----------------------------------------------------------------------------
+-- | [\<head\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/head)
+head_ :: [Attribute model action] -> [View context model action] -> View context model action
+head_ = nodeHtml "head"
+-----------------------------------------------------------------------------
+-- | [\<meta\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta)
+meta_ :: [Attribute model action] -> View context model action
+meta_ = flip (nodeHtml "meta") []
+-----------------------------------------------------------------------------
+-- | [\<area\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/area)
+--
+-- @since 1.9.0.0
+area_ :: [Attribute model action] -> View context model action
+area_ = flip (nodeHtml "area") []
+-----------------------------------------------------------------------------
+-- | [\<base\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/base)
+--
+-- @since 1.9.0.0
+base_ :: [Attribute model action] -> View context model action
+base_ = flip (nodeHtml "base") []
+-----------------------------------------------------------------------------
+-- | [\<data\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/data)
+--
+-- @since 1.9.0.0
+data_ :: [Attribute model action] -> [View context model action] -> View context model action
+data_ = nodeHtml "data"
+-----------------------------------------------------------------------------
+-- | [\<dialog\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog)
+--
+-- @since 1.9.0.0
+dialog_ :: [Attribute model action] -> [View context model action] -> View context model action
+dialog_ = nodeHtml "dialog"
+-----------------------------------------------------------------------------
+-- | [\<fencedframe\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/fencedframe)
+--
+-- @since 1.9.0.0
+fencedframe_ :: [Attribute model action] -> [View context model action] -> View context model action
+fencedframe_ = nodeHtml "fencedframe"
+-----------------------------------------------------------------------------
+-- | [\<hgroup\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/hgroup)
+--
+-- @since 1.9.0.0
+hgroup_ :: [Attribute model action] -> [View context model action] -> View context model action
+hgroup_ = nodeHtml "hgroup"
+-----------------------------------------------------------------------------
+-- | [\<map\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/map)
+--
+-- @since 1.9.0.0
+map_ :: [Attribute model action] -> [View context model action] -> View context model action
+map_ = nodeHtml "map"
+-----------------------------------------------------------------------------
+-- | [\<noscript\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/noscript)
+--
+-- @since 1.9.0.0
+noscript_ :: [Attribute model action] -> [View context model action] -> View context model action
+noscript_ = nodeHtml "noscript"
+-----------------------------------------------------------------------------
+-- | [\<picture\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/picture)
+--
+-- @since 1.9.0.0
+picture_ :: [Attribute model action] -> [View context model action] -> View context model action
+picture_ = nodeHtml "picture"
+-----------------------------------------------------------------------------
+-- | [\<search\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/search)
+--
+-- @since 1.9.0.0
+search_ :: [Attribute model action] -> [View context model action] -> View context model action
+search_ = nodeHtml "search"
+-----------------------------------------------------------------------------
+-- | [\<slot\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/slot)
+--
+-- @since 1.9.0.0
+slot_ :: [Attribute model action] -> [View context model action] -> View context model action
+slot_ = nodeHtml "slot"
+-----------------------------------------------------------------------------
+-- | [\<template\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/template)
+--
+-- @since 1.9.0.0
+template_ :: [Attribute model action] -> [View context model action] -> View context model action
+template_ = nodeHtml "template"
+-----------------------------------------------------------------------------
+-- | [\<title\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/title)
+--
+-- @since 1.9.0.0
+title_ :: [Attribute model action] -> [View context model action] -> View context model action
+title_ = nodeHtml "title"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Html/Event.hs b/src/Miso/Html/Event.hs
--- a/src/Miso/Html/Event.hs
+++ b/src/Miso/Html/Event.hs
@@ -1,165 +1,798 @@
-{-# LANGUAGE RankNTypes                #-}
-{-# LANGUAGE OverloadedStrings         #-}
-{-# LANGUAGE FlexibleContexts          #-}
-{-# LANGUAGE FlexibleInstances         #-}
-{-# LANGUAGE MultiParamTypeClasses     #-}
-{-# LANGUAGE DataKinds                 #-}
-{-# LANGUAGE KindSignatures            #-}
-{-# LANGUAGE TemplateHaskell           #-}
-{-# LANGUAGE ExistentialQuantification #-}
-{-# LANGUAGE CPP                       #-}
-{-# LANGUAGE TypeFamilies #-}
 -----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Html.Event
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
 --
-----------------------------------------------------------------------------
+-- = Overview
+--
+-- "Miso.Html.Event" provides pre-wired event-handler 'Miso.Types.Attribute'
+-- values for the most common browser events. Each handler is built on the
+-- lower-level 'Miso.Event.on' \/ 'Miso.Event.onWithOptions' primitives from
+-- "Miso.Event".
+--
+-- This module is re-exported in its entirety by "Miso.Html" and "Miso".
+--
+-- = Naming conventions
+--
+-- Handlers follow a consistent naming pattern:
+--
+-- [@onXxx action@] fires @action@; no event data extracted
+-- [@onXxxWith (a -> action)@] passes extracted event data or 'Miso.Effect.DOMRef'
+-- [@onXxxWithOptions opts act@] adds 'Miso.Event.Types.Options' (@preventDefault@ \/ @stopPropagation@) before firing
+-- [@onXxxCapture action@] registers in the capture phase instead of bubble
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+--
+-- view :: Model -> 'Miso.Types.View' Model Action
+-- view m =
+--   'Miso.Html.Element.div_' []
+--     [ 'Miso.Html.Element.button_' [ 'onClick' Increment ]        [ 'Miso.text' \"+\" ]
+--     , 'Miso.Html.Element.input_'  [ 'onInput' SetText
+--                     , 'Miso.Html.Property.value_' m.text ]      []
+--     , 'Miso.Html.Element.form_'   [ 'onSubmit' Submit ]         []  -- preventDefault by default
+--     ]
+-- @
+--
+-- = Event groups
+--
+-- * __Mouse__: 'onClick', 'onClickCapture', 'onClickWith', 'onClickWithOptions',
+--   'onClickPrevent', 'onDoubleClick', 'onDoubleClickWith',
+--   'onMouseDown', 'onMouseUp', 'onMouseEnter', 'onMouseLeave',
+--   'onMouseOver', 'onMouseOut', 'onContextMenuWithOptions'
+-- * __Keyboard__: 'onKeyDown', 'onKeyDownWithInfo', 'onKeyPress', 'onKeyUp', 'onEnter'
+-- * __Form__: 'onInput', 'onInputWith', 'onChange', 'onChangeWith',
+--   'onChecked', 'onSubmit', 'onSelect'
+-- * __Focus__: 'onFocus', 'onBlur'
+-- * __Drag__: 'onDrag', 'onDragStart', 'onDragEnd', 'onDragEnter',
+--   'onDragLeave', 'onDragOver', 'onDrop' (and @WithOptions@ variants)
+-- * __Pointer__: 'onPointerDown', 'onPointerUp', 'onPointerEnter',
+--   'onPointerLeave', 'onPointerOver', 'onPointerOut',
+--   'onPointerCancel', 'onPointerMove'
+-- * __Media__: 'onPlay', 'onPause', 'onEnded', 'onTimeUpdate',
+--   'onVolumeChange', 'onLoadedData', 'onLoadedMetadata', … (and @With@ variants)
+-- * __Touch__: 'onTouchStart', 'onTouchEnd', 'onTouchMove',
+--   'onTouchCancel' (and @WithOptions@ variants)
+-- * __Lifecycle__: 'onLoad', 'onUnload', 'onError'
+--
+-- = Notes
+--
+-- * 'onSubmit' enables @preventDefault@ by default to suppress the native
+--   form submission.
+-- * 'onEnter' is a convenience wrapper around 'onKeyDown' that fires
+--   different actions depending on whether @keyCode == 13@.
+-- * The @WithOptions@ variants require 'Miso.Event.Types.defaultEvents' (or a
+--   superset) to include the relevant event name in the component's @events@ map.
+--
+-- = See also
+--
+-- * "Miso.Event" — 'Miso.Event.on', 'Miso.Event.onCapture', 'Miso.Event.onWithOptions'
+-- * "Miso.Event.Decoder" — 'Miso.Event.Decoder.Decoder' for custom event extraction
+-- * "Miso.Event.Types" — 'Miso.Event.Types.Options', 'Miso.Event.Types.KeyCode',
+--   'Miso.Event.Types.PointerEvent'
+-----------------------------------------------------------------------------
 module Miso.Html.Event
-  ( -- * Custom event handlers
-    on
-  , onWithOptions
-  , Options (..)
-  , defaultOptions
-   -- * Mouse events
-  , onClick
+  ( -- *** Mouse
+    onClick
+  , onClickPrevent
+  , onClickCapture
+  , onClickWith
+  , onClickWithOptions
   , onDoubleClick
+  , onDoubleClickWith
+  , onDoubleClickWithOptions
   , onMouseDown
   , onMouseUp
   , onMouseEnter
   , onMouseLeave
   , onMouseOver
   , onMouseOut
-  -- * Keyboard events
+  , onContextMenuWithOptions
+  -- *** Keyboard
   , onKeyDown
+  , onKeyDownWithInfo
   , onKeyPress
   , onKeyUp
-  -- * Form events
+  , onEnter
+  -- *** Form
   , onInput
+  , onInputWith
   , onChange
+  , onChangeWith
   , onChecked
   , onSubmit
-  -- * Focus events
+  -- *** Focus
   , onBlur
   , onFocus
-  -- * Drag events
+  -- *** Drag
   , onDrag
+  , onDragWithOptions
   , onDragLeave
+  , onDragLeaveWithOptions
   , onDragEnter
+  , onDragEnterWithOptions
   , onDragEnd
+  , onDragEndWithOptions
   , onDragStart
+  , onDragStartWithOptions
   , onDragOver
-  -- * Drop events
+  , onDragOverWithOptions
+  -- *** Drop
   , onDrop
+  , onDropWithOptions
+  -- *** Select
+  , onSelect
+  -- *** Pointer
+  , onPointerDown
+  , onPointerUp
+  , onPointerEnter
+  , onPointerLeave
+  , onPointerOver
+  , onPointerOut
+  , onPointerCancel
+  , onPointerMove
+  -- *** Media
+  , onAbort
+  , onAbortWith
+  , onCanPlay
+  , onCanPlayWith
+  , onCanPlayThrough
+  , onCanPlayThroughWith
+  , onDurationChange
+  , onDurationChangeWith
+  , onEmptied
+  , onEmptiedWith
+  , onEnded
+  , onEndedWith
+  , onError
+  , onErrorWith
+  , onLoad
+  , onUnload
+  , onLoadedData
+  , onLoadedDataWith
+  , onLoadedMetadata
+  , onLoadedMetadataWith
+  , onLoadStart
+  , onLoadStartWith
+  , onPause
+  , onPauseWith
+  , onPlay
+  , onPlayWith
+  , onPlaying
+  , onPlayingWith
+  , onProgress
+  , onProgressWith
+  , onRateChange
+  , onRateChangeWith
+  , onSeeked
+  , onSeekedWith
+  , onSeeking
+  , onSeekingWith
+  , onStalled
+  , onStalledWith
+  , onSuspend
+  , onSuspendWith
+  , onTimeUpdate
+  , onTimeUpdateWith
+  , onVolumeChange
+  , onVolumeChangeWith
+  , onWaiting
+  , onWaitingWith
+  -- *** Touch
+  , onTouchStart
+  , onTouchStartWithOptions
+  , onTouchEnd
+  , onTouchEndWithOptions
+  , onTouchMove
+  , onTouchMoveWithOptions
+  , onTouchCancel
+  , onTouchCancelWithOptions
   ) where
-
-import Miso.Html.Internal ( Attribute, on, onWithOptions )
-import Miso.Event
-import Miso.String (MisoString)
-
--- | `blur` event defined with custom options
+-----------------------------------------------------------------------------
+import           Data.Bool (bool)
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.Media (Media(..))
+import           Miso.Types (DOMRef, Attribute)
+import           Miso.String (MisoString)
+-----------------------------------------------------------------------------
+-- | blur event defined with custom options
 --
 -- <https://developer.mozilla.org/en-US/docs/Web/Events/blur>
 --
-onBlur :: action -> Attribute action
-onBlur action = on "blur" emptyDecoder $ \() -> action
-
+onBlur :: action -> Attribute model action
+onBlur action = on "blur" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/change
-onChecked :: (Checked -> action) -> Attribute action
-onChecked = on "change" checkedDecoder
-
+onChecked :: (Checked -> action) -> Attribute model action
+onChecked f = on "change" checkedDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu
+--
+-- This can be used to disable right-click context menu from appearing
+--
+-- @
+-- div_ [ onContextMenuWithOptions NoOp defaultOptions { preventDefault = False } ] [ ]
+-- @
+--
+-- @since 1.9.0.0
+onContextMenuWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch when the context menu event fires
+  -> Attribute model action
+onContextMenuWithOptions opts action =
+  onWithOptions BUBBLE opts "contextmenu" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/click
-onClick :: action -> Attribute action
-onClick action = on "click" emptyDecoder $ \() -> action
-
+onClick :: action -> Attribute model action
+onClick action = on "click" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/click
+onClickCapture :: action -> Attribute model action
+onClickCapture action = onCapture "click" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/click
+-- Like 'onClick', but passes the DOM reference along (akin to @getElementById@).
+onClickWith :: (DOMRef -> action) -> Attribute model action
+onClickWith action = on "click" emptyDecoder $ \() _ domRef -> action domRef
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/click
+onClickWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch on click
+  -> Attribute model action
+onClickWithOptions options action = onWithOptions BUBBLE options "click" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/click
+onClickPrevent :: action -> Attribute model action
+onClickPrevent = onClickWithOptions preventDefault
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/focus
-onFocus :: action -> Attribute action
-onFocus action = on "focus" emptyDecoder $ \() -> action
-
+onFocus :: action -> Attribute model action
+onFocus action = on "focus" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/dblclick
-onDoubleClick :: action -> Attribute action
-onDoubleClick action = on "dblclick" emptyDecoder $ \() -> action
-
+onDoubleClick :: action -> Attribute model action
+onDoubleClick action = on "dblclick" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dblclick
+onDoubleClickWith :: (DOMRef -> action) -> Attribute model action
+onDoubleClickWith f = on "dblclick" emptyDecoder $ \() _ domRef -> f domRef
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dblclick
+onDoubleClickWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch on double-click
+  -> Attribute model action
+onDoubleClickWithOptions options action =
+  onWithOptions BUBBLE options "dblclick" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/input
-onInput :: (MisoString -> action) -> Attribute action
-onInput = on "input" valueDecoder
-
+onInput
+  :: (MisoString -> action)
+  -- ^ Callback receiving @event.target.value@
+  -> Attribute model action
+onInput f = on "input" valueDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/input
+onInputWith
+  :: (MisoString -> DOMRef -> action)
+  -- ^ Callback receiving @event.target.value@ and the element's 'DOMRef'
+  -> Attribute model action
+onInputWith f = on "input" valueDecoder $ \val _ domRef -> f val domRef
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/change
-onChange :: (MisoString -> action) -> Attribute action
-onChange = on "change" valueDecoder
-
+onChange
+  :: (MisoString -> action)
+  -- ^ Callback receiving @event.target.value@
+  -> Attribute model action
+onChange f = on "change" valueDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/change
+onChangeWith
+  :: (MisoString -> DOMRef -> action)
+  -- ^ Callback receiving @event.target.value@ and the element's 'DOMRef'
+  -> Attribute model action
+onChangeWith f = on "change" valueDecoder $ \val _ domRef -> f val domRef
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/select
+onSelect
+  :: (MisoString -> action)
+  -- ^ Callback receiving @event.target.value@ of the selected text
+  -> Attribute model action
+onSelect f = on "select" valueDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/keydown
-onKeyDown :: (KeyCode -> action) -> Attribute action
-onKeyDown = on "keydown" keycodeDecoder
-
+onKeyDownWithInfo
+  :: (KeyInfo -> action)
+  -- ^ Callback receiving the key code and modifier key state
+  -> Attribute model action
+onKeyDownWithInfo f = on "keydown" keyInfoDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/keydown
+onKeyDown
+  :: (KeyCode -> action)
+  -- ^ Callback receiving the numeric key code of the pressed key
+  -> Attribute model action
+onKeyDown f = on "keydown" keycodeDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | 'onEnter'
+--
+-- A convenience function for processing the @Enter@ key.
+--
+-- @
+--
+-- data Action = NoOp | OnEnter
+--
+-- type Model = Int
+--
+-- view :: Model -> View context Action
+-- view entryId = input_ [ onEnter NoOp OnEnter ]
+-- @
+--
+-- @since 1.9.0.0
+onEnter
+  :: action
+  -- ^ The action to call when the keydown *is not* 13 (typically @NoOp@ or @Id@)
+  -> action
+  -- ^ The action to call when keydown *is* 13.
+  -> Attribute model action
+onEnter nothing action = onKeyDown $ bool nothing action . (==13)
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/keypress
-onKeyPress :: (KeyCode -> action) -> Attribute action
-onKeyPress = on "keypress" keycodeDecoder
-
+onKeyPress
+  :: (KeyCode -> action)
+  -- ^ Callback receiving the numeric key code of the pressed key
+  -> Attribute model action
+onKeyPress f = on "keypress" keycodeDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/keyup
-onKeyUp :: (KeyCode -> action) -> Attribute action
-onKeyUp = on "keyup" keycodeDecoder
-
+onKeyUp
+  :: (KeyCode -> action)
+  -- ^ Callback receiving the numeric key code of the released key
+  -> Attribute model action
+onKeyUp f = on "keyup" keycodeDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseup
-onMouseUp :: action -> Attribute action
-onMouseUp action = on "mouseup" emptyDecoder $ \() -> action
-
+onMouseUp :: action -> Attribute model action
+onMouseUp action = on "mouseup" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/mousedown
-onMouseDown :: action -> Attribute action
-onMouseDown action = on "mousedown" emptyDecoder $ \() -> action
-
+onMouseDown :: action -> Attribute model action
+onMouseDown action = on "mousedown" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseenter
-onMouseEnter :: action -> Attribute action
-onMouseEnter action = on "mouseenter" emptyDecoder $ \() -> action
-
+onMouseEnter :: action -> Attribute model action
+onMouseEnter action = on "mouseenter" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseleave
-onMouseLeave :: action -> Attribute action
-onMouseLeave action = on "mouseleave" emptyDecoder $ \() -> action
-
+onMouseLeave :: action -> Attribute model action
+onMouseLeave action = on "mouseleave" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseover
-onMouseOver :: action -> Attribute action
-onMouseOver action = on "mouseover" emptyDecoder $ \() -> action
-
+onMouseOver :: action -> Attribute model action
+onMouseOver action = on "mouseover" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseout
-onMouseOut :: action -> Attribute action
-onMouseOut action = on "mouseout" emptyDecoder $ \() -> action
-
+onMouseOut :: action -> Attribute model action
+onMouseOut action = on "mouseout" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragstart
-onDragStart :: action -> Attribute action
-onDragStart action = on "dragstart" emptyDecoder $ \() -> action
-
+onDragStart :: action -> Attribute model action
+onDragStart action = on "dragstart" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragstart
+onDragStartWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch when the drag starts
+  -> Attribute model action
+onDragStartWithOptions options action =
+  onWithOptions BUBBLE options "dragstart" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragover
-onDragOver :: action -> Attribute action
-onDragOver action = on "dragover" emptyDecoder $ \() -> action
-
+onDragOver :: action -> Attribute model action
+onDragOver action = on "dragover" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragover
+onDragOverWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch while the dragged element is over this target
+  -> Attribute model action
+onDragOverWithOptions options action =
+  onWithOptions BUBBLE options "dragover" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragend
-onDragEnd :: action -> Attribute action
-onDragEnd action = on "dragend" emptyDecoder $ \() -> action
-
+onDragEnd :: action -> Attribute model action
+onDragEnd action = on "dragend" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragend
+onDragEndWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch when the drag operation ends
+  -> Attribute model action
+onDragEndWithOptions options action =
+  onWithOptions BUBBLE options "dragend" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragenter
-onDragEnter :: action -> Attribute action
-onDragEnter action = on "dragenter" emptyDecoder $ \() -> action
-
+onDragEnter :: action -> Attribute model action
+onDragEnter action = on "dragenter" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragenter
+onDragEnterWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch when a dragged element enters this target
+  -> Attribute model action
+onDragEnterWithOptions options action =
+  onWithOptions BUBBLE options "dragenter" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragleave
-onDragLeave :: action -> Attribute action
-onDragLeave action = on "dragleave" emptyDecoder $ \() -> action
-
+onDragLeave :: action -> Attribute model action
+onDragLeave action = on "dragleave" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragleave
+onDragLeaveWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch when a dragged element leaves this target
+  -> Attribute model action
+onDragLeaveWithOptions options action =
+  onWithOptions BUBBLE options "dragleave" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/drag
-onDrag :: action -> Attribute action
-onDrag action = on "drag" emptyDecoder $ \() -> action
-
+onDrag :: action -> Attribute model action
+onDrag action = on "drag" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/drag
+onDragWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch while the element is being dragged
+  -> Attribute model action
+onDragWithOptions options action =
+  onWithOptions BUBBLE options "drag" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/drop
-onDrop :: AllowDrop -> action -> Attribute action
-onDrop (AllowDrop allowDrop) action =
-  onWithOptions defaultOptions { preventDefault = allowDrop }
-    "drop" emptyDecoder (\() -> action)
-
+onDrop
+  :: Options
+  -- ^ Propagation options — typically include @preventDefault@ to allow the drop
+  -> action
+  -- ^ Action to dispatch when a dragged element is dropped on this target
+  -> Attribute model action
+onDrop options action =
+  onWithOptions BUBBLE options "drop" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/drop
+onDropWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch on drop
+  -> Attribute model action
+onDropWithOptions options action =
+  onWithOptions BUBBLE options "drop" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
 -- | https://developer.mozilla.org/en-US/docs/Web/Events/submit
-onSubmit :: action -> Attribute action
+--
+-- Note: This has `preventDefault` enabled by default.
+--
+onSubmit :: action -> Attribute model action
 onSubmit action =
-  onWithOptions defaultOptions { preventDefault = True }
-    "submit" emptyDecoder $ \() -> action
+  onWithOptions BUBBLE preventDefault
+    "submit" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerup
+onPointerUp
+  :: (PointerEvent -> action)
+  -- ^ Callback receiving the full t'PointerEvent'
+  -> Attribute model action
+onPointerUp f = on "pointerup" pointerDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerdown
+onPointerDown
+  :: (PointerEvent -> action)
+  -- ^ Callback receiving the full t'PointerEvent'
+  -> Attribute model action
+onPointerDown f = on "pointerdown" pointerDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerenter
+onPointerEnter
+  :: (PointerEvent -> action)
+  -- ^ Callback receiving the full t'PointerEvent'
+  -> Attribute model action
+onPointerEnter f = on "pointerenter" pointerDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerleave
+onPointerLeave
+  :: (PointerEvent -> action)
+  -- ^ Callback receiving the full t'PointerEvent'
+  -> Attribute model action
+onPointerLeave f = on "pointerleave" pointerDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerover
+onPointerOver
+  :: (PointerEvent -> action)
+  -- ^ Callback receiving the full t'PointerEvent'
+  -> Attribute model action
+onPointerOver f = on "pointerover" pointerDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerout
+onPointerOut
+  :: (PointerEvent -> action)
+  -- ^ Callback receiving the full t'PointerEvent'
+  -> Attribute model action
+onPointerOut f = on "pointerout" pointerDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointercancel
+onPointerCancel
+  :: (PointerEvent -> action)
+  -- ^ Callback receiving the full t'PointerEvent'
+  -> Attribute model action
+onPointerCancel f = on "pointercancel" pointerDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointermove
+onPointerMove
+  :: (PointerEvent -> action)
+  -- ^ Callback receiving the full t'PointerEvent'
+  -> Attribute model action
+onPointerMove f = on "pointermove" pointerDecoder (\action _ _ -> f action)
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_abort.asp
+onAbort :: action -> Attribute model action
+onAbort action = on "abort" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_abort.asp
+onAbortWith :: (Media -> action) -> Attribute model action
+onAbortWith action = on "abort" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_canplay.asp
+onCanPlay :: action -> Attribute model action
+onCanPlay action = on "canplay" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_canplay.asp
+onCanPlayWith :: (Media -> action) -> Attribute model action
+onCanPlayWith action = on "canplay" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_canplaythrough.asp
+onCanPlayThrough :: action -> Attribute model action
+onCanPlayThrough action = on "canplaythrough" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_canplaythrough.asp
+onCanPlayThroughWith :: (Media -> action) -> Attribute model action
+onCanPlayThroughWith action = on "canplaythrough" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_durationchange.asp
+onDurationChange :: action -> Attribute model action
+onDurationChange action = on "durationchange" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_durationchange.asp
+onDurationChangeWith :: (Media -> action) -> Attribute model action
+onDurationChangeWith action = on "durationchange" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/jsref/event_onemptied.asp
+onEmptied :: action -> Attribute model action
+onEmptied action = on "emptied" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/jsref/event_onemptied.asp
+onEmptiedWith :: (Media -> action) -> Attribute model action
+onEmptiedWith action = on "emptied" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_ended.asp
+onEnded :: action -> Attribute model action
+onEnded action = on "ended" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_ended.asp
+onEndedWith :: (Media -> action) -> Attribute model action
+onEndedWith action = on "ended" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_error.asp
+onError :: action -> Attribute model action
+onError action = on "error" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_error.asp
+onErrorWith :: (Media -> action) -> Attribute model action
+onErrorWith action = on "error" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/jsref/event_onload.asp
+onLoad :: action -> Attribute model action
+onLoad action = on "load" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | onUnload event
+onUnload :: action -> Attribute model action
+onUnload action = on "unload" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_loadeddata.asp
+onLoadedData :: action -> Attribute model action
+onLoadedData action = on "loadeddata" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_loadeddata.asp
+onLoadedDataWith :: (Media -> action) -> Attribute model action
+onLoadedDataWith action = on "loadeddata" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_loadedmetadata.asp
+onLoadedMetadata :: action -> Attribute model action
+onLoadedMetadata action = on "loadedmetadata" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_loadedmetadata.asp
+onLoadedMetadataWith :: (Media -> action) -> Attribute model action
+onLoadedMetadataWith action = on "loadedmetadata" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_loadstart.asp
+onLoadStart :: action -> Attribute model action
+onLoadStart action = on "loadstart" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_loadstart.asp
+onLoadStartWith :: (Media -> action) -> Attribute model action
+onLoadStartWith action = on "loadstart" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_pause.asp
+onPause :: action -> Attribute model action
+onPause action = on "pause" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_pause.asp
+onPauseWith :: (Media -> action) -> Attribute model action
+onPauseWith action = on "pause" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_play.asp
+onPlay :: action -> Attribute model action
+onPlay action = on "play" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_play.asp
+onPlayWith :: (Media -> action) -> Attribute model action
+onPlayWith action = on "play" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_playing.asp
+onPlaying :: action -> Attribute model action
+onPlaying action = on "playing" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_playing.asp
+onPlayingWith :: (Media -> action) -> Attribute model action
+onPlayingWith action = on "playing" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_progress.asp
+onProgress :: action -> Attribute model action
+onProgress action = on "progress" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_progress.asp
+onProgressWith :: (Media -> action) -> Attribute model action
+onProgressWith action = on "progress" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_ratechange.asp
+onRateChange :: action -> Attribute model action
+onRateChange action = on "ratechange" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_ratechange.asp
+onRateChangeWith :: (Media -> action) -> Attribute model action
+onRateChangeWith action = on "ratechange" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_seeked.asp
+onSeeked :: action -> Attribute model action
+onSeeked action = on "seeked" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_seeked.asp
+onSeekedWith :: (Media -> action) -> Attribute model action
+onSeekedWith action = on "seeked" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_seeking.asp
+onSeeking :: action -> Attribute model action
+onSeeking action = on "seeking" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_seeking.asp
+onSeekingWith :: (Media -> action) -> Attribute model action
+onSeekingWith action = on "seeking" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_stalled.asp
+onStalled :: action -> Attribute model action
+onStalled action = on "stalled" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_stalled.asp
+onStalledWith :: (Media -> action) -> Attribute model action
+onStalledWith action = on "stalled" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_suspend.asp
+onSuspend :: action -> Attribute model action
+onSuspend action = on "suspend" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_suspend.asp
+onSuspendWith :: (Media -> action) -> Attribute model action
+onSuspendWith action = on "suspend" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_timeupdate.asp
+onTimeUpdate :: action -> Attribute model action
+onTimeUpdate action = on "timeupdate" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_timeupdate.asp
+onTimeUpdateWith :: (Media -> action) -> Attribute model action
+onTimeUpdateWith action = on "timeupdate" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_volumechange.asp
+onVolumeChange :: action -> Attribute model action
+onVolumeChange action = on "volumechange" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_volumechange.asp
+onVolumeChangeWith :: (Media -> action) -> Attribute model action
+onVolumeChangeWith action = on "volumechange" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_waiting.asp
+onWaiting :: action -> Attribute model action
+onWaiting action = on "waiting" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://www.w3schools.com/tags/av_event_waiting.asp
+onWaitingWith :: (Media -> action) -> Attribute model action
+onWaitingWith action = on "waiting" emptyDecoder $ \() _ -> action . Media
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchstart
+onTouchStart :: action -> Attribute model action
+onTouchStart action = on "touchstart" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchstart
+onTouchStartWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch on touch start
+  -> Attribute model action
+onTouchStartWithOptions options action = onWithOptions BUBBLE options "touchstart" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchend
+onTouchEnd :: action -> Attribute model action
+onTouchEnd action = on "touchend" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchend
+onTouchEndWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch on touch end
+  -> Attribute model action
+onTouchEndWithOptions options action = onWithOptions BUBBLE options "touchend" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchmove
+onTouchMove :: action -> Attribute model action
+onTouchMove action = on "touchmove" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchmove
+onTouchMoveWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch while a touch point is moving
+  -> Attribute model action
+onTouchMoveWithOptions options action = onWithOptions BUBBLE options "touchmove" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchcancel
+onTouchCancel :: action -> Attribute model action
+onTouchCancel action = on "touchcancel" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchcancel
+onTouchCancelWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> action
+  -- ^ Action to dispatch when a touch point is cancelled
+  -> Attribute model action
+onTouchCancelWithOptions options action = onWithOptions BUBBLE options "touchcancel" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Html/Property.hs b/src/Miso/Html/Property.hs
--- a/src/Miso/Html/Property.hs
+++ b/src/Miso/Html/Property.hs
@@ -1,40 +1,112 @@
+-----------------------------------------------------------------------------
 {-# LANGUAGE OverloadedStrings #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Html.Property
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
 --
--- Construct custom properties on DOM elements
+-- = Overview
 --
--- > div_ [ prop "id" "foo" ] [ ]
+-- "Miso.Html.Property" provides smart constructors for
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Element#properties DOM properties>
+-- and
+-- <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes HTML attributes>.
+-- Each produces an 'Miso.Types.Attribute' that the virtual DOM applies to
+-- the corresponding DOM node on every render, diffing only changed values.
 --
-----------------------------------------------------------------------------
+-- All names are suffixed with @_@ to avoid clashing with Haskell
+-- @Prelude@ names. This module is re-exported in its entirety by
+-- "Miso.Html" and "Miso".
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+--
+-- view :: Model -> 'Miso.Types.View' Model Action
+-- view m =
+--   'Miso.Html.Element.div_' [ 'id_' \"app\", 'class_' \"container\" ]
+--     [ 'Miso.Html.Element.input_'
+--         [ 'type_' \"text\"
+--         , 'value_' m.text
+--         , 'placeholder_' \"Type here…\"
+--         , 'disabled_'
+--         ]
+--         []
+--     , 'Miso.Html.Element.img_'
+--         [ 'src_' \"logo.png\", 'alt_' \"Logo\", 'width_' \"64\", 'height_' \"64\" ]
+--         []
+--     ]
+-- @
+--
+-- = Class management
+--
+-- Four combinators handle CSS classes:
+--
+-- @
+-- 'class_'    \"foo bar\"              -- single string, set className
+-- 'className' \"foo bar\"              -- alias for class_
+-- 'classes_'  [\"foo\", \"bar\"]         -- list of class names
+-- 'classList_' [(\"active\", isActive)  -- conditional classes
+--             ,(\"error\",  hasError)]
+-- @
+--
+-- = Property groups
+--
+-- * __Global__: 'id_', 'class_', 'className', 'classes_', 'classList_',
+--   'title_', 'lang_', 'hidden_', 'inert_', 'draggable_', 'tabindex_',
+--   'role_', 'data_', 'aria_', 'xmlns_'
+-- * __Form__: 'type_', 'value_', 'defaultValue_', 'checked_', 'placeholder_',
+--   'selected_', 'disabled_', 'readonly_', 'required_', 'multiple_',
+--   'autofocus_', 'autocomplete_', 'autocorrect_', 'spellcheck_',
+--   'name_', 'for_', 'form_', 'action_', 'method_', 'enctype_',
+--   'noValidate_', 'accept_', 'acceptCharset_', 'pattern_',
+--   'min_', 'max_', 'step_', 'size_', 'maxlength_', 'minlength_',
+--   'list_', 'cols_', 'rows_', 'wrap_'
+-- * __Link \/ anchor__: 'href_', 'target_', 'rel_', 'hreflang_',
+--   'download_', 'downloadAs_', 'ping_', 'media_'
+-- * __Image \/ map__: 'src_', 'alt_', 'width_', 'height_', 'loading_',
+--   'ismap_', 'usemap_', 'shape_', 'coords_'
+-- * __Media__: 'autoplay_', 'controls_', 'loop_', 'muted_', 'preload_',
+--   'poster_', 'volume_', 'currentTime_', 'defaultMuted_',
+--   'defaultPlaybackRate_', 'playbackRate_', 'seeking_', 'mediaGroup_'
+-- * __Table__: 'colspan_', 'rowspan_', 'headers_', 'scope_', 'align_'
+-- * __\<script\> \/ \<meta\>__: 'async_', 'defer_', 'charset_', 'content_',
+--   'httpEquiv_', 'language_', 'scoped_'
+-- * __\<iframe\>__: 'sandbox_', 'seamless_', 'srcdoc_', 'frameborder_',
+--   'scrolling_'
+-- * __Misc__: 'open_', 'reversed_', 'default_', 'kind_', 'srclang_',
+--   'label_', 'autosave_', 'formation_', 'ref_'
+--
+-- = See also
+--
+-- * "Miso.Property" — lower-level 'Miso.Property.textProp', 'Miso.Property.boolProp',
+--   'Miso.Property.intProp', 'Miso.Property.doubleProp' combinators
+-- * "Miso.Html.Element" — element constructors that accept these attributes
+-- * "Miso.Html.Event" — event-handler attributes
+-- * "Miso.CSS" — style property DSL ('Miso.CSS.style_', 'Miso.CSS.styleInline_')
+-----------------------------------------------------------------------------
 module Miso.Html.Property
- (   -- * Construction
-     textProp
-   , stringProp
-   , boolProp
-   , intProp
-   , integerProp
-   , doubleProp
-    -- * Common attributes
-   , class_
+  ( -- *** Combinators
+     class_
+   , className
+   , classes_
    , classList_
    , id_
    , title_
    , hidden_
-   -- * Inputs
+   , inert_
+   , lang_
    , type_
    , value_
    , defaultValue_
    , checked_
    , placeholder_
    , selected_
-   -- * Input Helpers
    , accept_
    , acceptCharset_
    , action_
@@ -50,22 +122,20 @@
    , method_
    , multiple_
    , name_
-   , novalidate_
+   , noValidate_
    , pattern_
    , readonly_
    , required_
    , size_
    , for_
+   , ref_
    , form_
-   -- * Input Ranges
    , max_
    , min_
    , step_
-   -- * Input Text areas
    , cols_
    , rows_
    , wrap_
-   -- * Links and areas
    , href_
    , target_
    , download_
@@ -74,39 +144,40 @@
    , media_
    , ping_
    , rel_
-   -- * Maps
    , ismap_
    , usemap_
    , shape_
    , coords_
-   -- * Embedded Content
    , src_
    , height_
    , width_
    , alt_
-   -- * Audio and Video
+   , loading_
    , autoplay_
+   , currentTime_
+   , defaultMuted_
+   , volume_
    , controls_
    , loop_
+   , defaultPlaybackRate_
+   , mediaGroup_
+   , muted_
+   , playbackRate_
+   , seeking_
    , preload_
    , poster_
    , default_
    , kind_
    , srclang_
-   -- * iframes
    , sandbox_
    , seamless_
    , srcdoc_
-   -- * Ordered lists
    , reversed_
-   , start_
-   -- * Tables
    , align_
    , colspan_
    , rowspan_
    , headers_
    , scope_
-   -- * Headers
    , async_
    , charset_
    , content_
@@ -114,272 +185,451 @@
    , httpEquiv_
    , language_
    , scoped_
+   , data_
+   , autocorrect_
+   , spellcheck_
+   , role_
+   , xmlns_
+   , aria_
+   , label_
+   , draggable_
+   , frameborder_
+   , scrolling_
+   , tabindex_
+   , open_
    ) where
-
-import           Miso.Html.Internal
-import           Miso.String (MisoString, intercalate)
-
--- | Set field to `Bool` value
-boolProp :: MisoString -> Bool -> Attribute action
-boolProp = prop
--- | Set field to `String` value
-stringProp ::  MisoString -> String -> Attribute action
-stringProp = prop
--- | Set field to `Text` value
-textProp ::  MisoString -> MisoString -> Attribute action
-textProp = prop
--- | Set field to `Int` value
-intProp ::  MisoString -> Int -> Attribute action
-intProp = prop
--- | Set field to `Integer` value
-integerProp ::  MisoString -> Int -> Attribute action
-integerProp = prop
--- | Set field to `Double` value
-doubleProp ::  MisoString -> Double -> Attribute action
-doubleProp = prop
+-----------------------------------------------------------------------------
+import           Miso.Types
+import           Miso.Property
+-----------------------------------------------------------------------------
 -- | Define multiple classes conditionally
 --
 -- > div_ [ classList_ [ ("empty", null items) ] [ ]
 --
-classList_ ::  [(MisoString, Bool)] -> Attribute action
-classList_ xs =
-  textProp "class" $ intercalate (" " :: MisoString) [ t | (t, True) <- xs ]
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/title>
-title_ ::  MisoString -> Attribute action
+classList_ :: [(MisoString, Bool)] -> Attribute model action
+classList_ xs = classList [ t | (t, True) <- xs ]
+-----------------------------------------------------------------------------
+-- | Define multiple classes
+--
+-- > div_ [ classes_ [ "red", "warning" ] ] []
+--
+classes_ :: [MisoString] -> Attribute model action
+classes_ = classList
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title>
+title_ :: MisoString -> Attribute model action
 title_ = textProp "title"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/selected>
-selected_ ::  Bool -> Attribute action
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option#selected>
+selected_ :: Bool -> Attribute model action
 selected_ = boolProp "selected"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/hidden>
-hidden_ ::  Bool -> Attribute action
-hidden_             = boolProp "hidden"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/value>
-value_ ::  MisoString -> Attribute action
-value_             = textProp "value"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/defaultValue>
-defaultValue_ ::  MisoString -> Attribute action
-defaultValue_      = textProp "defaultValue"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/accept>
-accept_ ::  MisoString -> Attribute action
-accept_            = textProp "accept"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/acceptCharset>
-acceptCharset_ ::  MisoString -> Attribute action
-acceptCharset_     = textProp "acceptCharset"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/action>
-action_ ::  MisoString -> Attribute action
-action_            = textProp "action"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/autocomplete>
-autocomplete_ ::  Bool -> Attribute action
-autocomplete_ b = textProp "autocomplete" (if b then "on" else "off")
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/autosave>
-autosave_ ::  MisoString -> Attribute action
-autosave_          = textProp "autosave"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/disabled>
-disabled_ ::  Bool -> Attribute action
-disabled_          = boolProp "disabled"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/enctype>
-enctype_ ::  MisoString -> Attribute action
-enctype_           = textProp "enctype"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/formation>
-formation_ ::  MisoString -> Attribute action
-formation_         = textProp "formation"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/list>
-list_ ::  MisoString -> Attribute action
-list_              = textProp "list"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/maxlength>
-maxlength_ ::  MisoString -> Attribute action
-maxlength_         = textProp "maxlength"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/minlength>
-minlength_ ::  MisoString -> Attribute action
-minlength_         = textProp "minlength"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/method>
-method_ ::  MisoString -> Attribute action
-method_            = textProp "method"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/multiple>
-multiple_ ::  Bool -> Attribute action
-multiple_          = boolProp "multiple"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/novalidate>
-novalidate_ ::  Bool -> Attribute action
-novalidate_        = boolProp "noValidate"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/pattern>
-pattern_ ::  MisoString -> Attribute action
-pattern_           = textProp "pattern"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/readonly>
-readonly_ ::  Bool -> Attribute action
-readonly_          = boolProp "readOnly"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/required>
-required_ ::  Bool -> Attribute action
-required_          = boolProp "required"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/size>
-size_ ::  MisoString -> Attribute action
-size_              = textProp "size"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/for>
-for_ ::  MisoString -> Attribute action
-for_               = textProp "for"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/form>
-form_ ::  MisoString -> Attribute action
-form_               = textProp "form"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/max>
-max_ ::  MisoString -> Attribute action
-max_               = textProp "max"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/min>
-min_ ::  MisoString -> Attribute action
-min_               = textProp "min"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/step>
-step_ ::  MisoString -> Attribute action
-step_              = textProp "step"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/cols>
-cols_ ::  MisoString -> Attribute action
-cols_              = textProp "cols"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/rows>
-rows_ ::  MisoString -> Attribute action
-rows_              = textProp "rows"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/wrap>
-wrap_ ::  MisoString -> Attribute action
-wrap_              = textProp "wrap"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/target>
-target_ ::  MisoString -> Attribute action
-target_            = textProp "target"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/download>
-download_ ::  MisoString -> Attribute action
-download_          = textProp "download"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/downloadAs>
-downloadAs_ ::  MisoString -> Attribute action
-downloadAs_        = textProp "downloadAs"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/hreflang>
-hreflang_ ::  MisoString -> Attribute action
-hreflang_          = textProp "hreflang"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/media>
-media_ ::  MisoString -> Attribute action
-media_             = textProp "media"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/ping>
-ping_ ::  MisoString -> Attribute action
-ping_              = textProp "ping"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/rel>
-rel_ ::  MisoString -> Attribute action
-rel_               = textProp "rel"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/ismap>
-ismap_ ::  MisoString -> Attribute action
-ismap_             = textProp "ismap"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/usemap>
-usemap_ ::  MisoString -> Attribute action
-usemap_            = textProp "usemap"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/shape>
-shape_ ::  MisoString -> Attribute action
-shape_             = textProp "shape"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/coords>
-coords_ ::  MisoString -> Attribute action
-coords_            = textProp "coords"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/src>
-src_ ::  MisoString -> Attribute action
-src_               = textProp "src"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/height>
-height_ ::  MisoString -> Attribute action
-height_            = textProp "height"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/width>
-width_ ::  MisoString -> Attribute action
-width_             = textProp "width"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/alt>
-alt_ ::  MisoString -> Attribute action
-alt_               = textProp "alt"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/autoplay>
-autoplay_ ::  Bool -> Attribute action
-autoplay_          = boolProp "autoplay"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/controls>
-controls_ ::  Bool -> Attribute action
-controls_          = boolProp "controls"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/loop>
-loop_ ::  Bool -> Attribute action
-loop_              = boolProp "loop"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/preload>
-preload_ ::  MisoString -> Attribute action
-preload_           = textProp "preload"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/poster>
-poster_ ::  MisoString -> Attribute action
-poster_            = textProp "poster"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/default>
-default_ ::  Bool -> Attribute action
-default_           = boolProp "default"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/kind>
-kind_ ::  MisoString -> Attribute action
-kind_              = textProp "kind"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/srclang>
-srclang_ ::  MisoString -> Attribute action
-srclang_           = textProp "srclang"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/sandbox>
-sandbox_ ::  MisoString -> Attribute action
-sandbox_           = textProp "sandbox"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/seamless>
-seamless_ ::  MisoString -> Attribute action
-seamless_          = textProp "seamless"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/srcdoc>
-srcdoc_ ::  MisoString -> Attribute action
-srcdoc_            = textProp "srcdoc"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/reversed>
-reversed_ ::  MisoString -> Attribute action
-reversed_          = textProp "reversed"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/start>
-start_ ::  MisoString -> Attribute action
-start_             = textProp "start"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/align>
-align_ ::  MisoString -> Attribute action
-align_             = textProp "align"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/colspan>
-colspan_ ::  MisoString -> Attribute action
-colspan_           = textProp "colspan"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/rowspan>
-rowspan_ ::  MisoString -> Attribute action
-rowspan_           = textProp "rowspan"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/headers>
-headers_ ::  MisoString -> Attribute action
-headers_           = textProp "headers"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/scope>
-scope_ ::  MisoString -> Attribute action
-scope_             = textProp "scope"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/async>
-async_ ::  MisoString -> Attribute action
-async_             = textProp "async"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/charset>
-charset_ ::  MisoString -> Attribute action
-charset_           = textProp "charset"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/content>
-content_ ::  MisoString -> Attribute action
-content_           = textProp "content"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/defer>
-defer_ ::  MisoString -> Attribute action
-defer_             = textProp "defer"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/httpEquiv>
-httpEquiv_ ::  MisoString -> Attribute action
-httpEquiv_         = textProp "httpEquiv"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/language>
-language_ ::  MisoString -> Attribute action
-language_          = textProp "language"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/scoped>
-scoped_ ::  MisoString -> Attribute action
-scoped_            = textProp "scoped"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/type>
-type_ ::  MisoString -> Attribute action
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hidden>
+hidden_ :: Bool -> Attribute model action
+hidden_ = boolProp "hidden"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inert>
+inert_ :: Bool -> Attribute model action
+inert_ = boolProp "inert"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang>
+lang_ :: MisoString -> Attribute model action
+lang_ = textProp "lang"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/value>
+value_ :: MisoString -> Attribute model action
+value_ = textProp "value"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/defaultValue>
+defaultValue_ :: MisoString -> Attribute model action
+defaultValue_    = textProp "defaultValue"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept>
+accept_ :: MisoString -> Attribute model action
+accept_  = textProp "accept"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/acceptCharset>
+acceptCharset_ :: MisoString -> Attribute model action
+acceptCharset_   = textProp "acceptCharset"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/action>
+action_ :: MisoString -> Attribute model action
+action_  = textProp "action"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete>
+autocomplete_ :: MisoString -> Attribute model action
+autocomplete_ = textProp "autocomplete"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autosave>
+autosave_ :: MisoString -> Attribute model action
+autosave_ = textProp "autosave"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autocorrect>
+autocorrect_ :: Bool -> Attribute model action
+autocorrect_ b = textProp "autocorrect" (if b then "on" else "off")
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/spellcheck>
+spellcheck_ :: Bool -> Attribute model action
+spellcheck_ b = textProp "spellcheck" (if b then "true" else "false")
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/role>
+role_ :: MisoString -> Attribute model action
+role_ = textProp "role"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled>
+disabled_ :: Attribute model action
+disabled_ = boolProp "disabled" True
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/enctype>
+enctype_ :: MisoString -> Attribute model action
+enctype_ = textProp "enctype"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/formation>
+formation_ :: MisoString -> Attribute model action
+formation_ = textProp "formation"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/list>
+list_ :: MisoString -> Attribute model action
+list_  = textProp "list"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/maxlength>
+maxlength_ :: MisoString -> Attribute model action
+maxlength_ = textProp "maxlength"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/minlength>
+minlength_ :: MisoString -> Attribute model action
+minlength_ = textProp "minlength"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/method>
+method_ :: MisoString -> Attribute model action
+method_  = textProp "method"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/multiple>
+multiple_ :: Bool -> Attribute model action
+multiple_ = boolProp "multiple"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/noValidate>
+noValidate_ :: Bool -> Attribute model action
+noValidate_      = boolProp "noValidate"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/pattern>
+pattern_ :: MisoString -> Attribute model action
+pattern_ = textProp "pattern"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details#open>
+open_ :: Bool -> Attribute model action
+open_ = boolProp "open"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly>
+readonly_ :: Bool -> Attribute model action
+readonly_ = boolProp "readOnly"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/required>
+required_ :: Bool -> Attribute model action
+required_ = boolProp "required"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/size>
+size_ :: MisoString -> Attribute model action
+size_  = textProp "size"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/for>
+for_ :: MisoString -> Attribute model action
+for_ = textProp "for"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/ref>
+ref_ :: MisoString -> Attribute model action
+ref_ = textProp "ref"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/form>
+form_ :: MisoString -> Attribute model action
+form_ = textProp "form"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/max>
+max_ :: MisoString -> Attribute model action
+max_ = textProp "max"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/min>
+min_ :: MisoString -> Attribute model action
+min_ = textProp "min"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/step>
+step_ :: MisoString -> Attribute model action
+step_  = textProp "step"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/cols>
+cols_ :: MisoString -> Attribute model action
+cols_  = textProp "cols"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/rows>
+rows_ :: MisoString -> Attribute model action
+rows_  = textProp "rows"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/wrap>
+wrap_ :: MisoString -> Attribute model action
+wrap_  = textProp "wrap"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/target>
+target_ :: MisoString -> Attribute model action
+target_  = textProp "target"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/download>
+download_ :: MisoString -> Attribute model action
+download_ = textProp "download"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/downloadAs>
+downloadAs_ :: MisoString -> Attribute model action
+downloadAs_      = textProp "downloadAs"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hreflang>
+hreflang_ :: MisoString -> Attribute model action
+hreflang_ = textProp "hreflang"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/media>
+media_ :: MisoString -> Attribute model action
+media_ = textProp "media"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/ping>
+ping_ :: MisoString -> Attribute model action
+ping_  = textProp "ping"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/rel>
+rel_ :: MisoString -> Attribute model action
+rel_ = textProp "rel"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/isMap>
+ismap_ :: Bool -> Attribute model action
+ismap_ = boolProp "ismap"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/usemap>
+usemap_ :: MisoString -> Attribute model action
+usemap_  = textProp "usemap"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/shape>
+shape_ :: MisoString -> Attribute model action
+shape_ = textProp "shape"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/coords>
+coords_ :: MisoString -> Attribute model action
+coords_  = textProp "coords"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/src>
+src_ :: MisoString -> Attribute model action
+src_ = textProp "src"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/height>
+height_ :: MisoString -> Attribute model action
+height_  = textProp "height"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/width>
+width_ :: MisoString -> Attribute model action
+width_ = textProp "width"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/alt>
+alt_ :: MisoString -> Attribute model action
+alt_ = textProp "alt"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/loading>
+loading_ :: MisoString -> Attribute model action
+loading_ = textProp "loading"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/autoplay>
+autoplay_ :: Bool -> Attribute model action
+autoplay_ = boolProp "autoplay"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime>
+currentTime_ :: Double -> Attribute model action
+currentTime_ = doubleProp "currentTime"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/defaultMuted>
+defaultMuted_ :: Bool -> Attribute model action
+defaultMuted_ = boolProp "defaultMuted"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/defaultPlaybackRate>
+defaultPlaybackRate_ :: Double -> Attribute model action
+defaultPlaybackRate_ = doubleProp "defaultPlaybackRate"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/mediaGroup>
+mediaGroup_ :: MisoString -> Attribute model action
+mediaGroup_ = textProp "mediaGroup"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/muted>
+muted_ :: Bool -> Attribute model action
+muted_ = boolProp "muted"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/playbackRate>
+playbackRate_ :: Double -> Attribute model action
+playbackRate_ = doubleProp "playbackRate"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/preload>
+preload_ :: MisoString -> Attribute model action
+preload_ = textProp "preload"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seeking>
+seeking_ :: Bool -> Attribute model action
+seeking_ = boolProp "seeking"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/volume>
+volume_ :: Double -> Attribute model action
+volume_ = doubleProp "volume"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/controls>
+controls_ :: Bool -> Attribute model action
+controls_ = boolProp "controls"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/loop>
+loop_ :: Bool -> Attribute model action
+loop_  = boolProp "loop"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/poster>
+poster_ :: MisoString -> Attribute model action
+poster_  = textProp "poster"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/default>
+default_ :: Bool -> Attribute model action
+default_ = boolProp "default"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/kind>
+kind_ :: MisoString -> Attribute model action
+kind_  = textProp "kind"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/srclang>
+srclang_ :: MisoString -> Attribute model action
+srclang_ = textProp "srclang"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/sandbox>
+sandbox_ :: MisoString -> Attribute model action
+sandbox_ = textProp "sandbox"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/seamless>
+seamless_ :: MisoString -> Attribute model action
+seamless_ = textProp "seamless"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/srcdoc>
+srcdoc_ :: MisoString -> Attribute model action
+srcdoc_  = textProp "srcdoc"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ol#reversed>
+reversed_ :: Bool -> Attribute model action
+reversed_ = boolProp "reversed"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/align>
+align_ :: MisoString -> Attribute model action
+align_ = textProp "align"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/colspan>
+colspan_ :: MisoString -> Attribute model action
+colspan_ = textProp "colspan"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/rowspan>
+rowspan_ :: MisoString -> Attribute model action
+rowspan_ = textProp "rowspan"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/headers>
+headers_ :: MisoString -> Attribute model action
+headers_ = textProp "headers"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/scope>
+scope_ :: MisoString -> Attribute model action
+scope_ = textProp "scope"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/async>
+async_ :: Bool -> Attribute model action
+async_ = boolProp "async"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/charset>
+charset_ :: MisoString -> Attribute model action
+charset_ = textProp "charset"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/content>
+content_ :: MisoString -> Attribute model action
+content_ = textProp "content"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement/defer>
+defer_ :: Bool -> Attribute model action
+defer_ = boolProp "defer"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/httpEquiv>
+httpEquiv_ :: MisoString -> Attribute model action
+httpEquiv_ = textProp "httpEquiv"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/language>
+language_ :: MisoString -> Attribute model action
+language_ = textProp "language"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/scoped>
+scoped_ :: MisoString -> Attribute model action
+scoped_  = textProp "scoped"
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/type>
+type_ :: MisoString -> Attribute model action
 type_ = textProp "type"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/name>
-name_ ::  MisoString -> Attribute action
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/name>
+name_ :: MisoString -> Attribute model action
 name_ = textProp "name"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/href>
-href_ ::  MisoString -> Attribute action
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/href>
+href_ :: MisoString -> Attribute model action
 href_ = textProp "href"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/id>
-id_ ::  MisoString -> Attribute action
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id>
+id_ :: MisoString -> Attribute model action
 id_ = textProp "id"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/placeholder>
-placeholder_ ::  MisoString -> Attribute action
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/placeholder>
+placeholder_ :: MisoString -> Attribute model action
 placeholder_ = textProp "placeholder"
--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/checked>
-checked_ ::  Bool -> Attribute action
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/checked>
+checked_ :: Bool -> Attribute model action
 checked_ = boolProp "checked"
--- | Set "autofocus" property
--- <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/autofocus>
-autofocus_ ::  Bool -> Attribute action
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus>
+autofocus_ :: Bool -> Attribute model action
 autofocus_ = boolProp "autofocus"
+-----------------------------------------------------------------------------
 -- | Set "className" property
 -- <https://developer.mozilla.org/en-US/docs/Web/API/Element/className>
-class_ ::  MisoString -> Attribute action
-class_ = textProp "class"
+class_ :: MisoString -> Attribute model action
+class_ = className
+-----------------------------------------------------------------------------
+-- | Set "className" property
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Element/className>
+className :: MisoString -> Attribute model action
+className name = classList [name]
+-----------------------------------------------------------------------------
+-- | Set "data-*" property
+-- https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*
+data_ :: MisoString -> MisoString -> Attribute model action
+data_ k v = textProp ("data-" <> k) v
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+xmlns_ :: MisoString -> Attribute model action
+xmlns_ = textProp "xmlns"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+aria_ :: MisoString -> MisoString -> Attribute model action
+aria_ k = textProp ("aria-" <> k)
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+label_ :: MisoString -> Attribute model action
+label_ = textProp "label"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+draggable_ :: Bool -> Attribute model action
+draggable_ = boolProp "draggable"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+scrolling_ :: MisoString -> Attribute model action
+scrolling_ = textProp "scrolling"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+frameborder_ :: MisoString -> Attribute model action
+frameborder_ = textProp "frameborder"
+-----------------------------------------------------------------------------
+-- | [tabindex](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/tabindex) attribute
+--
+-- @since 1.9.0.0
+tabindex_ ::  MisoString -> Attribute model action
+tabindex_ = textProp "tabindex"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Html/Render.hs b/src/Miso/Html/Render.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Html/Render.hs
@@ -0,0 +1,299 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE ScopedTypeVariables   #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE CPP                   #-}
+#ifdef SSR
+{-# LANGUAGE RecordWildCards       #-}
+#endif
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Html.Render
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Html.Render" provides the 'ToHtml' typeclass for serialising a
+-- 'Miso.Types.View' tree to a lazy 'Data.ByteString.Lazy.ByteString' of
+-- UTF-8 HTML. This is the foundation of miso's
+-- <https://en.wikipedia.org/wiki/Server-side_scripting server-side rendering (SSR)>
+-- support.
+--
+-- Instances are provided for both @'Miso.Types.View' m a@ (a single node)
+-- and @['Miso.Types.View' m a]@ (a sequence of nodes).
+--
+-- = Quick start
+--
+-- @
+-- import           "Miso.Html.Render" ('ToHtml', 'toHtml')
+-- import qualified Data.ByteString.Lazy as L
+--
+-- renderPage :: Model -> L.ByteString
+-- renderPage m = 'toHtml' (view m)
+-- @
+--
+-- With @servant@, use @'toHtml'@ inside a @'Data.ByteString.Lazy.ByteString'@
+-- or @OctetStream@ response, or wire it into a 'Miso.Html.Render.ToHtml' servant
+-- MIME type.
+--
+-- = Rendering rules
+--
+-- * __'Miso.Types.VNode'__ — rendered as @\<tag attrs\>children\<\/tag\>@.
+--   Self-closing elements (@\<br\/\>@, @\<img\/\>@, @\<input\/\>@, …) are
+--   rendered without a closing tag.
+-- * __'Miso.Types.VText'__ — rendered as a raw text string (no escaping
+--   beyond what is already in the 'Miso.String.MisoString').
+-- * __'Miso.Types.VComp'__ — recursively renders the sub-component's view
+--   using its initial (or hydrated) model.
+-- * __'Miso.Types.VFrag'__ — renders all children inline, no wrapper tag.
+-- * __Event handlers__ (@'Miso.Types.On'@) — silently dropped; they have
+--   no meaning in a static HTML string.
+-- * __Boolean properties__ (@disabled@, @checked@, @required@, …) — rendered
+--   as bare attribute names when @True@, omitted entirely when @False@.
+-- * __Adjacent text nodes__ — collapsed into a single text node to match
+--   browser parsing behaviour during hydration.
+--
+-- = SSR flag
+--
+-- When compiled with @-fssr@ the renderer calls the component's optional
+-- @hydrateModel@ action to derive the initial model (e.g. by fetching from
+-- a database), falling back to the static @model@ if the action throws.
+--
+-- = See also
+--
+-- * "Miso.Hydrate" — client-side hydration from server-rendered HTML
+-- * "Miso.Html.Element" — element smart constructors
+-- * "Miso.Html" — top-level HTML DSL re-export hub
+-----------------------------------------------------------------------------
+module Miso.Html.Render
+  ( -- *** Classes
+    ToHtml (..)
+  ) where
+----------------------------------------------------------------------------
+import qualified Data.Set as S
+import           Data.Set (Set)
+import           Data.ByteString.Builder
+import qualified Data.ByteString.Lazy as L
+import qualified Data.Map.Strict as M
+import           System.IO.Unsafe (unsafePerformIO)
+#ifdef SSR
+import           Control.Exception (SomeException, catch)
+#endif
+----------------------------------------------------------------------------
+import           Data.IORef (readIORef)
+import           GHC.StaticPtr
+----------------------------------------------------------------------------
+import           Miso.JSON
+import           Miso.Runtime (globalContext)
+import           Miso.String hiding (intercalate)
+import qualified Miso.String as MS
+import           Miso.Types
+----------------------------------------------------------------------------
+-- | Class for rendering HTML
+class ToHtml a where
+  toHtml :: a -> L.ByteString
+----------------------------------------------------------------------------
+-- | Render a @Miso.Types.View@ to a @L.ByteString@
+instance ToHtml (View context model action) where
+  toHtml = renderView
+----------------------------------------------------------------------------
+-- | Render a @[Miso.Types.View]@ to a @L.ByteString@
+instance ToHtml [View context model action] where
+  toHtml = foldMap renderView
+----------------------------------------------------------------------------
+renderView :: View context model action -> L.ByteString
+renderView = toLazyByteString . renderBuilder
+----------------------------------------------------------------------------
+intercalate :: Builder -> [Builder] -> Builder
+intercalate _ [] = ""
+intercalate _ [x] = x
+intercalate sep (x:xs) =
+  mconcat
+  [ x
+  , sep
+  , intercalate sep xs
+  ]
+----------------------------------------------------------------------------
+booleanProperties :: Set MisoString
+booleanProperties = S.fromList
+  [ "allowfullscreen"
+  , "allowpaymentrequest"
+  , "allowusermedia"
+  , "async"
+  , "autofocus"
+  , "autoplay"
+  , "checked"
+  , "controls"
+  , "default"
+  , "defer"
+  , "disabled"
+  , "download"
+  , "formnovalidate"
+  , "hidden"
+  , "inert"
+  , "ismap"
+  , "itemscope"
+  , "loop"
+  , "multiple"
+  , "muted"
+  , "nomodule"
+  , "novalidate"
+  , "open"
+  , "playsinline"
+  , "readonly"
+  , "required"
+  , "reversed"
+  , "selected"
+  , "truespeed"
+  ]
+----------------------------------------------------------------------------
+renderBuilder :: View context model action -> Builder
+renderBuilder (VText _ "")    = fromMisoString " "
+renderBuilder (VText _ s)     = fromMisoString s
+renderBuilder (VNode _ "doctype" [] [] _) = "<!doctype html>"
+renderBuilder (VNode ns tag attrs children _) = mconcat
+  [ "<"
+  , fromMisoString tag
+  , mconcat [ " " <> intercalate " " (renderAttrs <$> attrs)
+            | not (Prelude.null attrs)
+            ]
+  , if tag `elem` selfClosing then "/>" else ">"
+  , mconcat
+    [ mconcat
+      [ foldMap renderBuilder (collapseSiblingTextNodes children)
+      , "</" <> fromMisoString tag <> ">"
+      ]
+    | tag `notElem` selfClosing
+    ]
+  ] where
+      selfClosing = htmls <> svgs <> mathmls
+      htmls = [ x
+              | ns == HTML
+              , x <- [ "area", "base", "col", "embed", "img", "input", "br", "hr", "meta", "link", "param", "source", "track", "wbr" ]
+              ]
+      svgs  = [ x
+              | ns == SVG
+              , x <- [ "circle", "line", "rect", "path", "ellipse", "polygon", "polyline", "use", "image"]
+              ]
+      mathmls =
+              [ x
+              | ns == MATHML
+              , x <- ["mglyph", "mprescripts", "none", "maligngroup", "malignmark" ]
+              ]
+renderBuilder (VComp someComp) =
+  case someComp of
+    SomeComponent _key props comp_ ->
+      -- The app-global @context@ is read from 'globalContext'. For the common
+      -- @context ~ ()@ case the 'Miso.Lens.view' ignores it, so the initial @undefined@ is
+      -- never forced. But if a 'Miso.Lens.view' here inspects a non-trivial @context@,
+      -- SSR must seed the cell with 'Miso.setContext' before serializing, or
+      -- forcing @ctx@ raises an exception. See 'Miso.setContext' for details.
+      let ctx = unsafePerformIO (readIORef globalContext) in
+#ifdef SSR
+      renderBuilder (view comp_ ctx props (getInitialComponentModel comp_))
+#else
+      renderBuilder (view comp_ ctx props (model comp_))
+#endif
+renderBuilder (VCompStatic ptr props0) =
+  case deRefStaticPtr ptr of
+   SomeStaticComponent mk -> case mk props0 of
+    SomeComponent _key props comp_ ->
+      -- The app-global @context@ is read from 'globalContext'. For the common
+      -- @context ~ ()@ case the 'Miso.Lens.view' ignores it, so the initial @undefined@ is
+      -- never forced. But if a 'Miso.Lens.view' here inspects a non-trivial @context@,
+      -- SSR must seed the cell with 'Miso.setContext' before serializing, or
+      -- forcing @ctx@ raises an exception. See 'Miso.setContext' for details.
+      let ctx = unsafePerformIO (readIORef globalContext) in
+#ifdef SSR
+      renderBuilder (view comp_ ctx props (getInitialComponentModel comp_))
+#else
+      renderBuilder (view comp_ ctx props (model comp_))
+#endif
+renderBuilder (VFrag _ kids) = foldMap renderBuilder kids
+----------------------------------------------------------------------------
+renderAttrs :: Attribute model action -> Builder
+renderAttrs (ClassList classes) =
+  mconcat
+  [ "class"
+  , stringUtf8 "=\""
+  , fromMisoString (MS.unwords classes)
+  , stringUtf8 "\""
+  ]
+renderAttrs (Property key (Bool enabled)) -- dmj: account for boolean properties
+  | S.member key booleanProperties, enabled = fromMisoString key
+  | S.member key booleanProperties, not enabled = mempty
+  | otherwise = mconcat
+      [ fromMisoString key
+      , stringUtf8 "=\""
+      , toHtmlFromJSON (Bool enabled)
+      , stringUtf8 "\""
+      ]
+renderAttrs (Property "key" _) = mempty
+renderAttrs (Property key value) =
+  mconcat
+  [ fromMisoString key
+  , stringUtf8 "=\""
+  , toHtmlFromJSON value
+  , stringUtf8 "\""
+  ]
+renderAttrs (On _) = mempty
+renderAttrs (OnStatic _) = mempty
+renderAttrs (Styles styles_) =
+  mconcat
+  [ "style"
+  , stringUtf8 "=\""
+  , mconcat
+    [ mconcat
+      [ fromMisoString k
+      , charUtf8 ':'
+      , fromMisoString v
+      , charUtf8 ';'
+      ]
+    | (k,v) <- M.toList styles_
+    ]
+  , stringUtf8 "\""
+  ]
+----------------------------------------------------------------------------
+-- | The browser can't distinguish between multiple text nodes
+-- and a single text node. So it will always parse a single text node
+-- this means we must collapse adjacent text nodes during hydration.
+collapseSiblingTextNodes :: [View context model action] -> [View context model action]
+collapseSiblingTextNodes [] = []
+collapseSiblingTextNodes (VText _ x : VText k y : xs) =
+  collapseSiblingTextNodes (VText k (x <> y) : xs)
+collapseSiblingTextNodes (x:xs) =
+  x : collapseSiblingTextNodes xs
+----------------------------------------------------------------------------
+-- | Helper for turning JSON into Text
+-- Object, Array and Null are kind of non-sensical here
+toHtmlFromJSON :: Value -> Builder
+toHtmlFromJSON (String t)   = fromMisoString (ms t)
+toHtmlFromJSON (Number t)   = fromMisoString $ ms (show t)
+toHtmlFromJSON (Bool True)  = "true"
+toHtmlFromJSON (Bool False) = "false"
+toHtmlFromJSON Null         = "null"
+toHtmlFromJSON (Object o)   = fromMisoString $ ms (show o)
+toHtmlFromJSON (Array a)    = fromMisoString $ ms (show a)
+-----------------------------------------------------------------------------
+#ifdef SSR
+-- | Used for server-side model hydration, internally only in 'renderView'.
+--
+-- We use 'unsafePerformIO' here because @servant@'s 'MimeRender' is a pure function
+-- yet we need to allow the users to hydrate in 'IO'.
+--
+getInitialComponentModel :: Component context props model action -> model
+getInitialComponentModel Component {..} =
+  case hydrateModel of
+    Nothing -> model
+    Just action -> unsafePerformIO $
+      action `catch` (\(e :: SomeException) -> do
+        putStrLn "Encountered exception during model hydration, falling back to default model"
+        print e
+        pure model)
+----------------------------------------------------------------------------
+#endif
diff --git a/src/Miso/Hydrate.hs b/src/Miso/Hydrate.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Hydrate.hs
@@ -0,0 +1,27 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Hydrate
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- Functions and helpers for Virtual DOM hydration.
+--
+----------------------------------------------------------------------------
+module Miso.Hydrate
+  ( hydrate
+  ) where
+-----------------------------------------------------------------------------
+import qualified Miso.FFI.Internal as FFI
+import           Miso.Types
+import           Miso.DSL
+-----------------------------------------------------------------------------
+-- | Hydration of a t'VTree'
+hydrate :: LogLevel -> DOMRef -> VTree -> IO Bool
+hydrate loggingLevel domRef vtree = do
+  jval <- toJSVal vtree
+  fromJSValUnchecked =<<
+    FFI.hydrate (loggingLevel `elem` [DebugHydrate, DebugAll]) domRef jval
+-----------------------------------------------------------------------------
diff --git a/src/Miso/JSON.hs b/src/Miso/JSON.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/JSON.hs
@@ -0,0 +1,1676 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE LambdaCase                 #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE KindSignatures             #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE DefaultSignatures          #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE TypeApplications           #-}
+{-# LANGUAGE AllowAmbiguousTypes        #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE UndecidableInstances       #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.JSON
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.JSON" is a JSON library tailored to 'MisoString', modelled after
+-- <https://hackage.haskell.org/package/aeson aeson> and inspired by
+-- <https://hackage.haskell.org/package/microaeson microaeson>. It provides
+-- encoding, decoding, and a Generic-deriving mechanism that mirrors aeson's
+-- defaults, making it straightforward to reuse existing aeson-compatible type
+-- class instances.
+--
+-- = Platform behaviour
+--
+-- * __Client__ (WASM \/ GHC JS backend) — 'encode' calls @JSON.stringify()@ and
+--   'decode' calls @JSON.parse()@ via FFI for maximum performance.
+-- * __Server__ (@-fssr@ \/ @VANILLA@ build) — a pure Haskell
+--   lexer\/parser pipeline ("Miso.JSON.Lexer" + "Miso.JSON.Parser") is used
+--   instead, with no JavaScript dependency.
+--
+-- The same type class instances work on both platforms; only the underlying
+-- serialisation primitive differs.
+--
+-- = Quick start
+--
+-- @
+-- {-\# LANGUAGE DeriveGeneric \#-}
+-- import GHC.Generics (Generic)
+-- import "Miso.JSON"
+-- import "Miso.String" ('MisoString')
+--
+-- data Person = Person
+--   { name :: MisoString
+--   , age  :: Int
+--   } deriving (Generic, Show, Eq)
+--
+-- instance 'ToJSON'   Person
+-- instance 'FromJSON' Person
+--
+-- -- Encode to a JSON string:
+-- encoded :: 'MisoString'
+-- encoded = 'encode' (Person \"Alice\" 30)
+-- -- Result: @\"{\\\"name\\\":\\\"Alice\\\",\\\"age\\\":30}\"@
+--
+-- -- Decode from a JSON string:
+-- decoded :: Maybe Person
+-- decoded = 'decode' encoded
+-- @
+--
+-- = Constructing JSON values
+--
+-- Use 'object' and @.=@ to build 'Value' trees without defining a type:
+--
+-- @
+-- point :: 'Value'
+-- point = 'object' [ \"x\" @.=@ (10 :: Int), \"y\" @.=@ (20 :: Int) ]
+-- @
+--
+-- = Writing instances by hand
+--
+-- @
+-- data Color = Red | Green | Blue
+--
+-- instance 'ToJSON' Color where
+--   'toJSON' Red   = 'Miso.JSON.Types.String' \"red\"
+--   'toJSON' Green = 'Miso.JSON.Types.String' \"green\"
+--   'toJSON' Blue  = 'Miso.JSON.Types.String' \"blue\"
+--
+-- instance 'FromJSON' Color where
+--   'parseJSON' = 'withText' \"Color\" $ \\case
+--     \"red\"   -> pure Red
+--     \"green\" -> pure Green
+--     \"blue\"  -> pure Blue
+--     t       -> 'typeMismatch' \"Color\" ('Miso.JSON.Types.String' t)
+-- @
+--
+-- = Generic encoding options
+--
+-- Generic instances follow aeson's default strategy. Customise with t'Options':
+--
+-- @
+-- myOptions :: t'Options'
+-- myOptions = 'defaultOptions' { 'fieldLabelModifier' = 'camelTo2' \'_\' }
+--
+-- instance 'ToJSON' Person where
+--   'toJSON' = 'genericToJSON' myOptions
+--
+-- -- { \"person_name\": \"Alice\", \"person_age\": 30 }
+-- @
+--
+-- = API groups
+--
+-- * __Core types__ — 'Value', t'Object', 'Pair', 'Result'
+-- * __Constructors__ — 'object', @.=@, 'emptyObject', 'emptyArray'
+-- * __Accessors__ — @.:@ (required), '.:?' (optional), '.:!' (optional\/nullable), '.!=' (default)
+-- * __Encoding__ — 'encode', 'encodePure', 'encodePretty', 'encodePretty''
+-- * __Decoding__ — 'decode', 'eitherDecode', 'Parser.decodePure'
+-- * __Type classes__ — 'ToJSON', 'FromJSON', t'Parser'
+-- * __Prism-style parsers__ — 'withObject', 'withText', 'withArray', 'withNumber', 'withBool'
+-- * __Conversion__ — 'fromJSON', 'parseMaybe', 'parseEither'
+-- * __Options \/ Generics__ — t'Options', 'defaultOptions', 'genericToJSON', 'genericParseJSON', 'camelTo2'
+-- * __FFI__ — 'toJSVal_Value', 'fromJSVal_Value', 'jsonStringify', 'jsonParse'
+--
+-- = See also
+--
+-- * "Miso.JSON.Types" — 'Value' and 'Result' type definitions
+-- * "Miso.JSON.Lexer" — pure Haskell JSON tokeniser (server build)
+-- * "Miso.JSON.Parser" — pure Haskell JSON parser (server build)
+-- * "Miso.Event.Decoder" — uses t'Parser' and 'Value' for DOM event decoding
+-- * "Miso.String" — 'MisoString', 'ms'
+--
+----------------------------------------------------------------------------
+module Miso.JSON
+  ( -- * JSON
+    -- ** Core JSON types
+    Value(..)
+  , Object
+  , Pair
+  , Result (..)
+    -- ** Constructors
+  , (.=)
+  , object
+  , emptyArray
+  , emptyObject
+    -- ** Accessors
+  , (.:)
+  , (.:?)
+  , (.:!)
+  , (.!=)
+    -- * Encoding and decoding
+  , encode
+  , encodePure
+  , decode
+  , Parser.decodePure
+    -- * Prism-style parsers
+  , withObject
+  , withText
+  , withArray
+  , withNumber
+  , withBool
+    -- * Type conversion
+  , FromJSON(parseJSON)
+#ifdef AESON
+  , Parser
+#else
+  , Parser (..)
+#endif
+  , parseMaybe
+  , ToJSON(..)
+  -- * Misc.
+  , fromJSON
+  , parseEither
+  , eitherDecode
+  , typeMismatch
+  -- * Pretty
+  , encodePretty
+  , encodePretty'
+  , defConfig
+  , Config (..)
+  -- * FFI
+  , fromJSVal_Value
+  , toJSVal_Value
+  , jsonStringify
+  , jsonParse
+  -- * Options
+  , Options (..)
+  , defaultOptions
+  -- * Generics
+#ifndef AESON
+  , GToJSON (..)
+  , GToFields (..)
+  , GToJSONRep (..)
+  , GToJSONSum (..)
+  , GToJSONSumNullary (..)
+  , GAllNullary (..)
+  , Fields (..)
+  , GFromJSON (..)
+  , GFromFields (..)
+  , GFromJSONRep (..)
+  , GFromJSONSum (..)
+  , GFromJSONSumNullary (..)
+#endif
+  , genericToJSON
+  , genericParseJSON
+  -- * Modifiers
+  , camelTo2
+  ) where
+----------------------------------------------------------------------------
+#ifdef GHCJS_BOTH
+import qualified GHCJS.Marshal as Marshal
+#endif
+----------------------------------------------------------------------------
+import           Control.Monad
+#if __GLASGOW_HASKELL__ <= 865
+import           Control.Monad.Fail
+import           GHC.Natural (Natural)
+#endif
+#ifdef AESON
+import           Data.Aeson.Types
+  ( ToJSON (..), FromJSON (..), Parser, Options (..), Key
+  , defaultOptions, camelTo2, genericToJSON, genericParseJSON
+  , object, emptyArray, emptyObject, parseMaybe, (.!=)
+  )
+import qualified Data.Aeson as Aeson
+import qualified Data.Aeson.Types as Aeson
+import qualified Data.Aeson.Key as Key
+import           Data.Bifunctor (first)
+import           Data.Scientific (Scientific, toRealFloat, fromFloatDigits)
+#ifndef VANILLA
+import           Data.Aeson.Types (ToJSONKey (..), FromJSONKey (..), FromJSONKeyFunction (..), toJSONKeyText)
+import qualified Data.Aeson.KeyMap as KeyMap
+#endif
+#else
+import           Control.Applicative
+import           Data.Char
+import qualified Data.Map.Strict as M
+import           Data.Map.Strict (Map)
+import           Data.Maybe (fromMaybe)
+import           Data.Int
+import           GHC.Natural (naturalToInteger, naturalFromInteger)
+import           GHC.TypeLits
+import           Data.Kind
+import qualified Data.Text.Lazy as LT
+import           Data.Word
+import           GHC.Generics
+#endif
+----------------------------------------------------------------------------
+import           Miso.DSL.FFI
+#ifdef AESON
+import           Miso.String (FromMisoString, ToMisoString, MisoString, ms, pack)
+#else
+import           Miso.String (FromMisoString, ToMisoString, MisoString, ms, singleton, pack)
+#endif
+import qualified Miso.String as MS
+import           Miso.JSON.Types
+import qualified Miso.JSON.Parser as Parser
+#ifndef AESON
+import           Numeric (showHex)
+#endif
+----------------------------------------------------------------------------
+#ifndef VANILLA
+import           Control.Monad.Trans.Maybe
+import           Data.Foldable (toList)
+import           System.IO.Unsafe (unsafePerformIO)
+import qualified Data.Text as T
+#endif
+
+----------------------------------------------------------------------------
+-- | Construct a JSON key\/value 'Pair'. Infix alias for @\\k v -> (k, 'toJSON' v)@.
+--
+-- @
+-- object [ \"name\" .= (\"Alice\" :: MisoString), \"age\" .= (30 :: Int) ]
+-- @
+infixr 8 .=
+#ifdef AESON
+(.=) :: ToJSON v => MisoString -> v -> Pair
+k .= v  = (toKey k, toJSON v)
+----------------------------------------------------------------------------
+-- | Convert a t'MisoString' to an aeson 'Key'.
+toKey :: MisoString -> Key
+toKey = Key.fromText . MS.fromMisoString
+----------------------------------------------------------------------------
+-- 'object', 'emptyObject', 'emptyArray', and '.!=' are re-exported from aeson.
+----------------------------------------------------------------------------
+-- | Look up a required key in a JSON t'Object'.
+-- Fails with a parse error if the key is absent.
+(.:) :: FromJSON a => Object -> MisoString -> Parser a
+m .: k = (Aeson..:) m (toKey k)
+----------------------------------------------------------------------------
+-- | Look up an optional key in a JSON t'Object'.
+-- Returns 'Nothing' if the key is absent; delegates to 'parseJSON' if present.
+(.:?) :: FromJSON a => Object -> MisoString -> Parser (Maybe a)
+m .:? k = (Aeson..:?) m (toKey k)
+----------------------------------------------------------------------------
+-- | Like '.:?' but always wraps a present value in 'Just', so a key with a
+-- @null@ JSON value decodes to @Just Null@ rather than 'Nothing'.
+-- Useful when you need to distinguish a missing key from an explicit null.
+(.:!) :: FromJSON a => Object -> MisoString -> Parser (Maybe a)
+m .:! k = (Aeson..:!) m (toKey k)
+#else
+(.=) :: ToJSON v => MisoString -> v -> Pair
+k .= v  = (k, toJSON v)
+----------------------------------------------------------------------------
+-- | Create a 'Value' from a list of name\/value 'Pair's.
+object :: [Pair] -> Value
+object = Object . M.fromList
+----------------------------------------------------------------------------
+-- | The empty JSON t'Object' (i.e. @{}@).
+emptyObject :: Value
+emptyObject = Object mempty
+----------------------------------------------------------------------------
+-- | The empty JSON 'Array' (i.e. @[]@).
+emptyArray :: Value
+emptyArray = Array mempty
+----------------------------------------------------------------------------
+-- | Look up a required key in a JSON t'Object'.
+-- Fails with a parse error if the key is absent.
+(.:) :: FromJSON a => Object -> MisoString -> Parser a
+m .: k = maybe (pfail ("Key not found: " <> k)) parseJSON (M.lookup k m)
+----------------------------------------------------------------------------
+-- | Look up an optional key in a JSON t'Object'.
+-- Returns 'Nothing' if the key is absent; delegates to 'parseJSON' if present.
+(.:?) :: FromJSON a => Object -> MisoString -> Parser (Maybe a)
+m .:? k = maybe (pure Nothing) parseJSON (M.lookup k m)
+----------------------------------------------------------------------------
+-- | Like '.:?' but always wraps a present value in 'Just', so a key with a
+-- @null@ JSON value decodes to @Just Null@ rather than 'Nothing'.
+-- Useful when you need to distinguish a missing key from an explicit null.
+(.:!) :: FromJSON a => Object -> MisoString -> Parser (Maybe a)
+m .:! k = maybe (pure Nothing) (fmap Just . parseJSON) (M.lookup k m)
+----------------------------------------------------------------------------
+-- | Provide a default when a t'Parser' produces 'Nothing'.
+-- Typically chained after '.:?':
+--
+-- @o '.:?' \"count\" '.!=' 0@
+(.!=) :: Parser (Maybe a) -> a -> Parser a
+mv .!= def = fmap (fromMaybe def) mv
+#endif
+----------------------------------------------------------------------------
+#ifdef AESON
+#if !defined(VANILLA) && !defined(MISO_TEXT)
+-- On the JavaScript and WASM backends t'MisoString' is @JSString@, which
+-- aeson does not know about; these orphans make it a first-class JSON
+-- citizen so code written against "Miso.JSON" keeps compiling.
+instance ToJSON MisoString where
+  toJSON = String . MS.fromMisoString
+----------------------------------------------------------------------------
+instance FromJSON MisoString where
+  parseJSON = withText "MisoString" pure
+----------------------------------------------------------------------------
+instance ToJSONKey MisoString where
+  toJSONKey = toJSONKeyText MS.fromMisoString
+----------------------------------------------------------------------------
+instance FromJSONKey MisoString where
+  fromJSONKey = FromJSONKeyText ms
+#endif
+#else
+-- | A type that can be serialised to a JSON 'Value'.
+--
+-- Instances for the most common Haskell types are provided. Derive via
+-- 'GHC.Generics' for product\/sum types, or write instances by hand for
+-- full control:
+--
+-- @
+-- -- Generic derivation (mirrors aeson defaults):
+-- data Point = Point { x :: Double, y :: Double }
+--   deriving (Generic, Show, Eq)
+-- instance 'ToJSON' Point
+--
+-- -- Manual instance:
+-- instance 'ToJSON' Point where
+--   'toJSON' (Point x y) = 'object' [\"x\" @.=@ x, \"y\" @.=@ y]
+-- @
+class ToJSON a where
+  -- | Convert a value to a JSON 'Value'.
+  toJSON :: a -> Value
+  default toJSON :: (Generic a, GToJSON (Rep a)) => a -> Value
+  toJSON = genericToJSON defaultOptions
+
+  -- | Encode a list of @a@. Defaults to a JSON 'Array'; overridden by the
+  -- 'Char' instance so that @[Char]@ (i.e. t'String') serializes as a JSON
+  -- string. This mirrors aeson and avoids overlapping @ToJSON [a]@ instances.
+  toJSONList :: [a] -> Value
+  toJSONList = Array . Prelude.map toJSON
+----------------------------------------------------------------------------
+-- | Derive 'toJSON' via 'GHC.Generics' with custom t'Options'.
+-- Called by the default 'ToJSON' implementation using 'defaultOptions'.
+genericToJSON
+  :: (Generic a, GToJSON (Rep a))
+  => Options
+  -- ^ Encoding options (field\/constructor name modifiers, etc.)
+  -> a
+  -- ^ Value to encode
+  -> Value
+genericToJSON opts = gToJSON opts . from
+----------------------------------------------------------------------------
+-- | Configuration for generic JSON encoding and decoding via 'genericToJSON'
+-- and 'genericParseJSON'. Mirrors the subset of aeson's @Options@ that is
+-- relevant to miso's Generic machinery.
+--
+-- Construct with 'defaultOptions' and override only the fields you need:
+--
+-- @
+-- myOpts :: t'Options'
+-- myOpts = 'defaultOptions' { 'fieldLabelModifier' = 'camelTo2' \'_\' }
+-- @
+data Options
+  = Options
+  { fieldLabelModifier    :: String -> String
+  -- ^ Applied to each record field name before encoding\/decoding (default: identity).
+  , constructorTagModifier :: String -> String
+  -- ^ Modify constructor names used as tags before encoding (default: identity).
+  , allNullaryToStringTag :: Bool
+  -- ^ When 'True' (the default, matching aeson) and every constructor of a
+  -- sum type is nullary, encode/decode each constructor as a bare JSON
+  -- t'String' (e.g. @\"Red\"@) rather than a tagged object
+  -- (e.g. @{\"tag\":\"Red\"}@).
+  , omitNothingFields :: Bool
+  -- ^ When 'True', record fields whose value is 'Nothing' are omitted from
+  -- the encoded object entirely. When @False@ (the default, matching aeson)
+  -- they are encoded as @null@.
+  }
+----------------------------------------------------------------------------
+-- | Default encoding\/decoding options, matching aeson's defaults:
+-- no field or constructor name transformation, 'allNullaryToStringTag' enabled,
+-- 'omitNothingFields' disabled.
+defaultOptions :: Options
+defaultOptions = Options
+  { fieldLabelModifier     = \x -> x
+  , constructorTagModifier = \x -> x
+  , allNullaryToStringTag  = True
+  , omitNothingFields      = False
+  }
+----------------------------------------------------------------------------
+-- | Convert a camelCase identifier to a separated form using the given delimiter.
+--
+-- @
+-- camelTo2 '_' \"camelCaseField\" == \"camel_case_field\"
+-- @
+--
+-- Commonly used as 'fieldLabelModifier' in a custom t'Options'.
+camelTo2
+  :: Char
+  -- ^ Delimiter character to insert between words (e.g. @\'_\'@ or @\'-\'@)
+  -> String
+  -- ^ camelCase identifier to transform
+  -> String
+camelTo2 c = Prelude.map toLower . go2 . go1
+    where go1 "" = ""
+          go1 (x:u:l:xs) | isUpper u && isLower l = x : c : u : l : go1 xs
+          go1 (x:xs) = x : go1 xs
+          go2 "" = ""
+          go2 (l:u:xs) | isLower l && isUpper u = l : c : u : go2 xs
+          go2 (x:xs) = x : go2 xs
+----------------------------------------------------------------------------
+-- | Intermediate representation of a constructor's fields after encoding.
+--
+-- 'RecordFields' is produced when every selector has a name (record syntax);
+-- 'PositionalFields' is produced for all other constructors.
+data Fields
+  = RecordFields   [(MisoString, Value)]
+  -- ^ Named fields (record constructor)
+  | PositionalFields [Value]
+  -- ^ Positional fields (non-record constructor)
+----------------------------------------------------------------------------
+combineFields :: Fields -> Fields -> Fields
+combineFields (RecordFields   xs) (RecordFields   ys) = RecordFields   (xs <> ys)
+combineFields (PositionalFields xs) (PositionalFields ys) = PositionalFields (xs <> ys)
+combineFields _ _ = PositionalFields []  -- mixed; shouldn't occur in valid GHC Generics
+----------------------------------------------------------------------------
+-- | Collect a constructor's fields into 'Fields'.
+class GToFields (f :: Type -> Type) where
+  gToFields :: Options -> f a -> Fields
+----------------------------------------------------------------------------
+instance GToFields U1 where
+  gToFields _ _ = PositionalFields []
+----------------------------------------------------------------------------
+instance GToFields V1 where
+  gToFields _ v = v `seq` PositionalFields []
+----------------------------------------------------------------------------
+instance (GToFields f, GToFields g) => GToFields (f :*: g) where
+  gToFields opts (x :*: y) = combineFields (gToFields opts x) (gToFields opts y)
+----------------------------------------------------------------------------
+instance (Selector m, GToFields f) => GToFields (S1 m f) where
+  gToFields opts (M1 x) =
+    let n = selName (M1 undefined :: S1 m f ())
+    in if null n
+       then gToFields opts x
+       else case gToFields opts x of
+              PositionalFields [v] -> RecordFields [(ms (fieldLabelModifier opts n), v)]
+              fs                   -> fs  -- shouldn't happen
+----------------------------------------------------------------------------
+instance ToJSON a => GToFields (K1 r a) where
+  gToFields _ (K1 x) = PositionalFields [toJSON x]
+----------------------------------------------------------------------------
+-- | Special 'GToFields' instance for @'Maybe' a@ fields that honours
+-- 'omitNothingFields': when the option is 'True' and the value is
+-- 'Nothing', the field is omitted from the encoded object entirely.
+instance {-# OVERLAPPING #-} (Selector m, ToJSON a)
+    => GToFields (S1 m (K1 r (Maybe a))) where
+  gToFields opts (M1 (K1 mx)) =
+    let n   = selName (M1 undefined :: S1 m (K1 r (Maybe a)) ())
+        key = ms (fieldLabelModifier opts n)
+    in if null n
+       then PositionalFields [toJSON mx]
+       else case mx of
+              Nothing | omitNothingFields opts -> RecordFields []
+              _                                -> RecordFields [(key, toJSON mx)]
+----------------------------------------------------------------------------
+-- | Determine at the type level whether every constructor of a sum type
+-- is nullary (has no fields). Used to implement 'allNullaryToStringTag'.
+class GAllNullary (f :: Type -> Type) where
+  gAllNullary :: Bool
+----------------------------------------------------------------------------
+instance GAllNullary U1 where
+  gAllNullary = True
+----------------------------------------------------------------------------
+instance GAllNullary (K1 r a) where
+  gAllNullary = False
+----------------------------------------------------------------------------
+instance (GAllNullary f, GAllNullary g) => GAllNullary (f :*: g) where
+  gAllNullary = False  -- has multiple fields, definitely not nullary
+----------------------------------------------------------------------------
+instance GAllNullary f => GAllNullary (S1 m f) where
+  gAllNullary = gAllNullary @f
+----------------------------------------------------------------------------
+instance GAllNullary f => GAllNullary (C1 m f) where
+  gAllNullary = gAllNullary @f
+----------------------------------------------------------------------------
+instance (GAllNullary f, GAllNullary g) => GAllNullary (f :+: g) where
+  gAllNullary = gAllNullary @f && gAllNullary @g
+----------------------------------------------------------------------------
+-- | Encode a single-constructor (product) type. No tag is added.
+--
+-- * Record:       @{"field1": v, ...}@
+-- * 0 fields:     @[]@
+-- * 1 field:      the value itself (unwrapped, like a newtype)
+-- * 2+ fields:    @[v1, v2, ...]@
+encodeProduct :: Fields -> Value
+encodeProduct = \case
+  RecordFields   kvs  -> Object (M.fromList kvs)
+  PositionalFields []  -> Array []
+  PositionalFields [v] -> v
+  PositionalFields vs  -> Array vs
+----------------------------------------------------------------------------
+-- | Encode a sum constructor. Adds a @\"tag\"@ key.
+--
+-- * Record:       @{\"tag\": \"C\", \"field1\": v, ...}@
+-- * 0 fields:     @{\"tag\": \"C\"}@
+-- * 1 field:      @{\"tag\": \"C\", \"contents\": v}@
+-- * 2+ fields:    @{\"tag\": \"C\", \"contents\": [v1, v2, ...]}@
+encodeTaggedCon :: MisoString -> Fields -> Value
+encodeTaggedCon tag = \case
+  RecordFields   kvs  -> Object (M.fromList (("tag", String tag) : kvs))
+  PositionalFields []  -> Object (M.singleton "tag" (String tag))
+  PositionalFields [v] -> object [("tag", String tag), ("contents", v)]
+  PositionalFields vs  -> object [("tag", String tag), ("contents", Array vs)]
+----------------------------------------------------------------------------
+-- | Top-level generic encoding class.
+--
+-- Encoding rules match aeson's defaults:
+--
+-- * All-nullary sum + 'allNullaryToStringTag':  @\"C\"@
+-- * Single-constructor record:                  @{\"field1\": v1, ...}@
+-- * Single-constructor positional:              @v@ (1 field), @[v1,v2,...]@ (n>1), @[]@ (0)
+-- * Sum record constructor:                     @{\"tag\": \"C\", \"field1\": v1, ...}@
+-- * Sum nullary constructor:                    @{\"tag\": \"C\"}@
+-- * Sum positional constructor:                 @{\"tag\": \"C\", \"contents\": v}@ or @[...]@
+class GToJSON (f :: Type -> Type) where
+  gToJSON :: Options -> f a -> Value
+----------------------------------------------------------------------------
+instance GToJSONRep f => GToJSON (D1 m f) where
+  gToJSON opts (M1 x) = gToJSONRep opts x
+----------------------------------------------------------------------------
+-- Internal: dispatches single-constructor vs sum at the child of D1.
+-- | Internal: dispatches on the child of @D1@, choosing the
+-- single-constructor encoding or the sum encoding. Sits between 'GToJSON' and
+-- 'GToFields' \/ 'GToJSONSum'.
+--
+-- @since 1.13.0.0
+class GToJSONRep (f :: Type -> Type) where
+  gToJSONRep :: Options -> f a -> Value
+-- Single constructor: no tag
+instance GToFields f => GToJSONRep (C1 m f) where
+  gToJSONRep opts (M1 x) = encodeProduct (gToFields opts x)
+-- Sum: branch on allNullaryToStringTag
+instance (GToJSONSum f, GToJSONSum g, GToJSONSumNullary f, GToJSONSumNullary g, GAllNullary f, GAllNullary g)
+    => GToJSONRep (f :+: g) where
+  gToJSONRep opts x
+    | allNullaryToStringTag opts && gAllNullary @f && gAllNullary @g
+    = gToJSONSumNullary opts x
+    | otherwise
+    = gToJSONSum opts x
+----------------------------------------------------------------------------
+-- | Encode all-nullary sum constructors as bare t'String' values.
+class GToJSONSumNullary (f :: Type -> Type) where
+  gToJSONSumNullary :: Options -> f a -> Value
+----------------------------------------------------------------------------
+instance (GToJSONSumNullary f, GToJSONSumNullary g) => GToJSONSumNullary (f :+: g) where
+  gToJSONSumNullary opts (L1 x) = gToJSONSumNullary opts x
+  gToJSONSumNullary opts (R1 x) = gToJSONSumNullary opts x
+----------------------------------------------------------------------------
+instance Constructor m => GToJSONSumNullary (C1 m U1) where
+  gToJSONSumNullary opts _ =
+    String (ms (constructorTagModifier opts (conName (undefined :: C1 m U1 ()))))
+----------------------------------------------------------------------------
+-- | Catch-all for non-nullary constructors — unreachable when 'gAllNullary'
+-- guards are in place, but required for instance resolution.
+instance {-# OVERLAPPABLE #-} Constructor m => GToJSONSumNullary (C1 m f) where
+  gToJSONSumNullary _ _ = error "GToJSONSumNullary: non-nullary constructor (impossible)"
+----------------------------------------------------------------------------
+-- | Encode sum constructors with a @\"tag\"@ key.
+class GToJSONSum (f :: Type -> Type) where
+  gToJSONSum :: Options -> f a -> Value
+----------------------------------------------------------------------------
+instance (GToJSONSum f, GToJSONSum g) => GToJSONSum (f :+: g) where
+  gToJSONSum opts (L1 x) = gToJSONSum opts x
+  gToJSONSum opts (R1 x) = gToJSONSum opts x
+----------------------------------------------------------------------------
+instance (Constructor m, GToFields f) => GToJSONSum (C1 m f) where
+  gToJSONSum opts (M1 x) =
+    encodeTaggedCon
+      (ms (constructorTagModifier opts (conName (undefined :: C1 m f ()))))
+      (gToFields opts x)
+----------------------------------------------------------------------------
+instance ToJSON () where
+  toJSON () = Array []
+----------------------------------------------------------------------------
+instance ToJSON Value where
+  toJSON = id
+----------------------------------------------------------------------------
+instance ToJSON Char where
+  toJSON c = String (singleton c)
+  toJSONList = String . MS.pack
+----------------------------------------------------------------------------
+instance ToJSON Bool where
+  toJSON = Bool
+----------------------------------------------------------------------------
+instance ToJSON a => ToJSON [a] where
+  toJSON = toJSONList
+----------------------------------------------------------------------------
+instance ToJSON v => ToJSON (M.Map MisoString v) where
+  toJSON = Object . M.map toJSON
+----------------------------------------------------------------------------
+instance ToJSON a => ToJSON (Maybe a) where
+  toJSON = \case
+    Nothing -> Null
+    Just a -> toJSON a
+----------------------------------------------------------------------------
+instance (ToJSON a,ToJSON b) => ToJSON (a,b) where
+  toJSON (a,b) = Array [toJSON a, toJSON b]
+----------------------------------------------------------------------------
+instance (ToJSON a,ToJSON b,ToJSON c) => ToJSON (a,b,c) where
+  toJSON (a,b,c) = Array [toJSON a, toJSON b, toJSON c]
+----------------------------------------------------------------------------
+instance (ToJSON a,ToJSON b,ToJSON c, ToJSON d) => ToJSON (a,b,c,d) where
+  toJSON (a,b,c,d) = Array [toJSON a, toJSON b, toJSON c, toJSON d]
+----------------------------------------------------------------------------
+instance ToJSON MisoString where
+  toJSON = String
+----------------------------------------------------------------------------
+#if !defined(VANILLA) && !defined(MISO_TEXT)
+instance ToJSON T.Text where
+  toJSON = toJSON . ms
+#endif
+----------------------------------------------------------------------------
+instance ToJSON LT.Text where
+  toJSON = toJSON . ms
+----------------------------------------------------------------------------
+instance ToJSON Float where
+  toJSON = Number . realToFrac
+----------------------------------------------------------------------------
+instance ToJSON Double where
+  toJSON = Number
+----------------------------------------------------------------------------
+instance ToJSON Int    where  toJSON = Number . realToFrac
+instance ToJSON Int8   where  toJSON = Number . realToFrac
+instance ToJSON Int16  where  toJSON = Number . realToFrac
+instance ToJSON Int32  where  toJSON = Number . realToFrac
+----------------------------------------------------------------------------
+instance ToJSON Word   where  toJSON = Number . realToFrac
+instance ToJSON Word8  where  toJSON = Number . realToFrac
+instance ToJSON Word16 where  toJSON = Number . realToFrac
+instance ToJSON Word32 where  toJSON = Number . realToFrac
+----------------------------------------------------------------------------
+-- | Possibly lossy due to conversion to 'Double'
+instance ToJSON Int64  where  toJSON = Number . realToFrac
+----------------------------------------------------------------------------
+-- | Possibly lossy due to conversion to 'Double'
+instance ToJSON Word64 where  toJSON = Number . realToFrac
+----------------------------------------------------------------------------
+-- | Possibly lossy due to conversion to 'Double'
+instance ToJSON Integer where toJSON = Number . fromInteger
+----------------------------------------------------------------------------
+-- | Possibly lossy due to conversion to 'Double'
+instance ToJSON Natural where toJSON = Number . fromInteger . naturalToInteger
+#endif
+----------------------------------------------------------------------------
+#ifndef AESON
+-- | A lightweight JSON parse monad. Wraps @Either MisoString a@ so that
+-- parse failures carry a human-readable error message.
+--
+-- t'Parser' is a 'Functor', 'Applicative', 'Monad', 'MonadFail', and
+-- 'Alternative'. The 'Alternative' instance tries the right branch only when
+-- the left branch fails — useful for decoding sum types with multiple valid
+-- shapes.
+--
+-- Combine with 'parseJSON' and the accessor operators (@.:@ etc.) to build
+-- composite decoders:
+--
+-- @
+-- data Point = Point Double Double
+--
+-- instance 'FromJSON' Point where
+--   'parseJSON' = 'withArray' \"Point\" $ \\xs ->
+--     Point \<$\> 'parseJSON' (xs '!!' 0)
+--           \<*\> 'parseJSON' (xs '!!' 1)
+-- @
+newtype Parser a = Parser
+  { unParser :: Either MisoString a
+  -- ^ The underlying result: @'Left' errMsg@ on failure, @'Right' a@ on success
+  } deriving (Functor, Applicative, Monad)
+----------------------------------------------------------------------------
+instance MonadFail Parser where
+  fail = pfail . pack
+----------------------------------------------------------------------------
+instance Alternative Parser where
+  empty = Parser (Left mempty)
+  Parser (Left _) <|> r = r
+  l <|> _ = l
+----------------------------------------------------------------------------
+instance MonadPlus Parser
+----------------------------------------------------------------------------
+-- | Run a parser function, returning 'Nothing' on failure instead of an error string.
+parseMaybe
+  :: (a -> Parser b)
+  -- ^ Parser function to apply
+  -> a
+  -- ^ Input value to parse
+  -> Maybe b
+parseMaybe m v =
+  case parseEither m v of
+    Left _ -> Nothing
+    Right r -> Just r
+----------------------------------------------------------------------------
+-- | Run a parser function, returning @'Left' errMsg@ on failure.
+parseEither
+  :: (a -> Parser b)
+  -- ^ Parser function to apply
+  -> a
+  -- ^ Input value to parse
+  -> Either MisoString b
+parseEither m v = unParser (m v)
+----------------------------------------------------------------------------
+pfail :: MisoString -> Parser a
+pfail message = Parser (Left message)
+#else
+----------------------------------------------------------------------------
+-- | Run a parser function, returning @'Left' errMsg@ on failure.
+parseEither
+  :: (a -> Parser b)
+  -- ^ Parser function to apply
+  -> a
+  -- ^ Input value to parse
+  -> Either MisoString b
+parseEither m v = first ms (Aeson.parseEither m v)
+#endif
+----------------------------------------------------------------------------
+#ifndef AESON
+-- | A type that can be deserialised from a JSON 'Value'.
+--
+-- Instances for the most common Haskell types are provided. Derive via
+-- 'GHC.Generics' for product\/sum types, or write instances by hand:
+--
+-- @
+-- -- Generic derivation:
+-- data Point = Point { x :: Double, y :: Double }
+--   deriving (Generic, Show, Eq)
+-- instance 'FromJSON' Point
+--
+-- -- Manual instance:
+-- instance 'FromJSON' Point where
+--   'parseJSON' = 'withObject' \"Point\" $ \\o ->
+--     Point \<$\> o @.:@ \"x\" \<*\> o @.:@ \"y\"
+-- @
+class FromJSON a where
+  -- | Parse a JSON 'Value' into @a@, failing with a descriptive error message
+  -- via t'Parser' on a type mismatch.
+  parseJSON :: Value -> Parser a
+  default parseJSON :: (Generic a, GFromJSON (Rep a)) => Value -> Parser a
+  parseJSON = genericParseJSON defaultOptions
+----------------------------------------------------------------------------
+-- | Top-level generic decoding class. Symmetric with 'GToJSON'.
+--
+-- Decoding rules match aeson's defaults (see t'Options' and 'defaultOptions').
+class GFromJSON (f :: Type -> Type) where
+  gParseJSON :: Options -> Value -> Parser (f a)
+----------------------------------------------------------------------------
+-- | Derive 'parseJSON' via 'GHC.Generics' with custom t'Options'.
+-- Called by the default 'FromJSON' implementation using 'defaultOptions'.
+genericParseJSON
+  :: (Generic a, GFromJSON (Rep a))
+  => Options
+  -- ^ Decoding options (field\/constructor name modifiers, etc.)
+  -> Value
+  -- ^ JSON 'Value' to decode
+  -> Parser a
+genericParseJSON opts value = to <$> gParseJSON opts value
+----------------------------------------------------------------------------
+instance GFromJSONRep f => GFromJSON (D1 m f) where
+  gParseJSON opts v = M1 <$> gFromJSONRep opts v
+----------------------------------------------------------------------------
+-- Internal: dispatches single-constructor vs sum at the child of D1.
+-- | Internal: the decoding counterpart of 'GToJSONRep'. Dispatches on the
+-- child of @D1@, choosing the single-constructor or sum decoder.
+--
+-- @since 1.13.0.0
+class GFromJSONRep (f :: Type -> Type) where
+  gFromJSONRep :: Options -> Value -> Parser (f a)
+-- Single constructor
+instance GFromFields f => GFromJSONRep (C1 m f) where
+  gFromJSONRep opts v = M1 <$> parseProd opts v
+-- Sum type: branch on allNullaryToStringTag
+instance (GFromJSONSum f, GFromJSONSum g, GFromJSONSumNullary f, GFromJSONSumNullary g, GAllNullary f, GAllNullary g)
+    => GFromJSONRep (f :+: g) where
+  gFromJSONRep opts v
+    | allNullaryToStringTag opts && gAllNullary @f && gAllNullary @g
+    = gFromJSONSumNullary opts v
+    | otherwise
+    = gFromJSONSum opts v
+----------------------------------------------------------------------------
+-- | Parse all-nullary sum constructors from bare t'String' values.
+class GFromJSONSumNullary (f :: Type -> Type) where
+  gFromJSONSumNullary :: Options -> Value -> Parser (f a)
+----------------------------------------------------------------------------
+instance (GFromJSONSumNullary f, GFromJSONSumNullary g) => GFromJSONSumNullary (f :+: g) where
+  gFromJSONSumNullary opts v =
+    (L1 <$> gFromJSONSumNullary opts v) <|> (R1 <$> gFromJSONSumNullary opts v)
+----------------------------------------------------------------------------
+instance Constructor m => GFromJSONSumNullary (C1 m U1) where
+  gFromJSONSumNullary opts v =
+    let tag = ms (constructorTagModifier opts (conName (undefined :: C1 m U1 ())))
+    in case v of
+         String t | t == tag  -> pure (M1 U1)
+                  | otherwise -> pfail ("expected \"" <> tag <> "\" got \"" <> t <> "\"")
+         _        -> pfail ("expected String for nullary constructor " <> tag)
+----------------------------------------------------------------------------
+-- | Catch-all for non-nullary constructors — unreachable when 'gAllNullary'
+-- guards are in place, but required for instance resolution.
+instance {-# OVERLAPPABLE #-} Constructor m => GFromJSONSumNullary (C1 m f) where
+  gFromJSONSumNullary _ _ = pfail "GFromJSONSumNullary: non-nullary constructor (impossible)"
+----------------------------------------------------------------------------
+-- | Parse sum constructors, trying each branch left-to-right.
+class GFromJSONSum (f :: Type -> Type) where
+  gFromJSONSum :: Options -> Value -> Parser (f a)
+----------------------------------------------------------------------------
+instance (GFromJSONSum f, GFromJSONSum g) => GFromJSONSum (f :+: g) where
+  gFromJSONSum opts v = (L1 <$> gFromJSONSum opts v) <|> (R1 <$> gFromJSONSum opts v)
+----------------------------------------------------------------------------
+instance (Constructor m, GFromFields f) => GFromJSONSum (C1 m f) where
+  gFromJSONSum opts v = M1 <$> parseTaggedCon tag opts v
+    where tag = ms (constructorTagModifier opts (conName (undefined :: C1 m f ())))
+----------------------------------------------------------------------------
+-- | Parse a single-constructor (product) type from a 'Value'.
+parseProd :: forall f a. GFromFields f => Options -> Value -> Parser (f a)
+parseProd opts v
+  | gIsRecord @f = withObject "generic record" (gFromRecord opts) v
+  | otherwise    = case v of
+      Array vs
+        | gFieldCount @f == 1 -> gFromPositional opts [Array vs]
+        | otherwise           -> gFromPositional opts vs
+      _
+        | gFieldCount @f == 0 -> pfail "expected Array [] for 0-field constructor"
+        | gFieldCount @f == 1 -> gFromPositional opts [v]  -- single-field shorthand
+        | otherwise           -> pfail "expected JSON Array for multi-field constructor"
+----------------------------------------------------------------------------
+-- | Parse a tagged sum constructor from an Object envelope.
+parseTaggedCon :: forall f a. GFromFields f => MisoString -> Options -> Value -> Parser (f a)
+parseTaggedCon tag opts = \case
+  Object o -> do
+    t <- case M.lookup "tag" o of
+           Just (String t) -> pure t
+           Just _          -> pfail "\"tag\" field is not a string"
+           Nothing         -> pfail "missing \"tag\" field"
+    if t /= tag
+      then pfail ("expected tag " <> ms (show tag) <> ", got " <> ms (show t))
+      else if gIsRecord @f
+           then gFromRecord opts o
+           else case M.lookup "contents" o of
+                  Just (Array vs)
+                    | gFieldCount @f == 1 -> gFromPositional opts [Array vs]
+                    | otherwise           -> gFromPositional opts vs
+                  Just single     -> gFromPositional opts [single]
+                  Nothing         -> gFromPositional opts []
+  _ -> pfail ("expected JSON object for constructor " <> ms (show tag))
+----------------------------------------------------------------------------
+-- | Field-level decoder. Knows whether the constructor is a record and
+-- how many fields it has; can decode from a JSON t'Object' (record mode)
+-- or a positional '[Value]' list.
+class GFromFields (f :: Type -> Type) where
+  -- | Is this a record constructor (all selectors have names)?
+  gIsRecord      :: Bool
+  -- | Number of fields.
+  gFieldCount    :: Int
+  -- | Decode from a JSON t'Object' (record mode: look up by field name).
+  gFromRecord    :: Options -> Object -> Parser (f a)
+  -- | Decode from a positional list of 'Value'.
+  gFromPositional :: Options -> [Value] -> Parser (f a)
+----------------------------------------------------------------------------
+instance GFromFields U1 where
+  gIsRecord       = False
+  gFieldCount     = 0
+  gFromRecord   _ _ = pure U1
+  gFromPositional _ _ = pure U1
+----------------------------------------------------------------------------
+instance GFromFields V1 where
+  gIsRecord       = False
+  gFieldCount     = 0
+  gFromRecord   _ _ = pfail "V1"
+  gFromPositional _ _ = pfail "V1"
+----------------------------------------------------------------------------
+instance (GFromFields f, GFromFields g) => GFromFields (f :*: g) where
+  gIsRecord       = gIsRecord @f
+  gFieldCount     = gFieldCount @f + gFieldCount @g
+  gFromRecord opts o =
+    (:*:) <$> gFromRecord opts o
+          <*> gFromRecord opts o
+  gFromPositional opts vs =
+    let n = gFieldCount @f
+    in (:*:) <$> gFromPositional opts (take n vs)
+             <*> gFromPositional opts (drop n vs)
+----------------------------------------------------------------------------
+-- | Selector with a 'Maybe' field: uses '.:?' so missing keys decode as Nothing.
+instance {-# OVERLAPPING #-} (Selector m, FromJSON a)
+    => GFromFields (S1 m (K1 r (Maybe a))) where
+  gIsRecord       = not (null name)
+    where name = selName (M1 undefined :: S1 m (K1 r (Maybe a)) ())
+  gFieldCount     = 1
+  gFromRecord opts o =
+    M1 . K1 <$> o .:? ms (fieldLabelModifier opts
+                    (selName (M1 undefined :: S1 m (K1 r (Maybe a)) ())))
+  gFromPositional _ vs = case vs of
+    (v:_) -> M1 . K1 <$> parseJSON v
+    []    -> pure (M1 (K1 Nothing))
+----------------------------------------------------------------------------
+-- | General selector.
+instance {-# OVERLAPPABLE #-} (Selector m, FromJSON a)
+    => GFromFields (S1 m (K1 r a)) where
+  gIsRecord       = not (null name)
+    where name = selName (M1 undefined :: S1 m (K1 r a) ())
+  gFieldCount     = 1
+  gFromRecord opts o =
+    M1 . K1 <$> o .: ms (fieldLabelModifier opts
+                    (selName (M1 undefined :: S1 m (K1 r a) ())))
+  gFromPositional _ vs = case vs of
+    (v:_) -> M1 . K1 <$> parseJSON v
+    []    -> pfail "gFromPositional: unexpected end of fields"
+----------------------------------------------------------------------------
+instance FromJSON Value where
+  parseJSON = pure
+----------------------------------------------------------------------------
+instance FromJSON Bool where
+  parseJSON = withBool "Bool" pure
+----------------------------------------------------------------------------
+instance FromJSON MisoString where
+  parseJSON = withText "MisoString" pure
+----------------------------------------------------------------------------
+#if !defined(VANILLA) && !defined(MISO_TEXT)
+instance FromJSON T.Text where
+  parseJSON = withText "Text" go
+    where
+      go s =
+        case MS.fromMisoStringEither s of
+          Right lt -> pure lt
+          Left e -> pfail $ ms e
+#endif
+----------------------------------------------------------------------------
+instance FromJSON LT.Text where
+  parseJSON = withText "LText" go
+    where
+      go s =
+        case MS.fromMisoStringEither s of
+          Right lt -> pure lt
+          Left e -> pfail $ ms e
+----------------------------------------------------------------------------
+instance {-# OVERLAPPING #-} FromJSON String where
+  parseJSON = withText "String" (pure . MS.unpack)
+----------------------------------------------------------------------------
+instance FromJSON a => FromJSON [a] where
+  parseJSON = withArray "[a]" (mapM parseJSON)
+----------------------------------------------------------------------------
+instance FromJSON Double where
+  parseJSON Null = pure (0/0)
+  parseJSON j    = withNumber "Double" pure j
+----------------------------------------------------------------------------
+instance FromJSON Float where
+  parseJSON Null = pure (0/0)
+  parseJSON j    = withNumber "Float" (pure . realToFrac) j
+----------------------------------------------------------------------------
+instance FromJSON Integer where
+  parseJSON = withNumber "Integer" (pure . round)
+----------------------------------------------------------------------------
+instance FromJSON Natural where
+  parseJSON = withNumber "Natural" parseNumber
+    where parseNumber d | d < 0 = pfail ("Cannot parse negative number as Natural: " <> ms d)
+                        | isNaN d = pfail ("Cannot parse NaN as Natural: " <> ms d)
+                        | otherwise  = pure $ naturalFromInteger $ fromInteger $ round d
+----------------------------------------------------------------------------
+instance FromJSON Int where
+  parseJSON = withNumber "Int" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON Int8 where
+  parseJSON = withNumber "Int8" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON Int16 where
+  parseJSON = withNumber "Int16" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON Int32 where
+  parseJSON = withNumber "Int32" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON Int64 where
+  parseJSON = withNumber "Int64" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON Word where
+  parseJSON = withNumber "Word" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON Word8 where
+  parseJSON = withNumber "Word8" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON Word16 where
+  parseJSON = withNumber "Word16" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON Word32 where
+  parseJSON = withNumber "Word32" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON Word64 where
+  parseJSON = withNumber "Word64" (pure . fromInteger . round)
+----------------------------------------------------------------------------
+instance FromJSON () where
+  parseJSON = withArray "()" $ \lst ->
+    case lst of
+      [] -> pure ()
+      _  -> pfail "expected ()"
+----------------------------------------------------------------------------
+instance (FromJSON a, FromJSON b) => FromJSON (a,b) where
+  parseJSON = withArray "(a,b)" $ \lst ->
+    case lst of
+      [a,b] -> liftM2 (,) (parseJSON a) (parseJSON b)
+      _     -> pfail "expected (a,b)"
+----------------------------------------------------------------------------
+instance (FromJSON a, FromJSON b, FromJSON c) => FromJSON (a,b,c) where
+  parseJSON = withArray "(a,b,c)" $ \lst ->
+    case lst of
+      [a,b,c] -> liftM3 (,,) (parseJSON a) (parseJSON b) (parseJSON c)
+      _       -> pfail "expected (a,b,c)"
+----------------------------------------------------------------------------
+instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d) => FromJSON (a,b,c,d) where
+  parseJSON = withArray "(a,b,c,d)" $ \lst ->
+    case lst of
+      [a,b,c,d] -> liftM4 (,,,) (parseJSON a) (parseJSON b) (parseJSON c) (parseJSON d)
+      _         -> pfail "expected (a,b,c,d)"
+----------------------------------------------------------------------------
+instance FromJSON a => FromJSON (Maybe a) where
+  parseJSON Null = pure Nothing
+  parseJSON j    = Just <$> parseJSON j
+----------------------------------------------------------------------------
+instance FromJSON Ordering where
+  parseJSON = withText "{'LT','EQ','GT'}" $ \s ->
+    case s of
+      "LT" -> pure LT
+      "EQ" -> pure EQ
+      "GT" -> pure GT
+      _    -> pfail "expected {'LT','EQ','GT'}"
+----------------------------------------------------------------------------
+instance FromJSON Char where
+  parseJSON = withText "Char" $ \xs ->
+    case xs of
+     x | MS.length x == 1 -> pure (MS.head x)
+       | otherwise -> pfail ("expected Char, received: " <> x)
+----------------------------------------------------------------------------
+instance FromJSON v => FromJSON (Map MisoString v) where
+  parseJSON = withObject "FromJSON v => Map MisoString v" $ mapM parseJSON
+#endif
+----------------------------------------------------------------------------
+#ifdef AESON
+-- | Succeed only when the 'Value' is a t'Bool'; fail with 'typeMismatch' otherwise.
+withBool
+  :: MisoString
+  -- ^ Expected type name used in the error message (e.g. @\"MyType\"@)
+  -> (Bool -> Parser a)
+  -- ^ Continuation receiving the unwrapped t'Bool'
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withBool expected = Aeson.withBool (MS.unpack expected)
+----------------------------------------------------------------------------
+-- | Succeed only when the 'Value' is a JSON string ('MisoString');
+-- fail with 'typeMismatch' otherwise.
+withText
+  :: MisoString
+  -- ^ Expected type name used in the error message
+  -> (MisoString -> Parser a)
+  -- ^ Continuation receiving the unwrapped string
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withText expected f = Aeson.withText (MS.unpack expected) (f . ms)
+----------------------------------------------------------------------------
+-- | Succeed only when the 'Value' is a JSON array; fail with 'typeMismatch' otherwise.
+-- The inner parser receives the list of elements.
+withArray
+  :: MisoString
+  -- ^ Expected type name used in the error message
+  -> ([Value] -> Parser a)
+  -- ^ Continuation receiving the list of array elements
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withArray expected f = Aeson.withArray (MS.unpack expected) (f . foldr (:) [])
+----------------------------------------------------------------------------
+-- | Succeed only when the 'Value' is a JSON object; fail with 'typeMismatch' otherwise.
+-- The inner parser receives the t'Object' map for key lookups with @.:@ etc.
+withObject
+  :: MisoString
+  -- ^ Expected type name used in the error message
+  -> (Object -> Parser a)
+  -- ^ Continuation receiving the t'Object' key\/value map
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withObject expected = Aeson.withObject (MS.unpack expected)
+----------------------------------------------------------------------------
+-- | Succeed only when the 'Value' is a JSON number; fail with 'typeMismatch' otherwise.
+-- The inner parser receives the underlying 'Double'.
+withNumber
+  :: MisoString
+  -- ^ Expected type name used in the error message
+  -> (Double -> Parser a)
+  -- ^ Continuation receiving the numeric value as a 'Double'
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withNumber expected f = Aeson.withScientific (MS.unpack expected) (f . toRealFloat)
+----------------------------------------------------------------------------
+-- | Produce a parse failure describing a type mismatch.
+-- Used by the @with*@ combinators and useful in hand-written 'FromJSON' instances.
+typeMismatch
+  :: MisoString
+  -- ^ Human-readable name of the expected type (e.g. @\"Int\"@)
+  -> Value
+  -- ^ The actual 'Value' that was encountered
+  -> Parser a
+typeMismatch expected = Aeson.typeMismatch (MS.unpack expected)
+#else
+-- | Succeed only when the 'Value' is a t'Bool'; fail with 'typeMismatch' otherwise.
+withBool
+  :: MisoString
+  -- ^ Expected type name used in the error message (e.g. @\"MyType\"@)
+  -> (Bool -> Parser a)
+  -- ^ Continuation receiving the unwrapped t'Bool'
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withBool _        f (Bool arr) = f arr
+withBool expected _ v          = typeMismatch expected v
+----------------------------------------------------------------------------
+-- | Succeed only when the 'Value' is a JSON string ('MisoString');
+-- fail with 'typeMismatch' otherwise.
+withText
+  :: MisoString
+  -- ^ Expected type name used in the error message
+  -> (MisoString -> Parser a)
+  -- ^ Continuation receiving the unwrapped string
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withText _        f (String txt) = f txt
+withText expected _ v            = typeMismatch expected v
+----------------------------------------------------------------------------
+-- | Succeed only when the 'Value' is a JSON array; fail with 'typeMismatch' otherwise.
+-- The inner parser receives the list of elements.
+withArray
+  :: MisoString
+  -- ^ Expected type name used in the error message
+  -> ([Value] -> Parser a)
+  -- ^ Continuation receiving the list of array elements
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withArray _        f (Array lst) = f lst
+withArray expected _ v           = typeMismatch expected v
+----------------------------------------------------------------------------
+-- | Succeed only when the 'Value' is a JSON object; fail with 'typeMismatch' otherwise.
+-- The inner parser receives the t'Object' map for key lookups with @.:@ etc.
+withObject
+  :: MisoString
+  -- ^ Expected type name used in the error message
+  -> (Object -> Parser a)
+  -- ^ Continuation receiving the t'Object' key\/value map
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withObject _        f (Object obj) = f obj
+withObject expected _ v            = typeMismatch expected v
+----------------------------------------------------------------------------
+-- | Succeed only when the 'Value' is a JSON number; fail with 'typeMismatch' otherwise.
+-- The inner parser receives the underlying 'Double'.
+withNumber
+  :: MisoString
+  -- ^ Expected type name used in the error message
+  -> (Double -> Parser a)
+  -- ^ Continuation receiving the numeric value as a 'Double'
+  -> Value
+  -- ^ JSON value to inspect
+  -> Parser a
+withNumber _        f (Number n) = f n
+withNumber expected _ v          = typeMismatch expected v
+----------------------------------------------------------------------------
+-- | Produce a parse failure describing a type mismatch.
+-- Used by the @with*@ combinators and useful in hand-written 'FromJSON' instances.
+typeMismatch
+  :: MisoString
+  -- ^ Human-readable name of the expected type (e.g. @\"Int\"@)
+  -> Value
+  -- ^ The actual 'Value' that was encountered
+  -> Parser a
+typeMismatch expected actual =
+  pfail
+    ( "typeMismatch: Expected " <> expected <> " but encountered " <> case actual of
+        Object _ -> "Object"
+        Array _ -> "Array"
+        String _ -> "String"
+        Number _ -> "Number"
+        Bool _ -> "Boolean"
+        Null -> "Null"
+    )
+#endif
+----------------------------------------------------------------------------
+-- | Encode a value as a JSON 'MisoString'.
+--
+-- On the client (WASM \/ GHC JS backend) calls @JSON.stringify()@ via FFI for
+-- maximum performance. On the server (@VANILLA@) falls back to 'encodePure'.
+#ifdef VANILLA
+encode :: ToJSON a => a -> MisoString
+encode = encodePure
+#else
+encode :: ToJSON a => a -> MisoString
+encode x = unsafePerformIO $ jsonStringify =<< toJSVal_Value (toJSON x)
+#endif
+----------------------------------------------------------------------------
+-- | Relies on the pure implementation of JSON parsing / serialization.
+--
+-- This can be used on the server or the client, it is more efficient to
+-- use 'encode' on the client (since it relies on @JSON.stringify()@).
+--
+encodePure :: ToJSON a => a -> MisoString
+encodePure = ms . toJSON
+----------------------------------------------------------------------------
+instance FromMisoString Value where
+  fromMisoStringEither = Parser.decodePure
+----------------------------------------------------------------------------
+#ifdef AESON
+instance ToMisoString Value where
+  toMisoString = ms . Aeson.encode
+#else
+-- | Escape special characters in a string for JSON serialization
+-- Handles: \, ", and all JSON control characters per RFC 8259
+escapeJSONString :: MisoString -> MisoString
+escapeJSONString = MS.concatMap escapeChar
+  where
+    escapeChar :: Char -> MisoString
+    escapeChar '\\' = "\\\\"   -- Backslash
+    escapeChar '"'  = "\\\""   -- Double quote
+    escapeChar '\b' = "\\b"    -- Backspace
+    escapeChar '\f' = "\\f"    -- Form feed
+    escapeChar '\n' = "\\n"    -- Newline
+    escapeChar '\r' = "\\r"    -- Carriage return
+    escapeChar '\t' = "\\t"    -- Tab
+    escapeChar c
+      | isControl c = ms ("\\u" <> padHex (ord c))  -- Other control chars as \uXXXX
+      | otherwise   = singleton c
+
+    padHex :: Int -> MisoString
+    padHex n = MS.pack $ replicate (4 - length h) '0' ++ h
+      where h = showHex n ""
+----------------------------------------------------------------------------
+instance ToMisoString Value where
+  toMisoString = \case
+    String s -> "\"" <> escapeJSONString s <> "\""
+    Number n
+      | (i, 0.0) <- properFraction n -> ms @Int i
+      | otherwise -> ms n
+    Null ->
+      "null"
+    Array xs ->
+      "[" <> MS.intercalate "," (fmap ms xs) <> "]"
+    Bool True ->
+      "true"
+    Bool False ->
+      "false"
+    Object o ->
+      "{" <>
+        MS.intercalate "," [ "\"" <> escapeJSONString k <> "\"" <> ":" <> ms v | (k,v) <- M.toList o ]
+      <> "}"
+#endif
+----------------------------------------------------------------------------
+-- | Decode a JSON 'MisoString' into a Haskell value, returning 'Nothing' on failure.
+--
+-- On the client calls @JSON.parse()@ via FFI. On the server uses the pure
+-- Haskell parser. For a human-readable error message on failure use 'eitherDecode'.
+#ifdef VANILLA
+decode :: FromJSON a => MisoString -> Maybe a
+decode s
+  | Right x <- Parser.decodePure s
+  , Success v <- fromJSON x = Just v
+  | otherwise = Nothing
+#else
+decode :: FromJSON a => MisoString -> Maybe a
+decode s
+  | Right x <- eitherDecode s = Just x
+  | otherwise = Nothing
+#endif
+-----------------------------------------------------------------------------
+#ifdef GHCJS_OLD
+foreign import javascript unsafe
+  "$r = JSON.stringify($1, null, $2)"
+  encodePretty_ffi :: JSVal -> Int -> IO MisoString
+#endif
+-----------------------------------------------------------------------------
+#ifdef GHCJS_NEW
+foreign import javascript unsafe
+  "(($1) => { return JSON.stringify($1, null, $2); })"
+  encodePretty_ffi :: JSVal -> Int -> IO MisoString
+#endif
+-----------------------------------------------------------------------------
+#ifdef WASM
+#ifdef MISO_TEXT
+foreign import javascript unsafe
+  "return JSON.stringify($1, null, $2);"
+  encodePretty_ffi_JSString :: JSVal -> Int -> IO JSString
+encodePretty_ffi :: JSVal -> Int -> IO MisoString
+encodePretty_ffi jsval n = textFromJSString <$> encodePretty_ffi_JSString jsval n
+#else
+foreign import javascript unsafe
+  "return JSON.stringify($1, null, $2);"
+  encodePretty_ffi :: JSVal -> Int -> IO MisoString
+#endif
+#endif
+-----------------------------------------------------------------------------
+-- | Like 'encodePretty' but with a custom t'Config'.
+-- Not available in the @VANILLA@ build.
+#ifdef VANILLA
+encodePretty' :: ToJSON a => Config -> a -> MisoString
+encodePretty' = error "encodePretty': not implemented"
+-----------------------------------------------------------------------------
+-- | Encode a value as indented (pretty-printed) JSON using 'defConfig'
+-- (4-space indentation). Not available in the @VANILLA@ build.
+encodePretty :: ToJSON a => a -> MisoString
+encodePretty _ = error "encodePretty: not implemented"
+-----------------------------------------------------------------------------
+#else
+-----------------------------------------------------------------------------
+encodePretty' :: ToJSON a => Config -> a -> MisoString
+encodePretty' (Config s) x = unsafePerformIO (flip encodePretty_ffi s =<< toJSVal_Value (toJSON x))
+-----------------------------------------------------------------------------
+encodePretty :: ToJSON a => a -> MisoString
+encodePretty = encodePretty' defConfig
+#endif
+-----------------------------------------------------------------------------
+-- | Pretty-printing configuration for 'encodePretty' and 'encodePretty''.
+newtype Config
+  = Config
+  { spaces :: Int
+  -- ^ Number of spaces per indentation level.
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Default pretty-print config: 4-space indentation.
+defConfig :: Config
+defConfig = Config 4
+-----------------------------------------------------------------------------
+-- | Call @JSON.stringify()@ on a JavaScript value, returning a JSON string.
+#ifdef GHCJS_OLD
+foreign import javascript unsafe
+  "$r = JSON.stringify($1)"
+  jsonStringify :: JSVal -> IO MisoString
+#endif
+-----------------------------------------------------------------------------
+#ifdef GHCJS_NEW
+foreign import javascript unsafe
+  "(($1) => { return JSON.stringify($1); })"
+  jsonStringify :: JSVal -> IO MisoString
+#endif
+-----------------------------------------------------------------------------
+#ifdef WASM
+#ifdef MISO_TEXT
+foreign import javascript unsafe
+  "return JSON.stringify($1);"
+  jsonStringify_JSString :: JSVal -> IO JSString
+jsonStringify :: JSVal -> IO MisoString
+jsonStringify jsval = textFromJSString <$> jsonStringify_JSString jsval
+#else
+foreign import javascript unsafe
+  "return JSON.stringify($1);"
+  jsonStringify :: JSVal -> IO MisoString
+#endif
+#endif
+-----------------------------------------------------------------------------
+#ifdef VANILLA
+jsonStringify :: JSVal -> IO MisoString
+jsonStringify _ = error "jsonStringify: not implemented"
+#endif
+-----------------------------------------------------------------------------
+-- | Call @JSON.parse()@ on a JSON string, returning a raw JavaScript value.
+#ifdef GHCJS_OLD
+foreign import javascript unsafe
+  "$r = JSON.parse($1)"
+  jsonParse :: MisoString -> IO JSVal
+#endif
+-----------------------------------------------------------------------------
+#ifdef GHCJS_NEW
+foreign import javascript unsafe
+  "(($1) => { return JSON.parse($1); })"
+  jsonParse :: MisoString -> IO JSVal
+#endif
+-----------------------------------------------------------------------------
+#ifdef WASM
+#ifdef MISO_TEXT
+foreign import javascript unsafe
+  "return JSON.parse($1);"
+  jsonParse_JSString :: JSString -> IO JSVal
+jsonParse :: MisoString -> IO JSVal
+jsonParse = jsonParse_JSString . textToJSString
+#else
+foreign import javascript unsafe
+  "return JSON.parse($1);"
+  jsonParse :: MisoString -> IO JSVal
+#endif
+#endif
+-----------------------------------------------------------------------------
+#ifdef VANILLA
+jsonParse :: MisoString -> IO JSVal
+jsonParse _ = error "jsonParse: not implemented"
+#endif
+-----------------------------------------------------------------------------
+-- | Decode a JSON 'MisoString', returning @'Left' errMsg@ on failure.
+-- Prefer 'decode' when the error message is not needed.
+#ifdef VANILLA
+eitherDecode :: FromJSON a => MisoString -> Either MisoString a
+eitherDecode string =
+  case Parser.decodePure string of
+    Left s ->
+      Left (pack s)
+    Right v ->
+      parseEither parseJSON v
+#else
+eitherDecode :: FromJSON a => MisoString -> Either MisoString a
+eitherDecode string = unsafePerformIO $ do
+  (jsonParse string >>= fromJSVal_Value) >>= \case
+    Nothing ->
+      pure $ Left ("eitherDecode: " <> string)
+    Just result ->
+      pure (case fromJSON result of
+        Success x -> Right x
+        Error err -> Left err)
+#endif
+----------------------------------------------------------------------------
+-- | Convert a JSON 'Value' to a Haskell type, returning a 'Result'.
+-- Useful when a 'Value' is already in hand; use 'decode' to parse from a string.
+fromJSON :: FromJSON a => Value -> Result a
+fromJSON value =
+  case parseEither parseJSON value of
+    Left s -> Error s
+    Right x -> Success x
+----------------------------------------------------------------------------
+#ifndef VANILLA
+-- Bridge helpers so the FFI marshalling code below is agnostic to whether
+-- 'Value' is miso's own representation or aeson's (Scientific numbers,
+-- Text strings, Vector arrays, KeyMap objects).
+#ifdef AESON
+numberToDouble :: Scientific -> Double
+numberToDouble = toRealFloat
+-----------------------------------------------------------------------------
+doubleToNumber :: Double -> Value
+doubleToNumber = Number . fromFloatDigits
+-----------------------------------------------------------------------------
+stringToMiso :: T.Text -> MisoString
+stringToMiso = ms
+-----------------------------------------------------------------------------
+mkString :: MisoString -> Value
+mkString = String . MS.fromMisoString
+-----------------------------------------------------------------------------
+mkArray :: [Value] -> Value
+mkArray = toJSON
+-----------------------------------------------------------------------------
+mkObject :: [(MisoString, Value)] -> Value
+mkObject kvs = Object (KeyMap.fromList [ (toKey k, v) | (k, v) <- kvs ])
+-----------------------------------------------------------------------------
+objectAssocs :: Object -> [(MisoString, Value)]
+objectAssocs o = [ (ms (Key.toText k), v) | (k, v) <- KeyMap.toList o ]
+#else
+numberToDouble :: Double -> Double
+numberToDouble = id
+-----------------------------------------------------------------------------
+doubleToNumber :: Double -> Value
+doubleToNumber = Number
+-----------------------------------------------------------------------------
+stringToMiso :: MisoString -> MisoString
+stringToMiso = id
+-----------------------------------------------------------------------------
+mkString :: MisoString -> Value
+mkString = String
+-----------------------------------------------------------------------------
+mkArray :: [Value] -> Value
+mkArray = Array
+-----------------------------------------------------------------------------
+mkObject :: [(MisoString, Value)] -> Value
+mkObject = Object . M.fromList
+-----------------------------------------------------------------------------
+objectAssocs :: Object -> [(MisoString, Value)]
+objectAssocs = M.toList
+#endif
+#endif
+-----------------------------------------------------------------------------
+-- | Convert a Miso JSON 'Value' to a raw JavaScript value via FFI.
+#ifdef GHCJS_BOTH
+toJSVal_Value :: Value -> IO JSVal
+toJSVal_Value = \case
+  Null ->
+    pure jsNull
+  Bool bool_ ->
+    Marshal.toJSVal bool_
+  String string ->
+    Marshal.toJSVal (stringToMiso string)
+  Number double ->
+    Marshal.toJSVal (numberToDouble double)
+  Array arr ->
+    toJSVal_List =<< mapM toJSVal_Value (toList arr)
+  Object hms -> do
+    o <- create_ffi
+    forM_ (objectAssocs hms) $ \(k,v) -> do
+      v' <- toJSVal_Value v
+      setProp_ffi k v' o
+    pure o
+#endif
+-----------------------------------------------------------------------------
+-- | Convert a raw JavaScript value to a Miso JSON 'Value' via FFI.
+-- Returns 'Nothing' if the JS value cannot be represented as a JSON 'Value'.
+#ifdef GHCJS_BOTH
+fromJSVal_Value :: JSVal -> IO (Maybe Value)
+fromJSVal_Value jsval_ = do
+  typeof jsval_ >>= \case
+    0 -> return (Just Null)
+    1 -> Just . doubleToNumber <$> Marshal.fromJSValUnchecked jsval_
+    2 -> Just . mkString <$> Marshal.fromJSValUnchecked jsval_
+    3 -> fromJSValUnchecked_Int jsval_ >>= \case
+      0 -> pure $ Just (Bool False)
+      1 -> pure $ Just (Bool True)
+      _ -> pure Nothing
+    4 -> do xs <- Marshal.fromJSValUnchecked jsval_
+            values <- forM xs fromJSVal_Value
+            pure (mkArray <$> sequence values)
+    5 -> do keys <- Marshal.fromJSValUnchecked =<< listProps_ffi jsval_
+            result <-
+              runMaybeT $ forM keys $ \k -> do
+                key <- MaybeT (Marshal.fromJSVal k)
+                raw <- MaybeT $ Just <$> getProp_ffi key jsval_
+                value <- MaybeT (fromJSVal_Value raw)
+                pure (key, value)
+            pure (toObject <$> result)
+    _ -> error "fromJSVal_Value: Unknown JSON type"
+  where
+    toObject = mkObject
+#endif
+-----------------------------------------------------------------------------
+#ifdef WASM
+fromJSVal_Value :: JSVal -> IO (Maybe Value)
+fromJSVal_Value jsval = do
+  typeof jsval >>= \case
+    0 -> return (Just Null)
+    1 -> Just . doubleToNumber <$> fromJSValUnchecked_Double jsval
+    2 -> pure $ Just $ mkString $
+#ifdef MISO_TEXT
+           textFromJSString (JSString jsval)
+#else
+           (JSString jsval)
+#endif
+    3 -> fromJSValUnchecked_Int jsval >>= \case
+      0 -> pure $ Just (Bool False)
+      1 -> pure $ Just (Bool True)
+      _ -> pure Nothing
+    4 -> do xs <- fromJSValUnchecked_List jsval
+            values <- forM xs fromJSVal_Value
+            pure (mkArray <$> sequence values)
+    5 -> do keys <- fromJSValUnchecked_List =<< listProps_ffi jsval
+            result <-
+              runMaybeT $ forM keys $ \k -> do
+                let key = JSString k
+                raw <- MaybeT $ Just <$> getProp_ffi key jsval
+                value <- MaybeT (fromJSVal_Value raw)
+                pure
+                  (
+#ifdef MISO_TEXT
+                    textFromJSString key
+#else
+                    key
+#endif
+                  , value)
+            pure (toObject <$> result)
+    _ -> error "fromJSVal_Value: Unknown JSON type"
+  where
+    toObject = mkObject
+#endif
+-----------------------------------------------------------------------------
+#ifdef VANILLA
+-----------------------------------------------------------------------------
+fromJSVal_Value :: JSVal -> IO (Maybe Value)
+fromJSVal_Value = error "fromJSVal_Value: not implemented"
+-----------------------------------------------------------------------------
+-- | Convert a Miso JSON t'Value' to a raw JavaScript value via FFI.
+toJSVal_Value :: Value -> IO JSVal
+toJSVal_Value = error "toJSVal_Value: not implemented"
+-----------------------------------------------------------------------------
+#endif
+-----------------------------------------------------------------------------
+#ifdef GHCJS_NEW
+foreign import javascript unsafe
+  "(($1) => { return globalThis.miso.typeOf($1); })"
+  typeof :: JSVal -> IO Int
+#endif
+-----------------------------------------------------------------------------
+#ifdef WASM
+foreign import javascript unsafe
+ "return globalThis.miso.typeOf($1);"
+  typeof :: JSVal -> IO Int
+#endif
+-----------------------------------------------------------------------------
+#ifdef GHCJS_OLD
+foreign import javascript unsafe
+  "$r = globalThis.miso.typeOf($1);"
+  typeof :: JSVal -> IO Int
+#endif
+-----------------------------------------------------------------------------
+#ifdef WASM
+-- | Convert a Miso JSON t'Value' to a raw JavaScript value via FFI.
+toJSVal_Value :: Value -> IO JSVal
+toJSVal_Value = \case
+  Null ->
+    pure jsNull
+  Bool bool_ ->
+    toJSVal_Bool bool_
+  String string ->
+#ifdef MISO_TEXT
+    toJSVal_Text (stringToMiso string)
+#else
+    toJSVal_JSString (stringToMiso string)
+#endif
+  Number double ->
+    toJSVal_Double (numberToDouble double)
+  Array arr ->
+    toJSVal_List =<< mapM toJSVal_Value (toList arr)
+  Object hms -> do
+    o <- create_ffi
+    forM_ (objectAssocs hms) $ \(k,v) -> do
+      v' <- toJSVal_Value v
+      setProp_ffi
+#ifdef MISO_TEXT
+        (textToJSString k)
+#else
+        k
+#endif
+        v' o
+    pure o
+#endif
+-----------------------------------------------------------------------------
diff --git a/src/Miso/JSON/Lexer.hs b/src/Miso/JSON/Lexer.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/JSON/Lexer.hs
@@ -0,0 +1,158 @@
+----------------------------------------------------------------------------
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.JSON.Lexer
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.JSON.Lexer" is the first stage of miso's pure Haskell JSON pipeline,
+-- which is used for server-side rendering (SSR). It tokenises a
+-- 'Miso.String.MisoString' into a stream of 'Token' values consumed by
+-- "Miso.JSON.Parser".
+--
+-- This module is __internal__. Application code should use "Miso.JSON" or
+-- "Miso.JSON.Parser" ('Miso.JSON.Parser.decodePure') instead.
+--
+-- This module was ported from <https://github.com/dmjio/json-test> by
+-- <https://github.com/ners @ners>.
+--
+-- = Token types
+--
+-- @
+-- data 'Token'
+--   = 'TokenPunctuator' Char    -- one of @[ ] { } , :@
+--   | 'TokenNumber'     Double  -- JSON number (integer or floating-point)
+--   | 'TokenBool'       Bool    -- @true@ or @false@
+--   | 'TokenString'     'Miso.String.MisoString' -- quoted string with escape sequences
+--   | 'TokenNull'               -- @null@
+-- @
+--
+-- String tokens handle all
+-- <https://www.rfc-editor.org/rfc/rfc8259#section-7 RFC 8259 escape sequences>
+-- including @\\uXXXX@ and UTF-16 surrogate pairs (@\\uD800\\uDC00@).
+--
+-- = See also
+--
+-- * "Miso.JSON.Parser" — consumes 'Token' streams produced here
+-- * "Miso.JSON.Types" — 'Miso.JSON.Types.Value' produced by the parser
+-- * "Miso.Util.Lexer" — the underlying 'Miso.Util.Lexer.Lexer' combinator library
+----------------------------------------------------------------------------
+module Miso.JSON.Lexer (Token (..), tokens) where
+----------------------------------------------------------------------------
+import           Control.Applicative (Alternative (some, many), optional)
+import           Control.Monad (replicateM)
+import           Data.Char (isHexDigit, chr, isSpace)
+import           Data.Foldable (Foldable (fold))
+import           Data.Functor (void)
+import           Data.Ix (Ix (inRange))
+import           Data.Maybe (catMaybes)
+import           Numeric (readHex)
+import           Prelude hiding (null)
+----------------------------------------------------------------------------
+import           Miso.String (fromMisoString, ToMisoString (toMisoString), MisoString)
+import           Miso.Util (oneOf)
+import           Miso.Util.Lexer hiding (string', token)
+----------------------------------------------------------------------------
+#if __GLASGOW_HASKELL__ <= 881
+import Control.Applicative (liftA2)
+#endif
+----------------------------------------------------------------------------
+-- | A single lexical token of JSON text, produced by 'tokens'.
+--
+-- Punctuators are the structural characters @{}[],:@; the remaining
+-- constructors carry already-decoded literals.
+data Token
+  = TokenPunctuator Char
+  | TokenNumber Double
+  | TokenBool Bool
+  | TokenString MisoString
+  | TokenNull
+  deriving (Eq, Show)
+----------------------------------------------------------------------------
+number :: Lexer Double
+number = fromMisoString . fold . catMaybes <$> sequence
+  [ optional $ string "-"
+  , Just <$> int
+  , optional $ liftA2 (<>) (string ".") int
+  , optional $ liftA2 (<>) (oneOf $ string <$> ["e", "e+", "e-", "E", "E+", "E-"]) int
+  ] where
+      digit = satisfy $ inRange ('0', '9')
+      int = toMisoString <$> some digit
+----------------------------------------------------------------------------
+bool :: Lexer Bool
+bool = oneOf
+  [ False <$ string "false"
+  , True <$ string "true"
+  ]
+----------------------------------------------------------------------------
+string' :: Lexer MisoString
+string' = char '"' *> (toMisoString <$> many character) <* char '"'
+  where
+    character = oneOf
+      [ satisfy $ \c -> c /= '"' && c /= '\\'
+      , escapedCharacter
+      ]
+    hexDigit = satisfy isHexDigit
+    escaped = (char '\\' *>)
+    escapedCharacter = escaped $ oneOf
+      [ char '"'
+      , char '\\'
+      , char '/'
+      , '\b' <$ char 'b'
+      , '\f' <$ char 'f'
+      , '\n' <$ char 'n'
+      , '\r' <$ char 'r'
+      , '\t' <$ char 't'
+      , unicodeHexQuad >>= \high -> do
+          if inRange highSurrogateRange high
+            then do
+              low <- escaped unicodeHexQuad
+              if inRange lowSurrogateRange low
+                then
+                  pure . chr . sum $
+                    [ (high - fst highSurrogateRange) * 0x400
+                    , low - fst lowSurrogateRange
+                    , 0x10000
+                    ]
+                else oops
+            else
+              pure $ chr high
+      ]
+    highSurrogateRange = (0xD800, 0xDBFF)
+    lowSurrogateRange = (0xDC00, 0xDFFF)
+    unicodeHexQuad = char 'u' *> do
+        [(num, "")] <- readHex <$> replicateM 4 hexDigit
+        pure num
+----------------------------------------------------------------------------
+null :: Lexer ()
+null = void (string "null")
+----------------------------------------------------------------------------
+punctuator :: Lexer Char
+punctuator = oneOf (char <$> "[]{},:")
+----------------------------------------------------------------------------
+whitespace :: Lexer ()
+whitespace = void (satisfy isSpace)
+----------------------------------------------------------------------------
+token :: Lexer Token
+token = oneOf
+  [ TokenPunctuator <$> punctuator
+  , TokenNumber <$> number
+  , TokenBool <$> bool
+  , TokenString <$> string'
+  , TokenNull <$ null
+  ]
+----------------------------------------------------------------------------
+-- | Lexes JSON source into a list of t'Token', skipping whitespace.
+--
+-- The first half of 'Miso.JSON.decode'; feed the result to
+-- "Miso.JSON.Parser".
+tokens :: Lexer [Token]
+tokens = some (many whitespace *> token)
+----------------------------------------------------------------------------
diff --git a/src/Miso/JSON/Parser.hs b/src/Miso/JSON/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/JSON/Parser.hs
@@ -0,0 +1,123 @@
+----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.JSON.Parser
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.JSON.Parser" is the second stage of miso's pure Haskell JSON
+-- pipeline, used for server-side rendering (SSR). It takes the 'Token'
+-- stream produced by "Miso.JSON.Lexer" and builds a 'Miso.JSON.Types.Value'
+-- tree.
+--
+-- The single public entry point is 'decodePure':
+--
+-- @
+-- 'decodePure' :: 'Miso.String.MisoString' -> Either String 'Miso.JSON.Types.Value'
+-- @
+--
+-- It returns @'Left' err@ on a lexical or parse error and @'Right' v@ on
+-- success. Error messages include the position and nature of the failure.
+--
+-- This module is __internal__. Use 'decodePure' via "Miso.JSON" in
+-- application code.
+--
+-- This module was ported from <https://github.com/dmjio/json-test> by
+-- <https://github.com/ners @ners>.
+--
+-- = See also
+--
+-- * "Miso.JSON.Lexer" — tokenizer that feeds this parser
+-- * "Miso.JSON.Types" — 'Miso.JSON.Types.Value' and 'Miso.JSON.Types.Result' types
+-- * "Miso.Util.Parser" — the underlying parser combinator library
+----------------------------------------------------------------------------
+{-# LANGUAGE CPP #-}
+----------------------------------------------------------------------------
+module Miso.JSON.Parser (decodePure) where
+----------------------------------------------------------------------------
+#ifdef AESON
+import qualified Data.Aeson as Aeson
+----------------------------------------------------------------------------
+import           Miso.JSON.Types (Value)
+import           Miso.String (MisoString, fromMisoString)
+----------------------------------------------------------------------------
+-- | Parses JSON text into a t'Value' purely, returning a message on failure.
+--
+-- Defined in terms of aeson's pure parser when the @aeson@ flag is enabled.
+decodePure :: MisoString -> Either String Value
+decodePure = Aeson.eitherDecode . fromMisoString
+#else
+import           Data.Bifunctor (Bifunctor(first))
+import           Data.Functor (void)
+import           Data.Map.Strict (Map)
+import qualified Data.Map.Strict as Map
+import           Prelude hiding (null)
+----------------------------------------------------------------------------
+import           Miso.JSON.Types
+import           Miso.JSON.Lexer (Token (..), tokens)
+import           Miso.String (MisoString)
+import           Miso.Util (sepBy, oneOf)
+import           Miso.Util.Parser
+import           Miso.Util.Lexer (runLexer, mkStream)
+----------------------------------------------------------------------------
+number :: Parser Token Double
+number = do
+  TokenNumber d <- anyToken
+  pure d
+----------------------------------------------------------------------------
+bool :: Parser Token Bool
+bool = do
+  TokenBool b <- anyToken
+  pure b
+----------------------------------------------------------------------------
+string' :: Parser Token MisoString
+string' = do
+  TokenString s <- anyToken
+  pure s
+----------------------------------------------------------------------------
+array :: Parser Token [Value]
+array = do
+  void . token_ $ TokenPunctuator '['
+  values <- sepBy (token_ $ TokenPunctuator ',') value
+  void . token_ $ TokenPunctuator ']'
+  pure values
+----------------------------------------------------------------------------
+object :: Parser Token (Map MisoString Value)
+object = do
+  void . token_ $ TokenPunctuator '{'
+  fields <- sepBy (token_ $ TokenPunctuator ',') $ do
+    key <- string'
+    void . token_ $ TokenPunctuator ':'
+    val <- value
+    pure (key, val)
+  void . token_ $ TokenPunctuator '}'
+  pure $ Map.fromList fields
+----------------------------------------------------------------------------
+null :: Parser Token ()
+null = void $ token_ TokenNull
+----------------------------------------------------------------------------
+value :: Parser Token Value
+value = oneOf
+  [ Number <$> number
+  , Bool <$> bool
+  , String <$> string'
+  , Array <$> array
+  , Object <$> object
+  , Null <$ null
+  ]
+----------------------------------------------------------------------------
+-- | Parses JSON text into a t'Value' purely, returning a message on failure.
+--
+-- Unlike 'Miso.JSON.decode' this does not go through the browser's
+-- @JSON.parse@, so it is usable off the main thread and in server builds.
+decodePure :: MisoString -> Either String Value
+decodePure = first show
+  . either (Left . LexicalError) (parse value . fst)
+  . runLexer tokens
+  . mkStream
+#endif
+----------------------------------------------------------------------------
diff --git a/src/Miso/JSON/Types.hs b/src/Miso/JSON/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/JSON/Types.hs
@@ -0,0 +1,166 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.JSON.Types
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.JSON.Types" defines the two core types used throughout miso's JSON
+-- support:
+--
+-- * 'Value' — an
+--   <https://www.json.org/ RFC 8259>-compliant JSON value. Used as the
+--   intermediate representation in event decoders
+--   ("Miso.Event.Decoder") and in 'Miso.DSL.ToJSVal' \/ 'Miso.DSL.FromJSVal'
+--   marshalling.
+--
+-- * 'Result' — a lightweight error monad (@'Success' a | 'Error' 'Miso.String.MisoString'@)
+--   used by JSON parsers to report decode failures. It has full
+--   'Functor', 'Applicative', 'Monad', 'MonadFail', 'Alternative',
+--   'Foldable', and 'Traversable' instances.
+--
+-- This module was ported from <https://github.com/dmjio/json-test> by
+-- <https://github.com/ners @ners>.
+--
+-- = Value constructors
+--
+-- @
+-- data 'Value'
+--   = 'Number' Double          -- JSON number
+--   | t'Bool'   Bool            -- JSON boolean
+--   | t'String' 'Miso.String.MisoString'   -- JSON string
+--   | 'Array'  ['Value']       -- JSON array
+--   | t'Object' ('Miso.JSON.Types.Object')  -- JSON object (Map MisoString Value)
+--   | 'Null'                   -- JSON null
+-- @
+--
+-- = See also
+--
+-- * "Miso.JSON" — top-level re-export hub; 'Miso.JSON.FromJSON', 'Miso.JSON.ToJSON', @(@.:@)@, 'Miso.JSON.withObject'
+-- * "Miso.JSON.Parser" — pure server-side JSON decoder ('Miso.JSON.Parser.decodePure')
+-- * "Miso.JSON.Lexer" — tokenizer used by the parser
+-- * "Miso.Event.Decoder" — uses 'Value' and 'Result' via 'Miso.JSON.Parser'
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP #-}
+----------------------------------------------------------------------------
+module Miso.JSON.Types
+  ( -- * Types
+    Value (..)
+  , Result (..)
+  , Pair
+  , Object
+  ) where
+----------------------------------------------------------------------------
+import Control.Applicative (Alternative (..))
+import Control.Monad (MonadPlus(..), ap)
+#ifdef AESON
+import Data.Aeson.Types (Value (..), Pair, Object)
+#else
+import Data.Map.Strict (Map)
+import Data.String (IsString(fromString))
+#endif
+----------------------------------------------------------------------------
+import Miso.String (MisoString, toMisoString)
+----------------------------------------------------------------------------
+#if __GLASGOW_HASKELL__ <= 881
+import Prelude hiding (fail)
+import Control.Monad.Fail (MonadFail (..))
+#endif
+----------------------------------------------------------------------------
+#ifndef AESON
+-- | A parsed JSON value.
+--
+-- The JSON data model: numbers are 'Double', objects are keyed by
+-- t'Miso.String.MisoString', and 'Null' is explicit. An 'IsString' instance
+-- makes string literals usable directly as a t'Value'.
+data Value
+  = Number Double
+  | Bool Bool
+  | String MisoString
+  | Array [Value]
+  | Object (Map MisoString Value)
+  | Null
+  deriving (Show, Eq)
+----------------------------------------------------------------------------
+instance IsString Value where
+  fromString = String . fromString
+----------------------------------------------------------------------------
+-- | A single key\/value member of a JSON object, as produced by
+-- 'Miso.JSON..=' and consumed by 'Miso.JSON.object'.
+type Pair = (MisoString, Value)
+----------------------------------------------------------------------------
+-- | A JSON object: its members keyed by name.
+type Object = Map MisoString Value
+#endif
+----------------------------------------------------------------------------
+-- | The outcome of decoding a t'Value' into a Haskell type.
+--
+-- 'Error' carries a human-readable message describing where decoding failed.
+data Result a
+  = Success a
+  | Error MisoString
+  deriving (Show, Eq)
+----------------------------------------------------------------------------
+instance Functor Result where
+  fmap f (Success a) = Success (f a)
+  fmap _ (Error err) = Error err
+  {-# INLINE fmap #-}
+----------------------------------------------------------------------------
+instance Applicative Result where
+  pure  = Success
+  {-# INLINE pure #-}
+  (<*>) = ap
+  {-# INLINE (<*>) #-}
+----------------------------------------------------------------------------
+instance Monad Result where
+  return = pure
+  {-# INLINE return #-}
+  Success a >>= k = k a
+  Error err >>= _ = Error err
+  {-# INLINE (>>=) #-}
+----------------------------------------------------------------------------
+instance MonadFail Result where
+  fail err = Error $ toMisoString err
+  {-# INLINE fail #-}
+----------------------------------------------------------------------------
+instance Alternative Result where
+  empty = mzero
+  {-# INLINE empty #-}
+  (<|>) = mplus
+  {-# INLINE (<|>) #-}
+----------------------------------------------------------------------------
+instance MonadPlus Result where
+  mzero = fail "mzero"
+  {-# INLINE mzero #-}
+  mplus a@(Success _) _ = a
+  mplus _ b             = b
+  {-# INLINE mplus #-}
+----------------------------------------------------------------------------
+instance Semigroup (Result a) where
+  (<>) = mplus
+  {-# INLINE (<>) #-}
+----------------------------------------------------------------------------
+instance Monoid (Result a) where
+  mempty  = fail "mempty"
+  {-# INLINE mempty #-}
+  mappend = (<>)
+  {-# INLINE mappend #-}
+----------------------------------------------------------------------------
+instance Foldable Result where
+  foldMap _ (Error _)   = mempty
+  foldMap f (Success y) = f y
+  {-# INLINE foldMap #-}
+----------------------------------------------------------------------------
+  foldr _ z (Error _)   = z
+  foldr f z (Success y) = f y z
+  {-# INLINE foldr #-}
+----------------------------------------------------------------------------
+instance Traversable Result where
+  traverse _ (Error err) = pure (Error err)
+  traverse f (Success a) = Success <$> f a
+  {-# INLINE traverse #-}
+----------------------------------------------------------------------------
diff --git a/src/Miso/Lens.hs b/src/Miso/Lens.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Lens.hs
@@ -0,0 +1,912 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE RecordWildCards     #-}
+{-# LANGUAGE TypeFamilies        #-}
+{-# LANGUAGE LambdaCase          #-}
+{-# LANGUAGE RankNTypes          #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Lens
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- A simple t'Lens' formulation compatible with @lens@ and @microlens@.
+--
+-- The t'Lens' type is defined as:
+--
+-- @
+-- data t'Lens' record field
+--  = t'Lens'
+--  { '_get' :: record -> field
+--  , '_set' :: record -> field -> record
+--  }
+-- @
+--
+-- Key features:
+--
+-- * Provides an out-of-the-box lens experience with a minimal dependency footprint.
+-- * Uses a simple formulation (not van Laarhoven) for smaller compilation payload.
+-- * Import separately: @import Miso.Lens@.
+-- * Works with the @Effect@ monad inside miso applications.
+-- * Fixity and interface parity with @lens@ and @microlens@; replace
+--   @import Miso.Lens@ with @import Control.Lens@ to switch seamlessly.
+-- * Re-exports t'Lens'' for easy migration to
+--   [lens](https://hackage.haskell.org/package/lens) or
+--   [microlens](https://hackage.haskell.org/package/microlens).
+--
+-- For more on the van Laarhoven formulation, see the
+-- [lens](https://hackage.haskell.org/package/lens) library.
+--
+-- === Example: Lenses for a nested record
+--
+-- @
+-- data Person = Person
+--   { _name :: String
+--   , _address :: Address
+--   , _age  :: Int
+--   } deriving (Show, Eq, Generic)
+--
+-- newtype Address
+--   = Address
+--   { _zipCode :: Zip
+--   } deriving (Show, Eq)
+--
+-- type Zip = String
+--
+-- name :: Lens Person String
+-- name = 'lens' _name $ \\record x -> record { _name = x }
+--
+-- address :: Lens Person Address
+-- address = 'lens' _address $ \\record x -> record { _address = x }
+--
+-- zipCode :: Lens Address Zip
+-- zipCode = 'lens' _zipCode $ \\record x -> record { _zipCode = x }
+--
+-- -- Lenses compose via '.'
+-- personZip :: Lens Person Zip
+-- personZip = zipCode . address
+--
+-- main :: IO ()
+-- main = print $ person '&' address '.~' Address "10012"
+--   -- Person { _name = "john", _age = 33, _address = Address {_zipCode = "10012"} }
+-- @
+--
+-- === Example: Usage with the @Effect@ monad
+--
+-- @
+-- newtype Model = Model { _value :: Int }
+--
+-- value :: Lens Model Int
+-- value = 'lens' _value $ \\model v -> model { _value = v }
+--
+-- data Action = AddOne | SubtractOne
+--
+-- updateModel :: Action -> Effect context props Model Action
+-- updateModel = \\case
+--   AddOne    -> value @+=@ 1
+--   SubtractOne -> value '-=' 1
+-- @
+----------------------------------------------------------------------------
+module Miso.Lens
+  ( -- ** Types
+    Lens
+  , LensCore (..)
+  , Prism (..)
+    -- ** Smart constructor
+  , lens
+  , prism
+    -- ** Re-exports
+  , (&)
+  , (<&>)
+    -- ** Lens Combinators
+  , (.~)
+  , (?~)
+  , set
+  , (%~)
+  , over
+  , (^.)
+  , (+~)
+  , (*~)
+  , (//~)
+  , (-~)
+  , (%=)
+  , (%?=)
+  , modifying
+  , (+=)
+  , (*=)
+  , (//=)
+  , (-=)
+  , (.=)
+  , (<~)
+  , (<%=)
+  , (<.=)
+  , (<?=)
+  , (<<.=)
+  , (<<%=)
+  , assign
+  , use
+  , view
+  , (?=)
+  , (<>~)
+  , _1
+  , _2
+  , _id
+  , this
+    -- ** Prism Combinators
+  , preview
+  , preuse
+  , review
+  , _Nothing
+  , _Just
+  , _Left
+  , _Right
+  , (^?)
+  -- *** Containers
+  , At (..)
+  -- *** Re-exports
+  , compose
+  -- *** Conversion
+  , Lens'
+  , toVL
+  , fromVL
+  ) where
+----------------------------------------------------------------------------
+import Control.Monad.Reader (MonadReader, asks)
+import Control.Monad.State (MonadState, modify, gets)
+import Control.Monad.Identity (Identity(..))
+import Control.Category (Category (..))
+import Control.Arrow ((>>>))
+import Data.Functor.Const (Const(..))
+import Data.Function ((&))
+import Data.Functor((<&>))
+import Data.Kind (Type)
+import qualified Data.Map.Strict as M
+import Data.Map.Strict (Map)
+import qualified Data.Set as S
+import Data.Set (Set)
+import qualified Data.IntMap.Strict as IM
+import Data.IntMap.Strict (IntMap)
+import qualified Data.IntSet as IS
+import Data.IntSet (IntSet)
+import Prelude hiding ((.))
+----------------------------------------------------------------------------
+import Miso.Util (compose)
+----------------------------------------------------------------------------
+-- | A t'Lens' is a generalized getter and setter.
+--
+-- Lenses allow both the retrieval of values from fields in a record and the
+-- assignment of values to fields in a record. The power of a t'Lens' comes
+-- from its ability to be composed with other lenses.
+--
+-- In the context of building applications with miso, the @model@ is
+-- often a deeply nested product type. This makes it highly conducive
+-- to t'Lens' operations (as defined below).
+--
+type Lens s a = LensCore a s
+----------------------------------------------------------------------------
+-- | t'LensCore' is an internal type used to reverse composition like
+-- VL libraries do.
+data LensCore field record
+  = Lens
+  { _get :: record -> field
+    -- ^ Retrieves a field from a record
+  , _set :: field -> record -> record
+    -- ^ Sets a field on a record
+  }
+----------------------------------------------------------------------------
+-- | van Laarhoven formulation, used for conversion w/ 'Miso.miso' t'Lens'.
+type Lens' s a = forall (f :: Type -> Type). Functor f => (a -> f a) -> s -> f s
+----------------------------------------------------------------------------
+-- | Convert a t'Lens' to a van Laarhoven t'Lens''
+toVL :: Lens record field -> Lens' record field
+toVL Lens {..} = \f record -> flip _set record <$> f (_get record)
+----------------------------------------------------------------------------
+-- | Convert a van Laarhoven t'Lens'' to a t'Lens'
+fromVL
+  :: Lens' record field
+  -- ^ Van Laarhoven lens to convert
+  -> Lens record field
+fromVL lens_ = Lens {..}
+  where
+    _get record = getConst (lens_ Const record)
+    _set field = runIdentity . lens_ (\_ -> Identity field)
+----------------------------------------------------------------------------
+-- | t'Lens' form a 'Category', and can therefore be composed.
+instance Category LensCore where
+  id = Lens Prelude.id const
+  Lens g1 s1 . Lens g2 s2 = Lens
+    { _get = g1 >>> g2
+    , _set = \f r -> s1 (s2 f (g1 r)) r
+    }
+----------------------------------------------------------------------------
+-- | Set a field on a record
+--
+-- @
+-- newtype Person = Person { _name :: String }
+--
+-- name :: Lens Person String
+-- name = lens _name $ \\person n -> person { _name = n }
+--
+-- setName :: Person -> String -> Person
+-- setName person newName = person & name .~ newName
+-- @
+infixr 4 .~
+(.~) :: Lens record field -> field -> record -> record
+(.~) _lens = _set _lens
+----------------------------------------------------------------------------
+-- | Synonym for '(.~)'
+--
+set :: Lens record field -> field -> record -> record
+set = (.~)
+----------------------------------------------------------------------------
+-- | Set an options field on a record
+--
+-- @
+-- newtype Person = Person { _name :: Maybe String }
+--
+-- name :: Lens Person (Maybe String)
+-- name = lens _name $ \\person n -> person { _name = n }
+--
+-- setName :: Person -> String -> Person
+-- setName person newName = person & name ?~ newName
+-- @
+infixr 4 ?~
+(?~) :: Lens record (Maybe field) -> field -> record -> record
+(?~) _lens f r = r & _lens .~ Just f
+----------------------------------------------------------------------------
+-- | Modify a field on a record by applying a function to it.
+--
+-- @
+-- newtype Counter = Counter { _value :: Int }
+--
+-- value :: Lens Counter Int
+-- value = lens _value $ \\counter v -> counter { _value = v }
+--
+-- increment :: Counter -> Counter
+-- increment counter = counter & value %~ (+1)
+-- @
+infixr 4 %~
+(%~) :: Lens record field -> (field -> field) -> record -> record
+(%~) _lens f record = _set _lens (f (record ^. _lens)) record
+----------------------------------------------------------------------------
+-- | Synonym for '(%~)'
+over :: Lens record field -> (field -> field) -> record -> record
+over = (%~)
+----------------------------------------------------------------------------
+-- | Read a field from a record using a t'Lens'
+--
+-- @
+-- newtype Person = Person { _name :: String }
+--   deriving (Show, Eq)
+--
+-- name :: Lens Person String
+-- name = lens _name $ \\person n -> person { _name = n }
+--
+-- getName :: Person -> String
+-- getName = person ^. name
+-- @
+infixl 8 ^.
+(^.) :: record -> Lens record field -> field
+(^.) = flip _get
+----------------------------------------------------------------------------
+-- | Increment a @Num field => field@ on a record using a t'Lens'
+--
+-- @
+-- newtype Person = Person { _age :: Int }
+--
+-- age :: Lens Person Int
+-- age = lens _age $ \\person a -> person { _age = a }
+--
+-- birthday :: Person -> Person
+-- birthday person = person & age +~ 1
+-- @
+infixr 4 +~
+(+~) :: Num field => Lens record field -> field -> record -> record
+(+~) _lens x record = record & _lens %~ (+x)
+----------------------------------------------------------------------------
+-- | Multiply a @Num@eric field on a record using a t'Lens'
+--
+-- @
+-- newtype Circle = Circle { _radius :: Int }
+--
+-- radius :: Lens Circle Int
+-- radius = lens _radius $ \\circle r -> circle { _radius = r }
+--
+-- expand :: Circle -> Circle
+-- expand circle = circle & radius *~ 10
+-- @
+infixr 4 *~
+(*~) :: Num field => Lens record field -> field -> record -> record
+(*~) _lens x record = record & _lens %~ (*x)
+----------------------------------------------------------------------------
+-- | Divide a @Fractional@ field on a record using a t'Lens'
+--
+-- @
+-- newtype Circle = Circle { _radius :: Int }
+--
+-- radius :: Lens Circle Int
+-- radius = lens _radius $ \\circle r -> circle { _radius = r }
+--
+-- shrink :: Circle -> Circle
+-- shrink circle = circle & radius //~ 10
+-- @
+infixr 4 //~
+(//~) :: Fractional field => Lens record field -> field -> record -> record
+(//~) _lens x record = record & _lens %~ (/x)
+----------------------------------------------------------------------------
+-- | Increment a @Num@eric field on a record using a t'Lens'
+--
+-- @
+-- newtype Person = Person { _age :: Int }
+--
+-- age :: Lens Person Int
+-- age = lens _age $ \\person a -> person { _age = a }
+--
+-- timeTravel :: Person -> Person
+-- timeTravel person = person & age -~ 1
+-- @
+infixr 4 -~
+(-~) :: Num field => Lens record field -> field -> record -> record
+(-~) _lens x record = record & _lens %~ subtract x
+----------------------------------------------------------------------------
+-- | Monoidally append a field in a record using a t'Lens'
+--
+-- @
+-- newtype List = List { _values :: [Int] }
+--
+-- values :: Lens List [Int]
+-- values = lens _values $ \\l vs -> l { _values = vs }
+--
+-- addElement :: List -> List
+-- addElement list = list & values <>~ [2]
+--
+-- addElement (List [])
+-- -- List [2]
+-- @
+--
+infixr 4 <>~
+(<>~) :: Monoid field => Lens record field -> field -> record -> record
+(<>~) _lens x record = record & _lens %~ (<> x)
+----------------------------------------------------------------------------
+-- | Execute a monadic action in @MonadState@ that returns a field. Sets the
+-- return value equal to the field in the record.
+--
+-- As a reasonable mnemonic, this lets you store the result of a monadic action in a t'Lens' rather than
+-- in a local variable.
+--
+-- @
+-- do foo <- bar
+--    ...
+-- @
+--
+-- will store the result in a variable, while
+--
+-- @
+-- do fooLens '<~' bar
+--    ...
+-- @
+--
+-- will store the result in field focused by the t'Lens'.
+infixr 2 <~
+(<~) :: MonadState record m => Lens record field -> m field -> m ()
+l <~ mb = do
+  b <- mb
+  l .= b
+----------------------------------------------------------------------------
+-- | Modify a record in @MonadState@ monad at a field using a t'Lens'
+--
+-- @
+-- newtype Model = Model { _value :: Int }
+--
+-- data Action = AddOne | SubtractOne
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update AddOne = do
+--   value %= (+1)
+-- @
+infix 4 %=
+(%=) :: MonadState record m => Lens record field -> (field -> field) -> m ()
+(%=) _lens f = modify (\r -> r & _lens %~ f)
+----------------------------------------------------------------------------
+-- | Synonym for '(%=)'
+modifying :: MonadState record m => Lens record field -> (field -> field) -> m ()
+modifying = (%=)
+----------------------------------------------------------------------------
+-- | Modify the field of a record in @MonadState@ using a t'Lens', then
+-- return the newly modified field from the updated record.
+--
+-- @
+-- import Miso.String (ms)
+--
+-- newtype Model = Model { _value :: Int }
+--   deriving (Show)
+--
+-- data Action = AddOne
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update AddOne = do
+--   result <- value <%= (+1)
+--   io_ $ consoleLog (ms result)
+-- @
+infix 4 <%=
+(<%=) :: MonadState record m => Lens record field -> (field -> field) -> m field
+l <%= f = do
+  l %= f
+  use l
+----------------------------------------------------------------------------
+-- | Assign the field of a record in @MonadState@ to a value using a t'Lens'
+-- Return the value after assignment.
+--
+-- @
+-- import Miso.String (ms)
+--
+-- newtype Model = Model { _value :: Int }
+--
+-- data Action = Assign Int
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (Assign x) = do
+--   result <- value <.= x
+--   io_ $ consoleLog (ms result) -- x
+-- @
+infix 4 <.=
+(<.=) :: MonadState record m => Lens record field -> field -> m field
+l <.= b = do
+  l .= b
+  return b
+----------------------------------------------------------------------------
+-- | Assign the field of a record in a @MonadState@ to a value (wrapped in a 'Just')
+-- using a t'Lens'. Return the value after assignment.
+--
+-- @
+-- import Miso.String (ms)
+--
+-- newtype Model = Model { _value :: Maybe Int }
+--
+-- data Action = SetValue Int
+--
+-- value :: Lens Model (Maybe Int)
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (SetValue x) = do
+--   result <- value <?= x
+--   io_ $ consoleLog (ms result) -- Just 1
+-- @
+infix 4 <?=
+(<?=) :: MonadState record m => Lens record (Maybe field) -> field -> m field
+l <?= b = do
+  l ?= b
+  return b
+----------------------------------------------------------------------------
+-- | Assign the field of a record in a @MonadState@ to a value using a t'Lens'.
+-- Returns the /previous/ value, before assignment.
+--
+-- @
+-- import Miso.String (ms)
+--
+-- newtype Model = Model { _value :: Int }
+--   deriving (Show, Eq)
+--
+-- data Action = Assign Int
+--   deriving (Show, Eq)
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (Assign x) = do
+--   value .= x
+--   previousValue <- value <<.= 1
+--   io_ $ consoleLog $ ms previousValue -- prints value at x
+-- @
+infix 4 <<.=
+(<<.=) :: MonadState record m => Lens record field -> field -> m field
+l <<.= b = do
+  old <- use l
+  l .= b
+  return old
+----------------------------------------------------------------------------
+-- | Retrieves the field associated with a record in @MonadReader@ using a t'Lens'.
+--
+-- @
+-- import Miso.String (ms)
+--
+-- newtype Model = Model { _value :: Int }
+--   deriving (Show, Eq)
+--
+-- data Action = PrintInt
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update PrintInt = do
+--   Model x <- view value
+--   io_ $ consoleLog (ms x) -- prints model value
+-- @
+----------------------------------------------------------------------------
+view :: MonadReader record m => Lens record field -> m field
+view lens_ = asks (^. lens_)
+----------------------------------------------------------------------------
+-- | Modifies the field of a record in @MonadState@ using a t'Lens'.
+-- Returns the /previous/ value, before modification.
+--
+-- @
+-- import Miso.String (ms)
+--
+-- newtype Model = Model { _value :: Int }
+--   deriving (Show, Eq)
+--
+-- data Action = Modify (Int -> Int)
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (Modify f) = do
+--   value .= 2
+--   result <- value <<%= f
+--   io_ $ consoleLog (ms result) -- prints previous value of 2
+-- @
+infix 4 <<%=
+(<<%=) :: MonadState record m => Lens record field -> (field -> field) -> m field
+l <<%= f = do
+  old <- use l
+  l %= f
+  return old
+----------------------------------------------------------------------------
+-- | Sets the value of a field in a record using @MonadState@ and a t'Lens'
+--
+-- @
+-- newtype Model = Model { _value :: Int }
+--   deriving (Show, Eq)
+--
+-- data Action = SetValue Int
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update' :: Action -> Effect context props Model Action
+-- update' (SetValue v) = value .= v
+-- @
+infix 4 .=
+(.=) :: MonadState record m => Lens record field -> field -> m ()
+(.=) _lens f = modify (\r -> r & _lens .~ f)
+----------------------------------------------------------------------------
+-- | Synonym for '(.=)'
+assign :: MonadState record m => Lens record field -> field -> m ()
+assign = (.=)
+----------------------------------------------------------------------------
+-- | Retrieves the value of a field in a record using a t'Lens' inside @MonadState@
+--
+-- @
+-- import Miso.String (ms)
+--
+-- newtype Model = Model { _value :: Int }
+--   deriving (Show, Eq)
+--
+-- data Action = SetValue Int
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (SetValue x) = do
+--   value .= x
+--   result <- use value
+--   io_ $ consoleLog (ms result) -- prints the value of x
+-- @
+use :: MonadState record m => Lens record field -> m field
+use _lens = gets (^. _lens)
+----------------------------------------------------------------------------
+-- | Sets the value of a field in a record using a t'Lens' inside a @MonadState@
+-- The value is wrapped in a @Just@ before being assigned.
+--
+-- @
+-- newtype Model = Model { _value :: Maybe Int }
+--   deriving (Show, Eq)
+--
+-- data Action = AssignValue Int
+--
+-- value :: Lens Model (Maybe Int)
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (AssignValue x) = value ?= x
+-- @
+infix 4 ?=
+(?=) :: MonadState record m => Lens record (Maybe field) -> field -> m ()
+(?=) _lens value = _lens .= Just value
+----------------------------------------------------------------------------
+-- | Alters the @Just@ value of a field in a record using a t'Lens' inside a @MonadState@
+--
+-- @
+-- newtype Model = Model { _value :: Maybe Int }
+--   deriving (Show, Eq)
+--
+-- data Action = IncrementIfJust
+--
+-- value :: Lens Model (Maybe Int)
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update IncrementIfJust = value %?= (+1)
+--
+-- @
+infix 4 %?=
+(%?=) :: MonadState record m => Lens record (Maybe field) -> (field -> field) -> m ()
+(%?=) _lens f = _lens %= \case
+  Nothing -> Nothing
+  Just x -> Just (f x)
+----------------------------------------------------------------------------
+-- | Increments the value of a @Num@eric field of a record using a t'Lens'
+-- inside a @State@ Monad.
+--
+-- @
+-- newtype Model = Model { _value :: Int }
+--   deriving (Show, Eq)
+--
+-- data Action = IncrementBy Int
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (IncrementBy x) = value @+=@ x
+-- @
+infix 4 +=
+(+=) :: (MonadState record m, Num field)  => Lens record field -> field -> m ()
+(+=) _lens f = modify (\r -> r & _lens +~ f)
+----------------------------------------------------------------------------
+-- | Multiplies the value of a @Num@eric field of a record using a t'Lens'
+-- inside a @State@ Monad.
+--
+-- @
+-- newtype Model = Model { _value :: Int }
+--   deriving (Show, Eq)
+--
+-- data Action = MultiplyBy Int
+--
+-- value :: Lens Model Int
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (MultiplyBy x) = value *= x
+-- @
+infix 4 *=
+(*=) :: (MonadState record m, Num field)  => Lens record field -> field -> m ()
+(*=) _lens f = modify (\r -> r & _lens *~ f)
+----------------------------------------------------------------------------
+-- | Divides the value of a @Fractional@ field of a record using a t'Lens'
+-- inside a @State@ Monad.
+--
+-- @
+-- newtype Model = Model { _value :: Double }
+--   deriving (Show, Eq)
+--
+-- data Action = DivideBy Double
+--
+-- value :: Lens Model Double
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (DivideBy x) = value //= x
+-- @
+infix 4 //=
+(//=) :: (MonadState record m, Fractional field)  => Lens record field -> field -> m ()
+(//=) _lens f = modify (\r -> r & _lens %~ (/ f))
+----------------------------------------------------------------------------
+-- | Subtracts the value of a @Num@eric field of a record using a t'Lens'
+-- inside of a @State@ Monad.
+--
+-- @
+-- newtype Model = Model { _value :: Double }
+--   deriving (Show, Eq)
+--
+-- data Action = SubtractBy Double
+--
+-- value :: Lens Model Double
+-- value = lens _value $ \\p x -> p { _value = x }
+--
+-- update :: Action -> Effect context props Model Action
+-- update (SubtractBy x) = value -= x
+-- @
+infix 4 -=
+(-=) :: (MonadState record m, Num field) => Lens record field -> field -> m ()
+(-=) _lens f = modify (\r -> r & _lens -~ f)
+---------------------------------------------------------------------------------
+-- | t'Lens' that operates on the first element of a tuple
+--
+-- @
+-- update AddOne = do
+--   _1 'Miso.Lens.+=' 1
+-- @
+_1 :: Lens (a,b) a
+_1 = lens fst $ \(_,b) x -> (x,b)
+---------------------------------------------------------------------------------
+-- | t'Lens' that operates on the second element of a tuple
+--
+-- @
+-- update AddOne = do
+--   _2 'Miso.Lens.+=' 1
+-- @
+_2 :: Lens (a,b) b
+_2 = lens snd $ \(a,_) x -> (a,x)
+---------------------------------------------------------------------------------
+-- | t'Lens' that operates on itself
+--
+-- @
+-- update AddOne = do
+--   _id 'Miso.Lens.+=' 1
+-- @
+_id :: Lens a a
+_id = Control.Category.id
+---------------------------------------------------------------------------------
+-- | t'Lens' that operates on itself
+--
+-- @
+-- update AddOne = do
+--   this 'Miso.Lens.+=' 1
+-- @
+this :: Lens a a
+this = _id
+---------------------------------------------------------------------------------
+-- | Smart constructor 'lens' function. Used to easily construct a t'Lens'
+--
+-- > name :: t'Lens' Person String
+-- > name = 'lens' _name $ \p n -> p { _name = n }
+--
+lens
+  :: (record -> field)
+  -- ^ Getter: read the field from a record
+  -> (record -> field -> record)
+  -- ^ Setter: write a new field value into a record
+  -> Lens record field
+lens getter setter = Lens getter (flip setter)
+----------------------------------------------------------------------------
+-- | A t'Prism' is a first-class reference into a sum type constructor.
+--
+-- t'Prism' values can be used with 'preview' to try to extract a value,
+-- and with 'review' to embed a value back into the sum type.
+data Prism s a
+  = Prism
+  { _up :: a -> s
+  -- ^ Embed a value @a@ back into the sum type @s@ (the @review@ direction).
+  , _down :: s -> Maybe a
+  -- ^ Try to extract a value @a@ from @s@; 'Nothing' if the wrong constructor.
+  }
+----------------------------------------------------------------------------
+-- | Embed a value into a sum type using a t'Prism'.
+review :: Prism s a -> a -> s
+review = _up
+----------------------------------------------------------------------------
+-- | Try to extract a value from a sum type using a t'Prism' inside 'MonadReader'.
+preview :: MonadReader r m => Prism r a -> m (Maybe a)
+preview = asks . preview
+----------------------------------------------------------------------------
+-- | Try to extract a value from a sum type using a t'Prism' inside 'MonadState'.
+preuse :: MonadState s m => Prism s a -> m (Maybe a)
+preuse = gets . preview
+----------------------------------------------------------------------------
+-- | t'Prism' for the 'Left' constructor of 'Either'.
+_Left :: Prism (Either a b) a
+_Left = prism Left $ either Just (const Nothing)
+----------------------------------------------------------------------------
+-- | t'Prism' for the 'Right' constructor of 'Either'.
+_Right :: Prism (Either a b) b
+_Right = prism Right (either (const Nothing) Just)
+----------------------------------------------------------------------------
+-- | t'Prism' for the 'Just' constructor of 'Maybe'.
+_Just :: Prism (Maybe a) a
+_Just = prism Just Prelude.id
+----------------------------------------------------------------------------
+-- | t'Prism' that matches a 'Nothing' value.
+_Nothing :: Prism (Maybe a) a
+_Nothing = prism (const Nothing) Prelude.id
+----------------------------------------------------------------------------
+-- | Infix alias for 'preview'. Try to extract a value using a t'Prism'.
+--
+-- @
+-- Right 42 '^?' '_Right' == Just 42
+-- Left  "x" '^?' '_Right' == Nothing
+-- @
+infixl 8 ^?
+(^?) :: s -> Prism s a -> Maybe a
+(^?) = flip preview
+----------------------------------------------------------------------------
+-- | Smart constructor for t'Prism'.
+prism
+  :: (a -> s)
+  -- ^ Embed direction: construct @s@ from @a@.
+  -> (s -> Maybe a)
+  -- ^ Match direction: try to extract @a@ from @s@.
+  -> Prism s a
+prism = Prism
+----------------------------------------------------------------------------
+-- | Class for getting and setting values across various container types.
+--
+-- > M.singleton 'a' "foo" & at 'a' .~ Just "bar"
+-- > -- fromList [('a',"bar")]
+--
+-- > update (SetValue value)
+-- >   at 10 ?= value
+--
+-- @since 1.9.0.0
+class At at where
+  type family Index at :: Type
+  -- ^ Index of the container
+  type family IxValue at :: Type
+  -- ^ Indexed value of the container
+  at :: Index at -> Lens at (Maybe (IxValue at))
+----------------------------------------------------------------------------
+instance Ord k => At (Map k v) where
+  type Index (Map k v) = k
+  type IxValue (Map k v) = v
+  at key = lens (M.lookup key) $ \m value ->
+    case value of
+      Nothing -> M.delete key m
+      Just v -> M.insert key v m
+----------------------------------------------------------------------------
+instance At (IntMap v) where
+  type Index (IntMap v) = Int
+  type IxValue (IntMap v) = v
+  at key = lens (IM.lookup key) $ \m value ->
+    case value of
+      Nothing -> IM.delete key m
+      Just v -> IM.insert key v m
+----------------------------------------------------------------------------
+instance Ord k => At (Set k) where
+  type Index (Set k) = k
+  type IxValue (Set k) = ()
+  at key = Lens {..}
+    where
+      _set = \v m ->
+        case v of
+          Nothing -> S.delete key m
+          Just () -> S.insert key m
+      _get m
+        | S.member key m = Just ()
+        | otherwise = Nothing
+----------------------------------------------------------------------------
+instance At IntSet where
+  type Index IntSet = Int
+  type IxValue IntSet = ()
+  at key = Lens {..}
+    where
+      _set = \v m ->
+        case v of
+          Nothing -> IS.delete key m
+          Just () -> IS.insert key m
+      _get m
+        | IS.member key m = Just ()
+        | otherwise = Nothing
+----------------------------------------------------------------------------
+instance At [a] where
+  type Index [a] = Int
+  type IxValue [a] = a
+  at key = Lens {..}
+    where
+      _set Nothing m
+        | key < 0 = m
+        | otherwise = splitAt key m & \(lhs, rhs) -> lhs <> drop 1 rhs
+      _set (Just v) m
+        | key < 0 = m
+        | otherwise = splitAt key m & \(lhs, rhs) ->
+            case rhs of
+              [] -> lhs
+              _ : xs -> lhs <> (v : xs)
+      _get = lookup key . zip [0..]
+----------------------------------------------------------------------------
diff --git a/src/Miso/Lens/Generic.hs b/src/Miso/Lens/Generic.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Lens/Generic.hs
@@ -0,0 +1,192 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE InstanceSigs #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+{-# LANGUAGE UndecidableSuperClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Lens.Generic
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Lens.Generic" derives 'Miso.Lens.Lens' values for record fields
+-- at compile time using @GHC.Generics@ and @GHC.Records@, without
+-- Template Haskell. Fields are addressed by name via 'GHC.OverloadedLabels'
+-- or the explicit 'field' combinator.
+--
+-- Enable the required extensions:
+--
+-- @
+-- {-\# LANGUAGE OverloadedLabels, DeriveGeneric \#-}
+-- import GHC.Generics (Generic)
+-- import "Miso.Lens.Generic" ('HasLens', 'field')
+-- import "Miso.Lens"         ('Lens', 'Miso.Lens.view', @set@, (@.=@), (@++=@))
+-- @
+--
+-- = Quick start
+--
+-- @
+-- data Counter = Counter { _count :: Int, _label :: 'Miso.String.MisoString' }
+--   deriving ('GHC.Generics.Generic')
+--
+-- -- Label syntax (requires OverloadedLabels):
+-- countLens :: 'Miso.Lens.Lens' Counter Int
+-- countLens = #_count
+--
+-- -- Explicit syntax (works without OverloadedLabels):
+-- labelLens :: 'Miso.Lens.Lens' Counter 'Miso.String.MisoString'
+-- labelLens = 'field' \@\"_label\"
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Counter Action
+-- update Increment = #_count @+=@ 1
+-- update (SetLabel l) = #_label @.=@ l
+-- @
+--
+-- = How it works
+--
+-- The 'HasLens' instance is resolved via 'GHC.Records.HasField' for the
+-- getter and a generic traversal ('GSet') for the setter. A type-level
+-- 'TotalityCheck' produces a descriptive compile error if the field name
+-- is absent from (or inconsistent across) the constructors.
+--
+-- = Comparison with Template Haskell
+--
+-- [Overloaded labels] "Miso.Lens.Generic" — no TH; derives via @Generic@
+-- [Template Haskell] "Miso.Lens.TH" — @makeLenses@ \/ @makeClassy@
+--
+-- = See also
+--
+-- * "Miso.Lens" — 'Miso.Lens.Lens', 'Miso.Lens.lens', operators
+-- * "Miso.Lens.TH" — Template Haskell alternative
+-----------------------------------------------------------------------------
+module Miso.Lens.Generic (HasLens(..), field, GSet(..), GetFieldType, TotalityCheck, And, Or) where
+
+-----------------------------------------------------------------------------
+import Data.Kind (Constraint, Type)
+import GHC.Generics (C1, D1, Generic (..), K1 (..), M1 (..), Meta (..), Rec0, S1, (:*:) (..), (:+:) (..))
+import GHC.OverloadedLabels (IsLabel (..))
+import GHC.Records (HasField (..))
+import GHC.TypeLits (ErrorMessage (..), Symbol, TypeError)
+-----------------------------------------------------------------------------
+import Miso.Lens (Lens, lens)
+-----------------------------------------------------------------------------
+
+-- | Provides a 'Lens' onto the field named @name@ of the record @s@.
+--
+-- The single instance is derived from @s@'s t'GHC.Generics.Generic'
+-- representation, so any record with a 'GHC.Generics.Generic' instance gets
+-- lenses for free. Also backs the @OverloadedLabels@ syntax @#fieldName@.
+--
+-- @since 1.11.0.0
+class Generic s => HasLens (name :: Symbol) s a | name s -> a where 
+  getLens :: Lens s a
+
+instance 
+  (HasField name s a, TotalityCheck name s a (GetFieldType name (Rep s)), GSet name a (Rep s), Generic s) => 
+  HasLens name s a where
+  getLens = lens (getField @name) (\s v -> to . gSet @name v . from $ s)
+  {-# INLINE getLens #-}
+
+instance HasLens name s a => IsLabel name (Lens s a)
+  where fromLabel = getLens @name
+
+{-# INLINE field #-}
+-- | A 'Lens' onto the record field named @name@, applied with a type
+-- application: @'field' \@"userName"@.
+--
+-- The @OverloadedLabels@ form @#userName@ is equivalent.
+--
+-- @since 1.11.0.0
+field :: forall name s a. HasLens name s a => Lens s a 
+field = fromLabel @name
+
+-- | Internal: writes the field named @name@ into a t'GHC.Generics.Generic'
+-- representation. Drives the setter half of 'HasLens'; you should not need to
+-- write instances.
+--
+-- @since 1.13.0.0
+class GSet (name :: Symbol) typ f where
+  gSet :: typ -> f x -> f x
+
+instance (GSet name typ a, GSet name typ b) => GSet name typ (a :*: b) where
+  gSet v (l :*: r) = gSet @name v l :*: gSet @name v r
+  {-# INLINE gSet #-}
+
+instance (GSet name typ a, GSet name typ b) => GSet name typ (a :+: b) where
+  gSet v (L1 l) = L1 $ gSet @name v l
+  gSet v (R1 r) = R1 $ gSet @name v r
+  {-# INLINE gSet #-}
+
+instance (GSet name typ f) => GSet name typ (C1 x f) where
+  gSet v (M1 f) = M1 $ gSet @name v f
+  {-# INLINE gSet #-}
+
+instance (GSet name typ f) => GSet name typ (D1 x f) where
+  gSet v (M1 f) = M1 $ gSet @name v f
+  {-# INLINE gSet #-}
+
+instance {-# OVERLAPPING #-} GSet name typ (S1 ('MetaSel ('Just name) b c d) (Rec0 typ)) where
+  gSet v (M1 (K1 _)) = M1 (K1 v)
+
+instance {-# OVERLAPPABLE #-} GSet name typ (S1 ('MetaSel ('Just anotherName) b c d) x) where
+  gSet _ f = f
+  {-# INLINE gSet #-}
+
+-- | Internal: turns a missing field into a readable @TypeError@ rather than an
+-- unsolved-constraint message. Fails when 'GetFieldType' found no field of
+-- that name, or found one that is not present in every constructor.
+--
+-- @since 1.13.0.0
+type family TotalityCheck (name :: Symbol) r a (res :: Maybe Type) :: Constraint where
+  TotalityCheck _ _ _ ('Just _) = ()
+  TotalityCheck name r a 'Nothing =
+    TypeError
+      ( 'ShowType r
+          ':<>: 'Text ": "
+          ':<>: 'Text name
+          ':<>: 'Text " field missing or not in all constructors"
+      )
+
+-- | Internal: looks up the type of the field named @field@ in a
+-- t'GHC.Generics.Generic' representation, yielding @'Just' t@ when found.
+-- Products search both sides ('Or'); sums require agreement ('And').
+--
+-- @since 1.13.0.0
+type family GetFieldType (field :: Symbol) f :: Maybe Type where
+  GetFieldType field (S1 ('MetaSel ('Just field) _ _ _) (Rec0 t)) ='Just t
+  GetFieldType field (l :*: r) = Or (GetFieldType field l) (GetFieldType field r)
+  GetFieldType field (l :+: r) = And (GetFieldType field l) (GetFieldType field r)
+  GetFieldType field (C1 _ f) = GetFieldType field f
+  GetFieldType field (D1 _ f) = GetFieldType field f
+  GetFieldType field x = 'Nothing
+
+-- | Internal: combines two 'GetFieldType' results across a sum, yielding
+-- @'Just' t@ only when both branches agree on @t@ — a field that is absent
+-- from some constructor is not addressable.
+--
+-- @since 1.13.0.0
+type family And (l :: Maybe Type) (r :: Maybe Type) :: Maybe Type where
+  And ('Just a) ('Just a) = 'Just a
+  And l r = 'Nothing
+
+-- | Internal: combines two 'GetFieldType' results across a product, taking
+-- whichever branch found the field.
+--
+-- @since 1.13.0.0
+type family Or (l :: Maybe Type) (r :: Maybe Type) :: Maybe Type where
+  Or ('Just l) _ = 'Just l
+  Or _ r = r
diff --git a/src/Miso/Lens/TH.hs b/src/Miso/Lens/TH.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Lens/TH.hs
@@ -0,0 +1,213 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase            #-}
+{-# LANGUAGE TemplateHaskellQuotes #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Lens.TH
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Lens.TH" generates 'Lens' definitions via Template Haskell, similar
+-- to @lens@'s @makeLenses@ and @makeClassy@. Fields must be prefixed with
+-- @_@ — the generated lens name is the field name with the underscore dropped.
+--
+-- Enable the extension and splice at the declaration level:
+--
+-- @
+-- {-\# LANGUAGE TemplateHaskell \#-}
+-- import "Miso.Lens.TH" ('makeLenses', 'makeClassy')
+-- @
+--
+-- = makeLenses
+--
+-- Generates a @'Lens' Record Field@ for each @_@-prefixed record field:
+--
+-- @
+-- data Model = Model
+--   { _count :: Int
+--   , _text  :: 'Miso.String.MisoString'
+--   } deriving (Eq)
+--
+-- 'makeLenses' \'\'Model
+-- -- Generates:
+-- --   count :: 'Lens' Model Int
+-- --   text  :: 'Lens' Model 'Miso.String.MisoString'
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update Increment   = count @+=@ 1
+-- update (SetText t) = text  @.=@ t
+-- @
+--
+-- = makeClassy
+--
+-- Generates a @HasFoo@ typeclass with a self-lens @foo :: Lens s Foo@ and
+-- one lens per @_@-prefixed field. This enables lens composition across
+-- record types that embed @Foo@:
+--
+-- @
+-- data Foo = Foo { _fooX :: Int, _fooY :: Int }
+-- 'makeClassy' \'\'Foo
+-- -- Generates:
+-- --   class HasFoo s where
+-- --     foo  :: 'Lens' s Foo
+-- --     fooX :: 'Lens' s Int   -- fooX = foo . lens _fooX ...
+-- --     fooY :: 'Lens' s Int
+-- --   instance HasFoo Foo where foo = 'this'
+--
+-- data Bar = Bar { _barFoo :: Foo, _barZ :: Double }
+-- 'makeLenses' \'\'Bar
+-- instance HasFoo Bar where foo = barFoo
+-- -- Now barX :: 'Lens' Bar Int  (via foo composition)
+-- @
+--
+-- = Comparison with Generic approach
+--
+-- [Template Haskell] "Miso.Lens.TH" — @_@ prefix required; explicit splice
+-- [Overloaded labels] "Miso.Lens.Generic" — no TH; derives via @Generic@
+--
+-- = See also
+--
+-- * "Miso.Lens" — 'Miso.Lens.Lens', 'Miso.Lens.lens', 'Miso.Lens.view',
+--   'Miso.Lens.set', and the update operators (@.=@, @+=@, @%=@, …)
+-- * "Miso.Lens.Generic" — label-based alternative requiring no TH splice
+-----------------------------------------------------------------------------
+module Miso.Lens.TH
+  ( -- ** TH
+    makeLenses
+  , makeClassy
+    -- ** Re-exports
+  , lens
+  , compose
+  , this
+  , Lens
+  ) where
+-----------------------------------------------------------------------------
+import Data.Char
+import Data.Maybe
+import Language.Haskell.TH
+-----------------------------------------------------------------------------
+import Miso.Util (compose)
+import Miso.Lens (this, lens, Lens)
+-----------------------------------------------------------------------------
+-- | Automatically generates Haskell lenses via template-haskell.
+--
+makeLenses
+  :: Name
+  -- ^ The name of the record type to derive lenses for (e.g. @\'\'MyModel@)
+  -> Q [Dec]
+makeLenses name = do
+  reify name >>= \case
+    TyConI (NewtypeD _ _ _ _ con _) -> do
+      case con of
+        RecC _ fieldNames ->
+          pure (processFieldNames fieldNames)
+        _ -> pure []
+    TyConI (DataD _ _ _ _ cons _) ->
+      flip concatMapM cons $ \case
+        RecC _ fieldNames -> do
+          pure (processFieldNames fieldNames)
+        _ -> pure []
+    _ -> pure []
+  where
+    processFieldNames fieldNames = concat
+      [ mkFields fieldName (ConT name) fieldType
+      | (fieldName, _, fieldType) <- fieldNames
+      , listToMaybe (nameBase fieldName) == Just '_'
+      ]
+    mkFields fieldName conType fieldType =
+     let -- dmj: drops '_' prefix
+       lensName = mkName (drop 1 (nameBase fieldName))
+     in
+       [ FunD lensName
+         [ Clause [] (NormalB (mkLens fieldName)) []
+         ]
+       , SigD lensName (mkLensType conType fieldType)
+       ]
+    concatMapM f xs =
+      concat <$> mapM f xs
+    mkLensType conType =
+      AppT (AppT (ConT ''Lens) conType)
+    mkLens fieldName =
+      AppE (AppE (VarE 'lens) (VarE fieldName))
+        $ LamE [ VarP recName, VarP fieldVar ]
+        $ RecUpdE (VarE recName) [ (fieldName, VarE fieldVar) ]
+      where
+        recName = mkName "record"
+        fieldVar = mkName "field"
+-----------------------------------------------------------------------------
+-- | Automatically generates classy lenses via template-haskell.
+makeClassy
+  :: Name
+  -- ^ The name of the record type to derive a @Has@ typeclass and lenses for (e.g. @\'\'MyModel@)
+  -> Q [Dec]
+makeClassy name = do
+  reify name >>= \case
+    TyConI (NewtypeD _ _ _ _ con _) -> do
+      case con of
+        RecC _ fieldNames ->
+          pure (processFieldNames fieldNames)
+        _ -> pure []
+    TyConI (DataD _ _ _ _ cons _) ->
+      flip concatMapM cons $ \case
+        RecC _ fieldNames -> do
+          pure (processFieldNames fieldNames)
+        _ -> pure []
+    _ -> pure []
+  where
+    instanceName =
+      AppT (ConT (mkName ("Has" <> baseName))) (ConT name)
+    baseName = nameBase name
+    baseNameLower
+      | x : xs <- baseName = toLower x : xs
+      | otherwise = []
+    processFieldNames fieldNames =
+        [ InstanceD Nothing [] instanceName
+          [ ValD (VarP (mkName baseNameLower)) (NormalB (VarE 'this)) []
+            -- instance HasFoo Foo where foo = this
+          ]
+        , ClassD [] (mkName $ "Has" <> nameBase name)
+            [ PlainTV (mkName baseNameLower) BndrReq
+            ] [] $ reverse $ concat
+            [ mkFields fieldName (VarT (mkName baseNameLower)) fieldType
+            | (fieldName, _, fieldType) <- fieldNames
+            , listToMaybe (nameBase fieldName) == Just '_'
+            ] ++
+            [ SigD
+                (mkName baseNameLower)
+                (AppT
+                   (AppT
+                      (ConT ''Lens)
+                      (VarT (mkName baseNameLower)))
+                      (ConT name))
+            ]
+        ]
+    mkFields fieldName varType fieldType =
+      let -- dmj: drops '_' prefix
+        lensName = mkName (drop 1 (nameBase fieldName))
+      in
+        [ FunD lensName
+          [ Clause [] (NormalB (wrapMkLens fieldName)) []
+          ]
+          -- fooX = lens _fooX (\r x -> r { _fooX = x }) . foo
+        , SigD lensName (mkLensType varType fieldType)
+          -- fooY :: Lens foo Int
+        ]
+    concatMapM f xs =
+      concat <$> mapM f xs
+    mkLensType varType x =
+      AppT (AppT (ConT ''Lens) varType) x
+    wrapMkLens fieldName =
+      AppE (AppE (VarE 'compose) (mkLens fieldName)) (VarE (mkName baseNameLower))
+    mkLens fieldName
+      = AppE (AppE (VarE 'lens) (VarE fieldName))
+      $ LamE [ VarP recName, VarP fieldVar ]
+      $ RecUpdE (VarE recName) [ (fieldName, VarE fieldVar) ]
+      where
+        recName = mkName "record"
+        fieldVar = mkName "field"
+-------------------------------------------------------------------------------
diff --git a/src/Miso/Mathml.hs b/src/Miso/Mathml.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Mathml.hs
@@ -0,0 +1,39 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Mathml
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [MathML](https://developer.mozilla.org/en-US/docs/Web/MathML) element
+-- combinators for rendering mathematical expressions in Miso views.
+-- Re-exports everything from "Miso.Mathml.Element".
+--
+-- __Example__ — render /x²/:
+--
+-- @
+-- xSquared :: View context action
+-- xSquared =
+--   math_ []
+--     [ msup_ []
+--         [ mi_ [] [ text \"x\" ]
+--         , mn_ [] [ text \"2\" ]
+--         ]
+--     ]
+-- @
+--
+-- For a more complete example see
+-- [miso-mathml](https://github.com/haskell-miso/miso-mathml).
+--
+----------------------------------------------------------------------------
+module Miso.Mathml
+   ( -- * Elements
+     module Miso.Mathml.Element
+   , module Miso.Mathml.Property
+   ) where
+-----------------------------------------------------------------------------
+import Miso.Mathml.Element
+import Miso.Mathml.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Mathml/Element.hs b/src/Miso/Mathml/Element.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Mathml/Element.hs
@@ -0,0 +1,288 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Mathml.Element
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Mathml.Element" provides smart constructors for every element in the
+-- <https://developer.mozilla.org/en-US/docs/Web/MathML MathML Core>
+-- vocabulary. Each constructor produces a 'Miso.Types.View' node in the
+-- @MATHML@ namespace:
+--
+-- @
+-- tagName_ :: ['Miso.Types.Attribute' action] -> ['Miso.Types.View' model action] -> 'Miso.Types.View' model action
+-- @
+--
+-- All names are suffixed with @_@. The module is re-exported by "Miso.Mathml".
+--
+-- = Quick start
+--
+-- Embed a fraction inside a paragraph using 'Miso.Html.Element.p_' and 'math_':
+--
+-- @
+-- import "Miso"
+-- import "Miso.Mathml.Element"
+-- import "Miso.Mathml.Property" (@display_@)
+--
+-- formula :: 'Miso.Types.View' model action
+-- formula =
+--   'Miso.Html.Element.p_' []
+--     [ 'math_' [ @display_@ \"block\" ]
+--         [ 'mfrac_' []
+--             [ 'mn_' [] [ 'Miso.text' \"1\" ]
+--             , 'msqrt_' [] [ 'mn_' [] [ 'Miso.text' \"2\" ] ]
+--             ]
+--         ]
+--     ]
+-- @
+--
+-- = Element groups
+--
+-- * __Top-level__: 'math_'
+-- * __Token elements__ (leaves): 'mi_' (identifier), 'mn_' (number),
+--   'mo_' (operator), 'ms_' (string literal), 'mtext_', 'mspace_'
+-- * __General layout__: 'mrow_', 'mfrac_', 'msqrt_', 'mroot_',
+--   'mpadded_', 'mphantom_', 'merror_', 'mstyle_', 'mfenced_'
+-- * __Script \& limit__: 'msub_', 'msup_', 'msubsup_',
+--   'mover_', 'munder_', 'munderover_', 'mmultiscripts_', 'mprescripts_'
+-- * __Tabular__: 'mtable_', 'mtr_', 'mtd_'
+-- * __Semantics__: 'semantics_', 'annotation_', 'annotationXml_'
+-- * __Custom__: 'nodeMathml' for any MathML tag not listed above
+--
+-- = See also
+--
+-- * "Miso.Mathml.Property" — MathML attribute combinators
+-- * "Miso.Mathml" — re-export hub for the full MathML DSL
+-- * "Miso.Html.Element" — HTML element constructors
+-- * "Miso.Svg.Element" — SVG element constructors
+-----------------------------------------------------------------------------
+module Miso.Mathml.Element
+  ( -- ** Combinator
+    nodeMathml
+   -- ** Elements
+  , math_
+  , annotationXml_
+  , annotation_
+  , merror_
+  , mfrac_
+  , mi_
+  , mmultiscripts_
+  , mn_
+  , mo_
+  , mover_
+  , mpadded_
+  , mphantom_
+  , mprescripts_
+  , mroot_
+  , mrow_
+  , ms_
+  , mspace_
+  , msqrt_
+  , mstyle_
+  , msub_
+  , msubsup_
+  , msup_
+  , mtable_
+  , mtd_
+  , mtext_
+  , mtr_
+  , munder_
+  , munderover_
+  , semantics_
+  , mfenced_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.Types
+-----------------------------------------------------------------------------
+-- | Low-level helper used to construct 'MATHML' 'node' in 'Miso.Types.View'.
+-- Most View helpers in this module are defined in terms of it.
+nodeMathml :: MisoString -> [Attribute model action] -> [View context model action] -> View context model action
+nodeMathml nodeName = node MATHML nodeName
+-----------------------------------------------------------------------------
+-- | [\<annotation-xml\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/annotation-xml)
+--
+-- @since 1.9.0.0
+annotationXml_ :: [Attribute model action] -> [View context model action] -> View context model action
+annotationXml_ = nodeMathml "annotation-xml"
+-----------------------------------------------------------------------------
+-- | [\<annotation\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/annotation)
+--
+-- @since 1.9.0.0
+annotation_ :: [Attribute model action] -> [View context model action] -> View context model action
+annotation_ = nodeMathml "annotation"
+-----------------------------------------------------------------------------
+-- | [\<math\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/math)
+--
+-- @since 1.9.0.0
+math_ :: [Attribute model action] -> [View context model action] -> View context model action
+math_ = nodeMathml "math"
+-----------------------------------------------------------------------------
+-- | [\<merror\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/merror)
+--
+-- @since 1.9.0.0
+merror_ :: [Attribute model action] -> [View context model action] -> View context model action
+merror_ = nodeMathml "merror"
+-----------------------------------------------------------------------------
+-- | [\<mfrac\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mfrac)
+--
+-- @since 1.9.0.0
+mfrac_ :: [Attribute model action] -> [View context model action] -> View context model action
+mfrac_ = nodeMathml "mfrac"
+-----------------------------------------------------------------------------
+-- | [\<mi\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mi)
+--
+-- @since 1.9.0.0
+mi_ :: [Attribute model action] -> [View context model action] -> View context model action
+mi_ = nodeMathml "mi"
+-----------------------------------------------------------------------------
+-- | [\<mmultiscripts\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mmultiscripts)
+--
+-- @since 1.9.0.0
+mmultiscripts_ :: [Attribute model action] -> [View context model action] -> View context model action
+mmultiscripts_ = nodeMathml "mmultiscripts"
+-----------------------------------------------------------------------------
+-- | [\<mn\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mn)
+--
+-- @since 1.9.0.0
+mn_ :: [Attribute model action] -> [View context model action] -> View context model action
+mn_ = nodeMathml "mn"
+-----------------------------------------------------------------------------
+-- | [\<mo\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mo)
+--
+-- @since 1.9.0.0
+mo_ :: [Attribute model action] -> [View context model action] -> View context model action
+mo_ = nodeMathml "mo"
+-----------------------------------------------------------------------------
+-- | [\<mover\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mover)
+--
+-- @since 1.9.0.0
+mover_ :: [Attribute model action] -> [View context model action] -> View context model action
+mover_ = nodeMathml "mover"
+-----------------------------------------------------------------------------
+-- | [\<mpadded\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mpadded)
+--
+-- @since 1.9.0.0
+mpadded_ :: [Attribute model action] -> [View context model action] -> View context model action
+mpadded_ = nodeMathml "mpadded"
+-----------------------------------------------------------------------------
+-- | [\<mphantom\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mphantom)
+--
+-- @since 1.9.0.0
+mphantom_ :: [Attribute model action] -> [View context model action] -> View context model action
+mphantom_ = nodeMathml "mphantom"
+-----------------------------------------------------------------------------
+-- | [\<mprescripts\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mprescripts)
+--
+-- @since 1.9.0.0
+mprescripts_ :: [Attribute model action] -> [View context model action] -> View context model action
+mprescripts_ = nodeMathml "mprescripts"
+-----------------------------------------------------------------------------
+-- | [\<mroot\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mroot)
+--
+-- @since 1.9.0.0
+mroot_ :: [Attribute model action] -> [View context model action] -> View context model action
+mroot_ = nodeMathml "mroot"
+-----------------------------------------------------------------------------
+-- | [\<mrow\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mrow)
+--
+-- @since 1.9.0.0
+mrow_ :: [Attribute model action] -> [View context model action] -> View context model action
+mrow_ = nodeMathml "mrow"
+-----------------------------------------------------------------------------
+-- | [\<ms\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/ms)
+--
+-- @since 1.9.0.0
+ms_ :: [Attribute model action] -> [View context model action] -> View context model action
+ms_ = nodeMathml "ms"
+-----------------------------------------------------------------------------
+-- | [\<mspace\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mspace)
+--
+-- @since 1.9.0.0
+mspace_ :: [Attribute model action] -> [View context model action] -> View context model action
+mspace_ = nodeMathml "mspace"
+-----------------------------------------------------------------------------
+-- | [\<msqrt\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/msqrt)
+--
+-- @since 1.9.0.0
+msqrt_ :: [Attribute model action] -> [View context model action] -> View context model action
+msqrt_ = nodeMathml "msqrt"
+-----------------------------------------------------------------------------
+-- | [\<mstyle\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mstyle)
+--
+-- @since 1.9.0.0
+mstyle_ :: [Attribute model action] -> [View context model action] -> View context model action
+mstyle_ = nodeMathml "mstyle"
+-----------------------------------------------------------------------------
+-- | [\<msub\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/msub)
+--
+-- @since 1.9.0.0
+msub_ :: [Attribute model action] -> [View context model action] -> View context model action
+msub_ = nodeMathml "msub"
+-----------------------------------------------------------------------------
+-- | [\<msubsup\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/msubsup)
+--
+-- @since 1.9.0.0
+msubsup_ :: [Attribute model action] -> [View context model action] -> View context model action
+msubsup_ = nodeMathml "msubsup"
+-----------------------------------------------------------------------------
+-- | [\<msup\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/msup)
+--
+-- @since 1.9.0.0
+msup_ :: [Attribute model action] -> [View context model action] -> View context model action
+msup_ = nodeMathml "msup"
+-----------------------------------------------------------------------------
+-- | [\<mtable\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mtable)
+--
+-- @since 1.9.0.0
+mtable_ :: [Attribute model action] -> [View context model action] -> View context model action
+mtable_ = nodeMathml "mtable"
+-----------------------------------------------------------------------------
+-- | [\<mtd\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mtd)
+--
+-- @since 1.9.0.0
+mtd_ :: [Attribute model action] -> [View context model action] -> View context model action
+mtd_ = nodeMathml "mtd"
+-----------------------------------------------------------------------------
+-- | [\<mtext\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mtext)
+--
+-- @since 1.9.0.0
+mtext_ :: [Attribute model action] -> [View context model action] -> View context model action
+mtext_ = nodeMathml "mtext"
+-----------------------------------------------------------------------------
+-- | [\<mtr\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mtr)
+--
+-- @since 1.9.0.0
+mtr_ :: [Attribute model action] -> [View context model action] -> View context model action
+mtr_ = nodeMathml "mtr"
+-----------------------------------------------------------------------------
+-- | [\<munder\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/munder)
+--
+-- @since 1.9.0.0
+munder_ :: [Attribute model action] -> [View context model action] -> View context model action
+munder_ = nodeMathml "munder"
+-----------------------------------------------------------------------------
+-- | [\<munderover\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/munderover)
+--
+-- @since 1.9.0.0
+munderover_ :: [Attribute model action] -> [View context model action] -> View context model action
+munderover_ = nodeMathml "munderover"
+-----------------------------------------------------------------------------
+-- | [\<semantics\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/semantics)
+--
+-- @since 1.9.0.0
+semantics_ :: [Attribute model action] -> [View context model action] -> View context model action
+semantics_ = nodeMathml "semantics"
+-----------------------------------------------------------------------------
+-- | [\<semantics\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mfenced)
+--
+-- @since 1.9.0.0
+mfenced_ :: [Attribute model action] -> [View context model action] -> View context model action
+mfenced_ = nodeMathml "mfenced"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Mathml/Property.hs b/src/Miso/Mathml/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Mathml/Property.hs
@@ -0,0 +1,272 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Mathml.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Mathml.Property" provides 'Miso.Types.Attribute' smart constructors
+-- for
+-- <https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Attribute MathML attributes>.
+-- They are used alongside the element constructors from "Miso.Mathml.Element".
+-- The module is re-exported by "Miso.Mathml".
+--
+-- = Quick start
+--
+-- @
+-- import "Miso.Mathml.Element"
+-- import "Miso.Mathml.Property"
+--
+-- styledFrac :: 'Miso.Types.View' model action
+-- styledFrac =
+--   'Miso.Mathml.Element.math_' [ 'display_' \"block\" ]
+--     [ 'Miso.Mathml.Element.mfrac_' [ 'linethickness_' \"2px\" ]
+--         [ 'Miso.Mathml.Element.mn_' [ 'mathvariant_' \"bold\" ] [ 'Miso.text' \"1\" ]
+--         , 'Miso.Mathml.Element.mn_' [] [ 'Miso.text' \"3\" ]
+--         ]
+--     ]
+-- @
+--
+-- = Attribute groups
+--
+-- * __Global MathML attributes__: 'dir_', 'displaystyle_', 'scriptlevel_',
+--   'id_', 'href_', 'mathbackground_', 'mathcolor_', 'mathsize_', 'mathvariant_'
+-- * __Layout__: 'display_', 'height_', 'width_', 'depth_', 'voffset_',
+--   'lspace_', 'rspace_', 'linethickness_', 'minsize_', 'maxsize_'
+-- * __Table__: 'align_', 'rowalign_', 'rowlines_', 'rowspacing_', 'rowspan_',
+--   'columnalign_', 'columnlines_', 'columnspacing_', 'columnspan_'
+-- * __Operator flags__ (boolean): 'accent_', 'accentunder_', 'fence_',
+--   'separator_', 'stretchy_', 'symmetric_', 'movablelimits_'
+-- * __Frame__: 'frame_', 'framespacing_'
+-- * __Grouping__: 'open_', 'close_', 'notation_'
+--
+-- For full semantics of each attribute consult the
+-- <https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Attribute MDN MathML attribute reference>.
+--
+-- = See also
+--
+-- * "Miso.Mathml.Element" — MathML element constructors
+-- * "Miso.Mathml" — re-export hub for the full MathML DSL
+-- * "Miso.Property" — low-level 'Miso.Property.textProp', 'Miso.Property.boolProp', 'Miso.Property.intProp'
+-----------------------------------------------------------------------------
+module Miso.Mathml.Property
+  ( -- * Global attributes
+    dir_
+  , displaystyle_
+  , scriptlevel_
+  -- * Regular attributes
+  , accent_
+  , accentunder_
+  , align_
+  , columnalign_
+  , columnlines_
+  , columnspacing_
+  , columnspan_
+  , depth_
+  , display_
+  , fence_
+  , frame_
+  , framespacing_
+  , height_
+  , href_
+  , id_
+  , linethickness_
+  , lspace_
+  , mathbackground_
+  , mathcolor_
+  , mathsize_
+  , mathvariant_
+  , maxsize_
+  , minsize_
+  , movablelimits_
+  , notation_
+  , rowalign_
+  , rowlines_
+  , rowspacing_
+  , rowspan_
+  , rspace_
+  , separator_
+  , stretchy_
+  , symmetric_
+  , voffset_
+  , width_
+  , close_
+  , open_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.Types
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | [dir](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Global_attributes/dir)
+--
+-- @since 1.9.0.0
+dir_ :: MisoString -> Attribute model action
+dir_ = textProp "dir"
+-----------------------------------------------------------------------------
+-- | [displaystyle](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Global_attributes/displaystyle)
+--
+-- @since 1.9.0.0
+displaystyle_ :: MisoString -> Attribute model action
+displaystyle_ = textProp "displaystyle"
+------------------------------------------------------------------------------
+-- | [scriptlevel](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Global_attributes/scriptlevel)
+--
+-- @since 1.9.0.0
+scriptlevel_ :: Int -> Attribute model action
+scriptlevel_ = intProp "scriptlevel"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+accent_ ::  Bool -> Attribute model action
+accent_ = boolProp "accent"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+accentunder_ ::  Bool -> Attribute model action
+accentunder_ = boolProp "accentunder"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+align_ ::  Bool -> Attribute model action
+align_ = boolProp "align"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+columnalign_ :: MisoString -> Attribute model action
+columnalign_ = textProp "columnalign"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+columnlines_ :: MisoString -> Attribute model action
+columnlines_ = textProp "columnlines"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+columnspacing_ :: MisoString -> Attribute model action
+columnspacing_ = textProp "columnspacing"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+columnspan_ :: Int -> Attribute model action
+columnspan_ = intProp "columnspan"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+depth_ :: MisoString -> Attribute model action
+depth_ = textProp "depth"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+display_ :: MisoString -> Attribute model action
+display_ = textProp "display"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+fence_ :: Bool -> Attribute model action
+fence_ = boolProp "fence"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+frame_ :: MisoString -> Attribute model action
+frame_ = textProp "frame"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+framespacing_ :: MisoString -> Attribute model action
+framespacing_ = textProp "framespacing"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+height_ :: MisoString -> Attribute model action
+height_ = textProp "height"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+href_ :: MisoString -> Attribute model action
+href_ = textProp "href"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+id_ :: MisoString -> Attribute model action
+id_ = textProp "id"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+linethickness_ :: MisoString -> Attribute model action
+linethickness_ = textProp "linethickness"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+lspace_ :: MisoString -> Attribute model action
+lspace_ = textProp "lspace"
+-- | @since 1.9.0.0
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+mathbackground_ :: MisoString -> Attribute model action
+mathbackground_ = textProp "mathbackground"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+mathcolor_ :: MisoString -> Attribute model action
+mathcolor_ = textProp "mathcolor"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+mathsize_ :: MisoString -> Attribute model action
+mathsize_ = textProp "mathsize"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+mathvariant_ :: MisoString -> Attribute model action
+mathvariant_ = textProp "mathvariant"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+maxsize_ :: MisoString -> Attribute model action
+maxsize_ = textProp "maxsize"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+minsize_ :: MisoString -> Attribute model action
+minsize_ = textProp "minsize"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+movablelimits_ :: Bool -> Attribute model action
+movablelimits_ = boolProp "movablelimits"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+notation_ :: MisoString -> Attribute model action
+notation_ = textProp "notation"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+rowalign_ :: MisoString -> Attribute model action
+rowalign_ = textProp "rowalign"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+rowlines_ :: MisoString -> Attribute model action
+rowlines_ = textProp "rowlines"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+rowspacing_ :: MisoString -> Attribute model action
+rowspacing_ = textProp "rowspacing"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+rowspan_ :: Int -> Attribute model action
+rowspan_ = intProp "rowspan"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+rspace_ :: MisoString -> Attribute model action
+rspace_ = textProp "rspace"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+separator_ :: Bool -> Attribute model action
+separator_ = boolProp "separator"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+stretchy_ :: Bool -> Attribute model action
+stretchy_ = boolProp "stretchy"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+symmetric_ :: Bool -> Attribute model action
+symmetric_ = boolProp "symmetric"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+voffset_ :: MisoString -> Attribute model action
+voffset_ = textProp "voffset"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+width_ :: MisoString -> Attribute model action
+width_ = textProp "width"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+close_ :: MisoString -> Attribute model action
+close_ = textProp "close"
+-----------------------------------------------------------------------------
+-- | @since 1.9.0.0
+open_ :: MisoString -> Attribute model action
+open_ = textProp "open"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Media.hs b/src/Miso/Media.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Media.hs
@@ -0,0 +1,337 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Media
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Media" is a Haskell wrapper around the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement HTMLMediaElement>
+-- API. It covers both @\<audio\>@ and @\<video\>@ elements through the
+-- unified t'Media' type, which wraps the underlying 'Miso.DSL.JSVal'.
+--
+-- All property reads and method calls run in 'IO'. Properties that can be
+-- set declaratively are cross-linked to their corresponding
+-- 'Miso.Html.Property' combinators.
+--
+-- = Quick start
+--
+-- Obtain a t'Media' handle from the DOM, then read or control it in an
+-- 'Miso.Effect.Effect':
+--
+-- @
+-- import "Miso"
+-- import "Miso.Media"
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update PlayVideo = 'Miso.Effect.io_' $ do
+--   m <- t'Media' \<$\> 'Miso.FFI.getElementById' \"myVideo\"
+--   'play' m
+-- update PauseVideo = 'Miso.Effect.io_' $ do
+--   m <- t'Media' \<$\> 'Miso.FFI.getElementById' \"myVideo\"
+--   'pause' m
+-- update ReadState = 'Miso.Effect.io' $ do
+--   m  <- t'Media' \<$\> 'Miso.FFI.getElementById' \"myVideo\"
+--   t  <- 'currentTime' m
+--   rs <- 'readyState' m
+--   pure (GotState t rs)
+-- @
+--
+-- Wire events using 'mediaEvents' and the handlers from "Miso.Html.Event":
+--
+-- @
+-- myComponent = ('Miso.component' model update view)
+--   { 'Miso.Types.events' = 'Miso.Event.Types.defaultEvents' \<\> 'mediaEvents' }
+-- @
+--
+-- = API groups
+--
+-- * __Methods__: 'play', 'pause', 'load', 'canPlayType', 'srcObject'
+-- * __Playback state__ (read-only): 'currentSrc', 'currentTime', 'duration',
+--   'ended', 'paused', 'seeking', 'networkState', 'readyState'
+-- * __Playback control__ (read; set via 'Miso.Html.Property'): 'autoplay',
+--   'controls', 'loop', 'muted', 'defaultMuted', 'volume', 'playbackRate',
+--   'defaultPlaybackRate', 'preload', 'mediaGroup'
+-- * __Video-specific__ (read-only): 'videoWidth', 'videoHeight', 'poster'
+-- * __Event map__: 'mediaEvents' — merge into 'Miso.Types.events' to enable
+--   media event delegation
+--
+-- = State enumerations
+--
+-- 'NetworkState' and 'ReadyState' mirror the integer constants defined by
+-- <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement HTMLMediaElement>
+-- and are derived from 'Enum' so @toEnum@ / @fromEnum@ round-trip correctly:
+--
+-- @
+-- -- NetworkState: NETWORK_EMPTY(0) NETWORK_IDLE(1) NETWORK_LOADING(2) NETWORK_NO_SOURCE(3)
+-- -- ReadyState:   HAVE_NOTHING(0) HAVE_METADATA(1) HAVE_CURRENT_DATA(2) HAVE_FUTURE_DATA(3) HAVE_ENOUGH_DATA(4)
+-- @
+--
+-- = See also
+--
+-- * "Miso.Html.Element" — 'Miso.Html.Element.audio_', 'Miso.Html.Element.video_'
+-- * "Miso.Html.Property" — 'Miso.Html.Property.autoplay_', 'Miso.Html.Property.controls_', …
+-- * "Miso.Html.Event" — 'Miso.Html.Event.onPlay', 'Miso.Html.Event.onPause', …
+-- * "Miso.Event.Types" — 'Miso.Event.Types.mediaEvents' (also re-exported here)
+-----------------------------------------------------------------------------
+module Miso.Media
+  ( -- *** Types
+    Media        (..)
+  , NetworkState (..)
+  , ReadyState   (..)
+  , Stream
+  -- *** Methods
+  , canPlayType
+  , load
+  , play
+  , pause
+  , srcObject
+  -- *** Properties
+  , autoplay
+  , controls
+  , currentSrc
+  , currentTime
+  , defaultMuted
+  , defaultPlaybackRate
+  , duration
+  , ended
+  , loop
+  , mediaGroup
+  , muted
+  , networkState
+  , paused
+  , playbackRate
+  , poster
+  , preload
+  , readyState
+  , seeking
+  , videoHeight
+  , videoWidth
+  , volume
+  -- *** Event Map
+  , mediaEvents
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.Event
+import           Miso.String
+-----------------------------------------------------------------------------
+-- | Type that abstracts over [Audio](https://www.w3schools.com/jsref/dom_obj_audio.asp)
+-- or [Video](https://www.w3schools.com/jsref/dom_obj_video.asp) media objects.
+--
+-- You can create them in the View using 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_'.
+-- To get the corresponding t'Media' object from the DOM, you can use
+--
+-- @
+-- media <- t'Media' \<$\> 'Miso.FFI.getElementById' "myVideo"
+-- @
+newtype Media = Media JSVal
+  deriving (ToJSVal, Eq)
+-----------------------------------------------------------------------------
+-- | Possible values of [networkState](https://www.w3schools.com/tags/av_prop_networkstate.asp) property.
+data NetworkState
+  = NETWORK_EMPTY
+  | NETWORK_IDLE
+  | NETWORK_LOADING
+  | NETWORK_NO_SOURCE
+  deriving (Show, Eq, Enum)
+-----------------------------------------------------------------------------
+-- | Possible values of [readyState](https://www.w3schools.com/tags/av_prop_readystate.asp) property.
+data ReadyState
+  = HAVE_NOTHING
+  | HAVE_METADATA
+  | HAVE_CURRENT_DATA
+  | HAVE_FUTURE_DATA
+  | HAVE_ENOUGH_DATA
+  deriving (Show, Eq, Enum)
+-----------------------------------------------------------------------------
+-- | The [load](https://www.w3schools.com/tags/av_met_load.asp) method
+-- re-loads the audio/video element.
+load :: Media -> IO ()
+load (Media m) = void $ m # ("load" :: MisoString) $ ()
+-----------------------------------------------------------------------------
+-- | The [play](https://www.w3schools.com/tags/av_met_play.asp) method starts
+-- playing the current audio or video.
+play :: Media -> IO ()
+play (Media m) = void $ m # ("play" :: MisoString) $ ()
+-----------------------------------------------------------------------------
+-- | The [pause](https://www.w3schools.com/tags/av_met_pause.asp) method pauses
+-- the currently playing audio or video.
+pause :: Media -> IO ()
+pause (Media a) = void $ a # ("pause" :: MisoString) $ ()
+-----------------------------------------------------------------------------
+-- | The [canPlayType](https://www.w3schools.com/tags/av_met_canplaytype.asp)
+-- method checks if the browser can play the specified audio/video type.
+canPlayType :: Media -> IO MisoString
+canPlayType (Media m) = do
+  fromJSValUnchecked =<< do
+    m # ("canPlayType" :: MisoString) $ ()
+-----------------------------------------------------------------------------
+-- | The [autoplay](https://www.w3schools.com/tags/av_prop_autoplay.asp) property
+-- returns whether the audio/video should start playing as soon as it is loaded.
+--
+-- To set the property, use 'Miso.Html.Property.autoplay_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+autoplay :: Media -> IO Bool
+autoplay (Media m) = fromJSValUnchecked =<< m ! ("autoplay" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [controls](https://www.w3schools.com/tags/av_prop_controls.asp)
+-- property returns whether the browser should display standard audio/video controls.
+--
+-- To set the property, use 'Miso.Html.Property.controls_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+controls :: Media -> IO Bool
+controls (Media m) = fromJSValUnchecked =<< m ! ("controls" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [currentSrc](https://www.w3schools.com/tags/av_prop_currentsrc.asp)
+-- property returns the URL of the current audio/video.
+currentSrc :: Media -> IO MisoString
+currentSrc (Media m) = fromJSValUnchecked =<< m ! ("currentSrc" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [currentTime](https://www.w3schools.com/tags/av_prop_currenttime.asp)
+-- property returns the current position (in seconds) of the audio/video playback.
+--
+-- To set the current time, use 'Miso.Html.Property.currentTime_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+currentTime :: Media -> IO Double
+currentTime (Media m) = fromJSValUnchecked =<< m ! ("currentTime" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [defaultMuted](https://www.w3schools.com/tags/av_prop_defaultmuted.asp)
+-- property returns whether the audio/video should be muted by default.
+--
+-- To set the property, use 'Miso.Html.Property.defaultMuted_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+defaultMuted :: Media -> IO Bool
+defaultMuted (Media m) = fromJSValUnchecked =<< m ! ("defaultMuted" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [defaultPlaybackRate](https://www.w3schools.com/tags/av_prop_defaultplaybackrate.asp)
+-- property returns the default playback speed of the audio/video.
+--
+-- To set the property, use 'Miso.Html.Property.defaultPlaybackRate_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+defaultPlaybackRate :: Media -> IO Double
+defaultPlaybackRate (Media m) = fromJSValUnchecked =<< m ! ("defaultPlaybackRate" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [duration](https://www.w3schools.com/tags/av_prop_duration.asp) property
+-- returns the length of the current audio/video, in seconds.
+duration :: Media -> IO Double
+duration (Media m) = fromJSValUnchecked =<< m ! ("duration" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [ended](https://www.w3schools.com/tags/av_prop_ended.asp) property
+-- returns whether the playback of the audio/video has ended.
+ended :: Media -> IO Bool
+ended (Media m) = fromJSValUnchecked =<< m ! ("ended" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [loop](https://www.w3schools.com/tags/av_prop_loop.asp) property
+-- returns whether the audio/video should start playing over again when it is finished.
+--
+-- To set the property, use 'Miso.Html.Property.loop_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+loop :: Media -> IO Bool
+loop (Media m) = fromJSValUnchecked =<< m ! ("loop" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [mediaGroup](https://www.w3schools.com/tags/av_prop_mediagroup.asp) property
+-- returns the name of the media group the audio/video is a part of.
+--
+-- To set the property, use 'Miso.Html.Property.mediaGroup_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+mediaGroup :: Media -> IO MisoString
+mediaGroup (Media m) = fromJSValUnchecked =<< m ! ("mediaGroup" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [muted](https://www.w3schools.com/tags/av_prop_muted.asp) property
+-- returns whether the audio/video should be muted (sound turned off).
+--
+-- To set the property, use 'Miso.Html.Property.muted_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+muted :: Media -> IO Bool
+muted (Media m) = fromJSValUnchecked =<< m ! ("muted" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [networkState](https://www.w3schools.com/tags/av_prop_networkstate.asp)
+-- property returns the current network state (activity) of the audio/video.
+networkState :: Media -> IO NetworkState
+networkState (Media m) = do
+  number <- fromJSValUnchecked =<< m ! ("networkState" :: MisoString)
+  pure (toEnum number)
+-----------------------------------------------------------------------------
+-- | The [paused](https://www.w3schools.com/tags/av_prop_paused.asp) property
+-- returns whether the audio/video is paused.
+paused :: Media -> IO Bool
+paused (Media a) = fromJSValUnchecked =<< a ! ("paused" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [playbackRate](https://www.w3schools.com/tags/av_prop_playbackRate.asp)
+-- property returns the current playback speed of the audio/video.
+--
+-- To set the playback rate, use 'Miso.Html.Property.playbackRate_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+playbackRate :: Media -> IO Double
+playbackRate (Media a) = fromJSValUnchecked =<< a ! ("playbackRate" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [poster](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/poster) property
+-- of the HTMLVideoElement interface is a string that reflects the URL for an image
+-- to be shown while no video data is available.
+--
+-- Specific to videos.
+poster :: Media -> IO MisoString
+poster (Media a) = fromJSValUnchecked =<< a ! ("poster" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [preload](https://www.w3schools.com/tags/av_prop_preload.asp) property
+-- returns whether the audio/video should start loading as soon as the page loads.
+--
+-- To set the preload property, use 'Miso.Html.Property.preload_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+preload :: Media -> IO MisoString
+preload (Media a) = fromJSValUnchecked =<< a ! ("preload" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [readyState](https://www.w3schools.com/tags/av_prop_readyState.asp) property
+-- returns the current ready state of the audio/video.
+readyState :: Media -> IO ReadyState
+readyState (Media a) = do
+  number <- fromJSValUnchecked =<< a ! ("readyState" :: MisoString)
+  pure (toEnum number)
+-----------------------------------------------------------------------------
+-- | The [seeking](https://www.w3schools.com/tags/av_prop_seeking.asp) property
+-- returns whether the user is currently seeking in the audio/video.
+seeking :: Media -> IO Bool
+seeking (Media a) = fromJSValUnchecked =<< a ! ("seeking" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The HTMLVideoElement interface's read-only
+-- [videoHeight](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoHeight)
+-- property indicates the intrinsic height of the video, expressed in CSS pixels.
+videoHeight :: Media -> IO Int
+videoHeight (Media m) = fromJSValUnchecked =<< m ! ("videoHeight" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The HTMLVideoElement interface's read-only
+-- [videoWidth](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoWidth)
+-- property indicates the intrinsic width of the video, expressed in CSS pixels
+videoWidth :: Media -> IO Int
+videoWidth (Media m) = fromJSValUnchecked =<< m ! ("videoWidth" :: MisoString)
+-----------------------------------------------------------------------------
+-- | The [volume](https://www.w3schools.com/tags/av_prop_volume.asp) property
+-- returns the current volume of the audio/video.
+--
+-- To set the volume, use 'Miso.Html.Property.volume_'
+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.
+volume :: Media -> IO Double
+volume (Media m) = fromJSValUnchecked =<< m ! ("volume" :: MisoString)
+-----------------------------------------------------------------------------
+-- | A media Stream
+type Stream = JSVal
+-----------------------------------------------------------------------------
+-- | Sets the `srcObject` on audio or video elements.
+srcObject
+  :: Stream
+  -- ^ A t'Stream' obtained from @navigator.mediaDevices.getUserMedia@ or similar
+  -> Media
+  -- ^ The audio\/video element whose @srcObject@ will be set
+  -> IO ()
+srcObject stream (Media media) = setField media "srcObject" stream
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native.hs b/src/Miso/Native.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native.hs
@@ -0,0 +1,469 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = miso native 📱
+--
+-- "Miso.Native" targets __native mobile devices__ by driving the
+-- [Lynx](https://lynxjs.org) runtime instead of the browser DOM. The same
+-- [MVU](https://elm-lang.org) programming model, t'Miso.Types.Component' API, event
+-- delegation and virtual-DOM diffing you use on the web ("Miso") carry over
+-- unchanged — only the element vocabulary differs ('Miso.Native.Element.view_',
+-- 'Miso.Native.Element.text_', … instead of 'Miso.Html.Element.div_' \/
+-- 'Miso.Html.Element.span_') and rendering is performed by Lynx's
+-- [element PAPI](https://lynxjs.org/api/engine/element-api) rather than by
+-- mutating a browser DOM.
+--
+-- This module is the native analog of the 'Miso.miso' \/ 'Miso.startApp'
+-- entrypoints: 'native' (and 'nativeWithContext') boot a root t'Miso.Types.Component' onto
+-- the Lynx runtime.
+--
+-- == Enabling native
+--
+-- The native backend is gated behind the @native@ /cabal flag/. It must be
+-- enabled to bring "Miso.Native" and the @Miso.Native.*@ element \/ event \/ FFI
+-- modules into scope (build with @-fnative@). Web \/ WASM builds are unaffected —
+-- all cross-thread machinery lives behind the @NATIVE@ CPP guard.
+--
+-- = The dual-thread architecture
+--
+-- Lynx runs your application across __two threads__, and miso maps onto both:
+--
+-- * __BTS__ — the /background thread/ (\"background thread script\"). This is
+--   where your application /logic/ lives. Everything runs here __by default__:
+--   the 'Miso.Types.update' function, event handling, 'Miso.Effect.Effect' scheduling and
+--   /all/ virtual-DOM diffing.
+--
+-- * __MTS__ — the /main thread/ (\"main thread script\"). This thread owns the
+--   actual element tree and /rendering/. It is where the pixels land. It is also
+--   available as a low-latency escape hatch for performance-critical event
+--   handling (see [Main-thread events](#mainthread) below).
+--
+-- The __same Haskell bundle runs on both threads__; the native runtime
+-- (@ts\/miso-native.ts@) selects the BTS or MTS drawing context per-thread from a
+-- global flag, so there is no renderer to register — 'native' starts the app
+-- directly.
+--
+-- The guiding principle: __everything originates on the BTS__. The MTS is a
+-- rendering surface that the BTS drives across the thread boundary.
+--
+-- == Knowing which thread you are on
+--
+-- Lynx builds the bundle with [rspeedy](https://lynxjs.org) — its Rust-based
+-- tooling — which compiles the sources /twice/, once per thread, inlining a
+-- __compile-time constant__ (@__BACKGROUND__@) that distinguishes the two. That
+-- constant surfaces in Haskell as three top-level 'Bool's re-exported from "Miso":
+--
+-- * @mts@ — 'True' when this execution context is the Lynx /main/ thread.
+-- * @bts@ — 'True' when this context is the Lynx /background/ thread.
+-- * @web@ — 'True' for a plain web \/ WASM build (neither Lynx thread).
+--
+-- Exactly one is 'True', and the value is invariant for the lifetime of a JS
+-- context, so the runtime computes it once and caches it. Runtime code branches
+-- on @mts@ \/ @bts@ to decide where work runs (e.g. the scheduler suppresses the
+-- paint step on the MTS, which keeps only a read-only @model@ replica).
+--
+-- == What crosses the thread boundary, and how
+--
+-- Because logic (BTS) and rendering (MTS) live on different threads, miso
+-- synchronizes them by shipping messages across the boundary. This is largely
+-- invisible, but understanding it explains the API constraints below.
+--
+-- * __Initial draw__ — The very first 'Draw' happens __on the MTS itself__, and
+--   it does __not__ rely on the BTS diffing a tree and transferring patches
+--   across the boundary. The root t'Miso.Types.Component' is booted from a 'StaticPtr' (via
+--   'native' \/ 'nativeWithContext'), so the MTS reconstructs it from the
+--   pointer's 'GHC.StaticPtr.StaticKey' alone and renders the first frame
+--   locally (Lynx's instant first frame). Only /after/ this initial draw does the
+--   cross-thread patch protocol take over: __every subsequent diff runs on the
+--   BTS and ships patches to the MTS__ to apply.
+--
+-- * __Subsequent component mounts__ — When the BTS 'Miso.Lens.view' mounts a child
+--   t'Miso.Types.Component', that mount is synchronized to the MTS __asynchronously__ using
+--   /static mounting/: the child is wrapped in a @static@ pointer
+--   (@-XStaticPointers@) so only its 'GHC.StaticPtr.StaticKey' — not a closure —
+--   needs to cross the boundary. The MTS dereferences the key to rebuild the
+--   component locally. See 'Miso.Types.vcomp' \/ 'Miso.Types.mountStatic'.
+--
+-- * __State synchronization__ — The BTS owns the shared @model@ and ships it to
+--   the MTS as it changes (JSON-serialized, hence the @ToJSON@ \/ @FromJSON@
+--   constraints on native mounting combinators), so main-thread @*MainWith@
+--   handlers observe an eventually-consistent copy. A child's initial @props@ ride
+--   the /static mount/ payload — the @static@ pointer carries the /constructor/
+--   and the @props@ value is shipped separately, so it may depend on the parent
+--   @model@. Neither @props@ nor the global @context@ is re-synced afterwards,
+--   however: the MTS keeps the values it booted with (matching ReactLynx — see
+--   [Main-thread events](#mainthread)).
+--
+-- * __Events__ — Events raised on the MTS are, by default, forwarded to the BTS
+--   where @update@ runs (see below). Cross-thread handlers are carried as an
+--   t'Miso.Types.EventHandler', embedded with 'Miso.Types.event' @. static (…)@ so
+--   the peer thread can rebuild the handler from its 'GHC.StaticPtr.StaticKey'.
+--
+-- == First-frame rendering (instant first frame)
+--
+-- The MTS painting frame one itself (the __Initial draw__ above) is Lynx's
+-- /instant first frame/: the user sees UI without waiting for a background render
+-- and patch round-trip. Meanwhile the BTS boots the /same/ root and builds the
+-- identical virtual-DOM tree in lockstep — with __deterministic @nodeId@
+-- parity__, so both threads address the same elements — but __suppresses its own
+-- create-patches__ for that first frame, since the MTS already painted them. A
+-- single global @initialDraw@ latch governs this on both threads; 'native' \/
+-- 'nativeWithContext' clears it once the whole root mount has finished.
+--
+-- After that handover the responsibilities are fixed, mirroring ReactLynx: the
+-- __BTS is the sole diff \/ paint authority__ — it runs @update@, diffs, and ships
+-- patches — while the __MTS only applies those patches__ (and runs main-thread
+-- scripts \/ handlers). The MTS never diffs or repaints from the scheduler again;
+-- this is why the shared @model@ is BTS-owned and why nothing you do on the MTS
+-- should try to redraw declaratively.
+--
+-- = Static mounting
+--
+-- Because component constructors, event handlers and effects may need to be
+-- reconstructed on the /other/ thread, native miso threads them across the
+-- boundary as @static@ pointers rather than closures. This requires the
+-- @-XStaticPointers@ language extension.
+--
+-- The root component is mounted with 'Miso.Types.mountStatic' wrapped in
+-- @static@:
+--
+-- @
+-- {-# LANGUAGE StaticPointers #-}
+-- -----------------------------------------------------------------------------
+-- module Main where
+-- -----------------------------------------------------------------------------
+-- import "Miso"
+-- import "Miso.Native"
+-- -----------------------------------------------------------------------------
+-- main :: 'IO' ()
+-- main = 'native' 'nativeEvents' (static ('Miso.Types.mountStatic' app))
+-- @
+--
+-- Child components are embedded in a 'Miso.Lens.view' the same way, with 'Miso.Types.vcomp':
+--
+-- @
+-- view _ _ _ = view_ [] [ 'Miso.Types.vcomp' () (static ('Miso.Types.mountStatic' childComponent)) ]
+-- @
+--
+-- __Static-pointer limitation.__ A @static@ form may only close over
+-- /top-level, closed/ bindings — it cannot capture local variables. This is why
+-- component constructors and main-thread handlers are supplied as references to
+-- top-level definitions, with any runtime data (props, decoded event payloads)
+-- shipped separately as serialized values rather than captured in a closure.
+--
+-- = Effects: choosing a thread
+--
+-- Because an 'IO' closure can't cross the thread boundary (only JSON-serialized
+-- @action@s can), cross-thread work is expressed as /dispatching an action/ to
+-- the thread that should handle it. Two combinators do this:
+--
+-- * 'Miso.Effect.runOnBG' @action@ — run @action@'s @update@ on the
+--   __background__ thread (BTS). Used by a main-thread event handler that needs
+--   to change shared state, since the BTS solely owns the @model@.
+-- * 'Miso.Effect.runOnMain' @action@ — run @action@'s @update@ on the __main__
+--   thread (MTS). Used by a BTS effect that needs an imperative main-thread
+--   operation (see "Miso.Native.MainThread").
+--
+-- Each ships only the given @action@ to the target thread (or dispatches it
+-- locally when already there), where its @update@ runs exactly once. Sibling
+-- effects in the current @update@ are unaffected, and nothing is
+-- double-executed. Off the native runtime both are an ordinary local dispatch,
+-- equivalent to 'Miso.Effect.issue'.
+--
+-- = Subscriptions and threads
+--
+-- A t'Miso.Effect.Sub' is dynamic — it is just a @'Miso.Effect.Sink' action ->
+-- IO ()@ run in a forked thread — and a component's subs are started on __every
+-- thread it mounts on__. So a 'Miso.Effect.Sub' runs on __both the BTS and the
+-- MTS__ (once each), and each copy dispatches into its own thread's scheduler.
+--
+-- Because a 'Miso.Effect.Sub' is ordinary runtime IO — unlike a @static@ event
+-- handler, whose thread is fixed at compile time — it selects its own thread at
+-- runtime with the @mts@ \/ @bts@ 'Bool's. This is the dynamic analog of a
+-- handler's @*Main@ variant:
+--
+-- @
+-- -- background-only: open the socket once, feed the model
+-- wsSub sink = when bts (websocketConnect \"wss:\/\/…\" sink)
+--
+-- -- main-thread-only: drive an imperative animation
+-- animSub _ = when mts ('Miso.Native.MainThread.eachFrame' step)
+-- @
+--
+-- __Guard anything that must be single-owned.__ Without a @bts@ \/ @mts@ gate a
+-- stateful sub double-runs — two websocket connections, a timer ticking on both
+-- threads — so pin such subs to one thread. The no-op fork on the other thread
+-- returns immediately.
+--
+-- = Main-thread events #mainthread#
+--
+-- __Thread affinity is per-handler, not per-event-name.__ Any given event can be
+-- handled on /either/ thread; the choice is made at each handler, so the same
+-- event (say @tap@) may run on the BTS for one element and the MTS for another.
+-- The __default is the BTS__ — a plain 'Miso.Native.Element.View.Event.onTap'
+-- handler runs on the background thread. Opting a handler into the MTS is
+-- explicit (the @*Main@ variants below); nothing runs on the main thread unless
+-- you ask for it.
+--
+-- By default an event handler runs on the __BTS__: the event is forwarded from
+-- the MTS, @update@ runs on the BTS, the model changes, and the resulting diff is
+-- shipped back to the MTS to paint. That round-trip is fine for most
+-- interactions but adds latency for gesture- and scroll-linked animation.
+--
+-- For those cases, handlers have __@*Main@-suffixed variants__ (e.g.
+-- 'Miso.Native.Element.View.Event.onTapMain',
+-- 'Miso.Native.Element.View.Event.onTouchMoveMain') that run __synchronously on
+-- the MTS__ — no VDOM diff, no patches, no BTS round-trip. Such a handler is
+-- /imperative/: it mutates the target element directly through the helpers in
+-- "Miso.Native.MainThread" (e.g. 'Miso.Native.MainThread.setStyleProperty'). The
+-- @*MainWith@ variants additionally hand the handler the current @model@ and the
+-- target 'Miso.Types.DOMRef' (@\\event model domRef -> action@).
+--
+-- Because a main-thread handler must be reconstructed on the MTS, it is an
+-- t'Miso.Types.EventHandler' embedded with 'Miso.Types.event' @. static@ — so
+-- __main-thread event handlers require @-XStaticPointers@__ (the @static@ keyword
+-- is how the handler crosses to the MTS by 'GHC.StaticPtr.StaticKey'):
+--
+-- @
+-- {-# LANGUAGE StaticPointers #-}
+--
+-- view _ _ _ =
+--   @view_@ [ 'Miso.Types.event' (static ('Miso.Native.Element.View.Event.onTapMain' HandleTap)) ] []
+-- @
+--
+-- The same @static@ capture limitation applies: an @onTapMain@ handler refers to
+-- a top-level action \/ function; runtime data reaches the handler via the
+-- decoded event payload, not a captured closure.
+--
+-- __The generic primitives ('Miso.Event.on' \/ 'Miso.Event.onMain').__ The
+-- per-element @on*@ \/ @on*Main@ helpers are sugar over two combinators, and the
+-- /same/ @(eventName, decoder, toAction)@ works with either — that is how one
+-- event is captured on whichever thread you choose, per handler:
+--
+-- * 'Miso.Event.on' @name decoder toAction@ → a plain 'Miso.Types.Attribute'
+--   that runs on the __BTS__. No @static@: a background handler is reconstructed
+--   nowhere else, so it may close over the enclosing 'Miso.Lens.view'.
+-- * 'Miso.Event.onMain' @name decoder toAction@ → an t'Miso.Types.EventHandler'
+--   that runs on the __MTS__, embedded with 'Miso.Types.event' @. static@.
+--
+-- @
+-- -- same @tap@ event, one handler per thread:
+-- view_ [ 'Miso.Event.on' \"tap\" emptyDecoder (\\_ _ _ -> Grow) ] children                     -- BTS
+-- view_ [ 'Miso.Types.event' (static ('Miso.Event.onMain' \"tap\" emptyDecoder onTapMain)) ] children  -- MTS
+-- @
+--
+-- The @Attribute@-versus-@EventHandler@+@static@ split /is/ the mechanism: only
+-- the main-thread handler has to cross to the MTS by 'GHC.StaticPtr.StaticKey',
+-- which is why 'Miso.Event.onMain' (and every @*Main@ helper) needs
+-- @-XStaticPointers@ while 'Miso.Event.on' does not. ('Miso.Event.onMainWithOptions'
+-- exposes 'Miso.Event.Types.Phase' \/ 'Miso.Event.Types.Options' for the MTS
+-- variant, mirroring 'Miso.Event.onWithOptions'.)
+--
+-- __Reaching the @model@ (and why it is passed, not captured).__ A static
+-- main-thread handler /cannot/ close over the @model@, @props@ or @context@ from
+-- the enclosing 'Miso.Lens.view' — those are local bindings, which @static@ forbids. So
+-- rather than capture them, the @*MainWith@ variants __pass the @model@ as an
+-- argument__ to the handler, giving imperative MTS code the state it needs to
+-- integrate without a BTS round-trip. Note this is the __main-thread's own copy__
+-- of the model: it is populated on the MTS __eventually consistently__ from the
+-- BTS (the authoritative model still lives on the background thread), so a
+-- handler may observe a value slightly behind the latest BTS state.
+--
+-- __Props and context are not kept up to date on the main thread.__ Both are
+-- /present/ on the MTS — a child's @props@ arrive on the initial @MOUNT@
+-- payload, and the @context@ is seeded when 'native' \/ 'nativeWithContext'
+-- boots the thread — but, unlike the @model@, neither is ever shipped again.
+-- The MTS holds whatever it booted with, so 'Miso.Effect.getProps' \/
+-- 'Miso.Effect.getContext' inside a main-thread handler return values frozen at
+-- mount time, arbitrarily far behind the BTS. (This matches ReactLynx, where
+-- React state — and therefore props and context — is background-thread-only.)
+-- Only the @model@ is re-synced, eventually consistently, as above.
+--
+-- If a main-thread handler needs a prop or context value that can change, fold
+-- it into the @model@ or carry it in the dispatched action payload — do not read
+-- @props@ or @context@ on the main thread. The upside is less cross-thread
+-- traffic: a @props@ change crosses only on the initial @MOUNT@, and a @context@
+-- change never crosses at all.
+--
+-- __Ownership caveat.__ A property you drive imperatively from the MTS must not
+-- /also/ be written declaratively by the BTS @view@ for the same element: both
+-- threads write the shared element tree through the same PAPI with no
+-- arbitration, so one will clobber the other. Keep a single owner per
+-- @(element, property)@ — typically compositor properties like @transform@ \/
+-- @opacity@ that the @view@ leaves alone.
+--
+-- = Main-thread-local state: 'Miso.Native.MainThread.MainThreadRef'
+--
+-- A main-thread handler is imperative and must not write the BTS-owned @model@:
+-- shared state changes belong on the background thread, so dispatch them with
+-- 'Miso.Effect.runOnBG'. But gestures and scroll-linked animation often need
+-- mutable state that lives /only/ on the MTS — the current drag offset, a fling
+-- velocity, whether a follow loop is active. For that, use a
+-- 'Miso.Native.MainThread.MainThreadRef', a thin 'Data.IORef.IORef' wrapper for
+-- main-thread-only state (the analog of ReactLynx's @MainThreadRef@):
+--
+-- @
+-- dragRef :: 'Miso.Native.MainThread.MainThreadRef' Double
+-- dragRef = 'Miso.Native.MainThread.mainThreadRef' 0
+-- {-\# NOINLINE dragRef \#-}
+-- @
+--
+-- 'Miso.Native.MainThread.mainThreadRef' allocates the underlying cell as a CAF
+-- via 'System.IO.Unsafe.unsafePerformIO', so __every top-level binding needs its
+-- own @{-\# NOINLINE \#-}@ pragma__ — otherwise GHC may inline the CAF and split
+-- the state into independent copies. Reads and writes
+-- ('Miso.Native.MainThread.readMainThreadRef' \/
+-- 'Miso.Native.MainThread.writeMainThreadRef' \/
+-- 'Miso.Native.MainThread.modifyMainThreadRef') are ordinary 'Data.IORef.IORef'
+-- operations — safe without atomics because the MTS is single-threaded —
+-- and 'Miso.Native.MainThread.modifyMainThreadRef_' takes a
+-- @'Control.Monad.State.State' a ()@ so you can drive updates with the
+-- "Miso.Lens" operators (@.=@, @%=@, @+=@, …).
+--
+-- It pairs with 'Miso.Native.MainThread.eachFrame' for a vsync-coalesced
+-- animation loop: read the latest gesture state from the ref, imperatively paint
+-- at most once per frame (via 'Miso.Native.MainThread.setStyleProperty' \/
+-- 'Miso.Native.MainThread.setStylePropertyTransform'), and stop by returning
+-- @False@ when the gesture ends.
+--
+-- = Platform APIs and thread restrictions
+--
+-- Mirroring Lynx (/\"not all APIs exist on both threads\"/), miso's native APIs
+-- are split by thread, and calling one from the wrong thread fails at runtime —
+-- the type system does not catch it, so guard with @mts@ \/ @bts@ when code may
+-- run on either thread. Neither module is re-exported here; import it directly.
+--
+-- * __Native modules (BTS-only)__ — "Miso.Native.Module" wraps Lynx's global
+--   @NativeModules@ (platform capabilities: storage, clipboard, device info, …).
+--   'Miso.Native.Module.callNativeModule' invokes a void-returning method and
+--   'Miso.Native.Module.callNativeModuleWith' a callback method whose result is
+--   decoded via 'Miso.JSON.FromJSON'. @NativeModules@ exists __only on the BTS__:
+--
+--     @
+--     'Miso.Native.Module.callNativeModule' \"NativeLocalStorageModule\" \"setStorageItem\"
+--       [ 'Miso.JSON.String' \"key\", 'Miso.JSON.String' \"value\" ]
+--     @
+--
+--   @update@ runs on the BTS by default, so this just works there; from a
+--   main-thread handler, hop to the BTS first with 'Miso.Effect.runOnBG'. On the
+--   MTS the module is @undefined@ and the call logs a @consoleError@.
+--
+-- * __Main-thread element ops (MTS-only)__ — the imperative helpers in
+--   "Miso.Native.MainThread" ('Miso.Native.MainThread.setStyleProperty' etc.) and
+--   the element PAPI they call exist __only on the MTS__; on the BTS they no-op.
+--   Drive them from a @*Main@ handler or via 'Miso.Effect.runOnMain'.
+--
+-- = A minimal native component
+--
+-- Note the import: "Miso" and "Miso.Native" both export a @text_@ — the string
+-- helper 'Miso.Types.text_' and the Lynx @\<text\>@ element
+-- 'Miso.Native.Element.text_' respectively — so the web one must be hidden.
+--
+-- @
+-- -----------------------------------------------------------------------------
+-- {-# LANGUAGE StaticPointers #-}
+-- -----------------------------------------------------------------------------
+-- import "Miso" hiding (text_)
+-- import "Miso.Native"
+-- -----------------------------------------------------------------------------
+-- view :: context -> props -> Model -> 'Miso.Types.View' context Model Action
+-- view _ _ m =
+--   'Miso.Types.vfrag'
+--   [ @view_@ [ 'Miso.Native.Element.View.Event.onTap' Increment ] [ 'text_' [] [ \"+\" ] ]
+--   , 'text_' [] [ 'Miso.Types.text' $ 'Miso.String.ms' ('show' m) ]
+--   , @view_@ [ 'Miso.Native.Element.View.Event.onTap' Decrement ] [ 'text_' [] [ \"-\" ] ]
+--   ]
+-- @
+--
+-- More information on how to use miso is available on GitHub
+--
+-- <http://github.com/dmjio/miso>
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native
+   ( -- * Entrypoint
+     native
+   , nativeWithContext
+     -- * t'Miso.Types.Component' mounting
+   , mountStatic
+   , mountStaticWithProps
+     -- * Element
+   , module Miso.Native.Element
+     -- * FFI
+   , module Miso.Native.FFI
+     -- * Event
+   , module Miso.Native.Event
+   ) where
+-----------------------------------------------------------------------------
+import Miso.Runtime (initComponent)
+import Miso.Types (Events, SomeStaticComponent(..), SomeComponent(..), Hydrate(..))
+import Miso.Types (mountStatic, mountStaticWithProps)
+-----------------------------------------------------------------------------
+import Miso.Native.Element
+import Miso.Native.FFI
+import Miso.Native.Event
+-----------------------------------------------------------------------------
+import GHC.StaticPtr (StaticPtr, deRefStaticPtr, staticKey)
+-----------------------------------------------------------------------------
+-- | The native drawing context is already selected per-thread by the runtime
+-- (@ts\/miso-native.ts@ picks @bts@ or @mts@ from @__BACKGROUND__@), so there
+-- is no renderer to register — we start the app directly.
+--
+-- @
+-- {-# LANGUAGE StaticPointers #-}
+--
+-- import Miso
+-- import Miso.Native
+--
+-- main :: IO ()
+-- main = native nativeEvents (static (mountStatic app))
+-- @
+--
+-- @since 1.13.0.0
+native
+  :: Events
+  -> StaticPtr (SomeStaticComponent () ())
+  -> IO ()
+native events ptr =
+  case deRefStaticPtr ptr of
+    SomeStaticComponent mk -> case mk () of
+      SomeComponent key props_ vcomp_ ->
+        initComponent events Draw False () vcomp_
+          key props_ (Just (staticKey ptr))
+-----------------------------------------------------------------------------
+-- | Like 'native', but the user can specify a global 'Miso.Effect.context' object.
+--
+-- @
+-- {-# LANGUAGE StaticPointers #-}
+--
+-- import "Miso"
+-- import "Miso.Native"
+--
+-- main :: IO ()
+-- main = 'nativeWithContext' 'nativeEvents' () (static ('mountStatic' app))
+-- @
+--
+-- @since 1.13.0.0
+nativeWithContext
+  :: Eq context
+  => Events
+  -> context
+  -> StaticPtr (SomeStaticComponent () context)
+  -> IO ()
+nativeWithContext events context ptr =
+  case deRefStaticPtr ptr of
+    SomeStaticComponent mk -> case mk () of
+      SomeComponent key props_ vcomp_ ->
+        initComponent events Draw False context vcomp_
+          key props_ (Just (staticKey ptr))
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element.hs b/src/Miso/Native/Element.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element.hs
@@ -0,0 +1,155 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE RecordWildCards   #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element
+  ( -- ** Smart constructor for lynx elements
+    lynx_
+  , lynxDirect_
+    -- ** Page
+  , page_
+    -- ** View
+  , view_
+    -- ** Scroll View
+  , scrollView_
+    -- ** Image
+  , image_
+    -- ** List
+  , list_
+  , listItem_
+    -- * Text
+  , text_
+    -- * Frame
+  , frame_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON (toJSON)
+import           Miso.Native.Element.List (ListOptions(..))
+import           Miso.Property (textProp, prop)
+import           Miso.String (MisoString)
+import           Miso.Types (View, Attribute, node, nodeDirectEvents, Namespace(HTML))
+-----------------------------------------------------------------------------
+-- | Smart constructor for constructing a built-in lynx element.
+--
+lynx_ :: MisoString -> [Attribute model action] -> [View context model action] -> View context model action
+lynx_ = node HTML
+-----------------------------------------------------------------------------
+-- | Like 'lynx_', but declares the events this element dispatches /directly/ on
+-- itself (Lynx component events like @input@\/@scroll@ that don't bubble to the
+-- delegated mount listener). The runtime binds an element-level listener for
+-- any of these events the element actually handles.
+--
+lynxDirect_
+  :: [MisoString]
+  -- ^ Events dispatched directly on this element
+  -> MisoString
+  -- ^ Tag name
+  -> [Attribute model action]
+  -> [View context model action]
+  -> View context model action
+lynxDirect_ direct tag attrs kids = nodeDirectEvents HTML tag attrs direct kids
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/page.html>
+--
+-- <page> element is the root node, only one <page> element is allowed per page.
+-- You can omit the explicit <page> wrapper, as the frontend framework will
+-- generate the root node by default.
+--
+-- You shouldn't use this, we already generate the @page@ for you when
+-- the initial @renderPage@ callback is invoked by PrimJS, and there can
+-- only be one @page@ present at at time. We include it here for completeness,
+-- and because @page@ functionality might change in the future.
+--
+page_ :: [Attribute model action] -> [View context model action] -> View context model action
+page_ = lynx_ "page"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/scroll-view.html>
+--
+-- Basic element, used to contain other elements. <view> is the foundation
+-- for all other elements; its attributes, events, and methods can be
+-- used in other elements.
+--
+scrollView_ :: [Attribute model action] -> [View context model action] -> View context model action
+scrollView_ = lynxDirect_
+  [ "scroll", "scrolltoupper", "scrolltolower", "scrollend", "contentsizechanged" ]
+  "scroll-view"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/view.html>
+--
+-- Basic element, used to contain other elements. <view> is the foundation
+-- for all other elements; its attributes, events, and methods can be
+-- used in other elements.
+--
+view_ :: [Attribute model action] -> [View context model action] -> View context model action
+view_ = lynx_ "view"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/image.html>
+--
+-- Used to display different types of images, including web images,
+-- static resources, and locally stored images.
+--
+-- <https://lynxjs.org/api/elements/built-in/image.html>
+--
+-- 'image_' does not support children.
+--
+-- <https://lynxjs.org/api/elements/built-in/image.html#required-src>
+--
+-- *Required*
+--
+-- 'image_' takes a required *src* parameter (as 'MisoString') by default.
+--
+-- The supported image formats are: *png*, *jpg*, *jpeg*, *bmp*, *gif*, and *webp*.
+--
+-- > image_ "https://url.com/image.png" []
+--
+image_ :: MisoString -> [Attribute model action] -> View context model action
+image_ url attrs = lynxDirect_
+  [ "load", "error", "startplay", "currentloopcomplete", "finalloopcomplete" ]
+  "image" (textProp "src" url : attrs) []
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/list.html>
+--
+listItem_ :: [Attribute model action] -> [View context model action] -> View context model action
+listItem_ = lynx_ "list-item"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/list.html>
+--
+list_ :: ListOptions -> [Attribute model action] -> [View context model action] -> View context model action
+list_ ListOptions {..} attrs = lynxDirect_
+  [ "scroll", "scrolltoupper", "scrolltolower", "scrollstatechange", "layoutcomplete", "snap" ]
+  "list" (defaults <> attrs)
+  where
+    defaults =
+      [ prop "list-type" (toJSON listType_)
+      , prop "span-count" (toJSON spanCount_)
+      , prop "scroll-orientation" (toJSON scrollOrientation_)
+      ]
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/text.html>
+--
+-- <text> is a built-in component in Lynx used to display text content.
+-- It supports specifying text style, binding click event callbacks, and can
+-- nest <text>, <image>, and <view> components to achieve relatively complex
+-- text and image content presentation.
+--
+text_ :: [Attribute model action] -> [View context model action] -> View context model action
+text_ = lynxDirect_ [ "layout", "selectionchange" ] "text"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/frame.html>
+--
+-- A page element similar to HTML's \<iframe\>, which can embed a Lynx page
+-- into the current page.
+--
+frame_ :: [Attribute model action] -> View context model action
+frame_ attrs = lynxDirect_ [ "load", "loadmetrics" ] "frame" attrs []
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Frame.hs b/src/Miso/Native/Element/Frame.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Frame.hs
@@ -0,0 +1,21 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Frame
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Frame
+  ( module Miso.Native.Element.Frame.Event
+  , module Miso.Native.Element.Frame.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.Element.Frame.Event
+import Miso.Native.Element.Frame.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Frame/Event.hs b/src/Miso/Native/Element/Frame/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Frame/Event.hs
@@ -0,0 +1,207 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Frame.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Frame.Event
+  ( -- *** Events
+    onLoad
+  , onLoadWith
+  , onLoadMain
+  , onLoadMainWith
+  , onLoadMetrics
+  , onLoadMetricsWith
+  , onLoadMetricsMain
+  , onLoadMetricsMainWith
+    -- *** Types
+  , FrameLoadEvent (..)
+  , FrameLoadMetricsEvent (..)
+    -- *** Decoders
+  , frameLoadDecoder
+  , frameLoadMetricsDecoder
+    -- *** Event Map
+  , frameEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<frame>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+frameEvents :: Events
+frameEvents
+  = M.fromList
+  [ ("load", BUBBLE)
+  , ("loadmetrics", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#bindload
+--
+-- Triggered when the embedded \<frame\> page finishes loading.
+data FrameLoadEvent
+  = FrameLoadEvent
+  { loadStatusCode :: Int
+    -- ^ The load status code
+  , loadStatusMessage :: MisoString
+    -- ^ The load status message
+  , loadUrl :: MisoString
+    -- ^ The url of the loaded \<frame\> resource
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'FrameLoadEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+frameLoadDecoder :: Decoder FrameLoadEvent
+frameLoadDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      FrameLoadEvent
+        <$> o .: "statusCode"
+        <*> o .: "statusMessage"
+        <*> o .: "url"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#bindloadmetrics
+--
+-- Triggered with performance metrics for the embedded \<frame\> page load.
+data FrameLoadMetricsEvent
+  = FrameLoadMetricsEvent
+  { metricsEntry :: Object
+    -- ^ The @FrameLoadMetricsEntry@ payload
+  , metricsMode :: MisoString
+    -- ^ The load mode
+  , metricsUrl :: MisoString
+    -- ^ The url of the loaded \<frame\> resource
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'FrameLoadMetricsEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+frameLoadMetricsDecoder :: Decoder FrameLoadMetricsEvent
+frameLoadMetricsDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      FrameLoadMetricsEvent
+        <$> o .: "entry"
+        <*> o .: "mode"
+        <*> o .: "url"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#bindload
+--
+-- @
+--
+-- data Action = HandleLoad FrameLoadEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = frame_ [ src_ "http://url", onLoad HandleLoad ] []
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleLoad FrameLoadEvent {..}) =
+--   io_ (consoleLog "frame load event received")
+--
+-- @
+--
+onLoad :: (FrameLoadEvent -> action) -> Attribute model action
+onLoad action = on "load" frameLoadDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLoad', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleLoad FrameLoadEvent
+--
+-- view_ [ event (static (onLoadMain HandleLoad)) ] [ "some view" ]
+-- @
+--
+onLoadMain :: (FrameLoadEvent -> action) -> EventHandler model action
+onLoadMain action = onMain "load" frameLoadDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLoadMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleLoad FrameLoadEvent Model DOMRef
+--
+-- view_ [ event (static (onLoadMainWith HandleLoad)) ] [ "some view" ]
+-- @
+--
+onLoadMainWith :: (FrameLoadEvent -> model -> DOMRef -> action) -> EventHandler model action
+onLoadMainWith action = onMain "load" frameLoadDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#bindloadmetrics
+--
+-- @
+--
+-- data Action = HandleMetrics FrameLoadMetricsEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = frame_ [ src_ "http://url", onLoadMetrics HandleMetrics ] []
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleMetrics FrameLoadMetricsEvent {..}) =
+--   io_ (consoleLog "frame load metrics event received")
+--
+-- @
+--
+onLoadMetrics :: (FrameLoadMetricsEvent -> action) -> Attribute model action
+onLoadMetrics action = on "loadmetrics" frameLoadMetricsDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLoadMetrics', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleMetrics FrameLoadMetricsEvent
+--
+-- view_ [ event (static (onLoadMetricsMain HandleMetrics)) ] [ "some view" ]
+-- @
+--
+onLoadMetricsMain :: (FrameLoadMetricsEvent -> action) -> EventHandler model action
+onLoadMetricsMain action = onMain "loadmetrics" frameLoadMetricsDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLoadMetricsMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleMetrics FrameLoadMetricsEvent Model DOMRef
+--
+-- view_ [ event (static (onLoadMetricsMainWith HandleMetrics)) ] [ "some view" ]
+-- @
+--
+onLoadMetricsMainWith :: (FrameLoadMetricsEvent -> model -> DOMRef -> action) -> EventHandler model action
+onLoadMetricsMainWith action = onMain "loadmetrics" frameLoadMetricsDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onLoad', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLoadWith :: (FrameLoadEvent -> DOMRef -> action) -> Attribute model action
+onLoadWith action = on "load" frameLoadDecoder $ \f _ domRef -> action f domRef
+-----------------------------------------------------------------------------
+-- | Like 'onLoadMetrics', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLoadMetricsWith :: (FrameLoadMetricsEvent -> DOMRef -> action) -> Attribute model action
+onLoadMetricsWith action = on "loadmetrics" frameLoadMetricsDecoder $ \f _ domRef -> action f domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Frame/Property.hs b/src/Miso/Native/Element/Frame/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Frame/Property.hs
@@ -0,0 +1,109 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Frame.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Frame.Property
+  ( -- *** Property
+    src_
+  , autoHeight_
+  , autoWidth_
+  , data_
+  , enableMultiAsyncThread_
+  , globalProps_
+  , presetHeight_
+  , presetWidth_
+  ) where
+----------------------------------------------------------------------------
+import           Miso.JSON (Value)
+import           Miso.Property
+import           Miso.Types
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#src
+--
+-- Sets the loading path for the \<frame\> resource. Supports @http@ / @https@.
+--
+-- > src_ "http://url-goes-here.com"
+--
+src_ :: MisoString -> Attribute model action
+src_ = textProp "src"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#auto-height
+--
+-- When enabled, the \<frame\> adjusts its height to match the embedded page.
+--
+-- > autoHeight_ True
+--
+-- Default Value: @False@
+--
+autoHeight_ :: Bool -> Attribute model action
+autoHeight_ = boolProp "auto-height"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#auto-width
+--
+-- When enabled, the \<frame\> adjusts its width to match the embedded page.
+--
+-- > autoWidth_ True
+--
+-- Default Value: @False@
+--
+autoWidth_ :: Bool -> Attribute model action
+autoWidth_ = boolProp "auto-width"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#data
+--
+-- Initial data (a JSON object) passed to the embedded \<frame\> page.
+--
+-- > data_ (object [ "key" .= "value" ])
+--
+data_ :: Value -> Attribute model action
+data_ = prop "data"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#enable-multi-async-thread
+--
+-- Whether the embedded page runs on its own async thread.
+--
+-- > enableMultiAsyncThread_ True
+--
+-- Default Value: @False@
+--
+enableMultiAsyncThread_ :: Bool -> Attribute model action
+enableMultiAsyncThread_ = boolProp "enable-multi-async-thread"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#global-props
+--
+-- Global properties (a JSON object) injected into the embedded \<frame\> page.
+--
+-- > globalProps_ (object [ "theme" .= "dark" ])
+--
+globalProps_ :: Value -> Attribute model action
+globalProps_ = prop "global-props"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#preset-height
+--
+-- Preset height of the \<frame\> before the embedded page loads, e.g. @\"100px\"@
+-- or @\"100rpx\"@.
+--
+-- > presetHeight_ "100px"
+--
+presetHeight_ :: MisoString -> Attribute model action
+presetHeight_ = textProp "preset-height"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/frame.html#preset-width
+--
+-- Preset width of the \<frame\> before the embedded page loads, e.g. @\"100px\"@
+-- or @\"100rpx\"@.
+--
+-- > presetWidth_ "100px"
+--
+presetWidth_ :: MisoString -> Attribute model action
+presetWidth_ = textProp "preset-width"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Image.hs b/src/Miso/Native/Element/Image.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Image.hs
@@ -0,0 +1,28 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Image
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<image/>](https://lynxjs.org/api/elements/built-in/image.html)
+--
+-- Used to display different types of images, including web images,
+-- static resources, and locally stored images.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Image
+  ( module Miso.Native.Element.Image.Event
+  , module Miso.Native.Element.Image.Method
+  , module Miso.Native.Element.Image.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.Element.Image.Event
+import Miso.Native.Element.Image.Method
+import Miso.Native.Element.Image.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Image/Event.hs b/src/Miso/Native/Element/Image/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Image/Event.hs
@@ -0,0 +1,364 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Image.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Image.Event
+  ( -- *** Events
+    onLoad
+  , onLoadWith
+  , onLoadMain
+  , onLoadMainWith
+  , onError
+  , onErrorWith
+  , onErrorMain
+  , onErrorMainWith
+  , onStartPlay
+  , onStartPlayWith
+  , onStartPlayMain
+  , onStartPlayMainWith
+  , onCurrentLoopComplete
+  , onCurrentLoopCompleteWith
+  , onCurrentLoopCompleteMain
+  , onCurrentLoopCompleteMainWith
+  , onFinalLoopComplete
+  , onFinalLoopCompleteWith
+  , onFinalLoopCompleteMain
+  , onFinalLoopCompleteMainWith
+  -- *** Decoder
+  , imageLoadDecoder
+  , imageErrorDecoder
+  -- *** Types
+  , ImageErrorEvent (..)
+  , ImageLoadEvent (..)
+  -- *** Event Map
+  , imageEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<image>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+imageEvents :: Events
+imageEvents
+  = M.fromList
+  [ ("load", BUBBLE)
+  , ("error", BUBBLE)
+  , ("startplay", BUBBLE)
+  , ("currentloopcomplete", BUBBLE)
+  , ("finalloopcomplete", BUBBLE)
+  ]
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#bindload
+--
+-- Triggered when the image request succeeds, outputting the image's width and height.
+--
+-- @
+--
+-- data Action = HandleImageLoad ImageLoadEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view model = image_ "url" [ onLoad HandleImageLoad ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleImageLoad ImageLoadEvent {..}) = do
+--   io_ (consoleLog "image load event received")
+--
+-- @
+--
+onLoad :: (ImageLoadEvent -> action) -> Attribute model action
+onLoad action = on "load" imageLoadDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLoad', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleImageLoad ImageLoadEvent
+--
+-- view_ [ event (static (onLoadMain HandleImageLoad)) ] [ "some view" ]
+-- @
+--
+onLoadMain :: (ImageLoadEvent -> action) -> EventHandler model action
+onLoadMain action = onMain "load" imageLoadDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLoadMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleImageLoad ImageLoadEvent Model DOMRef
+--
+-- view_ [ event (static (onLoadMainWith HandleImageLoad)) ] [ "some view" ]
+-- @
+--
+onLoadMainWith :: (ImageLoadEvent -> model -> DOMRef -> action) -> EventHandler model action
+onLoadMainWith action = onMain "load" imageLoadDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#binderror
+--
+-- Triggered when the image request fails, outputting the error message and code.
+--
+-- @
+--
+-- data Action = HandleImageError ImageErrorEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = image_ "url" [ onError HandleImageError ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleImageError ImageErrorEvent {..}) = do
+--   io_ (consoleLog "image error event received")
+--
+-- @
+--
+onError :: (ImageErrorEvent -> action) -> Attribute model action
+onError action = on "error" imageErrorDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onError', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleImageError ImageErrorEvent
+--
+-- view_ [ event (static (onErrorMain HandleImageError)) ] [ "some view" ]
+-- @
+--
+onErrorMain :: (ImageErrorEvent -> action) -> EventHandler model action
+onErrorMain action = onMain "error" imageErrorDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onErrorMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleImageError ImageErrorEvent Model DOMRef
+--
+-- view_ [ event (static (onErrorMainWith HandleImageError)) ] [ "some view" ]
+-- @
+--
+onErrorMainWith :: (ImageErrorEvent -> model -> DOMRef -> action) -> EventHandler model action
+onErrorMainWith action = onMain "error" imageErrorDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#bindstartplay
+--
+-- Triggered when the animated image starts playing.
+--
+-- @
+--
+-- data Action = HandleStartPlay
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = image_ "url" [ onStartPlay HandleStartPlay ]
+--
+-- @
+--
+onStartPlay :: action -> Attribute model action
+onStartPlay action = on "startplay" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onStartPlay', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleStartPlay
+--
+-- view_ [ event (static (onStartPlayMain HandleStartPlay)) ] [ "some view" ]
+-- @
+--
+onStartPlayMain :: action -> EventHandler model action
+onStartPlayMain action = onMain "startplay" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onStartPlayMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleStartPlay Model DOMRef
+--
+-- view_ [ event (static (onStartPlayMainWith HandleStartPlay)) ] [ "some view" ]
+-- @
+--
+onStartPlayMainWith :: (model -> DOMRef -> action) -> EventHandler model action
+onStartPlayMainWith action = onMain "startplay" emptyDecoder (\() m ref -> action m ref)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#bindcurrentloopcomplete
+--
+-- Triggered when one loop of the animated image finishes playing.
+--
+-- @
+--
+-- data Action = HandleCurrentLoopComplete
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = image_ "url" [ onCurrentLoopComplete HandleCurrentLoopComplete ]
+--
+-- @
+--
+onCurrentLoopComplete :: action -> Attribute model action
+onCurrentLoopComplete action = on "currentloopcomplete" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onCurrentLoopComplete', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleCurrentLoopComplete
+--
+-- view_ [ event (static (onCurrentLoopCompleteMain HandleCurrentLoopComplete)) ] [ "some view" ]
+-- @
+--
+onCurrentLoopCompleteMain :: action -> EventHandler model action
+onCurrentLoopCompleteMain action = onMain "currentloopcomplete" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onCurrentLoopCompleteMain', but the handler also receives read-only
+-- access to the @model@ and the target element's 'DOMRef' (for imperative MTS
+-- mutation).
+--
+-- @
+-- data Action = HandleCurrentLoopComplete Model DOMRef
+--
+-- view_ [ event (static (onCurrentLoopCompleteMainWith HandleCurrentLoopComplete)) ] [ "some view" ]
+-- @
+--
+onCurrentLoopCompleteMainWith :: (model -> DOMRef -> action) -> EventHandler model action
+onCurrentLoopCompleteMainWith action = onMain "currentloopcomplete" emptyDecoder (\() m ref -> action m ref)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#bindfinalloopcomplete
+--
+-- Triggered when the animated image finishes playing all 'Miso.Native.Element.Image.Property.loopCount_' loops.
+--
+-- @
+--
+-- data Action = HandleFinalLoopComplete
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = image_ "url" [ onFinalLoopComplete HandleFinalLoopComplete ]
+--
+-- @
+--
+onFinalLoopComplete :: action -> Attribute model action
+onFinalLoopComplete action = on "finalloopcomplete" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onFinalLoopComplete', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleFinalLoopComplete
+--
+-- view_ [ event (static (onFinalLoopCompleteMain HandleFinalLoopComplete)) ] [ "some view" ]
+-- @
+--
+onFinalLoopCompleteMain :: action -> EventHandler model action
+onFinalLoopCompleteMain action = onMain "finalloopcomplete" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onFinalLoopCompleteMain', but the handler also receives read-only
+-- access to the @model@ and the target element's 'DOMRef' (for imperative MTS
+-- mutation).
+--
+-- @
+-- data Action = HandleFinalLoopComplete Model DOMRef
+--
+-- view_ [ event (static (onFinalLoopCompleteMainWith HandleFinalLoopComplete)) ] [ "some view" ]
+-- @
+--
+onFinalLoopCompleteMainWith :: (model -> DOMRef -> action) -> EventHandler model action
+onFinalLoopCompleteMainWith action = onMain "finalloopcomplete" emptyDecoder (\() m ref -> action m ref)
+-----------------------------------------------------------------------------
+-- | Callback when an @image_@ fails to load
+data ImageErrorEvent
+  = ImageErrorEvent
+  { errorMessage :: MisoString
+    -- ^ error message
+  , errorCode :: Int
+    -- ^ error code
+  , lynxCategorizedCode :: Int
+    -- ^ lynx specific error code
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Callback when an @image_@ succeeds in loading
+data ImageLoadEvent
+  = ImageLoadEvent
+  { imageWidth :: Int
+    -- ^ @image_@ width
+  , imageHeight :: Int
+    -- ^ @image_@ height
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'ImageLoadEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+imageLoadDecoder :: Decoder ImageLoadEvent
+imageLoadDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      ImageLoadEvent
+        <$> o .: "width"
+        <*> o .: "height"
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'ImageErrorEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+imageErrorDecoder :: Decoder ImageErrorEvent
+imageErrorDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      ImageErrorEvent
+        <$> o .: "errMsg"
+        <*> o .: "error_code"
+        <*> o .: "lynx_categorized_code"
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- | Like 'onLoad', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLoadWith :: (ImageLoadEvent -> DOMRef -> action) -> Attribute model action
+onLoadWith action = on "load" imageLoadDecoder $ \x _ domRef -> action x domRef
+-----------------------------------------------------------------------------
+-- | Like 'onError', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onErrorWith :: (ImageErrorEvent -> DOMRef -> action) -> Attribute model action
+onErrorWith action = on "error" imageErrorDecoder $ \x _ domRef -> action x domRef
+-----------------------------------------------------------------------------
+-- | Like 'onStartPlay', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onStartPlayWith :: (DOMRef -> action) -> Attribute model action
+onStartPlayWith action = on "startplay" emptyDecoder (\() _ ref -> action ref)
+-----------------------------------------------------------------------------
+-- | Like 'onCurrentLoopComplete', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onCurrentLoopCompleteWith :: (DOMRef -> action) -> Attribute model action
+onCurrentLoopCompleteWith action = on "currentloopcomplete" emptyDecoder (\() _ ref -> action ref)
+-----------------------------------------------------------------------------
+-- | Like 'onFinalLoopComplete', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onFinalLoopCompleteWith :: (DOMRef -> action) -> Attribute model action
+onFinalLoopCompleteWith action = on "finalloopcomplete" emptyDecoder (\() _ ref -> action ref)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Image/Method.hs b/src/Miso/Native/Element/Image/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Image/Method.hs
@@ -0,0 +1,80 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Image.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Image.Method
+  ( -- *** Methods
+    startAnimation
+  , pauseAnimation
+  , stopAnimation
+  , resumeAnimation
+  ) where
+-----------------------------------------------------------------------------
+import           Miso
+import           Miso.Native.FFI (invokeExec)
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/image.html#startanimate>
+--
+-- Starts an animation at the ID selected
+--
+-- > startAnimation "someImageId" AnimationStarted AnimationError
+--
+startAnimation
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+startAnimation selector action =
+  invokeExec "startAnimate" selector () (\() -> action)
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/image.html#pauseanimation>
+--
+-- Pauses an animation at the ID selected
+--
+-- > pauseAnimation "someImageId" AnimationPauseed AnimationError
+--
+pauseAnimation
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+pauseAnimation selector action =
+  invokeExec "pauseAnimation" selector () (\() -> action)
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/image.html#resumeanimation>
+--
+-- Resumes an animation at the ID selected
+--
+-- > resumeAnimation "someImageId" AnimationResumeed AnimationError
+--
+resumeAnimation
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+resumeAnimation selector action =
+  invokeExec "resumeAnimation" selector () (\() -> action)
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/image.html#stopanimation>
+--
+-- Stops an animation at the ID selected
+--
+-- > stopAnimation "someImageId" AnimationStoped AnimationError
+--
+stopAnimation
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+stopAnimation selector action =
+  invokeExec "stopAnimation" selector () (\() -> action)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Image/Property.hs b/src/Miso/Native/Element/Image/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Image/Property.hs
@@ -0,0 +1,190 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Image.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Image.Property
+  ( -- *** Property
+    mode_
+  , placeholder_
+  , blurRadius_
+  , prefetchWidth_
+  , prefetchHeight_
+  , capInsets_
+  , capInsetsScale_
+  , loopCount_
+  , imageConfig_
+  , autoSize_
+  , deferSrcInvalidation_
+  , autoPlay_
+  , tintColor_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#mode
+--
+-- Specifies the image cropping/scaling mode
+--
+-- > mode_ "aspectFit"
+--
+-- Default Value: "scaleToFill"
+--
+mode_ :: MisoString -> Attribute model action
+mode_ = textProp "mode"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#placeholder
+--
+-- Specifies the path to the placeholder image. The usage and limitations
+-- are the same as for the @src@ attribute.
+--
+-- > placeholder_ "value"
+--
+placeholder_ :: MisoString -> Attribute model action
+placeholder_ = textProp "placeholder"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#blur-radius
+--
+-- Specifies the Gaussian blur radius for the image.
+--
+-- > image_ [ blurRadius_ "10px" ]
+--
+-- Default Value: "0px"
+--
+blurRadius_ :: MisoString -> Attribute model action
+blurRadius_ = textProp "blur-radius"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#prefetch-widthprefetch-height
+--
+-- Allows initiating a request when the image has a @width@ / @height@ of 0. This is
+-- typically used when preloading images. It's recommended to set the sizes
+-- to match the actual layout @width@ / @height@.
+--
+-- > prefetchWidth_ "10px"
+--
+-- Default Value: "0px"
+--
+prefetchWidth_ :: MisoString -> Attribute model action
+prefetchWidth_ = textProp "prefetch-width"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#prefetch-widthprefetch-height
+--
+-- Allows initiating a request when the image has a @width@ / @height@ of 0. This is
+-- typically used when preloading images. It's recommended to set the sizes
+-- to match the actual layout @width@ / @height@.
+--
+-- > prefetchHeight_ "10px"
+--
+-- Default Value: "0px"
+--
+prefetchHeight_ :: MisoString -> Attribute model action
+prefetchHeight_ = textProp "prefetch-height"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#cap-insets
+--
+-- Specifies the [9patch](https://developer.android.com/studio/write/draw9patch) image
+-- scaling area with four values representing the top, right, bottom, and left edges.
+-- Values must be specific numbers and do not support percentages or decimals.
+--
+-- > capInsets_ "0px 14px 0 14px"
+--
+-- Default Value: "0px 0px 0px 0px"
+--
+capInsets_ :: MisoString -> Attribute model action
+capInsets_ = textProp "cap-insets"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#cap-insets-scale
+--
+-- Works with `cap-insets` to adjust the pixel positions when stretching the image.
+--
+-- > capInsetsScale_ 10
+--
+-- Default Value: 1
+--
+capInsetsScale_ :: Int -> Attribute model action
+capInsetsScale_ = intProp "cap-insets-scale"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#loop-count
+--
+-- Specifies the number of times to play an animated image. The default is to loop indefinitely.
+--
+-- > loopCount_ 10
+--
+-- Default Value: 0
+--
+loopCount_ :: Int -> Attribute model action
+loopCount_ = intProp "loop-count"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#image-config
+--
+-- *Android* only.
+--
+-- Specifies the image data format. There are two options: @RGB_565@ | @ARGB_8888@;
+--
+-- > imageConfig_ "RGB_565"
+--
+-- Default Value: @ARGB_8888@
+--
+imageConfig_ :: MisoString -> Attribute model action
+imageConfig_ = textProp "image-config"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#auto-size
+--
+-- When set to true and the \<image\> element has no width or height,
+-- the size of the \<image\> will be automatically adjusted to match the image's
+-- original dimensions after the image is successfully loaded, ensuring that
+-- the aspect ratio is maintained.
+--
+-- > autoSize_ True
+--
+-- Default Value: @False@
+--
+autoSize_ :: Bool -> Attribute model action
+autoSize_ = boolProp "auto-size"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#defer-src-invalidation
+--
+-- When set to true, the \<image\> will only clear the previously displayed
+-- image resource after a new image has successfully loaded.
+--
+-- > deferSrcInvalidation_ True
+--
+-- Default Value: @False@
+--
+deferSrcInvalidation_ :: Bool -> Attribute model action
+deferSrcInvalidation_ = boolProp "defer-src-invalidation"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#autoplay
+--
+-- Specifies whether the animated image should start playing automatically once
+-- it is loaded.
+--
+-- > autoPlay_ False
+--
+-- Default Value: 'True'
+--
+autoPlay_ :: Bool -> Attribute model action
+autoPlay_ = boolProp "autoplay"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/image.html#tint-color
+--
+-- Changes the color of all non-transparent pixels to the tint-color specified.
+-- The value is a color.
+--
+-- > tintColor_ 10
+--
+-- Default Value: 0
+--
+tintColor_ :: Int -> Attribute model action
+tintColor_ = intProp "tint-color"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/List.hs b/src/Miso/Native/Element/List.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/List.hs
@@ -0,0 +1,24 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.List
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.List
+  ( module Miso.Native.Element.List.Event
+  , module Miso.Native.Element.List.Method
+  , module Miso.Native.Element.List.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.Element.List.Event
+import Miso.Native.Element.List.Method
+import Miso.Native.Element.List.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/List/Event.hs b/src/Miso/Native/Element/List/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/List/Event.hs
@@ -0,0 +1,643 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.List.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.List.Event
+  ( -- *** Event
+    onScroll
+  , onScrollWith
+  , onScrollMain
+  , onScrollMainWith
+  , onScrollToUpper
+  , onScrollToUpperWith
+  , onScrollToUpperMain
+  , onScrollToUpperMainWith
+  , onScrollToLower
+  , onScrollToLowerWith
+  , onScrollToLowerMain
+  , onScrollToLowerMainWith
+  , onScrollStateChange
+  , onScrollStateChangeWith
+  , onScrollStateChangeMain
+  , onScrollStateChangeMainWith
+  , onLayoutComplete
+  , onLayoutCompleteWith
+  , onLayoutCompleteMain
+  , onLayoutCompleteMainWith
+  , onSnap
+  , onSnapWith
+  , onSnapMain
+  , onSnapMainWith
+  -- *** Types
+  , ScrollEvent (..)
+  , SnapEvent (..)
+  , LayoutCompleteEvent (..)
+  , DiffResult (..)
+  , ListEventSource (..)
+  , Cell (..)
+  , ScrollStateChange (..)
+  , ListItemInfo (..)
+  -- *** Decoder
+  , scrollDecoder
+  , snapDecoder
+  , layoutCompleteDecoder
+  -- *** Event Map
+  , listEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+import           Miso.String (MisoString)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<list>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+listEvents :: Events
+listEvents
+  = M.fromList
+  [ ("scroll", BUBBLE)
+  , ("scrolltoupper", BUBBLE)
+  , ("scrolltolower", BUBBLE)
+  , ("scrollstatechange", BUBBLE)
+  , ("layoutcomplete", BUBBLE)
+  , ("snap", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'ScrollEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+scrollDecoder :: Decoder ScrollEvent
+scrollDecoder = ["detail"] `at` parseJSON
+-----------------------------------------------------------------------------
+instance FromJSON ScrollEvent where
+  parseJSON = withObject "ScrollEvent" $ \o ->
+    ScrollEvent
+      <$> o .:? "deltaX" .!= 0
+      <*> o .:? "deltaY" .!= 0
+      <*> o .:? "scrollLeft" .!= 0
+      <*> o .:? "scrollTop" .!= 0
+      <*> o .:? "scrollWidth" .!= 0
+      <*> o .:? "scrollHeight" .!= 0
+      <*> o .:? "listWidth" .!= 0
+      <*> o .:? "listHeight" .!= 0
+      -- `eventSource`/`attachedCells` are declared required in Lynx's
+      -- ListScrollInfo, but `attachedCells` is only populated when
+      -- `need-visible-item-info` is enabled (otherwise absent). Decode
+      -- defensively so a @scroll@ event without them still succeeds.
+      <*> o .:? "eventSource" .!= SCROLL
+      <*> o .:? "attachedCells" .!= []
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#scroll
+data ScrollEvent
+  = ScrollEvent
+  { deltaX, deltaY :: Double
+  -- ^ Horizontal / vertical scroll offset since the last scroll, in px
+  , scrollLeft, scrollTop :: Double
+  -- ^ Current horizontal / vertical scroll offset, in px
+  , scrollWidth, scrollHeight :: Double
+  -- ^ Current content area height / width, in px
+  , listWidth, listHeight :: Double
+  -- ^ List width / height in px
+  , listEventSource :: ListEventSource
+  -- ^ Scroll event source
+  , attachedCells :: [Cell]
+  -- ^ Attached cells
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | One cell currently attached to a @<list>@, as reported by
+-- 'Miso.Native.Element.List.Method.getVisibleCells' and the layout events.
+-- 
+-- @since 1.13.0.0
+data Cell
+  = Cell
+  { cellId :: MisoString
+  -- ^ Node id (Lynx types this @ListAttachedCell.id@ as a string)
+  , cellItemKey :: MisoString
+  -- ^ Node item-key
+  , cellIndex, cellLeft, cellTop, cellRight, cellBottom :: Double
+  -- ^ Node left/top/right/bottom boundary position relative to list, in px
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSON Cell where
+  parseJSON = withObject "Cell" $ \cell -> Cell
+    <$> cell .: "id"
+    <*> cell .: "itemKey"
+    <*> cell .: "index"
+    <*> cell .: "left"
+    <*> cell .: "top"
+    <*> cell .: "right"
+    <*> cell .: "bottom"
+-----------------------------------------------------------------------------
+-- | What triggered a @<list>@ layout-complete event: a data @DIFF@, a
+-- re-@LAYOUT@, or a @SCROLL@.
+-- 
+-- @since 1.13.0.0
+data ListEventSource
+  = DIFF
+  | LAYOUT
+  | SCROLL
+  deriving (Show, Eq, Enum)
+-----------------------------------------------------------------------------
+instance FromJSON ListEventSource where
+  parseJSON = withNumber "ListEventSource" $ \case
+    0 -> pure DIFF
+    1 -> pure LAYOUT
+    2 -> pure SCROLL
+    x -> typeMismatch "ListEventSource" (toJSON x)
+-----------------------------------------------------------------------------
+-- | The scroll state a @<list>@ has just entered — at rest, under the
+-- user's finger, coasting, or animating to a snap point.
+-- 
+-- @since 1.13.0.0
+data ScrollStateChange
+  = Stationary
+  | Dragging
+  | InertialScrolling
+  | SmoothAnimationScrolling
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Numbering matches Lynx's @ScrollState@ enum (@kIdle = 1@ … @kScrollAnimation
+-- = 4@), so 'toEnum'\/'fromEnum' agree with the wire and with 'FromJSON' below.
+-- (A derived 'Enum' would be 0-based and disagree with the values Lynx sends.)
+instance Enum ScrollStateChange where
+  fromEnum Stationary               = 1
+  fromEnum Dragging                 = 2
+  fromEnum InertialScrolling        = 3
+  fromEnum SmoothAnimationScrolling = 4
+  toEnum 1 = Stationary
+  toEnum 2 = Dragging
+  toEnum 3 = InertialScrolling
+  toEnum 4 = SmoothAnimationScrolling
+  toEnum n = error ("ScrollStateChange.toEnum: bad argument " <> show n)
+-----------------------------------------------------------------------------
+instance FromJSON ScrollStateChange where
+  parseJSON = withNumber "ScrollStateChange" $ \case
+    1 -> pure Stationary
+    2 -> pure Dragging
+    3 -> pure InertialScrolling
+    4 -> pure SmoothAnimationScrolling
+    x -> typeMismatch "ScrollStateChange" (toJSON x)
+-----------------------------------------------------------------------------
+scrollStateDecoder :: Decoder ScrollStateChange
+scrollStateDecoder = ["detail"] `at` withObject "ScrollStateChange" (.: "state")
+-----------------------------------------------------------------------------
+-- | Payload of a @<list>@ pagination (snap) event: which cell will be
+-- snapped to, and the scroll offsets at the moment of the snap.
+-- 
+-- @since 1.13.0.0
+data SnapEvent
+  = SnapEvent
+  { position :: Double
+  -- ^ The index of the node that will be paginated to
+  , currentScrollLeft :: Double
+  -- ^ Current horizontal scroll offset, in px
+  , currentScrollTop :: Double
+  -- ^ Current vertical scroll offset, in px
+  , targetScrollLeft :: Double
+  -- ^ Target horizontal scroll offset for pagination, in px
+  , targetScrollTop :: Double
+  -- ^ Target vertical scroll offset for pagination, in px
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'SnapEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+snapDecoder :: Decoder SnapEvent
+snapDecoder = ["detail"] `at` do
+  withObject "SnapEvent" $ \o ->
+    SnapEvent
+      <$> o .: "position"
+      <*> o .: "currentScrollLeft"
+      <*> o .: "currentScrollTop"
+      <*> o .: "targetScrollLeft"
+      <*> o .: "targetScrollTop"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#layoutcomplete
+--
+-- Enable @needLayoutCompleteInfo@ to use.
+--
+data LayoutCompleteEvent
+  = LayoutCompleteEvent
+  { layoutId :: Double
+  , scrollInfo :: ScrollEvent
+  -- ^ Current horizontal scroll offset, in px
+  , diffResult :: Maybe DiffResult
+  -- ^ Current vertical scroll offset, in px
+  , visibleCellsAfterUpdate :: [ListItemInfo]
+  -- ^ Target horizontal scroll offset for pagination, in px
+  , visibleCellsBeforeUpdate :: [ListItemInfo]
+  -- ^ Target vertical scroll offset for pagination, in px
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | The row-level changes a @<list>@ data update produced, as index lists:
+-- insertions, moves and removals.
+-- 
+-- @since 1.13.0.0
+data DiffResult
+  = DiffResult
+  { insertions :: [Double]
+  , moveFrom :: [Double]
+  , moveTo :: [Double]
+  , removals :: [Double]
+  , updateFrom :: [Double]
+  , updateTo :: [Double]
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSON DiffResult where
+  parseJSON = withObject "DiffResult" $ \o ->
+    DiffResult
+      <$> o .: "insertions"
+      <*> o .: "move_from"
+      <*> o .: "move_to"
+      <*> o .: "removals"
+      <*> o .: "update_from"
+      <*> o .: "update_to"
+-----------------------------------------------------------------------------
+-- | Position and identity of a single @<list>@ item, as reported in the
+-- layout-complete event's before\/after cell lists.
+-- 
+-- @since 1.13.0.0
+data ListItemInfo
+  = ListItemInfo
+  { listItemInfoHeight :: Double
+    -- ^ Child node height
+  , listItemInfoWidth :: Double
+    -- ^ Child node width
+  , listItemInfoItemKey :: MisoString
+    -- ^ Child node ItemKey
+  , listItemInfoIsBinding :: Bool
+    -- ^ Whether the child node is in rendering state
+  , listItemInfoOriginX :: Double
+    -- ^ X coordinate position of the child node relative to the entire scroll area
+  , listItemInfoOriginY :: Double
+    -- ^ Y coordinate position of the child node relative to the entire scroll area
+  , listItemInfoUpdated :: Bool
+    -- ^ Whether the child node has been updated
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSON ListItemInfo where
+  parseJSON = withObject "ListItemInfo" $ \o ->
+    ListItemInfo
+      <$> o .: "height"
+      <*> o .: "width"
+      <*> o .: "itemKey"
+      <*> o .: "isBinding"
+      <*> o .: "originX"
+      <*> o .: "originY"
+      <*> o .: "updated"
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'LayoutCompleteEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+layoutCompleteDecoder :: Decoder LayoutCompleteEvent
+layoutCompleteDecoder = ["detail"] `at` do
+  withObject "LayoutCompleteEvent" $ \o ->
+    LayoutCompleteEvent
+      <$> o .: "layout-id"
+      <*> o .: "scrollInfo"
+      <*> o .: "diffResult"
+      <*> o .: "visibleCellsAfterUpdate"
+      <*> o .: "visibleCellsBeforeUpdate"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#scroll
+--
+-- \<list\> scroll event.
+--
+-- @
+--
+-- data Action = HandleScroll ScrollEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = list_ defaultListOptions [ onScroll HandleScroll ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleScroll ScrollEvent {..}) =
+--   io_ (consoleLog "handled scroll event")
+--
+-- @
+--
+onScroll :: (ScrollEvent -> action) -> Attribute model action
+onScroll action = on "scroll" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScroll', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleScroll ScrollEvent
+--
+-- view_ [ event (static (onScrollMain HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollMain :: (ScrollEvent -> action) -> EventHandler model action
+onScrollMain action = onMain "scroll" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleScroll ScrollEvent Model DOMRef
+--
+-- view_ [ event (static (onScrollMainWith HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollMainWith :: (ScrollEvent -> model -> DOMRef -> action) -> EventHandler model action
+onScrollMainWith action = onMain "scroll" scrollDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#scrolltoupper
+--
+-- Callback triggered when scrolling to the top of \<list\>. The trigger
+-- position of this callback can be controlled by @upperThresholdItemCount@.
+--
+-- @
+--
+-- data Action = HandleScroll ScrollEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = list_ defaultListOptions [ onScrollToUpper HandleScroll ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleScroll ScrollEvent {..}) =
+--   io_ (consoleLog "handled scroll event")
+--
+-- @
+--
+onScrollToUpper :: (ScrollEvent -> action) -> Attribute model action
+onScrollToUpper action = on "scrolltoupper" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToUpper', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleScroll ScrollEvent
+--
+-- view_ [ event (static (onScrollToUpperMain HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollToUpperMain :: (ScrollEvent -> action) -> EventHandler model action
+onScrollToUpperMain action = onMain "scrolltoupper" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToUpperMain', but the handler also receives read-only access
+-- to the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleScroll ScrollEvent Model DOMRef
+--
+-- view_ [ event (static (onScrollToUpperMainWith HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollToUpperMainWith :: (ScrollEvent -> model -> DOMRef -> action) -> EventHandler model action
+onScrollToUpperMainWith action = onMain "scrolltoupper" scrollDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#scrolltolower
+--
+-- Callback triggered when scrolling to the bottom of \<list\>. The trigger
+-- position of this callback can be controlled by 'Miso.Native.Element.List.Property.lowerThresholdItemCount_'
+--
+-- @
+--
+-- data Action = HandleScroll ScrollEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = list_ defaultListOptions [ onScrollToLower HandleScroll ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleScroll ScrollEvent {..}) =
+--   io_ (consoleLog "handled scroll event")
+--
+-- @
+--
+onScrollToLower :: (ScrollEvent -> action) -> Attribute model action
+onScrollToLower action = on "scrolltolower" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToLower', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleScroll ScrollEvent
+--
+-- view_ [ event (static (onScrollToLowerMain HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollToLowerMain :: (ScrollEvent -> action) -> EventHandler model action
+onScrollToLowerMain action = onMain "scrolltolower" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToLowerMain', but the handler also receives read-only access
+-- to the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleScroll ScrollEvent Model DOMRef
+--
+-- view_ [ event (static (onScrollToLowerMainWith HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollToLowerMainWith :: (ScrollEvent -> model -> DOMRef -> action) -> EventHandler model action
+onScrollToLowerMainWith action = onMain "scrolltolower" scrollDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#scrollstatechange
+--
+-- Callback triggered when the scroll state of \<list\> changes. The state
+-- field in the event parameter's detail indicates the scroll state:
+-- * 1 for stationary
+-- * 2 for dragging
+-- * 3 for inertial scrolling
+-- * 4 for smooth animation scrolling.
+--
+-- @
+--
+-- data Action = HandleScrollState ScrollStateChange
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = list_ defaultListOptions [ onScrollStateChange HandleScrollState ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleScroll Stationary) =
+--   io_ (consoleLog "Received Stationary scroll state change")
+-- update _ = pure ()
+--
+-- @
+--
+onScrollStateChange :: (ScrollStateChange -> action) -> Attribute model action
+onScrollStateChange action = on "scrollstatechange" scrollStateDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollStateChange', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleScrollState ScrollStateChange
+--
+-- view_ [ event (static (onScrollStateChangeMain HandleScrollState)) ] [ "some view" ]
+-- @
+--
+onScrollStateChangeMain :: (ScrollStateChange -> action) -> EventHandler model action
+onScrollStateChangeMain action = onMain "scrollstatechange" scrollStateDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollStateChangeMain', but the handler also receives read-only
+-- access to the @model@ and the target element's 'DOMRef' (for imperative MTS
+-- mutation).
+--
+-- @
+-- data Action = HandleScrollState ScrollStateChange Model DOMRef
+--
+-- view_ [ event (static (onScrollStateChangeMainWith HandleScrollState)) ] [ "some view" ]
+-- @
+--
+onScrollStateChangeMainWith :: (ScrollStateChange -> model -> DOMRef -> action) -> EventHandler model action
+onScrollStateChangeMainWith action = onMain "scrollstatechange" scrollStateDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#layoutcomplete
+--
+-- Callback triggered after \<list\> layout is complete.
+--
+-- @
+--
+-- data Action = HandleLayout LayoutCompleteEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = list_ defaultListOptions [ onLayoutComplete HandleLayout ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleLayout LayoutCompleteEvent {..}) =
+--   io_ (consoleLog "Received LayoutCompleteEvent")
+--
+-- @
+--
+onLayoutComplete :: (LayoutCompleteEvent -> action) -> Attribute model action
+onLayoutComplete action = on "layoutcomplete" layoutCompleteDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onLayoutComplete', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleLayout LayoutCompleteEvent
+--
+-- view_ [ event (static (onLayoutCompleteMain HandleLayout)) ] [ "some view" ]
+-- @
+--
+onLayoutCompleteMain :: (LayoutCompleteEvent -> action) -> EventHandler model action
+onLayoutCompleteMain action = onMain "layoutcomplete" layoutCompleteDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onLayoutCompleteMain', but the handler also receives read-only access
+-- to the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleLayout LayoutCompleteEvent Model DOMRef
+--
+-- view_ [ event (static (onLayoutCompleteMainWith HandleLayout)) ] [ "some view" ]
+-- @
+--
+onLayoutCompleteMainWith :: (LayoutCompleteEvent -> model -> DOMRef -> action) -> EventHandler model action
+onLayoutCompleteMainWith action = onMain "layoutcomplete" layoutCompleteDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#snap
+--
+-- Callback when pagination scrolling is about to occur.
+--
+-- @
+--
+-- data Action = HandleSnap SnapEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = list_ defaultListOptions [ onSnap HandleSnap ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleSnap SnapEvent {..}) =
+--   io_ (consoleLog "Received SnapEvent")
+--
+-- @
+--
+onSnap :: (SnapEvent -> action) -> Attribute model action
+onSnap action = on "snap" snapDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onSnap', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleSnap SnapEvent
+--
+-- view_ [ event (static (onSnapMain HandleSnap)) ] [ "some view" ]
+-- @
+--
+onSnapMain :: (SnapEvent -> action) -> EventHandler model action
+onSnapMain action = onMain "snap" snapDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onSnapMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleSnap SnapEvent Model DOMRef
+--
+-- view_ [ event (static (onSnapMainWith HandleSnap)) ] [ "some view" ]
+-- @
+--
+onSnapMainWith :: (SnapEvent -> model -> DOMRef -> action) -> EventHandler model action
+onSnapMainWith action = onMain "snap" snapDecoder action
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- | Like 'onScroll', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onScrollWith :: (ScrollEvent -> DOMRef -> action) -> Attribute model action
+onScrollWith action = on "scroll" scrollDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToUpper', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onScrollToUpperWith :: (ScrollEvent -> DOMRef -> action) -> Attribute model action
+onScrollToUpperWith action = on "scrolltoupper" scrollDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToLower', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onScrollToLowerWith :: (ScrollEvent -> DOMRef -> action) -> Attribute model action
+onScrollToLowerWith action = on "scrolltolower" scrollDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onScrollStateChange', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onScrollStateChangeWith :: (ScrollStateChange -> DOMRef -> action) -> Attribute model action
+onScrollStateChangeWith action = on "scrollstatechange" scrollStateDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onLayoutComplete', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLayoutCompleteWith :: (LayoutCompleteEvent -> DOMRef -> action) -> Attribute model action
+onLayoutCompleteWith action = on "layoutcomplete" layoutCompleteDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onSnap', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onSnapWith :: (SnapEvent -> DOMRef -> action) -> Attribute model action
+onSnapWith action = on "snap" snapDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/List/Method.hs b/src/Miso/Native/Element/List/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/List/Method.hs
@@ -0,0 +1,213 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE RecordWildCards     #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications    #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.List.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.List.Method
+  ( -- *** Methods
+    scrollToPosition
+  , autoScroll
+  , getVisibleCells
+  , scrollBy
+  -- *** Types
+  , ScrollToPosition (..)
+  , AutoScroll (..)
+  , ScrollBy (..)
+  , Consumed (..)
+  -- *** Smart constructors
+  , defaultScrollToPosition
+  , defaultAutoScroll
+  , defaultScrollBy
+  ) where
+-----------------------------------------------------------------------------
+import Miso
+import Miso.Native.FFI
+-----------------------------------------------------------------------------
+-- | Parameters for 'scrollToPosition': which cell to scroll to, how far past
+-- it to continue, how to align it, and whether to animate.
+--
+-- @since 1.13.0.0
+data ScrollToPosition
+  = ScrollToPosition
+  { stpPosition :: Double
+  -- ^ Specifies the index of the node to scroll to, with a range of [0, data source count)
+  , stpOffset :: Double
+  -- ^ After applying alignTo alignment, continue scrolling the offset length
+  , stpAlignTo :: MisoString
+  -- ^ The position of the target node in the view after scrolling. 
+  , stpSmooth :: Bool
+  -- ^ Whether there is animation during the scrolling process
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Smart constructor for constructing 'scrollToPosition'
+defaultScrollToPosition :: ScrollToPosition
+defaultScrollToPosition
+  = ScrollToPosition
+  { stpPosition = 10
+  , stpOffset = 100
+  , stpAlignTo = "top"
+  , stpSmooth = False
+  }
+-----------------------------------------------------------------------------
+instance ToJSVal ScrollToPosition where
+  toJSVal ScrollToPosition {..} = do
+    object <- create
+    set "index" stpPosition object
+    set "offset" stpOffset object
+    set "alignTo" stpAlignTo object
+    set "smooth" stpSmooth object
+    toJSVal object 
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#scrolltoposition
+--
+-- The front end can execute 'Miso.Native.Element.View.Method.boundingClientRect' through the SelectorQuery API.
+--
+-- @
+--
+-- data Action
+--   = Success MisoString
+--   | Failure MisoString
+--   | GetRect
+--
+-- update :: Action -> Effect props model Action
+-- update GetRect =
+--   scrollToPosition defaultscrollToPosition "#box" Success Failure
+-- update (Succes _) =
+--   consoleLog "Successfuly got position"
+-- update (Failure errorMsg) =
+--   consoleLog ("Failed to call scrollToPosition: " <> errorMsg)
+--
+-- @
+--
+scrollToPosition
+  :: MisoString
+  -> ScrollToPosition
+  -> (MisoString -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+scrollToPosition = invokeExec "scrollToPosition"
+--------------------------------------------------------------------
+-- | Parameters for 'autoScroll': the scroll @rate@, whether to @start@ or
+-- stop, and whether to stop automatically at the end of the list.
+--
+-- @since 1.13.0.0
+data AutoScroll
+  = AutoScroll
+  { rate :: MisoString
+  , start :: Bool
+  , autoStop :: Bool
+  }
+--------------------------------------------------------------------
+instance ToJSVal AutoScroll where
+  toJSVal AutoScroll {..} = do
+    o <- create
+    set "rate" rate o
+    set "start" start o
+    set "autoStop" autoStop o
+    toJSVal o
+--------------------------------------------------------------------
+-- | A t'AutoScroll' with sensible defaults (stopped).
+--
+-- Override only the fields you need.
+--
+-- @since 1.13.0.0
+defaultAutoScroll :: AutoScroll
+defaultAutoScroll = AutoScroll
+  { rate = "60"
+  , start = False
+  , autoStop = True
+  }
+--------------------------------------------------------------------
+-- | Invokes the Lynx @autoScroll@ method on a @<list>@ element.
+--
+-- Takes a selector, a t'AutoScroll' of parameters, a success continuation and
+-- an error continuation.
+--
+-- @since 1.13.0.0
+autoScroll
+  :: MisoString
+  -> AutoScroll
+  -> (MisoString -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+autoScroll = invokeExec "autoScroll"
+--------------------------------------------------------------------
+-- | Invokes the Lynx @getVisibleCells@ method on a @<list>@ element,
+-- reporting the cells currently on screen.
+--
+-- @since 1.13.0.0
+getVisibleCells
+  :: MisoString
+  -> (MisoString -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+getVisibleCells name = invokeExec "getVisibleCells" name ()
+--------------------------------------------------------------------
+-- | Parameters for 'scrollBy': the distance to scroll from the current
+-- position.
+--
+-- @since 1.13.0.0
+data ScrollBy
+  = ScrollBy
+  { scrollByOffset :: Double
+  }
+--------------------------------------------------------------------
+instance ToJSVal ScrollBy where
+  toJSVal ScrollBy {..} = do
+    o <- create
+    set "offset" scrollByOffset o 
+    toJSVal o
+--------------------------------------------------------------------
+-- | A t'ScrollBy' with sensible defaults (zero offset).
+--
+-- Override only the fields you need.
+--
+-- @since 1.13.0.0
+defaultScrollBy :: ScrollBy
+defaultScrollBy = ScrollBy 0
+--------------------------------------------------------------------
+-- | Invokes the Lynx @scrollBy@ method on a @<list>@ element.
+--
+-- Takes a selector, a t'ScrollBy' of parameters, a success continuation and
+-- an error continuation.
+--
+-- @since 1.13.0.0
+scrollBy
+  :: MisoString
+  -> ScrollBy
+  -> (Consumed -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+scrollBy = invokeExec "scrollBy"
+--------------------------------------------------------------------
+-- | How much of a requested 'scrollBy' the @<list>@ actually consumed.
+--
+-- A list already at its end consumes less than was asked for; the remainder
+-- is what an enclosing scroller may take.
+--
+-- @since 1.13.0.0
+data Consumed
+  = Consumed
+  { consumedX, consumedY :: Double
+  , unconsumedX, unconsumedY :: Double
+  } deriving (Eq, Show)
+--------------------------------------------------------------------
+instance FromJSVal Consumed where
+  fromJSVal o = do
+    consumedX <- fromJSValUnchecked =<< o ! ("consumedX" :: MisoString)
+    consumedY <- fromJSValUnchecked =<< o ! ("consumedY" :: MisoString)
+    unconsumedX <- fromJSValUnchecked =<< o ! ("unconsumedX" :: MisoString)
+    unconsumedY <- fromJSValUnchecked =<< o ! ("unconsumedY" :: MisoString)
+    pure $ Just Consumed {..}
+--------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/List/Property.hs b/src/Miso/Native/Element/List/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/List/Property.hs
@@ -0,0 +1,371 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE RecordWildCards   #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.List.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.List.Property
+  ( -- *** Property
+    -- *** Types
+    ListOptions (..)
+  , ScrollOrientation (..)
+  , ListType (..)
+  , ListItemSnapAlignment (..)
+    -- *** Defaults
+  , defaultListOptions
+    -- *** Attributes
+  , itemKey_
+  , key_
+  , enableScroll_
+  , enableNestedScroll_
+  , listMainAxisGap_
+  , listCrossAxisGap_
+  , sticky_
+  , stickyOffset_
+  , stickyTop_
+  , stickyBottom_
+  , bounces_
+  , initialScrollIndex_
+  , needVisibleItemInfo_
+  , upperThresholdItemCount_
+  , lowerThresholdItemCount_
+  , scrollEventThrottle_
+  , itemSnap_
+  , needLayoutCompleteInfo_
+  , layoutId_
+  , preloadBufferCount_
+  , scrollBarEnable_
+  , reuseIdentifier_
+  , fullSpan_
+  , estimatedMainAxisSizePx_
+  , recyclable_
+  , updateAnimation_
+  , harmonyScrollEdgeEffect_
+  , experimentalRecycleStickyItem_
+  ) where
+-----------------------------------------------------------------------------
+import Miso.JSON
+import Miso.Property
+import Miso.String (MisoString)
+import Miso.Types (Attribute)
+----------------------------------------------------------------------------
+-- | ListOptions
+data ListOptions
+  = ListOptions
+  { listType_ :: ListType
+    -- ^ list-type: @single@ | @flow@ | @waterfall@
+  , spanCount_ :: Int
+    -- ^ Sets the number of columns or rows for the \<list\> component layout
+  , scrollOrientation_ :: ScrollOrientation
+    -- ^ @vertical@ ｜ @horizontal@
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | ScrollOrientation
+data ScrollOrientation
+  = Vertical
+  | Horizontal
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON ScrollOrientation where
+  toJSON Vertical   = "vertical"
+  toJSON Horizontal = "horizontal"
+-----------------------------------------------------------------------------
+-- | ListType
+data ListType
+  = Single
+  | Flow
+  | Waterfall
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON ListType where
+  toJSON Single    = "single"
+  toJSON Flow      = "flow"
+  toJSON Waterfall = "waterfall"
+-----------------------------------------------------------------------------
+-- | defaultListOptions
+defaultListOptions :: ListOptions
+defaultListOptions
+  = ListOptions
+  { listType_ = Single
+  , spanCount_ = 0
+  , scrollOrientation_ = Vertical
+  }
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#required-item-key
+--
+-- The item-key attribute is a required attribute on \<list-item\>.
+-- 
+--
+itemKey_ :: MisoString -> Attribute model action
+itemKey_ = textProp "item-key"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#enable-scroll
+--
+-- Indicates whether the \<list\> component is allowed to scroll.
+--
+enableScroll_ :: Bool -> Attribute model action
+enableScroll_ = boolProp "enable-scroll"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#enable-nested-scroll
+--
+-- Indicates whether \<list\> can achieve nested scrolling with other scrollable containers. When enabled, the inner container scrolls first, followed by the outer container.
+--
+enableNestedScroll_ :: Bool -> Attribute model action
+enableNestedScroll_ = boolProp "enable-nested-scroll"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#list-main-axis-gap
+--
+-- Specifies the spacing of \<list\> child nodes in the main axis direction,
+-- which needs to be written in the style.
+--
+listMainAxisGap_ :: MisoString -> Attribute model action
+listMainAxisGap_ = textProp "list-main-axis-gap"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#list-cross-axis-gap
+--
+-- Specifies the spacing of <list> child nodes in the cross axis direction,
+-- which needs to be written in the style.
+--
+listCrossAxisGap_ :: MisoString -> Attribute model action
+listCrossAxisGap_ = textProp "list-cross-axis-gap"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#sticky
+--
+-- Declared on the \<list\> component to control whether the \<list\> component
+-- as a whole is allowed to be sticky at the top or bottom.
+--
+sticky_ :: Bool -> Attribute model action
+sticky_ = boolProp "sticky"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#sticky-offset
+--
+-- The offset distance from the top or bottom of \<list\> for sticky positioning, in 'Miso.CSS.px'.
+--
+stickyOffset_ :: Int -> Attribute model action
+stickyOffset_ = intProp "sticky-offset"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#sticky-top
+--
+-- Declared on the \<list-item\> child node to control whether the node will
+-- be sticky at the top.
+--
+stickyTop_ :: Bool -> Attribute model action
+stickyTop_ = boolProp "sticky-top"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#sticky-bottom
+--
+-- Declared on the \<list-item\> child node to control whether the node
+-- will be sticky at the bottom.
+--
+stickyBottom_ :: Bool -> Attribute model action
+stickyBottom_ = boolProp "sticky-bottom"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#bounces
+--
+-- *iOS* only
+--
+-- Declared on the \<list-item\> child node to control whether the node
+-- will be sticky at the bottom.
+--
+-- Default value: 'True'
+--
+bounces_ :: Bool -> Attribute model action
+bounces_ = boolProp "bounces"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#initial-scroll-index
+--
+-- Specifies the node position to which \<list\> automatically scrolls after
+-- rendering effective only once.
+--
+initialScrollIndex_ :: Int -> Attribute model action
+initialScrollIndex_ = intProp "initial-scroll-index"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#need-visible-item-info
+--
+-- Controls whether the scroll event callback parameters include the position
+-- information of the currently rendering node.
+--
+-- The scroll events include:
+--  * @scroll@
+--  * @scrolltoupper@
+--  * @scrolltolower@
+--
+-- Default value: @False@
+--
+needVisibleItemInfo_ :: Bool -> Attribute model action
+needVisibleItemInfo_ = boolProp "need-visible-item-info"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#upper-threshold-item-count
+-- 
+-- Triggers a @scrolltoupper@ event once when the number of remaining displayable
+-- child nodes at the top of \<list\> is less than `upper-threshold-item-count`
+-- for the first time.
+--
+upperThresholdItemCount_ :: Int -> Attribute model action
+upperThresholdItemCount_ = intProp "upper-threshold-item-count"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#lower-threshold-item-count
+-- 
+-- Triggers a @scrolltolower@ event once when the number of remaining
+-- displayable child nodes at the bottom of \<list\> is less than
+-- `lower-threshold-item-count` for the first time.
+--
+lowerThresholdItemCount_ :: Int -> Attribute model action
+lowerThresholdItemCount_ = intProp "lower-threshold-item-count"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#scroll-event-throttle
+-- 
+-- Sets the time interval for the \<list\> callback @scroll@ event, in milliseconds (ms).
+-- By default, the scroll event is called back every 200 ms.
+--
+-- Default Value: 200
+--
+scrollEventThrottle_ :: Int -> Attribute model action
+scrollEventThrottle_ = intProp "scroll-event-throttle"
+-----------------------------------------------------------------------------
+-- | Where a @<list>@ item comes to rest when pagination snaps to it.
+-- 
+-- @since 1.13.0.0
+data ListItemSnapAlignment
+  = ListItemSnapAlignment
+  { factor :: Int
+  , offset :: Int
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON ListItemSnapAlignment where
+  toJSON ListItemSnapAlignment {..}
+    = object
+    [ "factor" .= factor
+    , "offset" .= offset
+    ]
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#item-snap
+-- 
+-- Used to mark the unique identifier for this data source update, which
+-- will be returned in the 'Miso.Native.Element.List.Event.onLayoutComplete' event callback.
+--
+-- - `factor`: The parameter for paginated positioning, with a range of `[0, 1]`.
+-- - `offset`: Additional `offset` parameter added on top of `factor`.
+--
+itemSnap_ :: ListItemSnapAlignment -> Attribute model action
+itemSnap_ = prop "item-snap"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#need-layout-complete-info
+-- 
+-- Controls whether the layoutcomplete event includes the node layout information
+-- before and after this layout, the \<list\> Diff information that triggered this
+-- layout, and the current \<list\> scroll state information.
+--
+needLayoutCompleteInfo_ :: Bool -> Attribute model action
+needLayoutCompleteInfo_ = prop "need-layout-complete-info"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#layout-id
+-- 
+-- Used to mark the unique identifier for this data source update,
+-- which will be returned in the layoutcomplete event callback.
+--
+-- Default Value: -1
+--
+layoutId_ :: Int -> Attribute model action
+layoutId_ = prop "layout-id"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#preload-buffer-count
+-- 
+-- This attribute controls the number of nodes outside \<list\> that are preloaded.
+--
+-- Default Value: 0
+--
+preloadBufferCount_ :: Int -> Attribute model action
+preloadBufferCount_ = intProp "preload-buffer-count"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#scroll-bar-enable
+--
+-- *iOS* only
+--
+-- Indicates whether the \<list\> component scroll bar is displayed.
+--
+-- Default value: 'True'
+--
+scrollBarEnable_ :: Bool -> Attribute model action
+scrollBarEnable_ = boolProp "scroll-bar-enable"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#reuse-identifier
+--
+-- Sets the reuse id for \<list-item\>. When rendering child nodes, the \<list\>
+-- component reuses \<list-item\> based on the reuse-identifier attribute value.
+-- Only \<list-item\> with the same reuse-identifier attribute value will be reused.
+--
+reuseIdentifier_ :: MisoString -> Attribute model action
+reuseIdentifier_ = textProp "reuse-identifier"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#full-span
+--
+-- The full-span attribute is used to indicate that a \<list-item\>
+-- occupies a full row or column.
+--
+fullSpan_ :: Bool -> Attribute model action
+fullSpan_ = boolProp "full-span"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#estimated-main-axis-size-px
+--
+-- Specifies the placeholder size in the main axis direction for \<list-item\>
+-- before it is fully rendered, in px. If not set, the default value is the size
+-- of \<list\> in the main axis direction.
+--
+estimatedMainAxisSizePx_ :: Int -> Attribute model action
+estimatedMainAxisSizePx_ = intProp "estimated-main-axis-size-px"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#recyclable
+--
+-- Declared on the \<list-item\> node to control whether the node can be recycled.
+--
+-- > recyclable_ False
+--
+-- Default Value: 'True'
+--
+recyclable_ :: Bool -> Attribute model action
+recyclable_ = boolProp "recyclable"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#update-animation
+--
+-- Controls the animation behavior during data source updates.
+-- One of @\"default\"@ | @\"none\"@.
+--
+-- > updateAnimation_ "none"
+--
+updateAnimation_ :: MisoString -> Attribute model action
+updateAnimation_ = textProp "update-animation"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#harmony-scroll-edge-effect
+--
+-- *Harmony* only
+--
+-- When the contentSize is smaller than its own container size, sets whether
+-- to enable the scroll (edge) effect.
+--
+-- > harmonyScrollEdgeEffect_ False
+--
+-- Default Value: 'True'
+--
+harmonyScrollEdgeEffect_ :: Bool -> Attribute model action
+harmonyScrollEdgeEffect_ = boolProp "harmony-scroll-edge-effect"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/list.html#experimental-recycle-sticky-item
+--
+-- Enables recycling of sticky nodes when they are pushed out of the view area.
+--
+-- > experimentalRecycleStickyItem_ False
+--
+-- Default Value: 'True'
+--
+experimentalRecycleStickyItem_ :: Bool -> Attribute model action
+experimentalRecycleStickyItem_ = boolProp "experimental-recycle-sticky-item"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/ScrollView.hs b/src/Miso/Native/Element/ScrollView.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/ScrollView.hs
@@ -0,0 +1,23 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.ScrollView
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.ScrollView
+  ( module Miso.Native.Element.ScrollView.Event
+  , module Miso.Native.Element.ScrollView.Method
+  , module Miso.Native.Element.ScrollView.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.Element.ScrollView.Event
+import Miso.Native.Element.ScrollView.Method
+import Miso.Native.Element.ScrollView.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/ScrollView/Event.hs b/src/Miso/Native/Element/ScrollView/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/ScrollView/Event.hs
@@ -0,0 +1,348 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.ScrollView.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.ScrollView.Event
+  ( -- *** Event
+    onScroll
+  , onScrollWith
+  , onScrollMain
+  , onScrollMainWith
+  , onScrollToUpper
+  , onScrollToUpperWith
+  , onScrollToUpperMain
+  , onScrollToUpperMainWith
+  , onScrollToLower
+  , onScrollToLowerWith
+  , onScrollToLowerMain
+  , onScrollToLowerMainWith
+  , onScrollEnd
+  , onScrollEndWith
+  , onScrollEndMain
+  , onScrollEndMainWith
+  , onContentSizeChanged
+  , onContentSizeChangedWith
+  , onContentSizeChangedMain
+  , onContentSizeChangedMainWith
+  -- *** Decoders
+  , scrollDecoder
+  -- *** Types
+  , ScrollEvent (..)
+  -- *** Event Map
+  , scrollViewEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+import           Miso.Event
+import           Miso.JSON (withObject, (.:?), (.!=))
+import           Miso.String (MisoString)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<scrollview>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+scrollViewEvents :: Events
+scrollViewEvents
+  = M.fromList
+  [ ("scroll", BUBBLE)
+  , ("scrolltoupper", BUBBLE)
+  , ("scrolltolower", BUBBLE)
+  , ("scrollend", BUBBLE)
+  , ("contentsizechanged", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'ScrollEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+scrollDecoder :: Decoder ScrollEvent
+scrollDecoder = ["detail"] `at` do
+  withObject "ScrollEvent" $ \o ->
+    ScrollEvent
+      -- @type@ is present on native scroll events but omitted by the web
+      -- (LynxDevTool) preview; keep it optional so decoding succeeds in both.
+      <$> o .:? "type" .!= ""
+      <*> o .:? "deltaX" .!= 0
+      <*> o .:? "deltaY" .!= 0
+      <*> o .:? "scrollLeft" .!= 0
+      <*> o .:? "scrollTop" .!= 0
+      <*> o .:? "scrollHeight" .!= 0
+      <*> o .:? "scrollWidth" .!= 0
+-----------------------------------------------------------------------------
+-- | Payload of a @<scroll-view>@ scroll event: the delta since the last
+-- event, the current offsets, and the full scrollable extent.
+-- 
+-- @since 1.13.0.0
+data ScrollEvent
+  = ScrollEvent
+  { scrollType :: MisoString
+  , deltaX, deltaY :: Double
+  , scrollLeft, scrollTop, scrollHeight, scrollWidth :: Double
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#scroll
+--
+-- @
+--
+-- data Action = HandleScroll ScrollEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = scrollView_ [ onScroll HandleScroll ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleScroll ScrollEvent {..}) =
+--   io_ (consoleLog "handled scroll event")
+--
+-- @
+--
+onScroll :: (ScrollEvent -> action) -> Attribute model action
+onScroll action = on "scroll" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScroll', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleScroll ScrollEvent
+--
+-- view_ [ event (static (onScrollMain HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollMain :: (ScrollEvent -> action) -> EventHandler model action
+onScrollMain action = onMain "scroll" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleScroll ScrollEvent Model DOMRef
+--
+-- view_ [ event (static (onScrollMainWith HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollMainWith :: (ScrollEvent -> model -> DOMRef -> action) -> EventHandler model action
+onScrollMainWith action = onMain "scroll" scrollDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#scrolltoupper
+--
+-- @
+--
+-- data Action = HandleScroll ScrollEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = scrollView_ [ onScrollToUpper HnadleScroll ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleScroll ScrollEvent {..}) =
+--   io_ (consoleLog "handled scroll event")
+--
+-- @
+--
+onScrollToUpper :: (ScrollEvent -> action) -> Attribute model action
+onScrollToUpper action = on "scrolltoupper" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToUpper', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleScroll ScrollEvent
+--
+-- view_ [ event (static (onScrollToUpperMain HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollToUpperMain :: (ScrollEvent -> action) -> EventHandler model action
+onScrollToUpperMain action = onMain "scrolltoupper" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToUpperMain', but the handler also receives read-only access
+-- to the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleScroll ScrollEvent Model DOMRef
+--
+-- view_ [ event (static (onScrollToUpperMainWith HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollToUpperMainWith :: (ScrollEvent -> model -> DOMRef -> action) -> EventHandler model action
+onScrollToUpperMainWith action = onMain "scrolltoupper" scrollDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#scrolltolower
+--
+-- @
+--
+-- data Action = HandleScroll ScrollEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = scrollView_ [ onScrollToLower HandleScroll ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleScroll ScrollEvent {..}) =
+--   io_ (consoleLog "handled scroll event")
+--
+-- @
+--
+onScrollToLower :: (ScrollEvent -> action) -> Attribute model action
+onScrollToLower action = on "scrolltolower" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToLower', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleScroll ScrollEvent
+--
+-- view_ [ event (static (onScrollToLowerMain HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollToLowerMain :: (ScrollEvent -> action) -> EventHandler model action
+onScrollToLowerMain action = onMain "scrolltolower" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToLowerMain', but the handler also receives read-only access
+-- to the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleScroll ScrollEvent Model DOMRef
+--
+-- view_ [ event (static (onScrollToLowerMainWith HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollToLowerMainWith :: (ScrollEvent -> model -> DOMRef -> action) -> EventHandler model action
+onScrollToLowerMainWith action = onMain "scrolltolower" scrollDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#scrollend
+--
+-- @
+--
+-- data Action = HandleScroll ScrollEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = scrollView_ [ onScrollToLower HandleScroll ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleScroll ScrollEvent {..}) =
+--   io_ (consoleLog "handled scroll event")
+--
+-- @
+--
+onScrollEnd :: (ScrollEvent -> action) -> Attribute model action
+onScrollEnd action = on "scrollend" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollEnd', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleScroll ScrollEvent
+--
+-- view_ [ event (static (onScrollEndMain HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollEndMain :: (ScrollEvent -> action) -> EventHandler model action
+onScrollEndMain action = onMain "scrollend" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onScrollEndMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleScroll ScrollEvent Model DOMRef
+--
+-- view_ [ event (static (onScrollEndMainWith HandleScroll)) ] [ "some view" ]
+-- @
+--
+onScrollEndMainWith :: (ScrollEvent -> model -> DOMRef -> action) -> EventHandler model action
+onScrollEndMainWith action = onMain "scrollend" scrollDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#contentsizechanged
+--
+-- Triggered when the content area comprised of direct child nodes changes in width
+-- or height. This event triggers after the \<scroll-view\> content completes layout.
+-- If updating \<scroll-view\> child nodes, call updated scrolling methods like
+-- `scrollTo` in this event.
+--
+-- @
+--
+-- data Action = HandleContentSizeChanged ScrollEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = scrollView_ [ onContentSizeChanged HandleContentSizeChanged ] [ ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleContentSizeChanged ScrollEvent {..}) =
+--   io_ (consoleLog "handled content size changed event")
+--
+-- @
+--
+onContentSizeChanged :: (ScrollEvent -> action) -> Attribute model action
+onContentSizeChanged action = on "contentsizechanged" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onContentSizeChanged', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleContentSizeChanged ScrollEvent
+--
+-- view_ [ event (static (onContentSizeChangedMain HandleContentSizeChanged)) ] [ "some view" ]
+-- @
+--
+onContentSizeChangedMain :: (ScrollEvent -> action) -> EventHandler model action
+onContentSizeChangedMain action = onMain "contentsizechanged" scrollDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onContentSizeChangedMain', but the handler also receives read-only
+-- access to the @model@ and the target element's 'DOMRef' (for imperative MTS
+-- mutation).
+--
+-- @
+-- data Action = HandleContentSizeChanged ScrollEvent Model DOMRef
+--
+-- view_ [ event (static (onContentSizeChangedMainWith HandleContentSizeChanged)) ] [ "some view" ]
+-- @
+--
+onContentSizeChangedMainWith :: (ScrollEvent -> model -> DOMRef -> action) -> EventHandler model action
+onContentSizeChangedMainWith action = onMain "contentsizechanged" scrollDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onScroll', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onScrollWith :: (ScrollEvent -> DOMRef -> action) -> Attribute model action
+onScrollWith action = on "scroll" scrollDecoder $ \se _ domRef -> action se domRef
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToUpper', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onScrollToUpperWith :: (ScrollEvent -> DOMRef -> action) -> Attribute model action
+onScrollToUpperWith action = on "scrolltoupper" scrollDecoder $ \se _ domRef -> action se domRef
+-----------------------------------------------------------------------------
+-- | Like 'onScrollToLower', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onScrollToLowerWith :: (ScrollEvent -> DOMRef -> action) -> Attribute model action
+onScrollToLowerWith action = on "scrolltolower" scrollDecoder $ \se _ domRef -> action se domRef
+-----------------------------------------------------------------------------
+-- | Like 'onScrollEnd', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onScrollEndWith :: (ScrollEvent -> DOMRef -> action) -> Attribute model action
+onScrollEndWith action = on "scrollend" scrollDecoder $ \se _ domRef -> action se domRef
+-----------------------------------------------------------------------------
+-- | Like 'onContentSizeChanged', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onContentSizeChangedWith :: (ScrollEvent -> DOMRef -> action) -> Attribute model action
+onContentSizeChangedWith action = on "contentsizechanged" scrollDecoder $ \se _ domRef -> action se domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/ScrollView/Method.hs b/src/Miso/Native/Element/ScrollView/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/ScrollView/Method.hs
@@ -0,0 +1,249 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.ScrollView.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.ScrollView.Method
+  ( -- *** Methods
+    scrollTo
+  , autoScroll
+  , scrollIntoView
+  , scrollBy
+  , getScrollInfo
+  -- *** Types
+  , ScrollTo (..)
+  , AutoScroll (..)
+  , ScrollIntoView (..)
+  , ScrollBy (..)
+  , ScrollInfo (..)
+  -- *** Smart constructors
+  , defaultScrollTo
+  , defaultAutoScroll
+  , defaultScrollIntoView
+  , defaultScrollBy
+  ) where
+-----------------------------------------------------------------------------
+import Miso hiding (scrollIntoView, inline)
+import Miso.Native.FFI
+-----------------------------------------------------------------------------
+-- | Parameters for @scrollTo@: the target @index@, an extra @offset@ to continue past it,
+-- and whether the movement is animated.
+--
+-- @since 1.13.0.0
+data ScrollTo
+  = ScrollTo
+  { offset :: Double
+  , index :: Double
+  , smooth :: Bool
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal ScrollTo where
+  toJSVal ScrollTo {..} = do
+    object <- create
+    set "offset" offset object
+    set "index" index object
+    set "smooth" smooth object
+    toJSVal object 
+-----------------------------------------------------------------------------
+-- | A t'ScrollTo' with sensible defaults (first index, no offset, animated).
+--
+-- Override only the fields you need.
+--
+-- @since 1.13.0.0
+defaultScrollTo :: ScrollTo
+defaultScrollTo = ScrollTo 0 1 True
+-----------------------------------------------------------------------------
+-- | Invokes the Lynx @scrollTo@ method on a @<scroll-view>@ element.
+--
+-- Takes a selector, a t'ScrollTo' of parameters, a success continuation and
+-- an error continuation.
+--
+-- @since 1.13.0.0
+scrollTo
+  :: MisoString
+  -> ScrollTo
+  -> (JSVal -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+scrollTo = invokeExec "scrollTo"
+-----------------------------------------------------------------------------
+-- | Parameters for 'autoScroll': the scroll @rate@, whether to @start@ or stop, and
+-- whether to stop automatically at the end.
+--
+-- @since 1.13.0.0
+data AutoScroll
+  = AutoScroll
+  { rate :: Double
+  , start :: Bool
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal AutoScroll where
+  toJSVal AutoScroll {..} = do
+    object <- create
+    set "rate" rate object
+    set "start" start object
+    toJSVal object 
+-----------------------------------------------------------------------------
+-- | A t'AutoScroll' with sensible defaults (stopped).
+--
+-- Override only the fields you need.
+--
+-- @since 1.13.0.0
+defaultAutoScroll :: AutoScroll
+defaultAutoScroll = AutoScroll 120 False
+-----------------------------------------------------------------------------
+-- | Invokes the Lynx @autoScroll@ method on a @<scroll-view>@ element.
+--
+-- Takes a selector, a t'AutoScroll' of parameters, a success continuation and
+-- an error continuation.
+--
+-- @since 1.13.0.0
+autoScroll
+  :: MisoString
+  -> AutoScroll
+  -> (JSVal -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+autoScroll = invokeExec "autoScroll"
+-----------------------------------------------------------------------------
+-- | Parameters for 'scrollIntoView': where the element should come to rest within the
+-- viewport.
+--
+-- @since 1.13.0.0
+data ScrollIntoView
+  = ScrollIntoView
+  { block :: MisoString
+    -- ^ Vertical alignment options: "start" aligns top | "center" centers | "end" aligns bottom
+  , inline :: MisoString
+    -- ^ Horizontal alignment options: "start" aligns left | "center" centers | "end" aligns right
+  , behavior :: MisoString
+    -- ^ "smooth" | "none" whether to animate scrolling
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal ScrollIntoView where
+  toJSVal ScrollIntoView {..} = do
+    object <- create
+    set "block" block object
+    set "inline" inline object
+    set "behavior" behavior object
+    scrollIntoViewOptions <- create
+    set "scrollIntoViewOptions" object scrollIntoViewOptions
+    toJSVal scrollIntoViewOptions
+-----------------------------------------------------------------------------
+-- | A t'ScrollIntoView' with sensible defaults (nearest alignment).
+--
+-- Override only the fields you need.
+--
+-- @since 1.13.0.0
+defaultScrollIntoView :: ScrollIntoView
+defaultScrollIntoView
+  = ScrollIntoView
+  { block = "center"
+  , inline = "start"
+  , behavior = "smooth"
+  }
+-----------------------------------------------------------------------------
+-- | Invokes the Lynx @scrollIntoView@ method on a @<scroll-view>@ element.
+--
+-- Takes a selector, a t'ScrollIntoView' of parameters, a success continuation and
+-- an error continuation.
+--
+-- @since 1.13.0.0
+scrollIntoView
+  :: MisoString
+  -> ScrollIntoView
+  -> (JSVal -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+scrollIntoView = invokeExec "scrollIntoView"
+-----------------------------------------------------------------------------
+-- | Parameters for 'scrollBy': the distance to scroll, relative to the current position.
+--
+-- @since 1.13.0.0
+newtype ScrollBy
+  = ScrollBy
+  { scrollByOffset :: Double
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal ScrollBy where
+  toJSVal ScrollBy {..} = do
+    object <- create
+    set "offset" scrollByOffset object
+    toJSVal object
+-----------------------------------------------------------------------------
+-- | A t'ScrollBy' with sensible defaults (zero offset).
+--
+-- Override only the fields you need.
+--
+-- @since 1.13.0.0
+defaultScrollBy :: ScrollBy
+defaultScrollBy = ScrollBy
+  { scrollByOffset = 0
+  }
+-----------------------------------------------------------------------------
+-- | Invokes the Lynx @scrollBy@ method on a @<scroll-view>@ element.
+--
+-- Takes a selector, a t'ScrollBy' of parameters, a success continuation and
+-- an error continuation.
+--
+-- @since 1.13.0.0
+scrollBy
+  :: MisoString
+  -> ScrollBy
+  -> (JSVal -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+scrollBy = invokeExec "scrollBy"
+-----------------------------------------------------------------------------
+-- | Result of calling 'getScrollInfo'
+data ScrollInfo
+  = ScrollInfo
+  { scrollRange :: Double
+    -- ^ Total scrollable range along the orientation, in PX
+  , scrollX :: Double
+    -- ^ Content offset on the X-axis, in PX
+  , scrollY :: Double
+    -- ^ Content offset on the Y-axis, in PX
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal ScrollInfo where
+  fromJSVal = \o -> do
+    let readProp = \name ->
+          fromJSValUnchecked =<< o ! (name :: MisoString)
+    scrollRange <- readProp "scrollRange"
+    scrollX     <- readProp "scrollX"
+    scrollY     <- readProp "scrollY"
+    pure $ Just ScrollInfo {..}
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#getscrollinfo
+--
+-- Retrieves the current scroll information of the \<scroll-view\>.
+--
+-- @
+--
+-- data Action = GetInfo | InfoReceived ScrollInfo | GotError MisoString
+--
+-- update :: Action -> Effect props model Action
+-- update = \\case
+--   GetInfo -> getScrollInfo "#box" InfoReceived GotError
+--   InfoReceived ScrollInfo {..} -> io_ (consoleLog "got scroll info")
+--   GotError errMsg -> io_ (consoleLog errMsg)
+--
+-- @
+--
+getScrollInfo
+  :: MisoString
+  -> (ScrollInfo -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+getScrollInfo selector = invokeExec "getScrollInfo" selector ()
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/ScrollView/Property.hs b/src/Miso/Native/Element/ScrollView/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/ScrollView/Property.hs
@@ -0,0 +1,104 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.ScrollView.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.ScrollView.Property
+  ( -- *** Property
+    scrollOrientation_
+  , enableScroll_
+  , initialScrollOffset_
+  , initialScrollToIndex_
+  , bounces_
+  , upperThreshold_
+  , lowerThreshold_
+  , scrollBarEnable_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#scroll-orientation
+--
+-- Set scroll orientation for the scrollable container.
+--
+-- Default Value: "vertical"
+--
+scrollOrientation_ :: MisoString -> Attribute model action
+scrollOrientation_ = textProp "scroll-orientation"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#enable-scroll
+--
+-- Sets whether to allow gesture dragging to scroll. Supports dynamic switching
+-- and takes effect on the next gesture. When scrolling is disabled, the
+-- user cannot scroll manually.
+--
+-- Default Value: True
+--
+enableScroll_ :: Bool -> Attribute model action
+enableScroll_ = boolProp "enable-scroll"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#initial-scroll-offset
+--
+-- Sets the absolute content offset distance during initial rendering
+-- (different from the offset concept in the scrollTo method). The horizontal
+-- or vertical direction is determined by `scroll-orientation`, and it only takes
+-- effect during the first render execution, not responding to subsequent changes.
+--
+initialScrollOffset_ :: MisoString -> Attribute model action
+initialScrollOffset_ = textProp "initial-scroll-offset"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#initial-scroll-to-index
+--
+-- Sets the child node to be positioned during initial rendering, only taking
+-- effect during the first render execution and not responding to subsequent changes.
+--
+initialScrollToIndex_ :: MisoString -> Attribute model action
+initialScrollToIndex_ = textProp "initial-scroll-to-index"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#bounces
+--
+-- *iOS* only
+--
+-- Declared on the \<list-item\> child node to control whether the node
+-- will be sticky at the bottom.
+--
+-- Default value: 'True'
+--
+bounces_ :: Bool -> Attribute model action
+bounces_ = boolProp "bounces"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#upper-threshold
+--
+-- Sets a scroll threshold (unit: `px`), indicating how far from the top
+-- or left before triggering the @scrolltoupper@ event.
+--
+upperThreshold_ :: MisoString -> Attribute model action
+upperThreshold_ = textProp "upper-threshold"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-view.html#lower-threshold
+--
+-- Sets a scroll threshold (unit: px), indicating how far from the top
+-- or left before triggering the scrolltolower event.
+--
+lowerThreshold_ :: MisoString -> Attribute model action
+lowerThreshold_ = textProp "lower-threshold"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/scroll-view.html#scroll-bar-enable>
+--
+-- Enables the scrollbar, supporting dynamic switching.
+--
+-- Default Value: False
+--
+scrollBarEnable_ :: Bool -> Attribute model action
+scrollBarEnable_ = boolProp "scroll-bar-enable"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Text.hs b/src/Miso/Native/Element/Text.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Text.hs
@@ -0,0 +1,23 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Text
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Text
+  ( module Miso.Native.Element.Text.Event
+  , module Miso.Native.Element.Text.Property
+  , module Miso.Native.Element.Text.Method
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.Element.Text.Event
+import Miso.Native.Element.Text.Property
+import Miso.Native.Element.Text.Method
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Text/Event.hs b/src/Miso/Native/Element/Text/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Text/Event.hs
@@ -0,0 +1,248 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Text.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Text.Event
+  ( -- *** Events
+    onLayout
+  , onLayoutWith
+  , onLayoutMain
+  , onLayoutMainWith
+  , onSelectionChange
+  , onSelectionChangeWith
+  , onSelectionChangeMain
+  , onSelectionChangeMainWith
+    -- *** Types
+  , LayoutEvent          (..)
+  , LineInfo             (..)
+  , Size                 (..)
+  , SelectionChangeEvent (..)
+  , Direction            (..)
+    -- *** Decoders
+  , layoutDecoder
+  , selectionChangeDecoder
+    -- *** Event Map
+  , textEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+import           Miso.Event
+import           Miso.JSON
+----------------------------------------------------------------------------
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<text>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+textEvents :: Events
+textEvents
+  = M.fromList
+  [ ("layout", BUBBLE)
+  , ("selectionchange", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#layout
+--
+-- The layout event returns the result information after text layout,
+-- including the number of lines of the current text, and the start and
+-- end positions of the text in each line relative to the entire text.
+--
+-- @
+--
+-- data Action = HandleLayout LayoutEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = text_ [ onLayout HandleLayout ] [ text "hi" ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleLayout LayoutEvent {..}) = io_ (consoleLog "layout event received")
+--
+-- @
+--
+onLayout :: (LayoutEvent -> action) -> Attribute model action
+onLayout action = on "layout" layoutDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLayout', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleLayout LayoutEvent
+--
+-- view_ [ event (static (onLayoutMain HandleLayout)) ] [ "some view" ]
+-- @
+--
+onLayoutMain :: (LayoutEvent -> action) -> EventHandler model action
+onLayoutMain action = onMain "layout" layoutDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLayoutMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleLayout LayoutEvent Model DOMRef
+--
+-- view_ [ event (static (onLayoutMainWith HandleLayout)) ] [ "some view" ]
+-- @
+--
+onLayoutMainWith :: (LayoutEvent -> model -> DOMRef -> action) -> EventHandler model action
+onLayoutMainWith action = onMain "layout" layoutDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#selectionchange
+--
+-- This event is triggered whenever the selected text range changes.
+--
+-- @
+--
+-- data Action = HandleSelectionChange SelectionChangeEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = text_ [ onSelectionChange HandleSelectionChange ] [ text "hi" ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleSelectionChange SelectionChangeEvent {..}) =
+--   io_ (consoleLog "selection change event received")
+--
+-- @
+--
+onSelectionChange :: (SelectionChangeEvent -> action) -> Attribute model action
+onSelectionChange action = on "selectionchange" selectionChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onSelectionChange', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = HandleSelectionChange SelectionChangeEvent
+--
+-- view_ [ event (static (onSelectionChangeMain HandleSelectionChange)) ] [ "some view" ]
+-- @
+--
+onSelectionChangeMain :: (SelectionChangeEvent -> action) -> EventHandler model action
+onSelectionChangeMain action = onMain "selectionchange" selectionChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onSelectionChangeMain', but the handler also receives read-only access
+-- to the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleSelectionChange SelectionChangeEvent Model DOMRef
+--
+-- view_ [ event (static (onSelectionChangeMainWith HandleSelectionChange)) ] [ "some view" ]
+-- @
+--
+onSelectionChangeMainWith :: (SelectionChangeEvent -> model -> DOMRef -> action) -> EventHandler model action
+onSelectionChangeMainWith action = onMain "selectionchange" selectionChangeDecoder action
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'SelectionChangeEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+selectionChangeDecoder :: Decoder SelectionChangeEvent
+selectionChangeDecoder = ["detail"] `at` parser
+  where
+    parser :: Value -> Parser SelectionChangeEvent
+    parser = withObject "SelectionChangeEvent" $ \o -> do
+      SelectionChangeEvent
+        <$> o .: "start"
+        <*> o .: "end"
+        <*> o .: "direction"
+-----------------------------------------------------------------------------
+-- | Payload of a @<text>@ selection-change event: the @start@ and @end@
+-- offsets of the new selection and the direction it was extended in.
+-- 
+-- @since 1.13.0.0
+data SelectionChangeEvent
+  = SelectionChangeEvent
+  { start, end :: Double
+  , direction :: Direction
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | The direction a text selection was extended in.
+-- 
+-- @since 1.13.0.0
+data Direction = Forward | Backward
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSON Direction where
+  parseJSON = withText "Direction" $ \case
+    "forward" -> pure Forward
+    "backward" -> pure Backward
+    x -> typeMismatch "Direction" (toJSON x)
+-----------------------------------------------------------------------------
+-- | Payload of a @<text>@ layout event: how many lines were laid out,
+-- per-line detail, and the resulting size.
+-- 
+-- @since 1.13.0.0
+data LayoutEvent
+  = LayoutEvent
+  { lineInfoLineCount     :: Double
+  , lineInfoLines         :: [LineInfo]
+  , lineInfoSize          :: Size
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'LayoutEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+layoutDecoder :: Decoder LayoutEvent
+layoutDecoder = ["detail"] `at` do
+  withObject "LayoutEvent" $ \o ->
+    LayoutEvent
+      <$> o .: "lineCount"
+      <*> o .: "lines"
+      <*> do
+        s <- o .: "size"
+        Size <$> s .: "width" <*> s .: "height"
+-----------------------------------------------------------------------------
+instance FromJSON LineInfo where
+  parseJSON = withObject "lineInfo" $ \o ->
+    LineInfo
+      <$> o .: "start"
+      <*> o .: "end"
+      <*> o .: "ellipsisCount"
+-----------------------------------------------------------------------------
+-- | Per-line detail from a @<text>@ layout event: the character range the
+-- line covers and how many characters were ellipsized.
+-- 
+-- @since 1.13.0.0
+data LineInfo
+  = LineInfo
+  { lineInfoStart, lineInfoEnd, lineInfoEllipsisCount :: Double
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | The measured width and height of laid-out @<text>@ content, in px.
+-- 
+-- @since 1.13.0.0
+data Size
+  = Size
+  { sizeWidth, sizeHeight :: Double
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Like 'onLayout', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLayoutWith :: (LayoutEvent -> DOMRef -> action) -> Attribute model action
+onLayoutWith action = on "layout" layoutDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onSelectionChange', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onSelectionChangeWith :: (SelectionChangeEvent -> DOMRef -> action) -> Attribute model action
+onSelectionChangeWith action = on "selectionchange" selectionChangeDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Text/Method.hs b/src/Miso/Native/Element/Text/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Text/Method.hs
@@ -0,0 +1,151 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Text.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Text.Method
+  ( -- *** Methods
+    setTextSelection
+  , getTextBoundingRect
+  , getSelectedText
+  -- *** Types
+  , SetTextSelection (..)
+  , GetTextBoundingRect (GetTextBoundingRect)
+  -- *** Smart constructors
+  , defaultGetTextBoundingRect
+  ) where
+-----------------------------------------------------------------------------
+import           Miso
+import           Miso.Native.FFI (invokeExec)
+-----------------------------------------------------------------------------
+-- | Parameters for @setTextSelection@: the start and end coordinates of the
+-- selection and whether to show its drag handles.
+--
+-- @since 1.13.0.0
+data SetTextSelection
+  = SetTextSelection
+  { startX, startY :: Double
+  -- ^ X/Y-coordinate of the selection start relative to the element
+  , endX, endY :: Double
+  -- ^ X/Y-coordinate of the selection end relative to the element
+  , showStartHandle, showEndHandle :: Bool
+  -- ^ Whether to show or hide the start/end handle
+  }
+-----------------------------------------------------------------------------
+instance ToJSVal SetTextSelection where
+  toJSVal SetTextSelection {..} = do
+    o <- create
+    set "startX" startX o
+    set "startY" startY o
+    set "endX" endX o
+    set "endY" endY o
+    set "showStartHandle" showStartHandle o
+    set "showEndHandle" showEndHandle o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/text.html#setTextSelection>
+--
+-- This method sets the selected text based on start and end positions and controls the visibility of selection handles. The response res contains:
+--
+-- @
+--
+-- data Action = SetText | TextSet | SetTextError MisoString
+--
+-- update :: Action -> Effect props model Action
+-- update = \\case
+--   SetText -> setTextSelection "someImageId" SetText SetTextError
+--   TextSet -> io_ (consoleLog "text was set")
+--   SetTextError e -> io_ (consoleLog e)
+--
+-- @
+--
+setTextSelection
+  :: MisoString
+  -> SetTextSelection
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+setTextSelection selector params action =
+  invokeExec "setTextSelection" selector params (\() -> action)
+-----------------------------------------------------------------------------
+-- | Parameters for 'getTextBoundingRect': the @start@ and @end@ offsets of
+-- the range to measure.
+--
+-- @since 1.13.0.0
+data GetTextBoundingRect
+  = GetTextBoundingRect
+  { start, end :: Double
+  -- ^ X/Y-coordinate of the selection start relative to the element
+  }
+-----------------------------------------------------------------------------
+instance ToJSVal GetTextBoundingRect where
+  toJSVal GetTextBoundingRect {..} = do
+    o <- create
+    set "start" start o
+    set "end" end o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | A t'GetTextBoundingRect' with sensible defaults (the whole range, offsets 0 to 0).
+--
+-- Override only the fields you need.
+--
+-- @since 1.13.0.0
+defaultGetTextBoundingRect :: GetTextBoundingRect
+defaultGetTextBoundingRect = GetTextBoundingRect 0 0
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#gettextboundingrect
+--
+-- This method retrieves the bounding box of a specific range of text.
+--
+-- @
+--
+-- data Action = RectReceived Rect | GetRect | GotError MisoString
+--
+-- update :: Action -> Effect props model Action
+-- update = \\case
+--   GetRect -> getTextBoundingRect "#box" defaultGetTextBoundingRect RectReceived GotError
+--   RectReceived rect -> io_ $ consoleLog ("got rect")
+--   GotError errMsg -> io_ (consoleLog errMsg)
+--
+-- @
+--
+getTextBoundingRect
+  :: MisoString
+  -> GetTextBoundingRect
+  -> (JSVal -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+getTextBoundingRect = invokeExec "getTextBoundingRect"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#getselectedtext
+--
+-- This method retrieves the string content of the currently selected text.
+--
+-- @
+--
+-- data Action = TextReceived MisoString | GetText | GotError MisoString
+--
+-- update :: Action -> Effect props model Action
+-- update = \\case
+--   GetText -> getSelectedText "#box" TextReceived GotError
+--   TextReceived txt -> io_ (consoleLog ("got text: " <> txt))
+--   GotError errMsg -> io_ (consoleLog errMsg)
+--
+-- @
+--
+getSelectedText
+  :: MisoString
+  -> (MisoString -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+getSelectedText selector = invokeExec "getSelectedText" selector ()
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/Text/Property.hs b/src/Miso/Native/Element/Text/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/Text/Property.hs
@@ -0,0 +1,119 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.Text.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.Text.Property
+  ( -- *** Property
+    textMaxLine_
+  , includeFontPadding_
+  , tailColorConvert_
+  , textSingleLineVerticalAlign_
+  , textSelection_
+  , customContextMenu_
+  , customTextSelection_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#text-maxline
+--
+-- Limits the maximum number of lines displayed for the text content,
+-- overflow:hidden should be set simultaneously.
+--
+-- > textMaxLine_ 0
+--
+-- Default Value: -1
+--
+textMaxLine_ :: Int -> Attribute model action
+textMaxLine_ = intProp "text-maxline"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#include-font-padding
+--
+-- *Android* only
+--
+-- Add additional padding for Android text on top and bottom. Enabling this
+-- may cause inconsistencies between platforms.
+--
+-- > includeFontPadding_ True
+-- 
+-- Default Value: @False@
+--
+includeFontPadding_ :: Bool -> Attribute model action
+includeFontPadding_ = boolProp "include-font-padding"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#tail-color-convert
+--
+-- By default, if the text is truncated, the inserted ... will be displayed with
+-- the color specified by the closest inline-text's style. If this attribute
+-- is enabled, the color of ... will be specified by the outermost text tag's style.
+--
+-- > tailColorConvert_ True
+-- 
+-- Default Value: @False@
+--
+tailColorConvert_ :: Bool -> Attribute model action
+tailColorConvert_ = boolProp "tail-color-convert"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#text-single-line-vertical-align
+--
+-- Used to set vertical alignment for single-line plain text. It can be changed
+-- by setting "top" | "center" | "bottom". It is recommended to use this only
+-- when the default font does not meet the center alignment requirements, as it
+-- increases text measurement time.
+--
+-- > textSingleLineVerticalAlign_ "normal"
+--
+-- Default Value: "normal"
+--
+textSingleLineVerticalAlign_ :: MisoString -> Attribute model action
+textSingleLineVerticalAlign_ = textProp "text-single-line-vertical-align"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#text-selection
+--
+-- Sets whether to enable text selection.
+-- When enabled, flatten = False should be set simultaneously.
+--
+-- > textSelection_ True
+--
+-- Default Value: @False@
+--
+textSelection_ :: Bool -> Attribute model action
+textSelection_ = boolProp "text-selection"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#custom-context-menu
+--
+-- Used to set whether to turn on the custom pop-up context menu after selection
+-- and copying. It takes effect after enabling text-selection.
+--
+-- > customContextMenu_ True
+--
+-- Default Value: @False@
+--
+customContextMenu_ :: Bool -> Attribute model action
+customContextMenu_ = boolProp "custom-context-menu"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/text.html#custom-text-selection
+--
+-- Used to set whether to enable the custom text selection function.
+-- When it is enabled, the element will no longer handle the gesture logic
+-- related to selection and copying. Developers need to control it through
+-- APIs such as `setTextSelection`. It takes effect after enabling text-selection.
+--
+-- > customTextSelection_ True
+--
+-- Default Value: @False@
+--
+customTextSelection_ :: Bool -> Attribute model action
+customTextSelection_ = boolProp "custom-text-selection"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/View.hs b/src/Miso/Native/Element/View.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/View.hs
@@ -0,0 +1,23 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.View
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.View
+  ( module Miso.Native.Element.View.Event
+  , module Miso.Native.Element.View.Method
+  , module Miso.Native.Element.View.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.Element.View.Event
+import Miso.Native.Element.View.Method
+import Miso.Native.Element.View.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/View/Event.hs b/src/Miso/Native/Element/View/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/View/Event.hs
@@ -0,0 +1,1125 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE CPP #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.View.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.View.Event
+  ( -- *** Events
+    onTouchStart
+  , onTouchStartWith
+  , onTouchStartMain
+  , onTouchStartMainWith
+  , onTouchMove
+  , onTouchMoveWith
+  , onTouchMoveMain
+  , onTouchMoveMainWith
+  , onTouchEnd
+  , onTouchEndWith
+  , onTouchEndMain
+  , onTouchEndMainWith
+  , onTouchCancel
+  , onTouchCancelWith
+  , onTouchCancelMain
+  , onTouchCancelMainWith
+  , onTap
+  , onTapMain
+  , onTapWith
+  , onTapMainWith
+  , onTapMainModel
+  , onLongPress
+  , onLongPressWith
+  , onLongPressMain
+  , onLongPressMainWith
+  , onLayoutChange
+  , onLayoutChangeWith
+  , onLayoutChangeMain
+  , onLayoutChangeMainWith
+  , onLayout
+  , onLayoutMainWith
+  , onAppear
+  , onAppearWith
+  , onAppearMain
+  , onAppearMainWith
+  , onDisappear
+  , onDisappearWith
+  , onDisappearMain
+  , onDisappearMainWith
+  , onAnimationStart
+  , onAnimationStartWith
+  , onAnimationStartMain
+  , onAnimationStartMainWith
+  , onAnimationEnd
+  , onAnimationEndWith
+  , onAnimationEndMain
+  , onAnimationEndMainWith
+  , onAnimationCancel
+  , onAnimationCancelWith
+  , onAnimationCancelMain
+  , onAnimationCancelMainWith
+  , onAnimationIteration
+  , onAnimationIterationWith
+  , onAnimationIterationMain
+  , onAnimationIterationMainWith
+  , onTransitionStart
+  , onTransitionStartWith
+  , onTransitionStartMain
+  , onTransitionStartMainWith
+  , onTransitionEnd
+  , onTransitionEndWith
+  , onTransitionEndMain
+  , onTransitionEndMainWith
+  , onTransitionCancel
+  , onTransitionCancelWith
+  , onTransitionCancelMain
+  , onTransitionCancelMainWith
+    -- *** Types
+  , TouchEvent (..)
+  , AnimationEvent (..)
+  , LayoutChangeDetailEvent (..)
+  , UIAppearanceDetailEvent (..)
+  , AnimationType (..)
+  , UIAppearanceDetailEventType (..)
+    -- *** Decoders
+  , touchDecoder
+  , animationDecoder
+  , layoutChangeDetailDecoder
+  , uiAppearanceDetailDecoder
+    -- *** Event Map
+  , viewEvents
+  ) where
+----------------------------------------------------------------------------
+#if __GLASGOW_HASKELL__ <= 881
+import Control.Applicative (liftA2)
+#endif
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+import           Miso.Event (on, onMain, Decoder(..), DecodeTarget(..), Events, emptyDecoder, Phase(BUBBLE))
+import           Miso.JSON
+import           Miso.String (MisoString, isPrefixOf)
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<view>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+viewEvents :: Events
+viewEvents = M.fromList
+  [ ("touchstart", BUBBLE)
+  , ("touchmove", BUBBLE)
+  , ("touchend", BUBBLE)
+  , ("touchcancel", BUBBLE)
+  , ("tap", BUBBLE)
+  , ("longpress", BUBBLE)
+  , ("layoutchange", BUBBLE)
+  , ("layout", BUBBLE)   -- released engines' name for layoutchange
+  , ("uiappear", BUBBLE)
+  , ("uidisappear", BUBBLE)
+  , ("animationstart", BUBBLE)
+  , ("animationend", BUBBLE)
+  , ("animationcancel", BUBBLE)
+  , ("animationiteration", BUBBLE)
+  , ("transitionstart", BUBBLE)
+  , ("transitionend", BUBBLE)
+  , ("transitioncancel", BUBBLE)
+  ]
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/lynx-api/event/touch-event.html
+data TouchEvent
+  = TouchEvent
+  { identifier :: Double
+    -- ^ Unique identifier of the touch point, which remains
+    -- unchanged during the same touch process
+  , xy :: (Double, Double)
+    -- ^ The horizontal / vertical position of the touch point in the
+    -- coordinate system of the element actually touched
+  , page :: (Double, Double)
+    -- ^ The horizontal / vertical position of the touch point in the
+    -- current LynxView coordinate system
+  , client :: (Double, Double)
+    -- ^ The horizontal / vertical position of the touch point in the
+    -- current window coordinate system
+  } deriving (Show, Eq)
+----------------------------------------------------------------------------
+-- | Touch decoder for use with events like 'onTap'
+touchDecoder :: Decoder TouchEvent
+touchDecoder = Decoder {..}
+  where
+    pair o x y = liftA2 (,) (o .: x) (o .: y)
+    -- Lynx nests touch fields inside `changedTouches` / `touches` arrays (each a
+    -- `Touch` with identifier/x/y/pageX/pageY/clientX/clientY); the browser-style
+    -- flat root has no `identifier`. Read the first changed touch point.
+    decodeAt = DecodeTarget ["changedTouches", "0"]
+    decoder = withObject "touchDecoder" $ \o ->
+       TouchEvent
+        <$> o .: "identifier"
+        <*> pair o "x" "y"
+        <*> pair o "pageX" "pageY"
+        <*> pair o "clientX" "clientY"
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/lynx-api/event/animation-event.html
+data AnimationEvent
+  = AnimationEvent
+  { animationType :: AnimationType
+    -- ^ The type of the animation. If it is a keyframe animation,
+    -- this value is `keyframe-animation`; if it is a transition animation,
+    -- this value is `transition-animation`.
+  , animationName :: Maybe MisoString
+    -- ^ The name of the animation. If it is a keyframe animation, it
+    -- is the name of `@keyframes` in CSS; if it is a transition animation,
+    -- it is the name of `transition-property` in CSS. 'Nothing' for
+    -- 'LegacyTransitionAnimation', whose property name is folded into
+    -- 'animationType' instead.
+  , newAnimator :: Bool
+    -- ^ 'True' only when the engine's new animator explicitly reports it
+    -- (always @true@ when present, on both keyframe and transition events);
+    -- pre-"new animator" engines never send this field at all, for
+    -- keyframe animations as well as 'LegacyTransitionAnimation', so
+    -- 'False' whenever the field is absent.
+  } deriving (Show, Eq)
+----------------------------------------------------------------------------
+-- | Which animation kind raised the event: a @\@keyframes@ animation or a
+-- CSS transition.
+-- 
+-- @since 1.13.0.0
+data AnimationType
+  = KeyFrameAnimation
+  | TransitionAnimation
+  | LegacyTransitionAnimation MisoString
+    -- ^ Pre-"new animator" engines report a CSS transition as
+    -- @transition-\<property\>@ (e.g. @transition-width@) instead of
+    -- @transition-animation@, and send no @animation_name@\/@new_animator@
+    -- alongside it. This carries the raw wire value (e.g. @transition-width@).
+  deriving (Show, Eq)
+----------------------------------------------------------------------------
+instance FromJSON AnimationType where
+  parseJSON = withText "animation-type" $ \case
+    "keyframe-animation" -> pure KeyFrameAnimation
+    "transition-animation" -> pure TransitionAnimation
+    x | "transition-" `isPrefixOf` x -> pure (LegacyTransitionAnimation x)
+      | otherwise -> typeMismatch "animation-type" (toJSON x)
+----------------------------------------------------------------------------
+-- | Animation decoder for use with events like 'onAnimationStart'
+animationDecoder :: Decoder AnimationEvent
+animationDecoder = Decoder {..}
+  where
+    decodeAt = DecodeTarget mempty
+    decoder = withObject "animationDecoder" $ \o -> do
+      d <- o .: "params"
+      aType <- d .: "animation_type"
+      name <- case aType of
+        LegacyTransitionAnimation _ -> pure Nothing
+        _ -> Just <$> d .: "animation_name"
+      newAnim <- d .:? "new_animator" .!= False
+      pure (AnimationEvent aType name newAnim)
+-----------------------------------------------------------------------------
+-- | Payload of a @<view>@ layout-change event: the target's id, its new
+-- box, and its @dataset@.
+-- 
+-- @since 1.13.0.0
+data LayoutChangeDetailEvent
+  = LayoutChangeDetailEvent
+  { layoutChangeDetailEventId :: MisoString
+    -- ^ The id selector of the target.
+  , layoutChangeDetailEventWidth :: Double
+    -- ^ The width of the target.
+  , layoutChangeDetailEventHeight :: Double
+    -- ^ The height of the target.
+  , layoutChangeDetailEventTop :: Double
+    -- ^ The top of the target.
+  , layoutChangeDetailEventRight :: Double
+    -- ^ The right of the target.
+  , layoutChangeDetailEventBottom :: Double
+    -- ^ The bottom of the target.
+  , layoutChangeDetailEventLeft :: Double
+    -- ^ The left of the target.
+  , layoutChangeDetailEventDataset :: Object
+    -- ^ The dataset of the target.
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'LayoutChangeDetailEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+layoutChangeDetailDecoder :: Decoder LayoutChangeDetailEvent
+layoutChangeDetailDecoder = Decoder {..}
+  where
+    decodeAt = DecodeTarget mempty
+    decoder = withObject "LayoutChangeDetailEvent" $ \o -> do
+      d <- o .: "detail"
+      LayoutChangeDetailEvent
+        <$> d .: "id"
+        <*> d .: "width"
+        <*> d .: "height"
+        <*> d .: "top"
+        <*> d .: "right"
+        <*> d .: "bottom"
+        <*> d .: "left"
+        <*> d .: "dataset"
+-----------------------------------------------------------------------------
+-- | Whether the element entered or left the viewport.
+-- 
+-- @since 1.13.0.0
+data UIAppearanceDetailEventType
+  = UIAppear
+  | UIDisappear
+  deriving (Show, Eq)
+----------------------------------------------------------------------------
+instance FromJSON UIAppearanceDetailEventType where
+  parseJSON = withText "UIAppearanceDetailEventType" $ \case
+    "uiappear" -> pure UIAppear
+    "uidisappear" -> pure UIDisappear
+    x -> typeMismatch "UIAppearanceDetailEventType" (toJSON x)
+-----------------------------------------------------------------------------
+-- | Payload of a @<view>@ appearance event: whether the element appeared
+-- or disappeared, plus the exposure identifiers Lynx assigns it.
+-- 
+-- @since 1.13.0.0
+data UIAppearanceDetailEvent
+  = UIAppearanceDetailEvent
+  { uiAppearanceDetailEventType :: UIAppearanceDetailEventType
+  , uiAppearanceDetailEventExposureId :: MisoString
+  , uiAppearanceDetailEventExposureScene :: MisoString
+  , uiAppearanceDetailEventUniqueId :: MisoString
+  , uiAppearanceDetailEventDataset :: Object
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'UIAppearanceDetailEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+uiAppearanceDetailDecoder :: Decoder UIAppearanceDetailEvent
+uiAppearanceDetailDecoder = Decoder {..}
+  where
+    decodeAt = DecodeTarget mempty
+    decoder = withObject "UIAppearanceDetailEvent" $ \o -> do
+      d <- o .: "detail"
+      UIAppearanceDetailEvent
+        <$> o .: "type"
+        <*> d .: "exposure-id"
+        <*> d .: "exposure-scene"
+        <*> d .: "unique-id"
+        <*> d .: "dataset"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#touchstart
+--
+-- It belongs to [touch event](https://lynxjs.org/api/lynx-api/event/touch-event.html),
+-- which is triggered when the finger starts to touch the touch surface.
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view model = view_ [ onTouchStart HandleTouch ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleTouch TouchEvent {..}) = do
+--   io_ (consoleLog "touch event received")
+--
+onTouchStart :: (TouchEvent -> action) -> Attribute model action
+onTouchStart action = on "touchstart" touchDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#touchmove
+--
+-- It belongs to [touch event](https://lynxjs.org/api/lynx-api/event/touch-event.html),
+-- which is triggered when the finger moves on the touch surface.
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onTouchMove HandleTouch ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleTouch TouchEvent {..}) = do
+--   io_ (consoleLog "touch event received")
+--
+-- @
+--
+onTouchMove :: (TouchEvent -> action) -> Attribute model action
+onTouchMove action = on "touchmove" touchDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#touchend
+--
+-- It belongs to [touch event](https://lynxjs.org/api/lynx-api/event/touch-event.html),
+-- which is triggered when the finger leaves the touch surface.
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onTouchEnd HandleTouch ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleTouch TouchEvent {..}) = do
+--   io_ (consoleLog "touch event received")
+--
+-- @
+--
+onTouchEnd :: (TouchEvent -> action) -> Attribute model action
+onTouchEnd action = on "touchend" touchDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#touchcancel
+--
+-- It belongs to [touch event](https://lynxjs.org/api/lynx-api/event/touch-event.html),
+-- which is triggered when the [touch event](https://lynxjs.org/api/lynx-api/event/touch-event.html),
+-- is interrupted by the system or Lynx external gesture.
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onTouchCancel HandleTouch ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleTouch TouchEvent {..}) =
+--   io_ (consoleLog "touch event received")
+--
+-- @
+--
+onTouchCancel :: (TouchEvent -> action) -> Attribute model action
+onTouchCancel action = on "touchcancel" touchDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#tap
+--
+-- It belongs to [touch event](https://lynxjs.org/api/lynx-api/event/touch-event.html),
+-- which is triggered when the finger clicks on the touch surface.
+--
+-- @
+-- data Action = HandleTap
+--
+-- view :: context -> props -> Model -> View context Action
+-- view model = view_ [ onTap HandleTap ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update HandleTap = io_ (consoleLog "touch event received")
+--
+-- @
+--
+onTap :: action -> Attribute model action
+onTap action = on "tap" emptyDecoder (\() _ _ -> action)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#tap
+--
+-- It belongs to [touch event](https://lynxjs.org/api/lynx-api/event/touch-event.html),
+-- which is triggered when the finger clicks on the touch surface.
+--
+-- Unlike 'onTap', 'onTapMain' is necessary for handling tap events on the main thread (MTS).
+--
+-- @
+-- data Action = HandleTap
+--
+-- view :: context -> props -> Model -> View context Action
+-- view model = view_ [ event $ static (onTapMain HandleTap) ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update HandleTap = io_ (consoleLog "touch event received")
+--
+-- @
+--
+onTapMain :: action -> EventHandler model action
+onTapMain action = onMain "tap" emptyDecoder (\() _ _ -> action)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#tap
+--
+-- It belongs to [touch event](https://lynxjs.org/api/lynx-api/event/touch-event.html),
+-- which is triggered when the finger clicks on the touch surface.
+--
+-- Unlike 'onTap', 'onTapMain' is necessary for handling tap events on the main thread (MTS).
+--
+-- @
+-- data Action = HandleTap
+--
+-- view :: context -> props -> Model -> View context Action
+-- view model = view_ [ event $ static (onTapMain HandleTap) ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update HandleTap = io_ (consoleLog "touch event received")
+--
+-- @
+--
+onTapMainWith :: (DOMRef -> action) -> EventHandler model action
+onTapMainWith action = onMain "tap" emptyDecoder (\() _ -> action)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#tap
+--
+-- It belongs to [touch event](https://lynxjs.org/api/lynx-api/event/touch-event.html),
+-- which is triggered when the finger clicks on the touch surface.
+--
+-- Unlike 'onTap', 'onTapMain' is necessary for handling tap events on the main thread (MTS).
+--
+-- @
+-- data Action = HandleTap
+--
+-- view :: context -> props -> Model -> View context Action
+-- view model = view_ [ event $ static (onTapMain HandleTap) ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update HandleTap = io_ (consoleLog "touch event received")
+--
+-- @
+--
+onTapMainModel :: (model -> action) -> EventHandler model action
+onTapMainModel action = onMain "tap" emptyDecoder (\() m _ -> action m)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#longpress
+--
+-- It belongs to the touch event, which is triggered when the finger is long
+-- pressed on the touch surface, and the interval between long press triggers is `500 ms`.
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view model = view_ [ onLongPress HandleTouch ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleTouch TouchEvent {..}) = io_ (consoleLog "touch event received")
+--
+-- @
+--
+onLongPress :: (TouchEvent -> action) -> Attribute model action
+onLongPress action = on "longpress" touchDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#layoutchange
+--
+-- It belongs to a [custom event](https://lynxjs.org/api/lynx-api/event/custom-event.html), which is triggered when the target node layout
+-- is completed, and returns the position information of the target node relative
+-- to the LynxView viewport coordinate system.
+--
+-- @
+-- data Action = HandleLayout LayoutChangeDetailEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onLayoutChange HandleLayout ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleLayout LayoutChangeDetailEvent {..}) =
+--   io_ (consoleLog "layout changed")
+-- @
+--
+onLayoutChange :: (LayoutChangeDetailEvent -> action) -> Attribute model action
+onLayoutChange action = on "layoutchange" layoutChangeDetailDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | Like 'onLayoutChange', but for engines that name the event @layout@:
+-- released Lynx builds (e.g. the LynxExplorer apps) emit the layout custom
+-- event as @layout@, while newer sources emit @layoutchange@. Bind both when
+-- the host engine version is not known.
+onLayout :: (LayoutChangeDetailEvent -> action) -> Attribute model action
+onLayout action = on "layout" layoutChangeDetailDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#uiappear
+--
+-- It belongs to custom event, which is triggered when the target node appears on the screen.
+--
+-- @
+-- data Action = HandleUI UIAppearanceDetailEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onAppear HandleUI ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleUI UIAppearanceDetailEvent {..}) = do
+--   io_ (consoleLog "appearance detail event received")
+-- @
+--
+onAppear :: (UIAppearanceDetailEvent -> action) -> Attribute model action
+onAppear action = on "uiappear" uiAppearanceDetailDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#uidisappear
+--
+-- It belongs to custom event, which is triggered when the target node appears on the screen.
+--
+-- @
+-- data Action = HandleUI UIAppearanceDetailEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onDisappear HandleUI ]
+--
+-- update :: Action -> Effect props Model Action
+-- update (HandleUI UIAppearanceDetailEvent {..}) = do
+--   io_ (consoleLog "appearance detail event received")
+-- @
+--
+onDisappear :: (UIAppearanceDetailEvent -> action) -> Attribute model action
+onDisappear action = on "uidisappear" uiAppearanceDetailDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#animationstart
+--
+-- It belongs to [animation event](https://lynxjs.org/api/lynx-api/event/animation-event.html), which is triggered when the Animation animation starts.
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onAnimationStart HandleAnimation ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleAnimation AnimationEvent {..}) =
+--   io_ (consoleLog "animation event received")
+-- @
+--
+onAnimationStart :: (AnimationEvent -> action) -> Attribute model action
+onAnimationStart action = on "animationstart" animationDecoder $ (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#animationend
+--
+-- It belongs to [animation event](https://lynxjs.org/api/lynx-api/event/animation-event.html), which is triggered when the Animation animation ends.
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view model = view_ [ onAnimationEnd HandleAnimation ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleAnimation AnimationEvent {..}) =
+--   io_ (consoleLog "animation event received")
+-- @
+--
+onAnimationEnd :: (AnimationEvent -> action) -> Attribute model action
+onAnimationEnd action = on "animationend" animationDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#animationcancel
+--
+-- It belongs to [animation event](https://lynxjs.org/api/lynx-api/event/animation-event.html), which is triggered when the Animation animation cancels.
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onAnimationCancel HandleAnimation ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleAnimation AnimationEvent {..}) =
+--   io_ (consoleLog "animation event received")
+-- @
+--
+onAnimationCancel :: (AnimationEvent -> action) -> Attribute model action
+onAnimationCancel action = on "animationcancel" animationDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#animationiteration
+--
+-- It belongs to [animation event](https://lynxjs.org/api/lynx-api/event/animation-event.html), which is triggered when the Animation animation iterates.
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onAnimationIteration HandleAnimation ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleAnimation AnimationEvent {..}) =
+--   io_ (consoleLog "animation event received")
+-- @
+--
+onAnimationIteration :: (AnimationEvent -> action) -> Attribute model action
+onAnimationIteration action = on "animationiteration" animationDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#transitionstart
+--
+-- It belongs to [animation event](https://lynxjs.org/api/lynx-api/event/animation-event.html), which is triggered when the Transition animation starts.
+--
+-- @
+-- data Action = HandleTransition AnimationEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onTransitionStart HandleTransition ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleTransition TransitionEvent {..}) =
+--   io_ (consoleLog "transition event received")
+-- @
+--
+onTransitionStart :: (AnimationEvent -> action) -> Attribute model action
+onTransitionStart action = on "transitionstart" animationDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#transitionend
+--
+-- It belongs to [animation event](https://lynxjs.org/api/lynx-api/event/animation-event.html), which is triggered when the Transition animation ends.
+--
+-- @
+-- data Action = HandleTransition AnimationEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onTransitionEnd HandleTransition ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleTransition TransitionEvent {..}) =
+--   io_ (consoleLog "transition event received")
+-- @
+--
+onTransitionEnd :: (AnimationEvent -> action) -> Attribute model action
+onTransitionEnd action = on "transitionend" animationDecoder (\x _ _ -> action x)
+----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#transitioncancel
+--
+-- It belongs to [animation event](https://lynxjs.org/api/lynx-api/event/animation-event.html), which is triggered when the Transition animation cancels.
+--
+-- @
+-- data Action = HandleTransition AnimationEvent
+--
+-- view :: context -> props -> Model -> View context Action
+-- view _ _ model = view_ [ onTransitionCancel HandleTransition ]
+--
+-- update :: Action -> Effect context props Model Action
+-- update (HandleTransition TransitionEvent {..}) =
+--   io_ (consoleLog "transition event received")
+-- @
+--
+onTransitionCancel :: (AnimationEvent -> action) -> Attribute model action
+onTransitionCancel action = on "transitioncancel" animationDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onTouchStart', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onTouchStartWith :: (TouchEvent -> DOMRef -> action) -> Attribute model action
+onTouchStartWith action = on "touchstart" touchDecoder $ \t _ d -> action t d
+-----------------------------------------------------------------------------
+-- | Like 'onTouchMove', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onTouchMoveWith :: (TouchEvent -> DOMRef -> action) -> Attribute model action
+onTouchMoveWith action = on "touchmove" touchDecoder $ \t _ d -> action t d
+-----------------------------------------------------------------------------
+-- | Like 'onTouchEnd', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onTouchEndWith :: (TouchEvent -> DOMRef -> action) -> Attribute model action
+onTouchEndWith action = on "touchend" touchDecoder $ \t _ d -> action t d
+-----------------------------------------------------------------------------
+-- | Like 'onTouchCancel', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onTouchCancelWith :: (TouchEvent -> DOMRef -> action) -> Attribute model action
+onTouchCancelWith action = on "touchcancel" touchDecoder $ \t _ d -> action t d
+-----------------------------------------------------------------------------
+-- | Like 'onTap', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onTapWith :: (DOMRef -> action) -> Attribute model action
+onTapWith action = on "tap" emptyDecoder (\() _ ref -> action ref)
+-----------------------------------------------------------------------------
+-- | Like 'onLongPress', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLongPressWith :: (TouchEvent -> DOMRef -> action) -> Attribute model action
+onLongPressWith action = on "longpress" touchDecoder $ \t _ d -> action t d
+-----------------------------------------------------------------------------
+-- | Like 'onLayoutChange', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLayoutChangeWith :: (LayoutChangeDetailEvent -> DOMRef -> action) -> Attribute model action
+onLayoutChangeWith action = on "layoutchange" layoutChangeDetailDecoder $ \lcde _ domRef -> action lcde domRef
+-----------------------------------------------------------------------------
+-- | Like 'onAppear', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onAppearWith :: (UIAppearanceDetailEvent -> DOMRef -> action) -> Attribute model action
+onAppearWith action = on "uiappear" uiAppearanceDetailDecoder $ \ui _ domRef -> action ui domRef
+-----------------------------------------------------------------------------
+-- | Like 'onDisappear', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onDisappearWith :: (UIAppearanceDetailEvent -> DOMRef -> action) -> Attribute model action
+onDisappearWith action = on "uidisappear" uiAppearanceDetailDecoder $ \ui _ domRef -> action ui domRef
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationStart', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onAnimationStartWith :: (AnimationEvent -> DOMRef -> action) -> Attribute model action
+onAnimationStartWith action = on "animationstart" animationDecoder $ \ui _ domRef -> action ui domRef
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationEnd', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onAnimationEndWith :: (AnimationEvent -> DOMRef -> action) -> Attribute model action
+onAnimationEndWith action = on "animationend" animationDecoder $ \ui _ domRef -> action ui domRef
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationCancel', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onAnimationCancelWith :: (AnimationEvent -> DOMRef -> action) -> Attribute model action
+onAnimationCancelWith action = on "animationcancel" animationDecoder $ \ui _ domRef -> action ui domRef
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationIteration', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onAnimationIterationWith :: (AnimationEvent -> DOMRef -> action) -> Attribute model action
+onAnimationIterationWith action = on "animationiteration" animationDecoder $ \ui _ domRef -> action ui domRef
+-----------------------------------------------------------------------------
+-- | Like 'onTransitionStart', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onTransitionStartWith :: (AnimationEvent -> DOMRef -> action) -> Attribute model action
+onTransitionStartWith action = on "transitionstart" animationDecoder $ \ui _ domRef -> action ui domRef
+-----------------------------------------------------------------------------
+-- | Like 'onTransitionEnd', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onTransitionEndWith :: (AnimationEvent -> DOMRef -> action) -> Attribute model action
+onTransitionEndWith action = on "transitionend" animationDecoder $ \ui _ domRef -> action ui domRef
+-----------------------------------------------------------------------------
+-- | Like 'onTransitionCancel', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onTransitionCancelWith :: (AnimationEvent -> DOMRef -> action) -> Attribute model action
+onTransitionCancelWith action = on "transitioncancel" animationDecoder $ \ui _ domRef -> action ui domRef
+-----------------------------------------------------------------------------
+-- Main-thread (@MTS@) variants of the events above.
+--
+-- Each @on*Main@ is like its background counterpart but dispatched on the Lynx
+-- __main thread__: it runs imperatively (no VDOM diff) and is meant to be used
+-- with @-XStaticPointers@ via @event (static (…))@. Each @on*MainWith@
+-- additionally hands the handler read-only access to the @model@ and the target
+-- element's 'DOMRef' for imperative MTS mutation.
+-----------------------------------------------------------------------------
+-- | Like 'onTouchStart', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view_ [ event (static (onTouchStartMain HandleTouch)) ] [ "some view" ]
+-- @
+--
+onTouchStartMain :: (TouchEvent -> action) -> EventHandler model action
+onTouchStartMain action = onMain "touchstart" touchDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onTouchStartMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleTouch TouchEvent Model DOMRef
+--
+-- view_ [ event (static (onTouchStartMainWith HandleTouch)) ] [ "some view" ]
+-- @
+--
+onTouchStartMainWith :: (TouchEvent -> model -> DOMRef -> action) -> EventHandler model action
+onTouchStartMainWith action = onMain "touchstart" touchDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onTouchMove', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view_ [ event (static (onTouchMoveMain HandleTouch)) ] [ "some view" ]
+-- @
+--
+onTouchMoveMain :: (TouchEvent -> action) -> EventHandler model action
+onTouchMoveMain action = onMain "touchmove" touchDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onTouchMoveMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleTouch TouchEvent Model DOMRef
+--
+-- view_ [ event (static (onTouchMoveMainWith HandleTouch)) ] [ "some view" ]
+-- @
+--
+onTouchMoveMainWith :: (TouchEvent -> model -> DOMRef -> action) -> EventHandler model action
+onTouchMoveMainWith action = onMain "touchmove" touchDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onTouchEnd', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view_ [ event (static (onTouchEndMain HandleTouch)) ] [ "some view" ]
+-- @
+--
+onTouchEndMain :: (TouchEvent -> action) -> EventHandler model action
+onTouchEndMain action = onMain "touchend" touchDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onTouchEndMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleTouch TouchEvent Model DOMRef
+--
+-- view_ [ event (static (onTouchEndMainWith HandleTouch)) ] [ "some view" ]
+-- @
+--
+onTouchEndMainWith :: (TouchEvent -> model -> DOMRef -> action) -> EventHandler model action
+onTouchEndMainWith action = onMain "touchend" touchDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onTouchCancel', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view_ [ event (static (onTouchCancelMain HandleTouch)) ] [ "some view" ]
+-- @
+--
+onTouchCancelMain :: (TouchEvent -> action) -> EventHandler model action
+onTouchCancelMain action = onMain "touchcancel" touchDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onTouchCancelMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleTouch TouchEvent Model DOMRef
+--
+-- view_ [ event (static (onTouchCancelMainWith HandleTouch)) ] [ "some view" ]
+-- @
+--
+onTouchCancelMainWith :: (TouchEvent -> model -> DOMRef -> action) -> EventHandler model action
+onTouchCancelMainWith action = onMain "touchcancel" touchDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onLongPress', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleTouch TouchEvent
+--
+-- view_ [ event (static (onLongPressMain HandleTouch)) ] [ "some view" ]
+-- @
+--
+onLongPressMain :: (TouchEvent -> action) -> EventHandler model action
+onLongPressMain action = onMain "longpress" touchDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onLongPressMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleTouch TouchEvent Model DOMRef
+--
+-- view_ [ event (static (onLongPressMainWith HandleTouch)) ] [ "some view" ]
+-- @
+--
+onLongPressMainWith :: (TouchEvent -> model -> DOMRef -> action) -> EventHandler model action
+onLongPressMainWith action = onMain "longpress" touchDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onLayoutChange', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleLayout LayoutChangeDetailEvent
+--
+-- view_ [ event (static (onLayoutChangeMain HandleLayout)) ] [ "some view" ]
+-- @
+--
+onLayoutChangeMain :: (LayoutChangeDetailEvent -> action) -> EventHandler model action
+onLayoutChangeMain action = onMain "layoutchange" layoutChangeDetailDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onLayoutChangeMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleLayout LayoutChangeDetailEvent Model DOMRef
+--
+-- view_ [ event (static (onLayoutChangeMainWith HandleLayout)) ] [ "some view" ]
+-- @
+--
+onLayoutChangeMainWith :: (LayoutChangeDetailEvent -> model -> DOMRef -> action) -> EventHandler model action
+onLayoutChangeMainWith action = onMain "layoutchange" layoutChangeDetailDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onLayoutChangeMainWith', but for engines that name the event
+-- @layout@ (see 'onLayout').
+onLayoutMainWith :: (LayoutChangeDetailEvent -> model -> DOMRef -> action) -> EventHandler model action
+onLayoutMainWith action = onMain "layout" layoutChangeDetailDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onAppear', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleAppear UIAppearanceDetailEvent
+--
+-- view_ [ event (static (onAppearMain HandleAppear)) ] [ "some view" ]
+-- @
+--
+onAppearMain :: (UIAppearanceDetailEvent -> action) -> EventHandler model action
+onAppearMain action = onMain "uiappear" uiAppearanceDetailDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onAppearMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleAppear UIAppearanceDetailEvent Model DOMRef
+--
+-- view_ [ event (static (onAppearMainWith HandleAppear)) ] [ "some view" ]
+-- @
+--
+onAppearMainWith :: (UIAppearanceDetailEvent -> model -> DOMRef -> action) -> EventHandler model action
+onAppearMainWith action = onMain "uiappear" uiAppearanceDetailDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onDisappear', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleDisappear UIAppearanceDetailEvent
+--
+-- view_ [ event (static (onDisappearMain HandleDisappear)) ] [ "some view" ]
+-- @
+--
+onDisappearMain :: (UIAppearanceDetailEvent -> action) -> EventHandler model action
+onDisappearMain action = onMain "uidisappear" uiAppearanceDetailDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onDisappearMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleDisappear UIAppearanceDetailEvent Model DOMRef
+--
+-- view_ [ event (static (onDisappearMainWith HandleDisappear)) ] [ "some view" ]
+-- @
+--
+onDisappearMainWith :: (UIAppearanceDetailEvent -> model -> DOMRef -> action) -> EventHandler model action
+onDisappearMainWith action = onMain "uidisappear" uiAppearanceDetailDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationStart', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent
+--
+-- view_ [ event (static (onAnimationStartMain HandleAnimation)) ] [ "some view" ]
+-- @
+--
+onAnimationStartMain :: (AnimationEvent -> action) -> EventHandler model action
+onAnimationStartMain action = onMain "animationstart" animationDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationStartMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent Model DOMRef
+--
+-- view_ [ event (static (onAnimationStartMainWith HandleAnimation)) ] [ "some view" ]
+-- @
+--
+onAnimationStartMainWith :: (AnimationEvent -> model -> DOMRef -> action) -> EventHandler model action
+onAnimationStartMainWith action = onMain "animationstart" animationDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationEnd', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent
+--
+-- view_ [ event (static (onAnimationEndMain HandleAnimation)) ] [ "some view" ]
+-- @
+--
+onAnimationEndMain :: (AnimationEvent -> action) -> EventHandler model action
+onAnimationEndMain action = onMain "animationend" animationDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationEndMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent Model DOMRef
+--
+-- view_ [ event (static (onAnimationEndMainWith HandleAnimation)) ] [ "some view" ]
+-- @
+--
+onAnimationEndMainWith :: (AnimationEvent -> model -> DOMRef -> action) -> EventHandler model action
+onAnimationEndMainWith action = onMain "animationend" animationDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationCancel', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent
+--
+-- view_ [ event (static (onAnimationCancelMain HandleAnimation)) ] [ "some view" ]
+-- @
+--
+onAnimationCancelMain :: (AnimationEvent -> action) -> EventHandler model action
+onAnimationCancelMain action = onMain "animationcancel" animationDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationCancelMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent Model DOMRef
+--
+-- view_ [ event (static (onAnimationCancelMainWith HandleAnimation)) ] [ "some view" ]
+-- @
+--
+onAnimationCancelMainWith :: (AnimationEvent -> model -> DOMRef -> action) -> EventHandler model action
+onAnimationCancelMainWith action = onMain "animationcancel" animationDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationIteration', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent
+--
+-- view_ [ event (static (onAnimationIterationMain HandleAnimation)) ] [ "some view" ]
+-- @
+--
+onAnimationIterationMain :: (AnimationEvent -> action) -> EventHandler model action
+onAnimationIterationMain action = onMain "animationiteration" animationDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onAnimationIterationMain', but also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleAnimation AnimationEvent Model DOMRef
+--
+-- view_ [ event (static (onAnimationIterationMainWith HandleAnimation)) ] [ "some view" ]
+-- @
+--
+onAnimationIterationMainWith :: (AnimationEvent -> model -> DOMRef -> action) -> EventHandler model action
+onAnimationIterationMainWith action = onMain "animationiteration" animationDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onTransitionStart', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleTransition AnimationEvent
+--
+-- view_ [ event (static (onTransitionStartMain HandleTransition)) ] [ "some view" ]
+-- @
+--
+onTransitionStartMain :: (AnimationEvent -> action) -> EventHandler model action
+onTransitionStartMain action = onMain "transitionstart" animationDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onTransitionStartMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleTransition AnimationEvent Model DOMRef
+--
+-- view_ [ event (static (onTransitionStartMainWith HandleTransition)) ] [ "some view" ]
+-- @
+--
+onTransitionStartMainWith :: (AnimationEvent -> model -> DOMRef -> action) -> EventHandler model action
+onTransitionStartMainWith action = onMain "transitionstart" animationDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onTransitionEnd', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleTransition AnimationEvent
+--
+-- view_ [ event (static (onTransitionEndMain HandleTransition)) ] [ "some view" ]
+-- @
+--
+onTransitionEndMain :: (AnimationEvent -> action) -> EventHandler model action
+onTransitionEndMain action = onMain "transitionend" animationDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onTransitionEndMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleTransition AnimationEvent Model DOMRef
+--
+-- view_ [ event (static (onTransitionEndMainWith HandleTransition)) ] [ "some view" ]
+-- @
+--
+onTransitionEndMainWith :: (AnimationEvent -> model -> DOMRef -> action) -> EventHandler model action
+onTransitionEndMainWith action = onMain "transitionend" animationDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onTransitionCancel', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- @
+-- data Action = HandleTransition AnimationEvent
+--
+-- view_ [ event (static (onTransitionCancelMain HandleTransition)) ] [ "some view" ]
+-- @
+--
+onTransitionCancelMain :: (AnimationEvent -> action) -> EventHandler model action
+onTransitionCancelMain action = onMain "transitioncancel" animationDecoder (\x _ _ -> action x)
+-----------------------------------------------------------------------------
+-- | Like 'onTransitionCancelMain', but also receives read-only access to the @model@
+-- and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = HandleTransition AnimationEvent Model DOMRef
+--
+-- view_ [ event (static (onTransitionCancelMainWith HandleTransition)) ] [ "some view" ]
+-- @
+--
+onTransitionCancelMainWith :: (AnimationEvent -> model -> DOMRef -> action) -> EventHandler model action
+onTransitionCancelMainWith action = onMain "transitioncancel" animationDecoder action
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/View/Method.hs b/src/Miso/Native/Element/View/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/View/Method.hs
@@ -0,0 +1,202 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE RecordWildCards     #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications    #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.View.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.View.Method
+  ( -- *** Methods
+    boundingClientRect
+  , takeScreenshot
+  , requestAccessibilityFocus
+  -- *** Types
+  , Rect (..)
+  , BoundingClientRect (..)
+  , TakeScreenshot (..)
+  -- *** Smart constructors
+  , defaultBoundingClientRect
+  , defaultTakeScreenshot
+  ) where
+-----------------------------------------------------------------------------
+import Miso
+import Miso.Native.FFI
+-----------------------------------------------------------------------------
+-- | Result of calling @getClientBoundingRect@
+data Rect
+  = Rect
+  { x,y :: Double
+  , width, height :: Double
+  , top, bottom :: Double
+  , right, left :: Double
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal Rect where
+  fromJSVal = \rect -> do
+    let readProp = \name ->
+          fromJSValUnchecked =<<
+            rect ! (name :: MisoString)
+    x      <- readProp "x"
+    y      <- readProp "y"
+    height <- readProp "height"
+    width  <- readProp "width"
+    top    <- readProp "top"
+    right  <- readProp "right"
+    left   <- readProp "left"
+    bottom <- readProp "bottom"
+    pure $ Just Rect {..}
+-----------------------------------------------------------------------------
+-- | Parameters for @getBoundingClientRect@: whether to honour @transform@
+-- on Android, and which node to measure relative to.
+-- 
+-- @since 1.13.0.0
+data BoundingClientRect
+  = BoundingClientRect
+  { androidEnableTransformProps :: Bool
+  -- ^ Specifies whether to consider the transform attribute
+  -- when calculating the position on Android. The default value is @False@
+  , relativeTo :: Maybe JSVal
+  -- ^ Specify the reference node, relative to LynxView by default.
+  }
+-----------------------------------------------------------------------------
+instance ToJSVal BoundingClientRect where
+  toJSVal BoundingClientRect {..} = do
+    o <- create
+    set "androidEnableTransformProps" androidEnableTransformProps o
+    set "relativeTo" relativeTo o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | Smart constructor for constructing 'boundingClientRect'
+defaultBoundingClientRect :: BoundingClientRect
+defaultBoundingClientRect
+  = BoundingClientRect
+  { androidEnableTransformProps = False
+  , relativeTo = Nothing
+  }
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#boundingclientrect
+--
+-- The front end can execute 'boundingClientRect' through the SelectorQuery API.
+--
+-- @
+--
+-- data Action
+--   = Success Rect
+--   | Failure MisoString
+--   | GetRect
+--
+-- update :: Action -> Effect props model Action
+-- update = \\case
+--   GetRect ->
+--     boundingClientRect defaultBoundingClientRect "#box" Success Failure
+--   Succes Rect {..} ->
+--     consoleLog "Successfuly got Rect"
+--   Failure errorMsg ->
+--     consoleLog ("Failed to call getClientBoundingRect: " <> errorMsg)
+--
+-- @
+--
+boundingClientRect
+  :: MisoString
+  -> BoundingClientRect
+  -> (Rect -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+boundingClientRect = invokeExec "boundingClientRect"
+-----------------------------------------------------------------------------
+-- | Parameters for 'takeScreenshot': the image @format@ and a @scale@ in
+-- @(0, 1]@ trading quality for size.
+-- 
+-- @since 1.13.0.0
+data TakeScreenshot
+  = TakeScreenshot
+  { format :: MisoString
+  -- ^ e.g. Specify the image format, supports jpeg and png, the default is jpeg
+  , scale :: Double
+  -- ^ e.g. Specify the image quality, 0 < scale <= 1, the default is 1,
+  -- the smaller the value, the blurrier and smaller the size.
+  }
+-----------------------------------------------------------------------------
+instance ToJSVal TakeScreenshot where
+  toJSVal TakeScreenshot {..} = do
+    o <- create
+    set "format" format o
+    set "scale" scale o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#takescreenshot
+--
+-- The front end can execute 'takeScreenshot' through the SelectorQuery API.
+--
+-- @
+--
+-- data Action
+--   = Success Image
+--   | Failure MisoString
+--   | GetScreenshot
+--
+-- update :: Action -> Effect props model Action
+-- update = \\case
+--   GetScreenshot ->
+--     takeScreenshot defaultTakeScreenshot "#my-view" Success Failure
+--   Succes image -> do
+--     consoleLog "Successfuly got image"
+--     consoleLog' image
+--   Failure errorMsg ->
+--     consoleLog ("Failed to call takeScreenshot: " <> errorMsg)
+--
+-- @
+--
+takeScreenshot
+  :: MisoString
+  -> TakeScreenshot
+  -> (JSVal -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+takeScreenshot = invokeExec "takeScreenshot"
+-----------------------------------------------------------------------------
+-- | Smart constructor for calling t'TakeScreenshot'
+defaultTakeScreenshot :: TakeScreenshot
+defaultTakeScreenshot
+  = TakeScreenshot
+  { scale = 1
+  , format = "jpeg"
+  }
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#requestaccessibilityfocus
+--
+-- The front end can execute @requestAccessiblityFocus@ through the SelectorQuery API.
+--
+-- @
+--
+-- data Action
+--   = Success
+--   | Failure MisoString
+--   | GetFocus
+--
+-- update :: Action -> Effect props model Action
+-- update = \\case
+--   GetFocus -> requestAccessibilityFocus "#my-view" Success Failure
+--   Success -> consoleLog "Successfuly got focus"
+--   Failure errorMsg ->
+--     consoleLog ("Failed to call requestAccessibilityFocus: " <> errorMsg)
+--
+-- @
+--
+requestAccessibilityFocus
+  :: MisoString
+  -> (JSVal -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+requestAccessibilityFocus selector =
+  invokeExec "requestAccessibilityFocus" selector ()
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Element/View/Property.hs b/src/Miso/Native/Element/View/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Element/View/Property.hs
@@ -0,0 +1,540 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Element.View.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Element.View.Property
+  ( -- *** Property
+    id_
+  , name_
+  , className_
+  , flatten_
+  , exposureId_
+  , exposureScene_
+  , exposeUIMarginTop_
+  , exposeUIMarginBottom_
+  , exposeUIMarginLeft_
+  , exposeUIMarginRight_
+  , exposeScreenMarginTop_
+  , exposeScreenMarginBottom_
+  , exposeScreenMarginLeft_
+  , exposeScreenMarginRight_
+  , exposureArea_
+  , enableExposureUIMargin_
+  , enableExposureUIClip_
+  , accessibilityElement_
+  , accessibilityLabel_
+  , accessibilityTrait_
+  , accessibilityElements_
+  , accessibilityElementsA11y_
+  , accessibilityElementsHidden_
+  , accessibilityExclusiveFocus_
+  , a11yId_
+  , iosPlatformAccessibilityId_
+  , userInteractionEnabled_
+  , nativeInteractionEnabled_
+  , panInterceptDirection_
+  , panInterceptScope_
+  , blockNativeEvent_
+  , blockNativeEventAreas_
+  , consumeSlideEvent_
+  , eventThroughActiveRegions_
+  , enableTouchPseudoPropagation_
+  , hitSlop_
+  , ignoreFocus_
+  , eventThrough_
+  , iosEnableSimultaneousTouch_
+  , lynxTimingFlag_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.Property
+import           Miso.Types
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#id
+--
+-- Used to specify the name of the element, generally for native to operate the corresponding node from the native side through @findViewByName@.
+--
+-- > id_ "test"
+--
+id_ :: MisoString -> Attribute model action
+id_ = textProp "id"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#name
+--
+-- Used to specify the name of the element, generally for native to operate the corresponding node from the native side through @findViewByName@.
+--
+-- > name_ "test"
+--
+name_ :: MisoString -> Attribute model action
+name_ = textProp "name"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#classname
+--
+-- Use `className` to set CSS class names, equivalent to 'Miso.Html.Property.class_'
+--
+-- > className_ "foo"
+--
+className_ :: MisoString -> Attribute model action
+className_ = textProp "className"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#flatten
+--
+-- *Android* only
+--
+-- Only available on Android platform, used to force specific nodes to create
+-- corresponding Android Views.
+--
+-- > flatten_ True
+--
+flatten_ :: Bool -> Attribute model action
+flatten_ = boolProp "flatten"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-id
+--
+-- Specify whether the target node needs to listen to [exposure/anti-exposure](https://lynxjs.org/guide/interaction/visibility-detection/exposure-ability.html#monitor-exposure-of-the-entire-page) events.
+--
+-- > exposureId_ "id-goes-here"
+--
+exposureId_ :: MisoString -> Attribute model action
+exposureId_ = textProp "exposure-id"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-scene
+--
+-- Specify the exposure scene of the target node, and use it together with
+-- 'exposureId_' to uniquely identify the node that needs to monitor exposure.
+--
+-- > exposureScene_ "example-scene"
+--
+exposureScene_ :: MisoString -> Attribute model action
+exposureScene_ = textProp "exposure-scene"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-ui-margin-
+--
+-- Specify the boundary scaling value of the target node itself in the exposure
+-- detection, which affects the viewport intersection judgment of the target node.
+-- Each node can have its own boundary scaling value.
+--
+-- > exposeUIMarginTop_ "10px"
+--
+-- Default Value: "0px"
+--
+exposeUIMarginTop_ :: MisoString -> Attribute model action
+exposeUIMarginTop_ = textProp "exposure-ui-margin-top"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-ui-margin-
+--
+-- Specify the boundary scaling value of the target node itself in the exposure
+-- detection, which affects the viewport intersection judgment of the target node.
+-- Each node can have its own boundary scaling value.
+--
+-- > exposeUIMarginBottom_ "10px"
+--
+-- Default Value: "0px"
+--
+exposeUIMarginBottom_ :: MisoString -> Attribute model action
+exposeUIMarginBottom_ = textProp "exposure-ui-margin-bottom"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-ui-margin-
+--
+-- Specify the boundary scaling value of the target node itself in the exposure
+-- detection, which affects the viewport intersection judgment of the target node.
+-- Each node can have its own boundary scaling value.
+--
+-- > exposeUIMarginLeft_ "10px"
+--
+-- Default Value: "0px"
+--
+exposeUIMarginLeft_ :: MisoString -> Attribute model action
+exposeUIMarginLeft_ = textProp "exposure-ui-margin-left"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-ui-margin-
+--
+-- Specify the boundary scaling value of the target node itself in the exposure
+-- detection, which affects the viewport intersection judgment of the target node.
+-- Each node can have its own boundary scaling value.
+--
+-- > exposeUIMarginRight_ "10px"
+--
+-- Default Value: "0px"
+--
+-----------------------------------------------------------------------------
+exposeUIMarginRight_ :: MisoString -> Attribute model action
+exposeUIMarginRight_ = textProp "exposure-ui-margin-right"
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-screen-margin-
+--
+-- Specify the boundary scaling value of the target node itself in the exposure
+-- detection, which affects the viewport intersection judgment of the target node.
+-- Each node can have its own boundary scaling value.
+--
+-- > exposeUIMarginTop_ "10px"
+--
+-- Default Value: "0px"
+--
+exposeScreenMarginTop_ :: MisoString -> Attribute model action
+exposeScreenMarginTop_ = textProp "exposure-screen-margin-top"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-screen-margin-
+--
+-- Specify the boundary scaling value of the target node itself in the exposure
+-- detection, which affects the viewport intersection judgment of the target node.
+-- Each node can have its own boundary scaling value.
+--
+-- > exposeScreenMarginBottom_ "10px"
+--
+-- Default Value: "0px"
+--
+exposeScreenMarginBottom_ :: MisoString -> Attribute model action
+exposeScreenMarginBottom_ = textProp "exposure-screen-margin-bottom"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-screen-margin-
+--
+-- Specify the boundary scaling value of the target node itself in the exposure
+-- detection, which affects the viewport intersection judgment of the target node.
+-- Each node can have its own boundary scaling value.
+--
+-- > exposeScreenMarginLeft_ "10px"
+--
+-- Default Value: "0px"
+--
+exposeScreenMarginLeft_ :: MisoString -> Attribute model action
+exposeScreenMarginLeft_ = textProp "exposure-screen-margin-left"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-screen-margin-
+--
+-- Specify the boundary scaling value of the target node itself in the exposure
+-- detection, which affects the viewport intersection judgment of the target node.
+-- Each node can have its own boundary scaling value.
+--
+-- > exposeScreenMarginRight_ "10px"
+--
+-- Default Value: "0px"
+--
+exposeScreenMarginRight_ :: MisoString -> Attribute model action
+exposeScreenMarginRight_ = textProp "exposure-screen-margin-right"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#exposure-area
+--
+-- Specify the viewport intersection ratio of the target node that can trigger
+-- the exposure event. When it is greater than this ratio, the exposure event
+-- is triggered. When it is less than this ratio, the reverse exposure event
+-- is triggered. By default, the exposure event is triggered when the target
+-- node is exposed.
+--
+-- > exposureArea_ (pct 10)
+--
+-- Default Value: "0%"
+--
+exposureArea_ :: MisoString -> Attribute model action
+exposureArea_ = textProp "exposure-area"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#enable-exposure-ui-margin
+--
+-- Specify whether the target node supports the [exposure-ui-margin-*](https://lynxjs.org/api/elements/built-in/view.html#exposure-ui-margin-) properties.
+--
+-- Setting it to true will change the behavior of [exposure-screen-margin-*](https://lynxjs.org/api/elements/built-in/view.html#exposure-screen-margin-) and may cause the lazy loading of the scrollable container to fail.
+--
+-- > enableExposureUIMargin_ True
+--
+-- Default Value: @False@
+--
+enableExposureUIMargin_ :: Bool -> Attribute model action
+enableExposureUIMargin_ = boolProp "enable-exposure-ui-margin"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#enable-exposure-ui-clip
+--
+-- Specify whether the exposure detection task takes into account the viewport
+-- clipping of the parent node.
+--
+-- > enableExposureUIClip_ True
+--
+-- Default Value: @False@
+--
+enableExposureUIClip_ :: Bool -> Attribute model action
+enableExposureUIClip_ = boolProp "enable-exposure-ui-clip"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#accessibility-element
+--
+-- Set whether the node supports accessibility.
+--
+-- > accessibilityElement_ True
+--
+accessibilityElement_ :: Bool -> Attribute model action
+accessibilityElement_ = boolProp "accessibility-element"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#accessibility-label
+--
+-- Set the content of the node voice broadcast.
+--
+-- If the \<text\> node does not set this attribute, the \<text\> node defaults to the \<text\> content.
+--
+-- > accessibilityLabel_ "some-label"
+--
+accessibilityLabel_ :: MisoString -> Attribute model action
+accessibilityLabel_ = textProp "accessibility-label"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#accessibility-trait
+--
+-- Set the type characteristics of the node. The system will have specific
+-- supplements to the playback content for different types of nodes.
+--
+-- > accessibilityTrait_ "button"
+--
+-- Default Value: "button"
+--
+accessibilityTrait_ :: MisoString -> Attribute model action
+accessibilityTrait_ = textProp "accessibility-trait"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#accessibility-elements
+--
+-- Customize the focus order of child nodes. This property is set on the parent node,
+-- and the focus order of its child nodes will be focused according to the
+-- order of the child node `id` specified by the `accessibility-elements` property.
+--
+-- > accessibilityElements_ "view-3,view-2,view-5,view-1,view-4"
+--
+accessibilityElements_ :: MisoString -> Attribute model action
+accessibilityElements_ = textProp "accessibility-elements"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#accessibility-elements-a11y
+--
+-- The same as @accessibilityElements_@, but the corresponding @id_@ is @a11yId_@.
+--
+-- > accessibilityElementsA11y_ "id"
+--
+accessibilityElementsA11y_ :: MisoString -> Attribute model action
+accessibilityElementsA11y_ = textProp "accessibility-elements-a11y"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#accessibility-exclusive-hidden
+--
+-- Marks the current node and all its child nodes as non-accessible nodes.
+--
+-- > accessibilityElementsHidden_ True
+--
+-- Default Value: 'False'
+--
+accessibilityElementsHidden_ :: Bool -> Attribute model action
+accessibilityElementsHidden_ = boolProp "accessibility-elements-hidden"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#accessibility-exclusive-focus
+--
+-- This property can be set for any node. In accessibility mode, sequential navigation will only focus on the child nodes under these nodes.
+--
+-- > accessibilityExclusiveFocus_ True
+--
+-- Default Value: 'False'
+--
+accessibilityExclusiveFocus_ :: Bool -> Attribute model action
+accessibilityExclusiveFocus_ = boolProp "accessibility-exclusive-focus"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#a11y-id
+--
+-- Different from `id`, it is used to identify barrier-free nodes separately.
+--
+-- > a11yId_ "test"
+--
+a11yId_ :: MisoString -> Attribute model action
+a11yId_ = textProp "a11y-id"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#ios-platform-accessibility-id
+--
+-- Used to specify the accessibility identifier of a @UIView@ in *iOS*. It is
+-- only used when the platform-level accessibility framework is accessed.
+--
+-- > iosPlatformAccessibilityId_ "view-3"
+--
+iosPlatformAccessibilityId_ :: MisoString -> Attribute model action
+iosPlatformAccessibilityId_ = textProp "ios-platform-accessibility-id"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#user-interaction-enabled
+--
+-- Specifies whether the target node and its child nodes can respond to Lynx touch events.
+-- This property does not affect platform-level gestures (such as scrolling of scroll-view).
+--
+-- > userInteractionEnabled_ False
+--
+-- Default Value: 'True'
+--
+userInteractionEnabled_ :: Bool -> Attribute model action
+userInteractionEnabled_ = boolProp "user-interaction-enabled"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#native-interaction-enabled
+--
+--
+-- Specify whether the target node consumes platform-layer touch events, affects
+-- platform-layer gestures (such as scrolling of scroll-view), does not affect
+-- Lynx touch events, and can achieve similar platform-layer gesture
+-- penetration/interception effects.
+--
+-- > nativeInteractionEnabled_ True
+--
+-- Default Value: 'True' for *iOS*, @False@ for *Android*
+--
+nativeInteractionEnabled_ :: Bool -> Attribute model action
+nativeInteractionEnabled_ = boolProp "native-interaction-enabled"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#pan-intercept-direction
+--
+-- Specify which direction to block platform-layer swipe gestures.
+--
+-- > panInterceptDirection_ "horizontal"
+--
+-- Default Value: "none"
+--
+panInterceptDirection_ :: MisoString -> Attribute model action
+panInterceptDirection_ = textProp "pan-intercept-direction"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#pan-intercept-scope
+--
+-- Specify the scope within which platform-layer swipe gestures in a particular
+-- direction will be blocked.
+--
+-- > panInterceptScope_ "none"
+--
+-- Default Value: "none"
+--
+panInterceptScope_ :: MisoString -> Attribute model action
+panInterceptScope_ = textProp "pan-intercept-scope"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#block-native-event
+--
+-- Specify whether to block platform layer gestures outside Lynx when the
+-- target node is on the event response chain, which can achieve an effect
+-- similar to blocking the platform layer side sliding back.
+--
+-- > blockNativeEvent True
+--
+-- Default Value: @False@
+--
+blockNativeEvent_ :: Bool -> Attribute model action
+blockNativeEvent_ = boolProp "block-native-event"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#block-native-event-areas
+--
+-- Specify whether to block platform layer gestures outside Lynx when the target node is on the [eventAreas response chain](../../../guide/interaction/eventAreas-handling/eventAreas-propagation.mdx#eventAreas-response-chain), which can achieve an effect similar to blocking the platform layer side sliding back.
+--
+-- > blockNativeEventAreas_ []
+--
+-- Default Value: []
+--
+blockNativeEventAreas_ :: [Int] -> Attribute model action
+blockNativeEventAreas_ = prop "block-native-event-areas"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#consume-slide-event
+--
+-- Specify the target node to slide a specific angle on the
+-- [event response chain](https://lynxjs.org/api/elements/built-in/view.html#consume-slide-event),
+-- whether the platform layer gesture responds, does not affect the touch event
+-- of Lynx, and can realize a front-end scrolling container similar to consuming
+-- the specified direction of sliding.
+--
+-- Each pair is a @(start, end)@ angle range in degrees (0° along the positive
+-- x-axis, valid range -180°–180°); slides at those angles are consumed by this
+-- node instead of the platform scroller. E.g. a horizontal pager inside a
+-- vertical @scroll-view@ (leftward slides sit at ±180°, so both flanks are
+-- needed):
+--
+-- > consumeSlideEvent_ [(-180, -135), (-45, 45), (135, 180)]
+--
+-- Default Value: []
+--
+consumeSlideEvent_ :: [(Double, Double)] -> Attribute model action
+consumeSlideEvent_ = prop "consume-slide-event"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#event-through
+--
+-- Specifies whether the touch event of the platform layer is distributed to Lynx
+-- when the touch is on the target node, which can achieve a similar effect of
+-- only displaying without interaction. This property supports inheritance.
+--
+-- > eventThrough_ True
+--
+-- Default Value: @False@
+--
+eventThrough_ :: Bool -> Attribute model action
+eventThrough_ = boolProp "event-through"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#event-through-active-regions
+--
+-- Specify the effective area for 'eventThrough_' functionality, given as a list
+-- of @[x, y, width, height]@ rectangles (values in px or %).
+--
+-- > eventThroughActiveRegions_ [[0,0,100,100]]
+--
+-- Default Value: []
+--
+eventThroughActiveRegions_ :: [[Double]] -> Attribute model action
+eventThroughActiveRegions_ = prop "event-through-active-regions"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#enable-touch-pseudo-propagation
+--
+-- Specify whether the target node supports the :active pseudo-class to continue bubbling
+-- up on the [event response chain](https://lynxjs.org/guide/interaction/event-handling/event-propagation.html#event-response-chain,platform=ios).
+--
+-- > enableTouchPseudoPropagation_ True
+--
+-- Default Value: @False@
+--
+enableTouchPseudoPropagation_ :: Bool -> Attribute model action
+enableTouchPseudoPropagation_ = boolProp "enable-touch-pseudo-propagation"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#hit-slop
+--
+-- Specify the touch event response hotspot of the target node, without
+-- affecting the platform layer gesture.
+--
+-- > hitSlop_ "0px"
+--
+-- Default Value: "0px"
+--
+hitSlop_ :: MisoString -> Attribute model action
+hitSlop_ = textProp "hit-slop"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#ignore-focus
+--
+-- Specify whether to not grab focus when touching the target node. By default,
+-- the node grabs focus when clicking on it, which can achieve a similar effect
+-- of not closing the keyboard when clicking other areas.
+--
+-- In addition, it also supports inheritance, that is, the default value of the
+-- child node is the ignore-focus value of the parent node, and the child node
+-- can override this value.
+--
+-- > ignoreFocus_ True
+--
+-- Default Value: 'False
+--
+ignoreFocus_ :: Bool -> Attribute model action
+ignoreFocus_ = boolProp "ignore-focus"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#ios-enable-simultaneous-touch
+--
+-- *iOS* only
+--
+-- > iosEnableSimultaneousTouch_ True
+--
+-- Default Value: @False@
+--
+iosEnableSimultaneousTouch_ :: Bool -> Attribute model action
+iosEnableSimultaneousTouch_ = boolProp "ios-enable-simultaneous-touch"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/view.html#__lynx_timing_flag
+--
+-- Add this flag to the current element to monitor the performance of the
+-- lynx pipeline it participates in. When flagged, the lynx engine generates
+-- a PipelineEntry event once the element completes its final painting phase.
+-- This event can be observed and analyzed by registering a PerformanceObserver().
+-- For more detailed usage, see the Marking Lynx Pipeline.
+--
+-- > lynxTimingFlag_ "test"
+--
+lynxTimingFlag_ :: MisoString -> Attribute model action
+lynxTimingFlag_ = textProp "__lynx_timing_flag"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Event.hs b/src/Miso/Native/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Event.hs
@@ -0,0 +1,72 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Event
+  ( -- * Events
+    nativeEvents
+  , nativeXEvents
+  ) where
+----------------------------------------------------------------------------
+import           Miso.Native.Element.Frame.Event      (frameEvents)
+import           Miso.Native.Element.Image.Event      (imageEvents)
+import           Miso.Native.Element.List.Event       (listEvents)
+import           Miso.Native.Element.ScrollView.Event (scrollViewEvents)
+import           Miso.Native.Element.Text.Event       (textEvents)
+import           Miso.Native.Element.View.Event       (viewEvents)
+----------------------------------------------------------------------------
+import           Miso.Native.X.Element.Input.Event    (inputEvents)
+import           Miso.Native.X.Element.Overlay.Event  (overlayEvents)
+import           Miso.Native.X.Element.Refresh.Event  (refreshEvents)
+import           Miso.Native.X.Element.ScrollCoordinator.Event (scrollCoordinatorEvents)
+import           Miso.Native.X.Element.Svg.Event      (svgEvents)
+import           Miso.Native.X.Element.Textarea.Event (textareaEvents)
+import           Miso.Native.X.Element.Viewpager.Event (viewpagerEvents)
+import           Miso.Native.X.Element.Webview.Event  (webviewEvents)
+----------------------------------------------------------------------------
+import           Miso.Event                           (Events)
+----------------------------------------------------------------------------
+-- | The combined 'Events' map for every built-in Lynx element.
+--
+-- Pass it to 'Miso.Native.native'; combine maps with @<>@ when an app
+-- needs both.
+--
+-- @since 1.13.0.0
+nativeEvents :: Events
+nativeEvents = mconcat
+  [ frameEvents
+  , imageEvents
+  , listEvents
+  , scrollViewEvents
+  , textEvents
+  , viewEvents
+  ]
+----------------------------------------------------------------------------
+-- | The combined 'Events' map for every extended (@x-@ namespace) Lynx element.
+--
+-- Pass it to 'Miso.Native.native'; combine maps with @<>@ when an app
+-- needs both.
+--
+-- @since 1.13.0.0
+nativeXEvents :: Events
+nativeXEvents = mconcat
+  [ inputEvents
+  , overlayEvents
+  , refreshEvents
+  , scrollCoordinatorEvents
+  , svgEvents
+  , textareaEvents
+  , viewpagerEvents
+  , webviewEvents
+  ]
+----------------------------------------------------------------------------
diff --git a/src/Miso/Native/FFI.hs b/src/Miso/Native/FFI.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/FFI.hs
@@ -0,0 +1,110 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.FFI
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.FFI
+  ( -- *** Lynx specific FFI
+    setInterval
+  , clearInterval
+  , invokeExec
+  , enableDebugging
+  ) where
+----------------------------------------------------------------------------
+import Control.Monad
+-----------------------------------------------------------------------------
+import Miso
+-----------------------------------------------------------------------------
+-- | Turn on the native console→syslog bridge for on-device debugging.
+--
+-- On a physical device, background-thread @console.*@ output is not printed to
+-- the platform log (iOS syslog / Android logcat) without a LynxDevTool
+-- connection. After calling this, every 'Miso.FFI.consoleError' (and any other
+-- @console.error@) is mirrored — prefixed @[miso]@ — through
+-- @lynx.reportError@, which the host /does/ surface in the device log. Grep for
+-- @[miso]@ in @idevicesyslog@ (iOS) or @adb logcat@ (Android).
+--
+-- Sets @globalThis.debug = true@; the bridge checks that flag per line, so this
+-- takes effect immediately even though it runs after startup. Enable it early
+-- (e.g. at the top of @main@) to capture diagnostics from the whole session.
+enableDebugging :: IO ()
+enableDebugging = set "debug" True . Object =<< jsg "globalThis"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/lynx-api/global/set-interval.html>
+--
+setInterval :: Double -> IO () -> IO Double
+setInterval delay f = do
+  cb <- toJSVal =<< asyncCallback f
+  v <- toJSVal delay
+  result <- jsg "lynx" # "setInterval" $ ([cb, v] :: [JSVal])
+  fromJSValUnchecked result
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/lynx-api/global/clear-interval.html>
+--
+clearInterval :: Double -> IO Double
+clearInterval intervalId = do
+  result <- jsg "lynx" # "clearInterval" $ [intervalId]
+  fromJSValUnchecked result
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/lynx-api/nodes-ref/nodes-ref-invoke.html>
+--
+-- Used to call methods on elements in @view_@, @image_@, etc.
+-- We use this internally to implement the various @Method@ sections
+-- per the lynx docs.
+--
+-- > invokeExec "gifs" "startAnimate" :: IO ()
+--
+-- @ 
+-- lynx.createSelectorQuery()
+--   .select('#gifs')
+--   .invoke({
+--    method: @startAnimate@，
+--  }).exec();
+-- @
+--
+--
+-- > invoke
+--
+invokeExec
+  :: (ToJSVal params, FromJSVal argument)
+  => MisoString
+  -- ^ method
+  -> MisoString
+  -- ^ selector
+  -> params
+  -- ^ params
+  -> (argument -> action)
+  -- ^ successful
+  -> (MisoString -> action)
+  -- ^ errorful
+  -> Effect context props model action
+invokeExec method selector params successful errorful = do
+  withSink $ \sink -> do
+    selector_ <- toJSVal selector
+    successful_ <- toJSVal =<< do
+      asyncCallback1 $ \arg -> do
+        result <- fromJSValUnchecked arg
+        sink (successful result)
+    errorful_ <- toJSVal =<< do
+      asyncCallback1 $ \arg -> do
+        rect <- fromJSValUnchecked arg
+        sink (errorful rect)
+    params_ <- toJSVal params
+    method__ <- toJSVal method
+    void $ do
+      jsg "globalThis" # "invokeExec" $
+        [ selector_
+        , method__
+        , params_
+        , successful_
+        , errorful_
+        ]
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/MainThread.hs b/src/Miso/Native/MainThread.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/MainThread.hs
@@ -0,0 +1,273 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.MainThread
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Main-thread (MTS) imperative element manipulation
+--
+-- Helpers for /main-thread events/ on the Lynx dual-thread runtime. A handler
+-- registered for a t'Miso.Event.Types.MTS' event (see
+-- 'Miso.Event.Types.mainThreadEvents') runs synchronously on the main thread and
+-- receives the target 'DOMRef' via a @*With@ combinator
+-- (e.g. 'Miso.Native.Element.View.Event.onTapWith'). Such a handler must be
+-- __imperative__: it mutates the element directly with the functions below.
+--
+-- It does __not__ go through the VDOM diff — no re-render, no patches, no
+-- background-thread round-trip. This is the low-latency path for gestures and
+-- scroll-linked animation.
+--
+-- @
+-- -- move an element with the finger, entirely on the main thread:
+-- view _ _ _ = view_ [ onTouchMoveWith Drag ] []
+--
+-- update (Drag touch domRef) = io_ $
+--   setStyleProperty domRef \"transform\"
+--     (\"translateY(\" <> ms (touchY touch) <> \"px)\")
+-- @
+--
+-- __Conflict caveat.__ A property you drive imperatively here must /not/ also be
+-- set declaratively by the background-thread @view@ for the same element: both
+-- threads write the shared element tree through the same PAPI, with no
+-- arbitration, so the next background re-render would clobber it (and vice
+-- versa). Keep a single owner per @(element, property)@ — typically compositor
+-- properties like @transform@ / @opacity@ that the @view@ leaves alone. This is
+-- the same discipline Lynx itself requires; it is not enforced.
+--
+-- These call Lynx element PAPI globals and are only meaningful on the native
+-- runtime's main thread.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.MainThread
+  ( -- *** Imperative element mutation (main thread only)
+    setStyleProperty
+  , setStyleProperties
+  , setStylePropertyTransform
+  , setAttribute
+  , getAttribute
+  , flushElementTree
+    -- *** Element-tree navigation (main thread only)
+  , firstElementChild
+  , nextElementSibling
+  , parentElement
+    -- *** Frame-driven animation (main thread only)
+  , eachFrame
+    -- *** Platform info (main thread only)
+  , SystemInfo(..)
+  , getSystemInfo
+    -- *** Main-thread-local mutable state
+  , MainThreadRef
+  , mainThreadRef
+  , readMainThreadRef
+  , writeMainThreadRef
+  , modifyMainThreadRef
+  , modifyMainThreadRef_
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad (void, forM_)
+import           Control.Monad.State (State, execState)
+import           Data.IORef (IORef, newIORef, readIORef, writeIORef, modifyIORef')
+import           System.IO.Unsafe (unsafePerformIO)
+-----------------------------------------------------------------------------
+import           Miso.CSS (transforms, TransformFn)
+import           Miso.DSL
+  ( jsg, jsg0, jsg1, jsg2, jsg3, (!), isUndefined, FromJSVal(..)
+  , requestAnimationFrame, syncCallback1, freeFunction, Function(..), jsNull )
+import           GHC.Generics (Generic)
+import           Miso.Effect (DOMRef)
+import           Miso.JSON (ToJSON(..), FromJSON(..), Value(Null))
+import           Miso.String (MisoString)
+-----------------------------------------------------------------------------
+-- | Lets a target 'DOMRef' ride inside a @*With@ handler's action. Native
+-- component actions must be @ToJSON@\/@FromJSON@, but a raw 'DOMRef' (a
+-- @JSVal@) has no meaningful serialization — and main-thread actions never
+-- cross the thread boundary anyway, so these are __inert placeholders__:
+-- 'toJSON' is @Null@ and 'parseJSON' fails. Only import "Miso.Native.MainThread"
+-- where you actually dispatch main-thread events.
+--
+-- ⚠ These are global orphan instances for @JSVal@; do not rely on round-tripping
+-- a 'DOMRef' through JSON anywhere.
+instance ToJSON DOMRef where
+  toJSON _ = Null
+instance FromJSON DOMRef where
+  parseJSON _ = fail "DOMRef: main-thread-only, never deserialized"
+-----------------------------------------------------------------------------
+-- | Set a single inline style property on the element, then flush.
+--
+-- > setStyleProperty domRef "transform" "translateX(20px)"
+setStyleProperty :: DOMRef -> MisoString -> MisoString -> IO ()
+setStyleProperty node name value = do
+  void (jsg3 "__AddInlineStyle" node name value)
+  flushElementTree
+-----------------------------------------------------------------------------
+-- | Set several inline style properties, then flush once.
+setStyleProperties :: DOMRef -> [(MisoString, MisoString)] -> IO ()
+setStyleProperties node styles = do
+  forM_ styles $ \(name, value) ->
+    void (jsg3 "__AddInlineStyle" node name value)
+  flushElementTree
+-----------------------------------------------------------------------------
+-- | Set the element's @transform@ from a list of typed t'Miso.CSS.TransformFn's
+-- (from "Miso.CSS"), then flush — a typed alternative to writing the
+-- @transform@ string by hand.
+--
+-- > setStylePropertyTransform ref [ CSS.translateX (CSS.px 20) ]
+setStylePropertyTransform :: DOMRef -> [TransformFn] -> IO ()
+setStylePropertyTransform node fns = setStyleProperties node [ transforms fns ]
+-----------------------------------------------------------------------------
+-- | Set an attribute on the element, then flush.
+setAttribute :: DOMRef -> MisoString -> MisoString -> IO ()
+setAttribute node key value = do
+  void (jsg3 "__SetAttribute" node key value)
+  flushElementTree
+-----------------------------------------------------------------------------
+-- | Read an attribute's current value from the element.
+getAttribute :: DOMRef -> MisoString -> IO MisoString
+getAttribute node key =
+  fromJSValUnchecked =<< jsg2 "__GetAttributeByName" node key
+-----------------------------------------------------------------------------
+-- | Commit pending element-tree mutations to the screen. The @set*@ helpers
+-- above already flush; call this directly only when batching lower-level calls.
+flushElementTree :: IO ()
+flushElementTree = void (jsg0 "__FlushElementTree")
+-----------------------------------------------------------------------------
+-- | First element child of a node (Lynx @__FirstElement@). Lets a main-thread
+-- handler reach a /different/ element than the event target by walking the
+-- tree — e.g. from a scroll handler's list ref to a sibling scrollbar thumb.
+firstElementChild :: DOMRef -> IO DOMRef
+firstElementChild = jsg1 "__FirstElement"
+-----------------------------------------------------------------------------
+-- | Next element sibling of a node (Lynx @__NextElement@).
+nextElementSibling :: DOMRef -> IO DOMRef
+nextElementSibling = jsg1 "__NextElement"
+-----------------------------------------------------------------------------
+-- | Parent element of a node (Lynx @__GetParent@).
+parentElement :: DOMRef -> IO DOMRef
+parentElement = jsg1 "__GetParent"
+-----------------------------------------------------------------------------
+-- | Drive @step@ once per animation frame until it returns @False@, then release
+-- the underlying callback. @step@ receives the frame timestamp in milliseconds.
+--
+-- This is the vsync-coalesced loop primitive for main-thread, scroll-linked
+-- animation: read the latest gesture state, imperatively paint at most once per
+-- frame (via 'setStyleProperty' \/ 'setStylePropertyTransform'), and stop by
+-- returning @False@ when the gesture ends.
+--
+-- @
+-- startFollow ref = 'eachFrame' $ \\_ts -> do
+--   d <- readDrag
+--   if not (active d) then pure False else do
+--     setStylePropertyTransform ref [ CSS.translateX (CSS.px (offset d)) ]
+--     pure True
+-- @
+eachFrame :: (Double -> IO Bool) -> IO ()
+eachFrame step = do
+  cbRef <- newIORef jsNull
+  let frame tsVal = do
+        keep <- step =<< fromJSValUnchecked tsVal
+        cb   <- readIORef cbRef
+        if keep
+          then void (requestAnimationFrame cb)
+          else freeFunction (Function cb)
+  cb <- syncCallback1 frame
+  writeIORef cbRef cb
+  void (requestAnimationFrame cb)
+-----------------------------------------------------------------------------
+-- | Lynx's @lynx.SystemInfo@: device pixel geometry and platform metadata. The
+-- field names match the Lynx @SystemInfo@ object, so it decodes directly. Fields
+-- that Lynx omits on some realms are 'Maybe' — notably 'runtimeType', which is
+-- unavailable in the lepus (main-thread) runtime.
+data SystemInfo = SystemInfo
+  { pixelWidth     :: Double
+    -- ^ Physical pixel width of the device.
+  , pixelHeight    :: Double
+    -- ^ Physical pixel height of the device.
+  , pixelRatio     :: Double
+    -- ^ Physical pixel ratio (device pixels per logical pixel).
+  , osVersion      :: MisoString
+    -- ^ Operating-system version.
+  , platform       :: MisoString
+    -- ^ Device platform, e.g. @\"Android\"@, @\"iOS\"@, @\"macOS\"@.
+  , lynxSdkVersion :: Maybe MisoString
+    -- ^ Lynx SDK version (deprecated upstream; may be absent).
+  , engineVersion  :: Maybe MisoString
+    -- ^ Lynx Engine version (absent on older engines).
+  , runtimeType    :: Maybe MisoString
+    -- ^ JS engine (@\"v8\"@ \/ @\"jsc\"@ \/ @\"quickjs\"@); not available in lepus.
+  , theme          :: Maybe Value
+    -- ^ Opaque theme object, when present.
+  } deriving (Show, Eq, Generic)
+
+instance FromJSVal SystemInfo
+
+-- | Read Lynx's @lynx.SystemInfo@, decoded into t'SystemInfo'. This global is
+-- main-thread-only: present on the MTS realm and absent on the BTS realm, so
+-- this returns 'Just' on the main thread and 'Nothing' on the background thread.
+-- The @undefined@ guard makes the background-thread read a safe 'Nothing' rather
+-- than a throw; a decode failure (e.g. a required field missing) is also
+-- 'Nothing'.
+getSystemInfo :: IO (Maybe SystemInfo)
+getSystemInfo = do
+  si <- jsg "lynx" >>= (! "SystemInfo")
+  u  <- isUndefined si
+  if u then pure Nothing else fromJSVal si
+-----------------------------------------------------------------------------
+-- | A thin wrapper over 'IORef' for state that lives __only__ on the main
+-- thread and must never reach the background thread's shared @model@ (which the
+-- BTS solely owns — see "Miso.Runtime"). Use it for transient, main-thread-local
+-- gesture\/animation state: the current drag offset, a fling velocity, whether a
+-- follow loop is active, etc.
+--
+-- Reads and writes are ordinary 'IORef' operations, safe here because the MTS is
+-- single-threaded; no atomics are needed.
+newtype MainThreadRef a = MainThreadRef (IORef a)
+-----------------------------------------------------------------------------
+-- | Create a top-level t'MainThreadRef' with an initial value.
+--
+-- This uses 'unsafePerformIO' to allocate the underlying 'IORef' as a CAF, so
+-- the ref is shared across all uses of the binding. __You must give every
+-- top-level t'MainThreadRef' binding a @{-\# NOINLINE \#-}@ pragma__ — otherwise
+-- GHC may inline the CAF and allocate a fresh, independent 'IORef' at each use
+-- site, silently splitting your state into multiple copies.
+--
+-- @
+-- dragRef :: t'MainThreadRef' Double
+-- dragRef = 'mainThreadRef' 0
+-- {-\# NOINLINE dragRef \#-}
+-- @
+mainThreadRef :: a -> MainThreadRef a
+mainThreadRef x = MainThreadRef (unsafePerformIO (newIORef x))
+{-# NOINLINE mainThreadRef #-}
+-----------------------------------------------------------------------------
+-- | Read the current value of a t'MainThreadRef'.
+readMainThreadRef :: MainThreadRef a -> IO a
+readMainThreadRef (MainThreadRef ref) = readIORef ref
+-----------------------------------------------------------------------------
+-- | Overwrite the value of a t'MainThreadRef'.
+writeMainThreadRef :: MainThreadRef a -> a -> IO ()
+writeMainThreadRef (MainThreadRef ref) = writeIORef ref
+-----------------------------------------------------------------------------
+-- | Strictly modify the value of a t'MainThreadRef'.
+modifyMainThreadRef :: MainThreadRef a -> (a -> a) -> IO ()
+modifyMainThreadRef (MainThreadRef ref) = modifyIORef' ref
+-----------------------------------------------------------------------------
+-- | Strictly modify a t'MainThreadRef' with a @'State' a ()@ computation, letting
+-- you drive the update with the "Miso.Lens" operators (@.=@, @%=@, @+=@, …).
+--
+-- @
+-- modifyMainThreadRef_ dragRef $ do
+--   offset @.=@ newX
+--   active @.=@ True
+-- @
+modifyMainThreadRef_ :: MainThreadRef a -> State a () -> IO ()
+modifyMainThreadRef_ ref go = modifyMainThreadRef ref (execState go)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/Module.hs b/src/Miso/Native/Module.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/Module.hs
@@ -0,0 +1,141 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.Module
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- Bindings to Lynx <https://lynxjs.org/guide/use-native-modules.html native modules>.
+--
+-- Native modules are exposed to JavaScript through a single global
+-- @NativeModules@ object and support two call shapes:
+--
+--   * __synchronous / void__ — @NativeModules.\<module\>.\<method\>(args…)@
+--   * __asynchronous__ — @NativeModules.\<module\>.\<method\>(args…, callback)@,
+--     where the native side invokes @callback@ with the result.
+--
+-- __N.B.__ Per the Lynx documentation, native modules can /only/ be used on the
+-- background thread (BTS). These are plain 'IO' actions, so the caller is
+-- responsible for running them on the BTS — e.g. from the @update@ of an action
+-- dispatched to the BTS with 'Miso.Effect.runOnBG', or a background-thread
+-- subscription.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.Module
+  ( -- * Combinators
+    callNativeModule
+  , callNativeModuleWith
+    -- * Low-level handles
+  , nativeModules
+  , getNativeModule
+  ) where
+----------------------------------------------------------------------------
+import           Control.Monad (void, when)
+import           Control.Concurrent.MVar (newMVar, modifyMVar)
+----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.FFI (consoleError)
+import           Miso.JSON
+  ( Value, FromJSON, fromJSON, Result(..), toJSVal_Value, fromJSVal_Value )
+import           Miso.String (MisoString, ms)
+----------------------------------------------------------------------------
+-- | The global Lynx @NativeModules@ object.
+--
+-- __N.B.__ only available on the background thread (BTS).
+nativeModules :: IO JSVal
+nativeModules = jsg "NativeModules"
+----------------------------------------------------------------------------
+-- | Look up a native module by name: @NativeModules.\<name\>@.
+--
+-- __N.B.__ only available on the background thread (BTS).
+getNativeModule :: MisoString -> IO JSVal
+getNativeModule name = nativeModules ! name
+----------------------------------------------------------------------------
+-- | Invoke a synchronous (void-returning) native-module method.
+--
+-- > callNativeModule "NativeLocalStorageModule" "setStorageItem"
+-- >   [ String "myKey", String "myValue" ]
+--
+-- __N.B.__ must be run on the background thread (BTS).
+callNativeModule
+  :: MisoString
+  -- ^ Module name
+  -> MisoString
+  -- ^ Method name
+  -> [Value]
+  -- ^ Arguments
+  -> IO ()
+callNativeModule name method args = do
+  m      <- getNativeModule name
+  undef  <- isUndefined m
+  -- A fire-and-forget call is otherwise silent: if the module isn't present
+  -- (e.g. run on the MTS, where @NativeModules@ doesn't exist), the call throws
+  -- and the failure vanishes. Surface it. Visible on device via
+  -- 'Miso.Native.FFI.enableDebugging'.
+  if undef
+    then consoleError ("callNativeModule: NativeModules." <> name <> " is undefined")
+    else do
+      jsArgs <- traverse toJSVal_Value args
+      void $ m # method $ jsArgs
+----------------------------------------------------------------------------
+-- | Invoke a callback-based native-module method. The native result is decoded
+-- via 'FromJSON' and handed to the supplied continuation, which fires exactly
+-- once — with @'Left' error@ if the native call errored or the result failed
+-- to decode. Callers that block awaiting the continuation (e.g. via an
+-- 'Control.Concurrent.MVar.MVar') can therefore rely on it always firing,
+-- instead of hanging forever on the error path.
+--
+-- > callNativeModuleWith "NativeLocalStorageModule" "getStorageItem"
+-- >   [ String "myKey" ] (either (const Nothing) Just)
+--
+-- The callback is appended to @args@ automatically.
+--
+-- __N.B.__ must be run on the background thread (BTS).
+callNativeModuleWith
+  :: FromJSON result
+  => MisoString
+  -- ^ Module name
+  -> MisoString
+  -- ^ Method name
+  -> [Value]
+  -- ^ Arguments (callback appended automatically)
+  -> (Either MisoString result -> IO ())
+  -- ^ Continuation invoked exactly once when the native callback fires
+  -> IO ()
+callNativeModuleWith name method args k = do
+  m      <- getNativeModule name
+  mUndef <- isUndefined m
+  when mUndef $
+    consoleError ("callNativeModuleWith: NativeModules." <> name <> " is undefined")
+  jsArgs <- traverse toJSVal_Value args
+  -- Fire the continuation exactly once, from whichever path responds first: some
+  -- Lynx native modules are callback-based (@method(args…, cb)@), others return
+  -- the value synchronously (@method(args…) -> value@). We pass a callback AND
+  -- inspect the synchronous return, guarding with a one-shot 'MVar' so a module
+  -- that does both (or neither) still yields a single 'k'.
+  fired  <- newMVar False
+  let deliver jval = do
+        already <- modifyMVar fired (\f -> pure (True, f))
+        if already then pure () else do
+          result <- fromJSVal_Value jval
+          case fromJSON <$> result of
+            Just (Success x) -> k (Right x)
+            Just (Error e)   -> do
+              consoleError ("callNativeModuleWith: " <> ms e)
+              k (Left (ms e))
+            Nothing          -> do
+              consoleError "callNativeModuleWith: unreadable native result"
+              k (Left "callNativeModuleWith: unreadable native result")
+  cb     <- toJSVal =<< asyncCallback1 deliver
+  ret    <- m # method $ (jsArgs ++ [cb])
+  -- If the module returned a usable value synchronously, deliver it now; if it
+  -- returned @undefined@ (the async shape), leave delivery to the callback.
+  isUndef <- isUndefined ret
+  isNul   <- isNull ret
+  if isUndef || isNul then pure () else deliver ret
+----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element.hs b/src/Miso/Native/X/Element.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element.hs
@@ -0,0 +1,178 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- Smart constructors for the Lynx
+-- [XElement](https://lynxjs.org/api/elements/built-in.html) family — the
+-- extended, opt-in built-in elements (@\<input\>@, @\<textarea\>@,
+-- @\<overlay\>@, @\<svg\>@, @\<refresh\>@, @\<viewpager\>@,
+-- @\<scroll-coordinator\>@, @\<blur-view\>@, @\<webview\>@ and
+-- @\<title-bar-view\>@).
+--
+-- Attributes, events and methods for each element live in the corresponding
+-- @Miso.Native.X.Element.\<Name\>@ modules.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element
+  ( -- ** Input
+    input_
+    -- ** Textarea
+  , textarea_
+    -- ** Overlay
+  , overlay_
+    -- ** Svg
+  , svg_
+    -- ** Refresh
+  , refresh_
+  , refreshHeader_
+    -- ** Viewpager
+  , viewpager_
+  , viewpagerItem_
+    -- ** Scroll Coordinator
+  , scrollCoordinator_
+  , scrollCoordinatorHeader_
+  , scrollCoordinatorSlot_
+  , scrollCoordinatorToolbar_
+    -- ** Blur View
+  , blurView_
+    -- ** Webview
+  , webview_
+    -- ** Title Bar View
+  , titleBarView_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.Native.Element (lynx_, lynxDirect_)
+import           Miso.String (MisoString)
+import           Miso.Types (View, Attribute)
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/input.html>
+--
+-- Single-line text input element. Does not support children.
+--
+input_ :: [Attribute model action] -> View context model action
+input_ attrs = lynxDirect_ inputDirectEvents "input" attrs []
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/textarea.html>
+--
+-- Multi-line text input element. Does not support children.
+--
+textarea_ :: [Attribute model action] -> View context model action
+textarea_ attrs = lynxDirect_ inputDirectEvents "textarea" attrs []
+-----------------------------------------------------------------------------
+-- | Events that @input@ and @textarea@ dispatch directly on the element (Lynx
+-- component events that do not bubble to the delegated mount listener).
+inputDirectEvents :: [MisoString]
+inputDirectEvents = [ "blur", "confirm", "focus", "input", "selection" ]
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/overlay.html>
+--
+-- Renders its children on an independent layer above the page.
+--
+overlay_ :: [Attribute model action] -> [View context model action] -> View context model action
+overlay_ = lynxDirect_
+  [ "dismissoverlay", "error", "overlaytouch", "requestclose", "showoverlay" ]
+  "overlay"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/svg.html>
+--
+-- Displays SVG content, supplied either inline via @content_@ or by URL via
+-- @src_@.
+--
+svg_ :: [Attribute model action] -> [View context model action] -> View context model action
+svg_ = lynxDirect_ [ "load" ] "svg"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/refresh.html>
+--
+-- Pull-to-refresh container. Wraps a @refreshHeader_@ and a vertically
+-- scrollable child.
+--
+refresh_ :: [Attribute model action] -> [View context model action] -> View context model action
+refresh_ = lynxDirect_
+  [ "headeroffset", "refreshstatechange", "startrefresh" ]
+  "refresh"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/refresh.html>
+--
+-- Customizable header revealed during the pull gesture of a @refresh_@.
+--
+refreshHeader_ :: [Attribute model action] -> [View context model action] -> View context model action
+refreshHeader_ = lynx_ "refresh-header"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/viewpager.html>
+--
+-- Horizontally paged container. Each page is a @viewpagerItem_@.
+--
+viewpager_ :: [Attribute model action] -> [View context model action] -> View context model action
+viewpager_ = lynxDirect_ [ "change", "offsetchange", "willchange" ] "viewpager"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/viewpager.html>
+--
+-- A single page within a @viewpager_@.
+--
+viewpagerItem_ :: [Attribute model action] -> [View context model action] -> View context model action
+viewpagerItem_ = lynx_ "viewpager-item"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/scroll-coordinator.html>
+--
+-- Coordinates nested scrolling, typically used with sticky headers and
+-- tabbed layouts.
+--
+scrollCoordinator_ :: [Attribute model action] -> [View context model action] -> View context model action
+scrollCoordinator_ = lynxDirect_ [ "offset" ] "scroll-coordinator"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/scroll-coordinator.html>
+--
+-- The collapsing header of a @scrollCoordinator_@. Folds away as the slot
+-- content scrolls. Required (together with @scrollCoordinatorSlot_@).
+--
+scrollCoordinatorHeader_ :: [Attribute model action] -> [View context model action] -> View context model action
+scrollCoordinatorHeader_ = lynx_ "scroll-coordinator-header"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/scroll-coordinator.html>
+--
+-- The main content region of a @scrollCoordinator_@, whose scroll drives the
+-- header fold. Holds the scrollable child (e.g. a @scrollView_@). Required
+-- (together with @scrollCoordinatorHeader_@).
+--
+scrollCoordinatorSlot_ :: [Attribute model action] -> [View context model action] -> View context model action
+scrollCoordinatorSlot_ = lynx_ "scroll-coordinator-slot"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/scroll-coordinator.html>
+--
+-- An optional sticky bar of a @scrollCoordinator_@ that stays pinned while the
+-- header folds (e.g. tabs above the content).
+--
+scrollCoordinatorToolbar_ :: [Attribute model action] -> [View context model action] -> View context model action
+scrollCoordinatorToolbar_ = lynx_ "scroll-coordinator-toolbar"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/blur-view.html>
+--
+-- Applies a Gaussian blur / material effect to the content behind it.
+--
+blurView_ :: [Attribute model action] -> [View context model action] -> View context model action
+blurView_ = lynx_ "blur-view"
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/webview.html>
+--
+-- Embeds a web page. Does not support children.
+--
+webview_ :: [Attribute model action] -> View context model action
+webview_ attrs = lynxDirect_
+  [ "error", "load", "locationchange", "message", "openwindow" ]
+  "webview" attrs []
+-----------------------------------------------------------------------------
+-- | <https://lynxjs.org/api/elements/built-in/title-bar-view.html>
+--
+-- Defines a custom draggable window region (Clay Windows / macOS).
+--
+titleBarView_ :: [Attribute model action] -> [View context model action] -> View context model action
+titleBarView_ = lynx_ "title-bar-view"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/BlurView.hs b/src/Miso/Native/X/Element/BlurView.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/BlurView.hs
@@ -0,0 +1,23 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.BlurView
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<blur-view/>](https://lynxjs.org/api/elements/built-in/blur-view.html)
+--
+-- Applies a Gaussian blur / material effect to the content behind it.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.BlurView
+  ( module Miso.Native.X.Element.BlurView.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.BlurView.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/BlurView/Property.hs b/src/Miso/Native/X/Element/BlurView/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/BlurView/Property.hs
@@ -0,0 +1,152 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.BlurView.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.BlurView.Property
+  ( -- *** Property
+    androidCaptureTarget_
+  , blurEffect_
+  , blurRadius_
+  , blurSampling_
+  , enableAutoBlur_
+  , experimentalUpdateBlurRadius_
+  , glassInteractive_
+  , glassStyle_
+  , glassTintColor_
+  , spacing_
+    -- *** Types
+  , BlurEffect (..)
+  , GlassStyle (..)
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON (ToJSON(..))
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | The blur/material effect of a \<blur-view\> (iOS), used by 'blurEffect_'.
+data BlurEffect
+  = BlurLight
+  | BlurExtraLight
+  | BlurDark
+  | BlurGlass
+  | BlurGlassContainer
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON BlurEffect where
+  toJSON BlurLight          = "light"
+  toJSON BlurExtraLight     = "extra-light"
+  toJSON BlurDark           = "dark"
+  toJSON BlurGlass          = "glass"
+  toJSON BlurGlassContainer = "glass-container"
+-----------------------------------------------------------------------------
+-- | The glass effect appearance of a \<blur-view\> (iOS), used by 'glassStyle_'.
+data GlassStyle
+  = GlassClear
+  | GlassRegular
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON GlassStyle where
+  toJSON GlassClear   = "clear"
+  toJSON GlassRegular = "regular"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#android-capture-target
+--
+-- *Android 3.9+*. The raw id of the Android Lynx view to capture and blur.
+--
+androidCaptureTarget_ :: MisoString -> Attribute model action
+androidCaptureTarget_ = textProp "android-capture-target"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#blur-effect
+--
+-- *iOS* only. Controls brightness of the blurred area; glass variants apply
+-- material effects.
+--
+-- > blurEffect_ BlurDark
+--
+-- Default Value: 'BlurLight'
+--
+blurEffect_ :: BlurEffect -> Attribute model action
+blurEffect_ = prop "blur-effect"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#blur-radius
+--
+-- Gaussian blur radius specification.
+--
+-- Default Value: @\"0px\"@
+--
+blurRadius_ :: MisoString -> Attribute model action
+blurRadius_ = textProp "blur-radius"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#blur-sampling
+--
+-- *Android* only. Downsampling ratio for performance optimization.
+--
+-- Default Value: 6
+--
+blurSampling_ :: Int -> Attribute model action
+blurSampling_ = intProp "blur-sampling"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#enable-auto-blur
+--
+-- *Android* only. Automatic blur update toggle.
+--
+-- Default Value: 'True'
+--
+enableAutoBlur_ :: Bool -> Attribute model action
+enableAutoBlur_ = boolProp "enable-auto-blur"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#experimental-update-blur-radius
+--
+-- *Android 3.4+*. Switches the internal blur-buffer refresh mechanism.
+--
+experimentalUpdateBlurRadius_ :: Bool -> Attribute model action
+experimentalUpdateBlurRadius_ = boolProp "experimental-update-blur-radius"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#glass-interactive
+--
+-- *iOS 3.8+*. Enables interactive glass effect behavior.
+--
+-- Default Value: @False@
+--
+glassInteractive_ :: Bool -> Attribute model action
+glassInteractive_ = boolProp "glass-interactive"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#glass-style
+--
+-- *iOS 3.8+*. Glass effect visual appearance.
+--
+-- > glassStyle_ GlassClear
+--
+-- Default Value: 'GlassRegular'
+--
+glassStyle_ :: GlassStyle -> Attribute model action
+glassStyle_ = prop "glass-style"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#glass-tint-color
+--
+-- *iOS 3.8+*. Tint color applied to the glass effect.
+--
+-- Default Value: @\"transparent\"@
+--
+glassTintColor_ :: MisoString -> Attribute model action
+glassTintColor_ = textProp "glass-tint-color"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/blur-view.html#spacing
+--
+-- *iOS* only. Distance threshold for element merging.
+--
+-- Default Value: 0
+--
+spacing_ :: Int -> Attribute model action
+spacing_ = intProp "spacing"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Input.hs b/src/Miso/Native/X/Element/Input.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Input.hs
@@ -0,0 +1,27 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Input
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<input/>](https://lynxjs.org/api/elements/built-in/input.html)
+--
+-- Single-line text input element.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Input
+  ( module Miso.Native.X.Element.Input.Event
+  , module Miso.Native.X.Element.Input.Method
+  , module Miso.Native.X.Element.Input.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.Input.Event
+import Miso.Native.X.Element.Input.Method
+import Miso.Native.X.Element.Input.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Input/Event.hs b/src/Miso/Native/X/Element/Input/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Input/Event.hs
@@ -0,0 +1,324 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Input.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Input.Event
+  ( -- *** Events
+    onBlur
+  , onBlurWith
+  , onBlurMain
+  , onBlurMainWith
+  , onConfirm
+  , onConfirmWith
+  , onConfirmMain
+  , onConfirmMainWith
+  , onFocus
+  , onFocusWith
+  , onFocusMain
+  , onFocusMainWith
+  , onInput
+  , onInputWith
+  , onInputMain
+  , onInputMainWith
+  , onSelection
+  , onSelectionWith
+  , onSelectionMain
+  , onSelectionMainWith
+    -- *** Types
+  , InputEvent (..)
+  , SelectionEvent (..)
+    -- *** Decoders
+  , inputValueDecoder
+  , inputDecoder
+  , selectionDecoder
+    -- *** Event Map
+  , inputEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<input>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+inputEvents :: Events
+inputEvents
+  = M.fromList
+  [ ("blur", BUBBLE)
+  , ("confirm", BUBBLE)
+  , ("focus", BUBBLE)
+  , ("input", BUBBLE)
+  , ("selection", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Payload of the @bindinput@ event.
+data InputEvent
+  = InputEvent
+  { inputValue :: MisoString
+    -- ^ The current input content
+  , inputSelectionStart :: Int
+    -- ^ Start position of the selection
+  , inputSelectionEnd :: Int
+    -- ^ End position of the selection
+  , inputIsComposing :: Bool
+    -- ^ Whether the input is mid-composition (IME)
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Payload of the @bindselection@ event.
+data SelectionEvent
+  = SelectionEvent
+  { selStart :: Int
+    -- ^ Start position of the selection
+  , selEnd :: Int
+    -- ^ End position of the selection
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Decodes the @value@ field shared by @bindblur@, @bindconfirm@ and @bindfocus@.
+inputValueDecoder :: Decoder MisoString
+inputValueDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o -> o .: "value"
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'InputEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+inputDecoder :: Decoder InputEvent
+inputDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      InputEvent
+        <$> o .: "value"
+        <*> o .:? "selectionStart" .!= 0
+        <*> o .:? "selectionEnd" .!= 0
+        -- Lynx's native input sends @isComposing@ as a number (0/1), bridged
+        -- from an ObjC @BOOL@ — not a JSON boolean — so decode it as an 'Int'
+        -- and coerce. Absent (e.g. on the simulator's non-composing path) is
+        -- @False@. Decoding it as 'Bool' fails the whole decoder on device.
+        <*> (maybe False (/= (0 :: Int)) <$> o .:? "isComposing")
+-----------------------------------------------------------------------------
+-- Note: the JS keys stay @selectionStart@/@selectionEnd@; the record fields are
+-- 'selStart'/'selEnd' to avoid clashing with 'InputValue' when the hub module
+-- re-exports Event and Method together.
+-- | t'Decoder' producing a t'SelectionEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+selectionDecoder :: Decoder SelectionEvent
+selectionDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      SelectionEvent
+        <$> o .: "selectionStart"
+        <*> o .: "selectionEnd"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#bindblur
+--
+-- Triggered when the input is blurred, outputting the current value.
+--
+onBlur :: (MisoString -> action) -> Attribute model action
+onBlur action = on "blur" inputValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onBlur', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Blurred MisoString
+--
+-- view_ [ event (static (onBlurMain Blurred)) ] [ "some view" ]
+-- @
+--
+onBlurMain :: (MisoString -> action) -> EventHandler model action
+onBlurMain action = onMain "blur" inputValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onBlurMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Blurred MisoString Model DOMRef
+--
+-- view_ [ event (static (onBlurMainWith Blurred)) ] [ "some view" ]
+-- @
+--
+onBlurMainWith :: (MisoString -> model -> DOMRef -> action) -> EventHandler model action
+onBlurMainWith action = onMain "blur" inputValueDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#bindconfirm
+--
+-- Triggered when the confirm button is clicked, outputting the current value.
+--
+onConfirm :: (MisoString -> action) -> Attribute model action
+onConfirm action = on "confirm" inputValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onConfirm', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Confirmed MisoString
+--
+-- view_ [ event (static (onConfirmMain Confirmed)) ] [ "some view" ]
+-- @
+--
+onConfirmMain :: (MisoString -> action) -> EventHandler model action
+onConfirmMain action = onMain "confirm" inputValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onConfirmMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Confirmed MisoString Model DOMRef
+--
+-- view_ [ event (static (onConfirmMainWith Confirmed)) ] [ "some view" ]
+-- @
+--
+onConfirmMainWith :: (MisoString -> model -> DOMRef -> action) -> EventHandler model action
+onConfirmMainWith action = onMain "confirm" inputValueDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#bindfocus
+--
+-- Triggered when the input is focused, outputting the current value.
+--
+onFocus :: (MisoString -> action) -> Attribute model action
+onFocus action = on "focus" inputValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onFocus', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Focused MisoString
+--
+-- view_ [ event (static (onFocusMain Focused)) ] [ "some view" ]
+-- @
+--
+onFocusMain :: (MisoString -> action) -> EventHandler model action
+onFocusMain action = onMain "focus" inputValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onFocusMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Focused MisoString Model DOMRef
+--
+-- view_ [ event (static (onFocusMainWith Focused)) ] [ "some view" ]
+-- @
+--
+onFocusMainWith :: (MisoString -> model -> DOMRef -> action) -> EventHandler model action
+onFocusMainWith action = onMain "focus" inputValueDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#bindinput
+--
+-- Triggered when the input content changes.
+--
+onInput :: (InputEvent -> action) -> Attribute model action
+onInput action = on "input" inputDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onInput', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Changed InputEvent
+--
+-- view_ [ event (static (onInputMain Changed)) ] [ "some view" ]
+-- @
+--
+onInputMain :: (InputEvent -> action) -> EventHandler model action
+onInputMain action = onMain "input" inputDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onInputMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Changed InputEvent Model DOMRef
+--
+-- view_ [ event (static (onInputMainWith Changed)) ] [ "some view" ]
+-- @
+--
+onInputMainWith :: (InputEvent -> model -> DOMRef -> action) -> EventHandler model action
+onInputMainWith action = onMain "input" inputDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#bindselection
+--
+-- Triggered when the input selection changes.
+--
+onSelection :: (SelectionEvent -> action) -> Attribute model action
+onSelection action = on "selection" selectionDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onSelection', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Selected SelectionEvent
+--
+-- view_ [ event (static (onSelectionMain Selected)) ] [ "some view" ]
+-- @
+--
+onSelectionMain :: (SelectionEvent -> action) -> EventHandler model action
+onSelectionMain action = onMain "selection" selectionDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onSelectionMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Selected SelectionEvent Model DOMRef
+--
+-- view_ [ event (static (onSelectionMainWith Selected)) ] [ "some view" ]
+-- @
+--
+onSelectionMainWith :: (SelectionEvent -> model -> DOMRef -> action) -> EventHandler model action
+onSelectionMainWith action = onMain "selection" selectionDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onBlur', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onBlurWith :: (MisoString -> DOMRef -> action) -> Attribute model action
+onBlurWith action = on "blur" inputValueDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onConfirm', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onConfirmWith :: (MisoString -> DOMRef -> action) -> Attribute model action
+onConfirmWith action = on "confirm" inputValueDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onFocus', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onFocusWith :: (MisoString -> DOMRef -> action) -> Attribute model action
+onFocusWith action = on "focus" inputValueDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onInput', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onInputWith :: (InputEvent -> DOMRef -> action) -> Attribute model action
+onInputWith action = on "input" inputDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onSelection', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onSelectionWith :: (SelectionEvent -> DOMRef -> action) -> Attribute model action
+onSelectionWith action = on "selection" selectionDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Input/Method.hs b/src/Miso/Native/X/Element/Input/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Input/Method.hs
@@ -0,0 +1,139 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Input.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Input.Method
+  ( -- *** Methods
+    focus
+  , blur
+  , setValue
+  , setSelectionRange
+  , getValue
+    -- *** Types
+  , InputValue (..)
+  ) where
+-----------------------------------------------------------------------------
+import Miso hiding (focus, blur, setValue, setSelectionRange)
+import Miso.Native.FFI (invokeExec)
+-----------------------------------------------------------------------------
+-- | Result of calling 'getValue'.
+data InputValue
+  = InputValue
+  { value :: MisoString
+    -- ^ The current input content
+  , selectionStart :: Int
+    -- ^ Start position of the selection
+  , selectionEnd :: Int
+    -- ^ End position of the selection
+  , isComposing :: Bool
+    -- ^ Whether the input is mid-composition (IME)
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal InputValue where
+  fromJSVal o = do
+    let readProp name = fromJSValUnchecked =<< o ! (name :: MisoString)
+    value          <- readProp "value"
+    selectionStart <- readProp "selectionStart"
+    selectionEnd   <- readProp "selectionEnd"
+    isComposing    <- readProp "isComposing"
+    pure $ Just InputValue {..}
+-----------------------------------------------------------------------------
+-- | Params object for 'setValue'.
+newtype SetValue = SetValue MisoString
+-----------------------------------------------------------------------------
+instance ToJSVal SetValue where
+  toJSVal (SetValue v) = do
+    o <- create
+    set "value" v o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | Params object for 'setSelectionRange'.
+data SetSelectionRange = SetSelectionRange Int Int
+-----------------------------------------------------------------------------
+instance ToJSVal SetSelectionRange where
+  toJSVal (SetSelectionRange s e) = do
+    o <- create
+    set "selectionStart" s o
+    set "selectionEnd" e o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#focus
+--
+-- Requests focus for the selected \<input\>.
+--
+-- > focus "#myInput" Focused FocusFailed
+--
+focus
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+focus selector action = invokeExec "focus" selector () (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#blur
+--
+-- Releases focus for the selected \<input\>.
+--
+-- > blur "#myInput" Blurred BlurFailed
+--
+blur
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+blur selector action = invokeExec "blur" selector () (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#setvalue
+--
+-- Sets the input content of the selected \<input\>.
+--
+-- > setValue "#myInput" "hello" ValueSet ValueSetFailed
+--
+setValue
+  :: MisoString
+  -> MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+setValue selector v action =
+  invokeExec "setValue" selector (SetValue v) (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#setselectionrange
+--
+-- Sets the selection range of the selected \<input\>.
+--
+-- > setSelectionRange "#myInput" 0 3 RangeSet RangeSetFailed
+--
+setSelectionRange
+  :: MisoString
+  -> Int
+  -> Int
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+setSelectionRange selector s e action =
+  invokeExec "setSelectionRange" selector (SetSelectionRange s e) (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#getvalue
+--
+-- Retrieves the current value (and selection) of the selected \<input\>.
+--
+-- > getValue "#myInput" GotValue GetValueFailed
+--
+getValue
+  :: MisoString
+  -> (InputValue -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+getValue selector = invokeExec "getValue" selector ()
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Input/Property.hs b/src/Miso/Native/X/Element/Input/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Input/Property.hs
@@ -0,0 +1,187 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Input.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Input.Property
+  ( -- *** Property
+    androidFullscreenMode_
+  , confirmType_
+  , disabled_
+  , inputFilter_
+  , iosAutoCorrect_
+  , iosSpellCheck_
+  , maxlength_
+  , placeholder_
+  , readonly_
+  , showSoftInputOnFocus_
+  , type_
+    -- *** Types
+  , InputType (..)
+  , ConfirmType (..)
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON (ToJSON(..))
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | The content type of an \<input\>, used by 'type_'.
+data InputType
+  = InputNumber
+  | InputText
+  | InputDigit
+  | InputPassword
+  | InputTel
+  | InputEmail
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON InputType where
+  toJSON InputNumber   = "number"
+  toJSON InputText     = "text"
+  toJSON InputDigit    = "digit"
+  toJSON InputPassword = "password"
+  toJSON InputTel      = "tel"
+  toJSON InputEmail    = "email"
+-----------------------------------------------------------------------------
+-- | The confirm button type of an \<input\>, used by 'confirmType_'.
+data ConfirmType
+  = ConfirmSearch
+  | ConfirmSend
+  | ConfirmGo
+  | ConfirmDone
+  | ConfirmNext
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON ConfirmType where
+  toJSON ConfirmSearch = "search"
+  toJSON ConfirmSend   = "send"
+  toJSON ConfirmGo     = "go"
+  toJSON ConfirmDone   = "done"
+  toJSON ConfirmNext   = "next"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#android-fullscreen-mode
+--
+-- Whether to enter the full-screen input mode when in landscape screen.
+--
+-- > androidFullscreenMode_ False
+--
+-- Default Value: 'True'
+--
+androidFullscreenMode_ :: Bool -> Attribute model action
+androidFullscreenMode_ = boolProp "android-fullscreen-mode"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#confirm-type
+--
+-- Specifies the confirm button type.
+--
+-- > confirmType_ ConfirmDone
+--
+-- Default Value: 'ConfirmSend'
+--
+confirmType_ :: ConfirmType -> Attribute model action
+confirmType_ = prop "confirm-type"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#disabled
+--
+-- Controls whether interaction is enabled.
+--
+-- > disabled_ True
+--
+-- Default Value: @False@
+--
+disabled_ :: Bool -> Attribute model action
+disabled_ = boolProp "disabled"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#input-filter
+--
+-- Filters the input content in the form of a regular expression.
+--
+-- > inputFilter_ "[0-9]"
+--
+inputFilter_ :: MisoString -> Attribute model action
+inputFilter_ = textProp "input-filter"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#ios-auto-correct
+--
+-- Enables auto-correction on iOS.
+--
+-- > iosAutoCorrect_ False
+--
+-- Default Value: 'True'
+--
+iosAutoCorrect_ :: Bool -> Attribute model action
+iosAutoCorrect_ = boolProp "ios-auto-correct"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#ios-spell-check
+--
+-- Enables spell-checking on iOS.
+--
+-- > iosSpellCheck_ False
+--
+-- Default Value: 'True'
+--
+iosSpellCheck_ :: Bool -> Attribute model action
+iosSpellCheck_ = boolProp "ios-spell-check"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#maxlength
+--
+-- Maximum input length allowed.
+--
+-- > maxlength_ 32
+--
+-- Default Value: 140
+--
+maxlength_ :: Int -> Attribute model action
+maxlength_ = intProp "maxlength"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#placeholder
+--
+-- Placeholder text display.
+--
+-- > placeholder_ "Enter your name"
+--
+placeholder_ :: MisoString -> Attribute model action
+placeholder_ = textProp "placeholder"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#readonly
+--
+-- Makes the input read-only.
+--
+-- > readonly_ True
+--
+-- Default Value: @False@
+--
+readonly_ :: Bool -> Attribute model action
+readonly_ = boolProp "readonly"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#show-soft-input-on-focus
+--
+-- Show soft input keyboard while focused.
+--
+-- > showSoftInputOnFocus_ False
+--
+-- Default Value: 'True'
+--
+showSoftInputOnFocus_ :: Bool -> Attribute model action
+showSoftInputOnFocus_ = boolProp "show-soft-input-on-focus"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/input.html#type
+--
+-- Input content type.
+--
+-- > type_ InputPassword
+--
+-- Default Value: 'InputText'
+--
+type_ :: InputType -> Attribute model action
+type_ = prop "type"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Overlay.hs b/src/Miso/Native/X/Element/Overlay.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Overlay.hs
@@ -0,0 +1,25 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Overlay
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<overlay/>](https://lynxjs.org/api/elements/built-in/overlay.html)
+--
+-- Renders its children on an independent layer above the page.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Overlay
+  ( module Miso.Native.X.Element.Overlay.Event
+  , module Miso.Native.X.Element.Overlay.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.Overlay.Event
+import Miso.Native.X.Element.Overlay.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Overlay/Event.hs b/src/Miso/Native/X/Element/Overlay/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Overlay/Event.hs
@@ -0,0 +1,330 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase        #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Overlay.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Overlay.Event
+  ( -- *** Events
+    onDismissOverlay
+  , onDismissOverlayWith
+  , onDismissOverlayMain
+  , onDismissOverlayMainWith
+  , onError
+  , onErrorWith
+  , onErrorMain
+  , onErrorMainWith
+  , onOverlayTouch
+  , onOverlayTouchWith
+  , onOverlayTouchMain
+  , onOverlayTouchMainWith
+  , onRequestClose
+  , onRequestCloseWith
+  , onRequestCloseMain
+  , onRequestCloseMainWith
+  , onShowOverlay
+  , onShowOverlayWith
+  , onShowOverlayMain
+  , onShowOverlayMainWith
+    -- *** Types
+  , OverlayErrorEvent (..)
+  , OverlayTouchEvent (..)
+  , OverlayTouchState (..)
+    -- *** Decoders
+  , overlayErrorDecoder
+  , overlayTouchDecoder
+    -- *** Event Map
+  , overlayEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<overlay>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+overlayEvents :: Events
+overlayEvents
+  = M.fromList
+  [ ("dismissoverlay", BUBBLE)
+  , ("error", BUBBLE)
+  , ("overlaytouch", BUBBLE)
+  , ("requestclose", BUBBLE)
+  , ("showoverlay", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Payload of the @binderror@ event.
+data OverlayErrorEvent
+  = OverlayErrorEvent
+  { errorCode :: Int
+    -- ^ The error code
+  , errorMsg :: MisoString
+    -- ^ The error message
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Touch phase of a @bindoverlaytouch@ event, mirrored from Lynx's
+-- @OverlayTouchState@ enum.
+--
+-- @since 1.13.0.0
+data OverlayTouchState
+  = OverlayTouchDown
+  | OverlayTouchMove
+  | OverlayTouchUp
+  | OverlayTouchCancel
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Numbering matches Lynx's @OverlayTouchState@ enum (@OverlayTouchStateDown
+-- = 0@ … @OverlayTouchStateCancel = 3@), the shape the wire actually sends.
+instance FromJSON OverlayTouchState where
+  parseJSON = withNumber "OverlayTouchState" $ \case
+    0 -> pure OverlayTouchDown
+    1 -> pure OverlayTouchMove
+    2 -> pure OverlayTouchUp
+    3 -> pure OverlayTouchCancel
+    x -> typeMismatch "OverlayTouchState" (toJSON x)
+-----------------------------------------------------------------------------
+-- | Payload of the @bindoverlaytouch@ event.
+data OverlayTouchEvent
+  = OverlayTouchEvent
+  { touchState :: OverlayTouchState
+    -- ^ The @OverlayTouchState@
+  , touchX :: Double
+    -- ^ The horizontal position of the touch
+  , touchY :: Double
+    -- ^ The vertical position of the touch
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'OverlayErrorEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+overlayErrorDecoder :: Decoder OverlayErrorEvent
+overlayErrorDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      OverlayErrorEvent
+        <$> o .: "errorCode"
+        <*> o .: "errorMsg"
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'OverlayTouchEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+overlayTouchDecoder :: Decoder OverlayTouchEvent
+overlayTouchDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      OverlayTouchEvent
+        <$> o .: "state"
+        <*> o .: "x"
+        <*> o .: "y"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/overlay.html#binddismissoverlay
+--
+-- Triggered when the overlay is hidden.
+--
+onDismissOverlay :: action -> Attribute model action
+onDismissOverlay action = on "dismissoverlay" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onDismissOverlay', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Dismissed
+--
+-- view_ [ event (static (onDismissOverlayMain Dismissed)) ] [ "some view" ]
+-- @
+--
+onDismissOverlayMain :: action -> EventHandler model action
+onDismissOverlayMain action = onMain "dismissoverlay" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onDismissOverlayMain', but the handler also receives read-only access
+-- to the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Dismissed Model DOMRef
+--
+-- view_ [ event (static (onDismissOverlayMainWith Dismissed)) ] [ "some view" ]
+-- @
+--
+onDismissOverlayMainWith :: (model -> DOMRef -> action) -> EventHandler model action
+onDismissOverlayMainWith action = onMain "dismissoverlay" emptyDecoder (\() m ref -> action m ref)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/overlay.html#binderror
+--
+-- *Android 2.18+*. Triggered on an overlay error.
+--
+onError :: (OverlayErrorEvent -> action) -> Attribute model action
+onError action = on "error" overlayErrorDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onError', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Errored OverlayErrorEvent
+--
+-- view_ [ event (static (onErrorMain Errored)) ] [ "some view" ]
+-- @
+--
+onErrorMain :: (OverlayErrorEvent -> action) -> EventHandler model action
+onErrorMain action = onMain "error" overlayErrorDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onErrorMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Errored OverlayErrorEvent Model DOMRef
+--
+-- view_ [ event (static (onErrorMainWith Errored)) ] [ "some view" ]
+-- @
+--
+onErrorMainWith :: (OverlayErrorEvent -> model -> DOMRef -> action) -> EventHandler model action
+onErrorMainWith action = onMain "error" overlayErrorDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/overlay.html#bindoverlaytouch
+--
+-- Triggered when the overlay is touched.
+--
+onOverlayTouch :: (OverlayTouchEvent -> action) -> Attribute model action
+onOverlayTouch action = on "overlaytouch" overlayTouchDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onOverlayTouch', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Touched OverlayTouchEvent
+--
+-- view_ [ event (static (onOverlayTouchMain Touched)) ] [ "some view" ]
+-- @
+--
+onOverlayTouchMain :: (OverlayTouchEvent -> action) -> EventHandler model action
+onOverlayTouchMain action = onMain "overlaytouch" overlayTouchDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onOverlayTouchMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Touched OverlayTouchEvent Model DOMRef
+--
+-- view_ [ event (static (onOverlayTouchMainWith Touched)) ] [ "some view" ]
+-- @
+--
+onOverlayTouchMainWith :: (OverlayTouchEvent -> model -> DOMRef -> action) -> EventHandler model action
+onOverlayTouchMainWith action = onMain "overlaytouch" overlayTouchDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/overlay.html#bindrequestclose
+--
+-- Triggered when the back button is clicked.
+--
+onRequestClose :: action -> Attribute model action
+onRequestClose action = on "requestclose" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onRequestClose', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = RequestedClose
+--
+-- view_ [ event (static (onRequestCloseMain RequestedClose)) ] [ "some view" ]
+-- @
+--
+onRequestCloseMain :: action -> EventHandler model action
+onRequestCloseMain action = onMain "requestclose" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onRequestCloseMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = RequestedClose Model DOMRef
+--
+-- view_ [ event (static (onRequestCloseMainWith RequestedClose)) ] [ "some view" ]
+-- @
+--
+onRequestCloseMainWith :: (model -> DOMRef -> action) -> EventHandler model action
+onRequestCloseMainWith action = onMain "requestclose" emptyDecoder (\() m ref -> action m ref)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/overlay.html#bindshowoverlay
+--
+-- Triggered when the overlay is displayed.
+--
+onShowOverlay :: action -> Attribute model action
+onShowOverlay action = on "showoverlay" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onShowOverlay', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Shown
+--
+-- view_ [ event (static (onShowOverlayMain Shown)) ] [ "some view" ]
+-- @
+--
+onShowOverlayMain :: action -> EventHandler model action
+onShowOverlayMain action = onMain "showoverlay" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onShowOverlayMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Shown Model DOMRef
+--
+-- view_ [ event (static (onShowOverlayMainWith Shown)) ] [ "some view" ]
+-- @
+--
+onShowOverlayMainWith :: (model -> DOMRef -> action) -> EventHandler model action
+onShowOverlayMainWith action = onMain "showoverlay" emptyDecoder (\() m ref -> action m ref)
+-----------------------------------------------------------------------------
+-- | Like 'onDismissOverlay', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onDismissOverlayWith :: (DOMRef -> action) -> Attribute model action
+onDismissOverlayWith action = on "dismissoverlay" emptyDecoder (\() _ ref -> action ref)
+-----------------------------------------------------------------------------
+-- | Like 'onError', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onErrorWith :: (OverlayErrorEvent -> DOMRef -> action) -> Attribute model action
+onErrorWith action = on "error" overlayErrorDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onOverlayTouch', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onOverlayTouchWith :: (OverlayTouchEvent -> DOMRef -> action) -> Attribute model action
+onOverlayTouchWith action = on "overlaytouch" overlayTouchDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onRequestClose', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onRequestCloseWith :: (DOMRef -> action) -> Attribute model action
+onRequestCloseWith action = on "requestclose" emptyDecoder (\() _ ref -> action ref)
+-----------------------------------------------------------------------------
+-- | Like 'onShowOverlay', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onShowOverlayWith :: (DOMRef -> action) -> Attribute model action
+onShowOverlayWith action = on "showoverlay" emptyDecoder (\() _ ref -> action ref)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Overlay/Property.hs b/src/Miso/Native/X/Element/Overlay/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Overlay/Property.hs
@@ -0,0 +1,101 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Overlay.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Overlay.Property
+  ( -- *** Property
+    iosEnableSwipeBack_
+  , level_
+  , mode_
+  , visible_
+    -- *** Types
+  , OverlayLevel (..)
+  , OverlayMode (..)
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON (ToJSON(..))
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | Layer level of an \<overlay\>, used by 'level_'.
+data OverlayLevel
+  = Level1
+  | Level2
+  | Level3
+  | Level4
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON OverlayLevel where
+  toJSON Level1 = toJSON (1 :: Int)
+  toJSON Level2 = toJSON (2 :: Int)
+  toJSON Level3 = toJSON (3 :: Int)
+  toJSON Level4 = toJSON (4 :: Int)
+-----------------------------------------------------------------------------
+-- | The level at which the overlay content resides (iOS), used by 'mode_'.
+-- 'ModeOther' carries a custom client class name.
+data OverlayMode
+  = ModeWindow
+  | ModeTop
+  | ModePage
+  | ModeOther MisoString
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON OverlayMode where
+  toJSON ModeWindow      = "window"
+  toJSON ModeTop         = "top"
+  toJSON ModePage        = "page"
+  toJSON (ModeOther cls) = toJSON cls
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/overlay.html#ios-enable-swipe-back
+--
+-- *iOS* only. When the overlay is displayed, whether swiping right closes the
+-- current page.
+--
+-- Default Value: @False@
+--
+iosEnableSwipeBack_ :: Bool -> Attribute model action
+iosEnableSwipeBack_ = boolProp "ios-enable-swipe-back"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/overlay.html#level
+--
+-- Layer level, from 'Level1' to 'Level4'. The larger the value, the closer it
+-- is to the bottom.
+--
+-- > level_ Level2
+--
+-- Default Value: 'Level1'
+--
+level_ :: OverlayLevel -> Attribute model action
+level_ = prop "level"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/overlay.html#mode
+--
+-- *iOS* only. The level at which the overlay content resides. Use 'ModeOther'
+-- for a custom client class name.
+--
+-- > mode_ ModeTop
+--
+-- Default Value: 'ModeWindow'
+--
+mode_ :: OverlayMode -> Attribute model action
+mode_ = prop "mode"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/overlay.html#visible
+--
+-- Controls whether the overlay is displayed.
+--
+-- Default Value: @False@
+--
+visible_ :: Bool -> Attribute model action
+visible_ = boolProp "visible"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Refresh.hs b/src/Miso/Native/X/Element/Refresh.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Refresh.hs
@@ -0,0 +1,27 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Refresh
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<refresh/>](https://lynxjs.org/api/elements/built-in/refresh.html)
+--
+-- Pull-to-refresh container.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Refresh
+  ( module Miso.Native.X.Element.Refresh.Event
+  , module Miso.Native.X.Element.Refresh.Method
+  , module Miso.Native.X.Element.Refresh.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.Refresh.Event
+import Miso.Native.X.Element.Refresh.Method
+import Miso.Native.X.Element.Refresh.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Refresh/Event.hs b/src/Miso/Native/X/Element/Refresh/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Refresh/Event.hs
@@ -0,0 +1,255 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE LambdaCase        #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Refresh.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Refresh.Event
+  ( -- *** Events
+    onHeaderOffset
+  , onHeaderOffsetWith
+  , onHeaderOffsetMain
+  , onHeaderOffsetMainWith
+  , onRefreshStateChange
+  , onRefreshStateChangeWith
+  , onRefreshStateChangeMain
+  , onRefreshStateChangeMainWith
+  , onStartRefresh
+  , onStartRefreshWith
+  , onStartRefreshMain
+  , onStartRefreshMainWith
+    -- *** Types
+  , HeaderOffsetEvent (..)
+  , RefreshStateChangeEvent (..)
+  , RefreshState (..)
+  , StartRefreshEvent (..)
+    -- *** Decoders
+  , headerOffsetDecoder
+  , refreshStateChangeDecoder
+  , startRefreshDecoder
+    -- *** Event Map
+  , refreshEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<refresh>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+refreshEvents :: Events
+refreshEvents
+  = M.fromList
+  [ ("headeroffset", BUBBLE)
+  , ("refreshstatechange", BUBBLE)
+  , ("startrefresh", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Payload of the @bindheaderoffset@ event.
+data HeaderOffsetEvent
+  = HeaderOffsetEvent
+  { isDragging :: Bool
+    -- ^ Whether the \<refresh-header\> is being dragged
+  , offsetPercent :: Double
+    -- ^ Ratio of the pull-down distance to the header's own height
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | The state of a \<refresh-header\>, mirrored from Lynx's @RefreshState@ enum.
+--
+-- @since 1.13.0.0
+data RefreshState
+  = Idle
+  | OverDragRelease
+  | Refreshing
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Numbering matches Lynx's @RefreshState@ enum (@IDLE = 0@ … @REFRESHING
+-- = 2@), the shape the wire actually sends.
+instance FromJSON RefreshState where
+  parseJSON = withNumber "RefreshState" $ \case
+    0 -> pure Idle
+    1 -> pure OverDragRelease
+    2 -> pure Refreshing
+    x -> typeMismatch "RefreshState" (toJSON x)
+-----------------------------------------------------------------------------
+-- | Payload of the @bindrefreshstatechange@ event.
+newtype RefreshStateChangeEvent
+  = RefreshStateChangeEvent
+  { state :: RefreshState
+    -- ^ The @RefreshState@ of the \<refresh-header\>
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Payload of the @bindstartrefresh@ event.
+newtype StartRefreshEvent
+  = StartRefreshEvent
+  { isManual :: Bool
+    -- ^ Whether the @startrefresh@ event was triggered by a manual drag
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'HeaderOffsetEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+headerOffsetDecoder :: Decoder HeaderOffsetEvent
+headerOffsetDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      HeaderOffsetEvent
+        <$> o .: "isDragging"
+        <*> o .: "offsetPercent"
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'RefreshStateChangeEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+refreshStateChangeDecoder :: Decoder RefreshStateChangeEvent
+refreshStateChangeDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      RefreshStateChangeEvent <$> o .: "state"
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'StartRefreshEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+startRefreshDecoder :: Decoder StartRefreshEvent
+startRefreshDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      StartRefreshEvent <$> o .: "isManual"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/refresh.html#bindheaderoffset
+--
+-- Triggered during movement while the \<refresh-header\> is exposed.
+--
+onHeaderOffset :: (HeaderOffsetEvent -> action) -> Attribute model action
+onHeaderOffset action = on "headeroffset" headerOffsetDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onHeaderOffset', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Offset HeaderOffsetEvent
+--
+-- view_ [ event (static (onHeaderOffsetMain Offset)) ] [ "some view" ]
+-- @
+--
+onHeaderOffsetMain :: (HeaderOffsetEvent -> action) -> EventHandler model action
+onHeaderOffsetMain action = onMain "headeroffset" headerOffsetDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onHeaderOffsetMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Offset HeaderOffsetEvent Model DOMRef
+--
+-- view_ [ event (static (onHeaderOffsetMainWith Offset)) ] [ "some view" ]
+-- @
+--
+onHeaderOffsetMainWith :: (HeaderOffsetEvent -> model -> DOMRef -> action) -> EventHandler model action
+onHeaderOffsetMainWith action = onMain "headeroffset" headerOffsetDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/refresh.html#bindrefreshstatechange
+--
+-- Triggered when the \<refresh-header\> state changes.
+--
+onRefreshStateChange :: (RefreshStateChangeEvent -> action) -> Attribute model action
+onRefreshStateChange action = on "refreshstatechange" refreshStateChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onRefreshStateChange', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = StateChanged RefreshStateChangeEvent
+--
+-- view_ [ event (static (onRefreshStateChangeMain StateChanged)) ] [ "some view" ]
+-- @
+--
+onRefreshStateChangeMain :: (RefreshStateChangeEvent -> action) -> EventHandler model action
+onRefreshStateChangeMain action = onMain "refreshstatechange" refreshStateChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onRefreshStateChangeMain', but the handler also receives read-only
+-- access to the @model@ and the target element's 'DOMRef' (for imperative MTS
+-- mutation).
+--
+-- @
+-- data Action = StateChanged RefreshStateChangeEvent Model DOMRef
+--
+-- view_ [ event (static (onRefreshStateChangeMainWith StateChanged)) ] [ "some view" ]
+-- @
+--
+onRefreshStateChangeMainWith :: (RefreshStateChangeEvent -> model -> DOMRef -> action) -> EventHandler model action
+onRefreshStateChangeMainWith action = onMain "refreshstatechange" refreshStateChangeDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/refresh.html#bindstartrefresh
+--
+-- Triggered when the pull threshold is reached or @autoStartRefresh@ is called.
+--
+onStartRefresh :: (StartRefreshEvent -> action) -> Attribute model action
+onStartRefresh action = on "startrefresh" startRefreshDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onStartRefresh', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Started StartRefreshEvent
+--
+-- view_ [ event (static (onStartRefreshMain Started)) ] [ "some view" ]
+-- @
+--
+onStartRefreshMain :: (StartRefreshEvent -> action) -> EventHandler model action
+onStartRefreshMain action = onMain "startrefresh" startRefreshDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onStartRefreshMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Started StartRefreshEvent Model DOMRef
+--
+-- view_ [ event (static (onStartRefreshMainWith Started)) ] [ "some view" ]
+-- @
+--
+onStartRefreshMainWith :: (StartRefreshEvent -> model -> DOMRef -> action) -> EventHandler model action
+onStartRefreshMainWith action = onMain "startrefresh" startRefreshDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onHeaderOffset', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onHeaderOffsetWith :: (HeaderOffsetEvent -> DOMRef -> action) -> Attribute model action
+onHeaderOffsetWith action = on "headeroffset" headerOffsetDecoder $ \h _ domRef -> action h domRef
+-----------------------------------------------------------------------------
+-- | Like 'onRefreshStateChange', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onRefreshStateChangeWith :: (RefreshStateChangeEvent -> DOMRef -> action) -> Attribute model action
+onRefreshStateChangeWith action = on "refreshstatechange" refreshStateChangeDecoder $ \h _ domRef -> action h domRef
+-----------------------------------------------------------------------------
+-- | Like 'onStartRefresh', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onStartRefreshWith :: (StartRefreshEvent -> DOMRef -> action) -> Attribute model action
+onStartRefreshWith action = on "startrefresh" startRefreshDecoder $ \h _ domRef -> action h domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Refresh/Method.hs b/src/Miso/Native/X/Element/Refresh/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Refresh/Method.hs
@@ -0,0 +1,52 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Refresh.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Refresh.Method
+  ( -- *** Methods
+    autoStartRefresh
+  , finishRefresh
+  ) where
+-----------------------------------------------------------------------------
+import           Miso
+import           Miso.Native.FFI (invokeExec)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/refresh.html#autostartrefresh
+--
+-- When @enable-refresh@ is true, exposes the entire \<refresh-header\>,
+-- triggering the @startrefresh@ event.
+--
+-- > autoStartRefresh "#myRefresh" Started StartFailed
+--
+autoStartRefresh
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+autoStartRefresh selector action =
+  invokeExec "autoStartRefresh" selector () (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/refresh.html#finishrefresh
+--
+-- Called after the @startrefresh@ event to end the refresh state, making the
+-- \<refresh-header\> rebound.
+--
+-- > finishRefresh "#myRefresh" Finished FinishFailed
+--
+finishRefresh
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+finishRefresh selector action =
+  invokeExec "finishRefresh" selector () (\() -> action)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Refresh/Property.hs b/src/Miso/Native/X/Element/Refresh/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Refresh/Property.hs
@@ -0,0 +1,33 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Refresh.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Refresh.Property
+  ( -- *** Property
+    enableRefresh_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/refresh.html#enable-refresh
+--
+-- Determines if dragging down or calling @autoStartRefresh@ can trigger the
+-- @startrefresh@ event.
+--
+-- > enableRefresh_ False
+--
+-- Default Value: 'True'
+--
+enableRefresh_ :: Bool -> Attribute model action
+enableRefresh_ = boolProp "enable-refresh"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/ScrollCoordinator.hs b/src/Miso/Native/X/Element/ScrollCoordinator.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/ScrollCoordinator.hs
@@ -0,0 +1,28 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.ScrollCoordinator
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<scroll-coordinator/>](https://lynxjs.org/api/elements/built-in/scroll-coordinator.html)
+--
+-- Coordinates nested scrolling, typically used with sticky headers and tabbed
+-- layouts.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.ScrollCoordinator
+  ( module Miso.Native.X.Element.ScrollCoordinator.Event
+  , module Miso.Native.X.Element.ScrollCoordinator.Method
+  , module Miso.Native.X.Element.ScrollCoordinator.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.ScrollCoordinator.Event
+import Miso.Native.X.Element.ScrollCoordinator.Method
+import Miso.Native.X.Element.ScrollCoordinator.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/ScrollCoordinator/Event.hs b/src/Miso/Native/X/Element/ScrollCoordinator/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/ScrollCoordinator/Event.hs
@@ -0,0 +1,103 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.ScrollCoordinator.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.ScrollCoordinator.Event
+  ( -- *** Events
+    onOffset
+  , onOffsetWith
+  , onOffsetMain
+  , onOffsetMainWith
+    -- *** Types
+  , ScrollCoordinatorOffsetEvent (..)
+    -- *** Decoders
+  , offsetDecoder
+    -- *** Event Map
+  , scrollCoordinatorEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<scrollcoordinator>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+scrollCoordinatorEvents :: Events
+scrollCoordinatorEvents = M.fromList [ ("offset", BUBBLE) ]
+-----------------------------------------------------------------------------
+-- | Payload of the @bindoffset@ event.
+data ScrollCoordinatorOffsetEvent
+  = ScrollCoordinatorOffsetEvent
+  { height :: Double
+    -- ^ The scrollable distance
+  , offset :: Double
+    -- ^ The header scroll offset
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'ScrollCoordinatorOffsetEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+offsetDecoder :: Decoder ScrollCoordinatorOffsetEvent
+offsetDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      ScrollCoordinatorOffsetEvent
+        <$> o .: "height"
+        <*> o .: "offset"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#bindoffset
+--
+-- Callback reporting folding progress.
+--
+onOffset :: (ScrollCoordinatorOffsetEvent -> action) -> Attribute model action
+onOffset action = on "offset" offsetDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onOffset', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Offset ScrollCoordinatorOffsetEvent
+--
+-- view_ [ event (static (onOffsetMain Offset)) ] [ "some view" ]
+-- @
+--
+onOffsetMain :: (ScrollCoordinatorOffsetEvent -> action) -> EventHandler model action
+onOffsetMain action = onMain "offset" offsetDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onOffsetMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Offset ScrollCoordinatorOffsetEvent Model DOMRef
+--
+-- view_ [ event (static (onOffsetMainWith Offset)) ] [ "some view" ]
+-- @
+--
+onOffsetMainWith :: (ScrollCoordinatorOffsetEvent -> model -> DOMRef -> action) -> EventHandler model action
+onOffsetMainWith action = onMain "offset" offsetDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onOffset', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onOffsetWith :: (ScrollCoordinatorOffsetEvent -> DOMRef -> action) -> Attribute model action
+onOffsetWith action = on "offset" offsetDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/ScrollCoordinator/Method.hs b/src/Miso/Native/X/Element/ScrollCoordinator/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/ScrollCoordinator/Method.hs
@@ -0,0 +1,50 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.ScrollCoordinator.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.ScrollCoordinator.Method
+  ( -- *** Methods
+    setFoldExpanded
+  ) where
+-----------------------------------------------------------------------------
+import           Miso
+import           Miso.Native.FFI (invokeExec)
+-----------------------------------------------------------------------------
+-- | Params object for 'setFoldExpanded'.
+data SetFoldExpanded = SetFoldExpanded MisoString Bool
+-----------------------------------------------------------------------------
+instance ToJSVal SetFoldExpanded where
+  toJSVal (SetFoldExpanded offset_ smooth) = do
+    o <- create
+    set "offset" offset_ o
+    set "smooth" smooth o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#setfoldexpanded
+--
+-- Adjusts the fold expansion state, optionally with animation. The @offset_@ is
+-- a @px@ / @rpx@ value, e.g. @\"100px\"@.
+--
+-- > setFoldExpanded "#coordinator" "100px" True Expanded ExpandFailed
+--
+setFoldExpanded
+  :: MisoString
+  -> MisoString
+  -- ^ Offset_ (px \/ rpx)
+  -> Bool
+  -- ^ Whether to animate
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+setFoldExpanded selector offset_ smooth action =
+  invokeExec "setFoldExpanded" selector (SetFoldExpanded offset_ smooth) (\() -> action)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/ScrollCoordinator/Property.hs b/src/Miso/Native/X/Element/ScrollCoordinator/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/ScrollCoordinator/Property.hs
@@ -0,0 +1,130 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.ScrollCoordinator.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.ScrollCoordinator.Property
+  ( -- *** Property
+    androidNestedScrollAsChild_
+  , bounces_
+  , enableScroll_
+  , enableScrollBar_
+  , granularity_
+  , headerOverSlot_
+  , iosForceScrollDetach_
+  , iosScrollsToTop_
+  , refreshMode_
+    -- *** Types
+  , RefreshMode (..)
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON (ToJSON(..))
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | The pull-to-refresh mode of the foldview (iOS), used by 'refreshMode_'.
+data RefreshMode
+  = RefreshNone
+  | RefreshPage
+  | RefreshFold
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON RefreshMode where
+  toJSON RefreshNone = "none"
+  toJSON RefreshPage = "page"
+  toJSON RefreshFold = "fold"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#android-nested-scroll-as-child
+--
+-- *Android* only. Enables nested scroll behavior as a child element in other
+-- scrolling widgets.
+--
+-- Default Value: @False@
+--
+androidNestedScrollAsChild_ :: Bool -> Attribute model action
+androidNestedScrollAsChild_ = boolProp "android-nested-scroll-as-child"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#bounces
+--
+-- *iOS \/ Harmony* only. Enables the bounce effect when scrolling past the
+-- boundary.
+--
+-- Default Value: 'True'
+--
+bounces_ :: Bool -> Attribute model action
+bounces_ = boolProp "bounces"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#enable-scroll
+--
+-- Controls whether vertical scrolling is permitted.
+--
+-- Default Value: 'True'
+--
+enableScroll_ :: Bool -> Attribute model action
+enableScroll_ = boolProp "enable-scroll"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#enable-scroll-bar
+--
+-- *iOS \/ Harmony* only. Determines scrollbar visibility during coordinator
+-- scrolling.
+--
+-- Default Value: @False@
+--
+enableScrollBar_ :: Bool -> Attribute model action
+enableScrollBar_ = boolProp "enable-scroll-bar"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#granularity
+--
+-- The event response granularity of @bindoffset@.
+--
+-- Default Value: 0.01
+--
+granularity_ :: Double -> Attribute model action
+granularity_ = doubleProp "granularity"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#header-over-slot
+--
+-- Controls header layering hierarchy relative to slot content.
+--
+-- Default Value: @False@
+--
+headerOverSlot_ :: Bool -> Attribute model action
+headerOverSlot_ = boolProp "header-over-slot"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#ios-force-scroll-detach
+--
+-- *iOS* only. Forces @nested-vertical-scroll-behavior@ invalidation.
+--
+-- Default Value: @False@
+--
+iosForceScrollDetach_ :: Bool -> Attribute model action
+iosForceScrollDetach_ = boolProp "ios-force-scroll-detach"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#ios-scrolls-to-top
+--
+-- *iOS* only. Enables status-bar tap-to-scroll-top functionality.
+--
+-- Default Value: @False@
+--
+iosScrollsToTop_ :: Bool -> Attribute model action
+iosScrollsToTop_ = boolProp "ios-scrolls-to-top"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/scroll-coordinator.html#refresh-mode
+--
+-- *iOS* only. The pull-to-refresh mode of the foldview.
+--
+-- > refreshMode_ RefreshFold
+--
+-- Default Value: 'RefreshNone'
+--
+refreshMode_ :: RefreshMode -> Attribute model action
+refreshMode_ = prop "refresh-mode"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Svg.hs b/src/Miso/Native/X/Element/Svg.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Svg.hs
@@ -0,0 +1,25 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Svg
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<svg/>](https://lynxjs.org/api/elements/built-in/svg.html)
+--
+-- Displays SVG content supplied inline or by URL.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Svg
+  ( module Miso.Native.X.Element.Svg.Event
+  , module Miso.Native.X.Element.Svg.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.Svg.Event
+import Miso.Native.X.Element.Svg.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Svg/Event.hs b/src/Miso/Native/X/Element/Svg/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Svg/Event.hs
@@ -0,0 +1,75 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Svg.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Svg.Event
+  ( -- *** Events
+    onLoad
+  , onLoadWith
+  , onLoadMain
+  , onLoadMainWith
+    -- *** Event Map
+  , svgEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<svg>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+svgEvents :: Events
+svgEvents = M.fromList [ ("load", BUBBLE) ]
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/svg.html#bindload
+--
+-- Triggered when the SVG finishes loading.
+--
+onLoad :: action -> Attribute model action
+onLoad action = on "load" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onLoad', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Loaded
+--
+-- view_ [ event (static (onLoadMain Loaded)) ] [ "some view" ]
+-- @
+--
+onLoadMain :: action -> EventHandler model action
+onLoadMain action = onMain "load" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onLoadMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Loaded Model DOMRef
+--
+-- view_ [ event (static (onLoadMainWith Loaded)) ] [ "some view" ]
+-- @
+--
+onLoadMainWith :: (model -> DOMRef -> action) -> EventHandler model action
+onLoadMainWith action = onMain "load" emptyDecoder (\() m ref -> action m ref)
+-----------------------------------------------------------------------------
+-- | Like 'onLoad', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLoadWith :: (DOMRef -> action) -> Attribute model action
+onLoadWith action = on "load" emptyDecoder (\() _ ref -> action ref)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Svg/Property.hs b/src/Miso/Native/X/Element/Svg/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Svg/Property.hs
@@ -0,0 +1,54 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Svg.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Svg.Property
+  ( -- *** Property
+    content_
+  , contentRaw_
+  , src_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.String (MisoString, ms)
+import           Miso.Types (Attribute, View)
+import           Miso.Property
+import           Miso.Html.Render (toHtml)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/svg.html#content
+--
+-- Inline SVG XML content.
+--
+-- > content_ "<svg>...</svg>"
+--
+contentRaw_ :: MisoString -> Attribute model action
+contentRaw_ = textProp "content"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/svg.html#content
+--
+-- Inline SVG XML content using 'Miso.miso' 'Miso.Typess.View' Syntax.
+--
+-- > content_ (svg_ [] [])
+--
+-- N.B. Must use "Miso.Svg" and 'Miso.Svg.Element.svg_' combinator.
+--
+content_ :: View context model action -> Attribute model action
+content_ = textProp "content" . ms . toHtml
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/svg.html#src
+--
+-- SVG resource URL.
+--
+-- > src_ "https://url.com/image.svg"
+--
+src_ :: MisoString -> Attribute model action
+src_ = textProp "src"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Textarea.hs b/src/Miso/Native/X/Element/Textarea.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Textarea.hs
@@ -0,0 +1,27 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Textarea
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<textarea/>](https://lynxjs.org/api/elements/built-in/textarea.html)
+--
+-- Multi-line text input element.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Textarea
+  ( module Miso.Native.X.Element.Textarea.Event
+  , module Miso.Native.X.Element.Textarea.Method
+  , module Miso.Native.X.Element.Textarea.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.Textarea.Event
+import Miso.Native.X.Element.Textarea.Method
+import Miso.Native.X.Element.Textarea.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Textarea/Event.hs b/src/Miso/Native/X/Element/Textarea/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Textarea/Event.hs
@@ -0,0 +1,320 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Textarea.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Textarea.Event
+  ( -- *** Events
+    onBlur
+  , onBlurWith
+  , onBlurMain
+  , onBlurMainWith
+  , onConfirm
+  , onConfirmWith
+  , onConfirmMain
+  , onConfirmMainWith
+  , onFocus
+  , onFocusWith
+  , onFocusMain
+  , onFocusMainWith
+  , onInput
+  , onInputWith
+  , onInputMain
+  , onInputMainWith
+  , onSelection
+  , onSelectionWith
+  , onSelectionMain
+  , onSelectionMainWith
+    -- *** Types
+  , TextareaEvent (..)
+  , SelectionEvent (..)
+    -- *** Decoders
+  , textareaValueDecoder
+  , textareaDecoder
+  , selectionDecoder
+    -- *** Event Map
+  , textareaEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<textarea>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+textareaEvents :: Events
+textareaEvents = M.fromList
+  [ ("blur", BUBBLE)
+  , ("confirm", BUBBLE)
+  , ("focus", BUBBLE)
+  , ("input", BUBBLE)
+  , ("selection", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Payload of the @bindinput@ event.
+data TextareaEvent
+  = TextareaEvent
+  { textareaValue :: MisoString
+    -- ^ The current input content
+  , textareaSelectionStart :: Int
+    -- ^ Start position of the selection
+  , textareaSelectionEnd :: Int
+    -- ^ End position of the selection
+  , textareaIsComposing :: Bool
+    -- ^ Whether the input is mid-composition (IME)
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Payload of the @bindselection@ event.
+data SelectionEvent
+  = SelectionEvent
+  { selStart :: Int
+    -- ^ Start position of the selection
+  , selEnd :: Int
+    -- ^ End position of the selection
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Decodes the @value@ field shared by @bindblur@, @bindconfirm@ and @bindfocus@.
+textareaValueDecoder :: Decoder MisoString
+textareaValueDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o -> o .: "value"
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'TextareaEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+textareaDecoder :: Decoder TextareaEvent
+textareaDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      TextareaEvent
+        <$> o .: "value"
+        <*> o .:? "selectionStart" .!= 0
+        <*> o .:? "selectionEnd" .!= 0
+        -- See 'Miso.Native.X.Element.Input.Event': Lynx sends @isComposing@ as
+        -- a number (0/1), not a JSON boolean, so decode as 'Int' and coerce.
+        <*> (maybe False (/= (0 :: Int)) <$> o .:? "isComposing")
+-----------------------------------------------------------------------------
+-- Note: the JS keys stay @selectionStart@/@selectionEnd@; the record fields are
+-- 'selStart'/'selEnd' to avoid clashing with 'TextareaValue' when the hub module
+-- re-exports Event and Method together.
+-- | t'Decoder' producing a t'SelectionEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+selectionDecoder :: Decoder SelectionEvent
+selectionDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      SelectionEvent
+        <$> o .: "selectionStart"
+        <*> o .: "selectionEnd"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bindblur
+--
+-- Triggered when the textarea is blurred, outputting the current value.
+--
+onBlur :: (MisoString -> action) -> Attribute model action
+onBlur action = on "blur" textareaValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bindblur
+--
+-- Triggered when the textarea is blurred, outputting the current value.
+--
+-- Called on main thread, provides read-only access to model.
+-- Meant to be used with '-XStaticPointers'.
+--
+-- data Action = CurrentValue MisoString
+--
+-- @
+-- view_ [ event (static (onBlurMain CurrentValue)) ] [ "some view" ]
+-- @
+--
+onBlurMain :: (MisoString -> action) -> EventHandler model action
+onBlurMain action = onMain "blur" textareaValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bindblur
+--
+-- Triggered when the textarea is blurred, outputting the current value.
+--
+-- Called on main thread, provides read-only access to model.
+-- Meant to be used with '-XStaticPointers'.
+--
+-- @
+--
+-- data Action = CurrentValue MisoString Model DOMRef
+--
+-- view_ [ event (static (onBlurMain CurrentValue)) ] [ "some view" ]
+--
+-- @
+--
+onBlurMainWith :: (MisoString -> model -> DOMRef -> action) -> EventHandler model action
+onBlurMainWith action = onMain "blur" textareaValueDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bindconfirm
+--
+-- Triggered when the confirm button is clicked (only when @confirm-type@ is
+-- defined), outputting the current value.
+--
+onConfirm :: (MisoString -> action) -> Attribute model action
+onConfirm action = on "confirm" textareaValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bindconfirm
+--
+-- Triggered when the confirm button is clicked (only when @confirm-type@ is
+-- defined), outputting the current value.
+--
+onConfirmMain :: (MisoString -> action) -> EventHandler model action
+onConfirmMain action = onMain "confirm" textareaValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bindconfirm
+--
+-- Triggered when the confirm button is clicked (only when @confirm-type@ is
+-- defined), outputting the current value.
+--
+onConfirmMainWith :: (MisoString -> model -> DOMRef -> action) -> EventHandler model action
+onConfirmMainWith action = onMain "confirm" textareaValueDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bindfocus
+--
+-- Triggered when the textarea is focused, outputting the current value.
+--
+onFocus :: (MisoString -> action) -> Attribute model action
+onFocus action = on "focus" textareaValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onFocus', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Focused MisoString
+--
+-- view_ [ event (static (onFocusMain Focused)) ] [ "some view" ]
+-- @
+--
+onFocusMain :: (MisoString -> action) -> EventHandler model action
+onFocusMain action = onMain "focus" textareaValueDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onFocusMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Focused MisoString Model DOMRef
+--
+-- view_ [ event (static (onFocusMainWith Focused)) ] [ "some view" ]
+-- @
+--
+onFocusMainWith :: (MisoString -> model -> DOMRef -> action) -> EventHandler model action
+onFocusMainWith action = onMain "focus" textareaValueDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bindinput
+--
+-- Triggered when the textarea content changes.
+--
+onInput :: (TextareaEvent -> action) -> Attribute model action
+onInput action = on "input" textareaDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onInput', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Changed TextareaEvent
+--
+-- view_ [ event (static (onInputMain Changed)) ] [ "some view" ]
+-- @
+--
+onInputMain :: (TextareaEvent -> action) -> EventHandler model action
+onInputMain action = onMain "input" textareaDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onInputMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Changed TextareaEvent Model DOMRef
+--
+-- view_ [ event (static (onInputMainWith Changed)) ] [ "some view" ]
+-- @
+--
+onInputMainWith :: (TextareaEvent -> model -> DOMRef -> action) -> EventHandler model action
+onInputMainWith action = onMain "input" textareaDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bindselection
+--
+-- Triggered when the textarea selection changes.
+--
+onSelection :: (SelectionEvent -> action) -> Attribute model action
+onSelection action = on "selection" selectionDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onSelection', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Selected SelectionEvent
+--
+-- view_ [ event (static (onSelectionMain Selected)) ] [ "some view" ]
+-- @
+--
+onSelectionMain :: (SelectionEvent -> action) -> EventHandler model action
+onSelectionMain action = onMain "selection" selectionDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onSelectionMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Selected SelectionEvent Model DOMRef
+--
+-- view_ [ event (static (onSelectionMainWith Selected)) ] [ "some view" ]
+-- @
+--
+onSelectionMainWith :: (SelectionEvent -> model -> DOMRef -> action) -> EventHandler model action
+onSelectionMainWith action = onMain "selection" selectionDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onBlur', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onBlurWith :: (MisoString -> DOMRef -> action) -> Attribute model action
+onBlurWith action = on "blur" textareaValueDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onConfirm', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onConfirmWith :: (MisoString -> DOMRef -> action) -> Attribute model action
+onConfirmWith action = on "confirm" textareaValueDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onFocus', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onFocusWith :: (MisoString -> DOMRef -> action) -> Attribute model action
+onFocusWith action = on "focus" textareaValueDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onInput', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onInputWith :: (TextareaEvent -> DOMRef -> action) -> Attribute model action
+onInputWith action = on "input" textareaDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onSelection', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onSelectionWith :: (SelectionEvent -> DOMRef -> action) -> Attribute model action
+onSelectionWith action = on "selection" selectionDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Textarea/Method.hs b/src/Miso/Native/X/Element/Textarea/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Textarea/Method.hs
@@ -0,0 +1,129 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Textarea.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Textarea.Method
+  ( -- *** Methods
+    focus
+  , blur
+  , setValue
+  , setSelectionRange
+  , getValue
+    -- *** Types
+  , TextareaValue (..)
+  ) where
+-----------------------------------------------------------------------------
+import Miso hiding (focus, blur, setValue, setSelectionRange)
+import Miso.Native.FFI (invokeExec)
+-----------------------------------------------------------------------------
+-- | Result of calling 'getValue'.
+data TextareaValue
+  = TextareaValue
+  { value :: MisoString
+    -- ^ The current input content
+  , selectionStart :: Int
+    -- ^ Start position of the selection
+  , selectionEnd :: Int
+    -- ^ End position of the selection
+  , isComposing :: Bool
+    -- ^ Whether the input is mid-composition (IME)
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal TextareaValue where
+  fromJSVal o = do
+    let readProp name = fromJSValUnchecked =<< o ! (name :: MisoString)
+    value          <- readProp "value"
+    selectionStart <- readProp "selectionStart"
+    selectionEnd   <- readProp "selectionEnd"
+    isComposing    <- readProp "isComposing"
+    pure $ Just TextareaValue {..}
+-----------------------------------------------------------------------------
+-- | Params object for 'setValue'.
+newtype SetValue = SetValue MisoString
+-----------------------------------------------------------------------------
+instance ToJSVal SetValue where
+  toJSVal (SetValue v) = do
+    o <- create
+    set "value" v o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | Params object for 'setSelectionRange'.
+data SetSelectionRange = SetSelectionRange Int Int
+-----------------------------------------------------------------------------
+instance ToJSVal SetSelectionRange where
+  toJSVal (SetSelectionRange s e) = do
+    o <- create
+    set "selectionStart" s o
+    set "selectionEnd" e o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#focus
+--
+-- Requests focus for the selected \<textarea\>.
+--
+focus
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+focus selector action = invokeExec "focus" selector () (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#blur
+--
+-- Releases focus for the selected \<textarea\>.
+--
+blur
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+blur selector action = invokeExec "blur" selector () (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#setvalue
+--
+-- Sets the input content of the selected \<textarea\>.
+--
+setValue
+  :: MisoString
+  -> MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+setValue selector v action =
+  invokeExec "setValue" selector (SetValue v) (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#setselectionrange
+--
+-- Sets the selection range of the selected \<textarea\>.
+--
+setSelectionRange
+  :: MisoString
+  -> Int
+  -> Int
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+setSelectionRange selector s e action =
+  invokeExec "setSelectionRange" selector (SetSelectionRange s e) (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#getvalue
+--
+-- Retrieves the current value (and selection) of the selected \<textarea\>.
+--
+getValue
+  :: MisoString
+  -> (TextareaValue -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+getValue selector = invokeExec "getValue" selector ()
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Textarea/Property.hs b/src/Miso/Native/X/Element/Textarea/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Textarea/Property.hs
@@ -0,0 +1,199 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Textarea.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Textarea.Property
+  ( -- *** Property
+    androidFullscreenMode_
+  , bounces_
+  , confirmType_
+  , disabled_
+  , enableScrollBar_
+  , inputFilter_
+  , iosAutoCorrect_
+  , iosSpellCheck_
+  , lineSpacing_
+  , maxlength_
+  , maxlines_
+  , placeholder_
+  , readonly_
+  , showSoftInputOnFocus_
+  , type_
+    -- *** Types
+  , TextareaType (..)
+  , ConfirmType (..)
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON (ToJSON(..))
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | The content type of a \<textarea\>, used by 'type_'.
+data TextareaType
+  = TextareaNumber
+  | TextareaText
+  | TextareaDigit
+  | TextareaTel
+  | TextareaEmail
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON TextareaType where
+  toJSON TextareaNumber = "number"
+  toJSON TextareaText   = "text"
+  toJSON TextareaDigit  = "digit"
+  toJSON TextareaTel    = "tel"
+  toJSON TextareaEmail  = "email"
+-----------------------------------------------------------------------------
+-- | The confirm button type of a \<textarea\>, used by 'confirmType_'.
+data ConfirmType
+  = ConfirmSearch
+  | ConfirmSend
+  | ConfirmGo
+  | ConfirmDone
+  | ConfirmNext
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSON ConfirmType where
+  toJSON ConfirmSearch = "search"
+  toJSON ConfirmSend   = "send"
+  toJSON ConfirmGo     = "go"
+  toJSON ConfirmDone   = "done"
+  toJSON ConfirmNext   = "next"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#android-fullscreen-mode
+--
+-- Whether to enter the full-screen input mode when in landscape screen.
+--
+-- Default Value: 'True'
+--
+androidFullscreenMode_ :: Bool -> Attribute model action
+androidFullscreenMode_ = boolProp "android-fullscreen-mode"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#bounces
+--
+-- *iOS* only. Bounce effect when scrolling past the boundary.
+--
+-- Default Value: 'True'
+--
+bounces_ :: Bool -> Attribute model action
+bounces_ = boolProp "bounces"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#confirm-type
+--
+-- Specifies the confirm button type.
+--
+-- Default Value: 'ConfirmDone'
+--
+confirmType_ :: ConfirmType -> Attribute model action
+confirmType_ = prop "confirm-type"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#disabled
+--
+-- Controls whether interaction is enabled.
+--
+-- Default Value: @False@
+--
+disabled_ :: Bool -> Attribute model action
+disabled_ = boolProp "disabled"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#enable-scroll-bar
+--
+-- Whether to show the scroll bar.
+--
+-- Default Value: @False@
+--
+enableScrollBar_ :: Bool -> Attribute model action
+enableScrollBar_ = boolProp "enable-scroll-bar"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#input-filter
+--
+-- Filters the input content in the form of a regular expression.
+--
+inputFilter_ :: MisoString -> Attribute model action
+inputFilter_ = textProp "input-filter"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#ios-auto-correct
+--
+-- Enables auto-correction on iOS.
+--
+-- Default Value: 'True'
+--
+iosAutoCorrect_ :: Bool -> Attribute model action
+iosAutoCorrect_ = boolProp "ios-auto-correct"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#ios-spell-check
+--
+-- Enables spell-checking on iOS.
+--
+-- Default Value: 'True'
+--
+iosSpellCheck_ :: Bool -> Attribute model action
+iosSpellCheck_ = boolProp "ios-spell-check"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#line-spacing
+--
+-- Line spacing.
+--
+lineSpacing_ :: Double -> Attribute model action
+lineSpacing_ = doubleProp "line-spacing"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#maxlength
+--
+-- Maximum input length allowed.
+--
+-- Default Value: 140
+--
+maxlength_ :: Int -> Attribute model action
+maxlength_ = intProp "maxlength"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#maxlines
+--
+-- Maximum number of input lines.
+--
+maxlines_ :: Int -> Attribute model action
+maxlines_ = intProp "maxlines"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#placeholder
+--
+-- Placeholder text display.
+--
+placeholder_ :: MisoString -> Attribute model action
+placeholder_ = textProp "placeholder"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#readonly
+--
+-- Makes the input read-only.
+--
+-- Default Value: @False@
+--
+readonly_ :: Bool -> Attribute model action
+readonly_ = boolProp "readonly"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#show-soft-input-on-focus
+--
+-- Show soft input keyboard while focused.
+--
+-- Default Value: 'True'
+--
+showSoftInputOnFocus_ :: Bool -> Attribute model action
+showSoftInputOnFocus_ = boolProp "show-soft-input-on-focus"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/textarea.html#type
+--
+-- Input content type.
+--
+-- Default Value: 'TextareaText'
+--
+type_ :: TextareaType -> Attribute model action
+type_ = prop "type"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/TitleBarView.hs b/src/Miso/Native/X/Element/TitleBarView.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/TitleBarView.hs
@@ -0,0 +1,23 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.TitleBarView
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<title-bar-view/>](https://lynxjs.org/api/elements/built-in/title-bar-view.html)
+--
+-- Defines a custom draggable window region (Clay Windows / macOS).
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.TitleBarView
+  ( module Miso.Native.X.Element.TitleBarView.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.TitleBarView.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/TitleBarView/Property.hs b/src/Miso/Native/X/Element/TitleBarView/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/TitleBarView/Property.hs
@@ -0,0 +1,32 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.TitleBarView.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.TitleBarView.Property
+  ( -- *** Property
+    moveable_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/title-bar-view.html#moveable
+--
+-- When set to true, dragging the title bar view moves the window.
+--
+-- > moveable_ True
+--
+-- Default Value: @False@
+--
+moveable_ :: Bool -> Attribute model action
+moveable_ = boolProp "moveable"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Viewpager.hs b/src/Miso/Native/X/Element/Viewpager.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Viewpager.hs
@@ -0,0 +1,27 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Viewpager
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<viewpager/>](https://lynxjs.org/api/elements/built-in/viewpager.html)
+--
+-- Horizontally paged container.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Viewpager
+  ( module Miso.Native.X.Element.Viewpager.Event
+  , module Miso.Native.X.Element.Viewpager.Method
+  , module Miso.Native.X.Element.Viewpager.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.Viewpager.Event
+import Miso.Native.X.Element.Viewpager.Method
+import Miso.Native.X.Element.Viewpager.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Viewpager/Event.hs b/src/Miso/Native/X/Element/Viewpager/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Viewpager/Event.hs
@@ -0,0 +1,204 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Viewpager.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Viewpager.Event
+  ( -- *** Events
+    onChange
+  , onChangeWith
+  , onChangeMain
+  , onChangeMainWith
+  , onOffsetChange
+  , onOffsetChangeWith
+  , onOffsetChangeMain
+  , onOffsetChangeMainWith
+  , onWillChange
+  , onWillChangeWith
+  , onWillChangeMain
+  , onWillChangeMainWith
+    -- *** Types
+  , ViewpagerChangeEvent (..)
+    -- *** Decoders
+  , viewpagerChangeDecoder
+  , offsetChangeDecoder
+    -- *** Event Map
+  , viewpagerEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.Types (DOMRef, Attribute, EventHandler)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<viewpager>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+viewpagerEvents :: Events
+viewpagerEvents
+  = M.fromList
+  [ ("change", BUBBLE)
+  , ("offsetchange", BUBBLE)
+  , ("willchange", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Payload of the @bindchange@ and @bindwillchange@ events.
+data ViewpagerChangeEvent
+  = ViewpagerChangeEvent
+  { index :: Int
+    -- ^ The page index
+  , isDragged :: Bool
+    -- ^ Whether the change was user-initiated
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'ViewpagerChangeEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+viewpagerChangeDecoder :: Decoder ViewpagerChangeEvent
+viewpagerChangeDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      ViewpagerChangeEvent
+        <$> o .: "index"
+        <*> o .: "isDragged"
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'Double' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+offsetChangeDecoder :: Decoder Double
+offsetChangeDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o -> o .: "offset"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#bindchange
+--
+-- Triggered with the current page index after the transition completes.
+--
+onChange :: (ViewpagerChangeEvent -> action) -> Attribute model action
+onChange action = on "change" viewpagerChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onChange', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Changed ViewpagerChangeEvent
+--
+-- view_ [ event (static (onChangeMain Changed)) ] [ "some view" ]
+-- @
+--
+onChangeMain :: (ViewpagerChangeEvent -> action) -> EventHandler model action
+onChangeMain action = onMain "change" viewpagerChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onChangeMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Changed ViewpagerChangeEvent Model DOMRef
+--
+-- view_ [ event (static (onChangeMainWith Changed)) ] [ "some view" ]
+-- @
+--
+onChangeMainWith :: (ViewpagerChangeEvent -> model -> DOMRef -> action) -> EventHandler model action
+onChangeMainWith action = onMain "change" viewpagerChangeDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#bindoffsetchange
+--
+-- Triggered with the scrolling progress during a page transition.
+--
+onOffsetChange :: (Double -> action) -> Attribute model action
+onOffsetChange action = on "offsetchange" offsetChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onOffsetChange', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = OffsetChanged Double
+--
+-- view_ [ event (static (onOffsetChangeMain OffsetChanged)) ] [ "some view" ]
+-- @
+--
+onOffsetChangeMain :: (Double -> action) -> EventHandler model action
+onOffsetChangeMain action = onMain "offsetchange" offsetChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onOffsetChangeMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = OffsetChanged Double Model DOMRef
+--
+-- view_ [ event (static (onOffsetChangeMainWith OffsetChanged)) ] [ "some view" ]
+-- @
+--
+onOffsetChangeMainWith :: (Double -> model -> DOMRef -> action) -> EventHandler model action
+onOffsetChangeMainWith action = onMain "offsetchange" offsetChangeDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#bindwillchange
+--
+-- Triggered with the next page index before the transition starts.
+--
+onWillChange :: (ViewpagerChangeEvent -> action) -> Attribute model action
+onWillChange action = on "willchange" viewpagerChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onWillChange', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = WillChange ViewpagerChangeEvent
+--
+-- view_ [ event (static (onWillChangeMain WillChange)) ] [ "some view" ]
+-- @
+--
+onWillChangeMain :: (ViewpagerChangeEvent -> action) -> EventHandler model action
+onWillChangeMain action = onMain "willchange" viewpagerChangeDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onWillChangeMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = WillChange ViewpagerChangeEvent Model DOMRef
+--
+-- view_ [ event (static (onWillChangeMainWith WillChange)) ] [ "some view" ]
+-- @
+--
+onWillChangeMainWith :: (ViewpagerChangeEvent -> model -> DOMRef -> action) -> EventHandler model action
+onWillChangeMainWith action = onMain "willchange" viewpagerChangeDecoder action
+-----------------------------------------------------------------------------
+-- | Like 'onChange', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onChangeWith :: (ViewpagerChangeEvent -> DOMRef -> action) -> Attribute model action
+onChangeWith action = on "change" viewpagerChangeDecoder $ \vpce _ domRef -> action vpce domRef
+-----------------------------------------------------------------------------
+-- | Like 'onOffsetChange', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onOffsetChangeWith :: (Double -> DOMRef -> action) -> Attribute model action
+onOffsetChangeWith action = on "offsetchange" offsetChangeDecoder $ \vpce _ domRef -> action vpce domRef
+-----------------------------------------------------------------------------
+-- | Like 'onWillChange', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onWillChangeWith :: (ViewpagerChangeEvent -> DOMRef -> action) -> Attribute model action
+onWillChangeWith action = on "willchange" viewpagerChangeDecoder $ \vpce _ domRef -> action vpce domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Viewpager/Method.hs b/src/Miso/Native/X/Element/Viewpager/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Viewpager/Method.hs
@@ -0,0 +1,49 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Viewpager.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Viewpager.Method
+  ( -- *** Methods
+    selectTab
+  ) where
+-----------------------------------------------------------------------------
+import           Miso
+import           Miso.Native.FFI (invokeExec)
+-----------------------------------------------------------------------------
+-- | Params object for 'selectTab'.
+data SelectTab = SelectTab Int Bool
+-----------------------------------------------------------------------------
+instance ToJSVal SelectTab where
+  toJSVal (SelectTab i smooth) = do
+    o <- create
+    set "index" i o
+    set "smooth" smooth o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#selecttab
+--
+-- Programmatically navigates to the specified page, optionally with animation.
+--
+-- > selectTab "#myPager" 2 True TabSelected TabSelectFailed
+--
+selectTab
+  :: MisoString
+  -> Int
+  -- ^ Page index
+  -> Bool
+  -- ^ Whether to animate the transition
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+selectTab selector i smooth action =
+  invokeExec "selectTab" selector (SelectTab i smooth) (\() -> action)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Viewpager/Property.hs b/src/Miso/Native/X/Element/Viewpager/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Viewpager/Property.hs
@@ -0,0 +1,119 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Viewpager.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Viewpager.Property
+  ( -- *** Property
+    androidAlwaysOverscroll_
+  , androidForceCanScroll_
+  , bounces_
+  , enableScroll_
+  , initialSelectIndex_
+  , iosGestureDirection_
+  , iosGestureOffset_
+  , iosRecognizedGestureClass_
+  , iosRecognizedViewTag_
+  , keepItemView_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#android-always-overscroll
+--
+-- *Android* only. Controls the bounce effect at the edges.
+--
+-- Default Value: @False@
+--
+androidAlwaysOverscroll_ :: Bool -> Attribute model action
+androidAlwaysOverscroll_ = boolProp "android-always-overscroll"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#android-force-can-scroll
+--
+-- *Android* only. Prevents gesture pass-through to the parent.
+--
+-- Default Value: @False@
+--
+androidForceCanScroll_ :: Bool -> Attribute model action
+androidForceCanScroll_ = boolProp "android-force-can-scroll"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#bounces
+--
+-- *iOS \/ Desktop \/ Harmony* only. Enables the spring effect.
+--
+-- Default Value: 'True'
+--
+bounces_ :: Bool -> Attribute model action
+bounces_ = boolProp "bounces"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#enable-scroll
+--
+-- Activates horizontal scroll gestures.
+--
+-- Default Value: 'True'
+--
+enableScroll_ :: Bool -> Attribute model action
+enableScroll_ = boolProp "enable-scroll"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#initial-select-index
+--
+-- Selects the specified page on initialization.
+--
+-- Default Value: 0
+--
+initialSelectIndex_ :: Int -> Attribute model action
+initialSelectIndex_ = intProp "initial-select-index"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#ios-gesture-direction
+--
+-- *iOS* only. Allows the outer container to respond when at the edges.
+--
+-- Default Value: @False@
+--
+iosGestureDirection_ :: Bool -> Attribute model action
+iosGestureDirection_ = boolProp "ios-gesture-direction"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#ios-gesture-offset
+--
+-- *iOS* only. Edge zone distance where the back gesture takes priority.
+--
+-- Default Value: 0
+--
+iosGestureOffset_ :: Int -> Attribute model action
+iosGestureOffset_ = intProp "ios-gesture-offset"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#ios-recognized-gesture-class
+--
+-- *iOS* only. @UIGestureRecognizer@ class name for simultaneous recognition.
+--
+iosRecognizedGestureClass_ :: MisoString -> Attribute model action
+iosRecognizedGestureClass_ = textProp "ios-recognized-gesture-class"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#ios-recognized-view-tag
+--
+-- *iOS* only. @UIView@ tag identifying the gesture recognizer source.
+--
+-- Default Value: 0
+--
+iosRecognizedViewTag_ :: Int -> Attribute model action
+iosRecognizedViewTag_ = intProp "ios-recognized-view-tag"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/viewpager.html#keep-item-view
+--
+-- Enables lazy-load mode with early exposure.
+--
+-- Default Value: @False@
+--
+keepItemView_ :: Bool -> Attribute model action
+keepItemView_ = boolProp "keep-item-view"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Webview.hs b/src/Miso/Native/X/Element/Webview.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Webview.hs
@@ -0,0 +1,27 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Webview
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- [/<webview/>](https://lynxjs.org/api/elements/built-in/webview.html)
+--
+-- Embeds a web page.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Webview
+  ( module Miso.Native.X.Element.Webview.Event
+  , module Miso.Native.X.Element.Webview.Method
+  , module Miso.Native.X.Element.Webview.Property
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Native.X.Element.Webview.Event
+import Miso.Native.X.Element.Webview.Method
+import Miso.Native.X.Element.Webview.Property
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Webview/Event.hs b/src/Miso/Native/X/Element/Webview/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Webview/Event.hs
@@ -0,0 +1,295 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Webview.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Webview.Event
+  ( -- *** Events
+    onError
+  , onErrorWith
+  , onErrorMain
+  , onErrorMainWith
+  , onLoad
+  , onLoadWith
+  , onLoadMain
+  , onLoadMainWith
+  , onLocationChange
+  , onLocationChangeWith
+  , onLocationChangeMain
+  , onLocationChangeMainWith
+  , onMessage
+  , onMessageWith
+  , onMessageMain
+  , onMessageMainWith
+  , onOpenWindow
+  , onOpenWindowWith
+  , onOpenWindowMain
+  , onOpenWindowMainWith
+    -- *** Types
+  , WebviewErrorEvent (..)
+    -- *** Decoders
+  , webviewErrorDecoder
+  , urlDecoder
+  , messageDecoder
+    -- *** Event Map
+  , webviewEvents
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.Map as M
+-----------------------------------------------------------------------------
+import           Miso.Event
+import           Miso.JSON
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute, EventHandler, DOMRef)
+-----------------------------------------------------------------------------
+-- | The 'Events' map for the Lynx @<webview>@ element.
+--
+-- Combine with other element maps using @<>@ and pass the result to
+-- 'Miso.Native.native', so the delegator listens for these events.
+--
+-- @since 1.13.0.0
+webviewEvents :: Events
+webviewEvents
+  = M.fromList
+  [ ("error", BUBBLE)
+  , ("load", BUBBLE)
+  , ("locationchange", BUBBLE)
+  , ("message", BUBBLE)
+  , ("openwindow", BUBBLE)
+  ]
+-----------------------------------------------------------------------------
+-- | Payload of the @binderror@ event.
+data WebviewErrorEvent
+  = WebviewErrorEvent
+  { errorCode :: Int
+    -- ^ The error code
+  , errorMsg :: MisoString
+    -- ^ The error message
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | t'Decoder' producing a t'WebviewErrorEvent' from the raw Lynx event payload.
+--
+-- Pass it to 'Miso.Event.on' \/ 'Miso.Event.onMain' when writing a handler by
+-- hand; the @on*@ helpers in this module already use it.
+--
+-- @since 1.13.0.0
+webviewErrorDecoder :: Decoder WebviewErrorEvent
+webviewErrorDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o ->
+      WebviewErrorEvent
+        <$> o .: "errorCode"
+        <*> o .: "errorMsg"
+-----------------------------------------------------------------------------
+-- | Decodes the @url@ field of @bindlocationchange@ and @bindopenwindow@.
+urlDecoder :: Decoder MisoString
+urlDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o -> o .: "url"
+-----------------------------------------------------------------------------
+-- | Decodes the @msg@ field of @bindmessage@.
+messageDecoder :: Decoder MisoString
+messageDecoder = ["detail"] `at` details
+  where
+    details = withObject "detail" $ \o -> o .: "msg"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#binderror
+--
+-- Triggered on a webview error.
+--
+onError :: (WebviewErrorEvent -> action) -> Attribute model action
+onError action = on "error" webviewErrorDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onError', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Errored WebviewErrorEvent
+--
+-- view_ [ event (static (onErrorMain Errored)) ] [ "some view" ]
+-- @
+--
+onErrorMain :: (WebviewErrorEvent -> action) -> EventHandler model action
+onErrorMain action = onMain "error" webviewErrorDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onErrorMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Errored WebviewErrorEvent Model DOMRef
+--
+-- view_ [ event (static (onErrorMainWith Errored)) ] [ "some view" ]
+-- @
+--
+onErrorMainWith :: (WebviewErrorEvent -> model -> DOMRef -> action) -> EventHandler model action
+onErrorMainWith action = onMain "error" webviewErrorDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#bindload
+--
+-- Triggered when the webview loads successfully.
+--
+onLoad :: action -> Attribute model action
+onLoad action = on "load" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onLoad', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Loaded
+--
+-- view_ [ event (static (onLoadMain Loaded)) ] [ "some view" ]
+-- @
+--
+onLoadMain :: action -> EventHandler model action
+onLoadMain action = onMain "load" emptyDecoder (\() _ _ -> action)
+-----------------------------------------------------------------------------
+-- | Like 'onLoadMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Loaded Model DOMRef
+--
+-- view_ [ event (static (onLoadMainWith Loaded)) ] [ "some view" ]
+-- @
+--
+onLoadMainWith :: (model -> DOMRef -> action) -> EventHandler model action
+onLoadMainWith action = onMain "load" emptyDecoder (\() m ref -> action m ref)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#bindlocationchange
+--
+-- *Desktop, Lynx 3.5+*. Triggered when the location changes.
+--
+onLocationChange :: (MisoString -> action) -> Attribute model action
+onLocationChange action = on "locationchange" urlDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLocationChange', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = LocationChanged MisoString
+--
+-- view_ [ event (static (onLocationChangeMain LocationChanged)) ] [ "some view" ]
+-- @
+--
+onLocationChangeMain :: (MisoString -> action) -> EventHandler model action
+onLocationChangeMain action = onMain "locationchange" urlDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onLocationChangeMain', but the handler also receives read-only access
+-- to the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = LocationChanged MisoString Model DOMRef
+--
+-- view_ [ event (static (onLocationChangeMainWith LocationChanged)) ] [ "some view" ]
+-- @
+--
+onLocationChangeMainWith :: (MisoString -> model -> DOMRef -> action) -> EventHandler model action
+onLocationChangeMainWith action = onMain "locationchange" urlDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#bindmessage
+--
+-- Triggered when a message is posted from JavaScript.
+--
+onMessage :: (MisoString -> action) -> Attribute model action
+onMessage action = on "message" messageDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onMessage', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = Message MisoString
+--
+-- view_ [ event (static (onMessageMain Message)) ] [ "some view" ]
+-- @
+--
+onMessageMain :: (MisoString -> action) -> EventHandler model action
+onMessageMain action = onMain "message" messageDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onMessageMain', but the handler also receives read-only access to the
+-- @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = Message MisoString Model DOMRef
+--
+-- view_ [ event (static (onMessageMainWith Message)) ] [ "some view" ]
+-- @
+--
+onMessageMainWith :: (MisoString -> model -> DOMRef -> action) -> EventHandler model action
+onMessageMainWith action = onMain "message" messageDecoder action
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#bindopenwindow
+--
+-- *Desktop, Lynx 3.5+*. Triggered on an open-window event.
+--
+onOpenWindow :: (MisoString -> action) -> Attribute model action
+onOpenWindow action = on "openwindow" urlDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onOpenWindow', but dispatched on the Lynx __main thread__ (@MTS@).
+--
+-- Runs imperatively on the MTS (no VDOM diff). Meant to be used with
+-- @-XStaticPointers@.
+--
+-- @
+-- data Action = OpenWindow MisoString
+--
+-- view_ [ event (static (onOpenWindowMain OpenWindow)) ] [ "some view" ]
+-- @
+--
+onOpenWindowMain :: (MisoString -> action) -> EventHandler model action
+onOpenWindowMain action = onMain "openwindow" urlDecoder (\e _ _ -> action e)
+-----------------------------------------------------------------------------
+-- | Like 'onOpenWindowMain', but the handler also receives read-only access to
+-- the @model@ and the target element's 'DOMRef' (for imperative MTS mutation).
+--
+-- @
+-- data Action = OpenWindow MisoString Model DOMRef
+--
+-- view_ [ event (static (onOpenWindowMainWith OpenWindow)) ] [ "some view" ]
+-- @
+--
+onOpenWindowMainWith :: (MisoString -> model -> DOMRef -> action) -> EventHandler model action
+onOpenWindowMainWith action = onMain "openwindow" urlDecoder action
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- | Like 'onError', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onErrorWith :: (WebviewErrorEvent -> DOMRef -> action) -> Attribute model action
+onErrorWith action = on "error" webviewErrorDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onLoad', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLoadWith :: (DOMRef -> action) -> Attribute model action
+onLoadWith action = on "load" emptyDecoder (\() _ ref -> action ref)
+-----------------------------------------------------------------------------
+-- | Like 'onLocationChange', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onLocationChangeWith :: (MisoString -> DOMRef -> action) -> Attribute model action
+onLocationChangeWith action = on "locationchange" urlDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onMessage', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onMessageWith :: (MisoString -> DOMRef -> action) -> Attribute model action
+onMessageWith action = on "message" messageDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
+-- | Like 'onOpenWindow', but the handler also receives the target element's 'DOMRef'.
+-- Use for main-thread (@MTS@) handlers that imperatively mutate the element.
+onOpenWindowWith :: (MisoString -> DOMRef -> action) -> Attribute model action
+onOpenWindowWith action = on "openwindow" urlDecoder $ \v _ domRef -> action v domRef
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Webview/Method.hs b/src/Miso/Native/X/Element/Webview/Method.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Webview/Method.hs
@@ -0,0 +1,65 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Webview.Method
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- __N.B.__ The Desktop-only @cookies.*@ methods
+-- (@cookies.get@ / @cookies.set@ / @cookies.remove@ / @cookies.flushStore@)
+-- are not modelled here. They can be invoked directly with
+-- 'Miso.Native.FFI.invokeExec' if required.
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Webview.Method
+  ( -- *** Methods
+    reload
+  , eval
+  ) where
+-----------------------------------------------------------------------------
+import           Miso hiding (eval, reload)
+import           Miso.Native.FFI (invokeExec)
+-----------------------------------------------------------------------------
+-- | Params object for 'eval'.
+newtype Eval = Eval MisoString
+-----------------------------------------------------------------------------
+instance ToJSVal Eval where
+  toJSVal (Eval func) = do
+    o <- create
+    set "func" func o
+    toJSVal o
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#reload
+--
+-- Reloads the selected \<webview\>.
+--
+-- > reload "#myWebview" Reloaded ReloadFailed
+--
+reload
+  :: MisoString
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+reload selector action = invokeExec "reload" selector () (\() -> action)
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#eval
+--
+-- Calls a JavaScript function inside the selected \<webview\>.
+--
+-- > eval "#myWebview" "alert('hi')" Evaluated EvalFailed
+--
+eval
+  :: MisoString
+  -> MisoString
+  -- ^ JavaScript function to evaluate
+  -> action
+  -> (MisoString -> action)
+  -> Effect context props model action
+eval selector func action =
+  invokeExec "eval" selector (Eval func) (\() -> action)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Native/X/Element/Webview/Property.hs b/src/Miso/Native/X/Element/Webview/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Native/X/Element/Webview/Property.hs
@@ -0,0 +1,116 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Native.X.Element.Webview.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- @since 1.13.0.0
+----------------------------------------------------------------------------
+module Miso.Native.X.Element.Webview.Property
+  ( -- *** Property
+    bounces_
+  , cookies_
+  , enableDebug_
+  , html_
+  , initjs_
+  , params_
+  , scrollBarEnable_
+  , src_
+  , useOsr_
+  , webviewType_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON (Value)
+import           Miso.String (MisoString)
+import           Miso.Types (Attribute)
+import           Miso.Property
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#bounces
+--
+-- *iOS* only. Enables the bounce effect.
+--
+-- Default Value: @False@
+--
+bounces_ :: Bool -> Attribute model action
+bounces_ = boolProp "bounces"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#cookies
+--
+-- *Desktop, Lynx 3.5+*. Preset cookies.
+--
+cookies_ :: Value -> Attribute model action
+cookies_ = prop "cookies"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#enable-debug
+--
+-- Enables WebView debugging on Android so it can be debugged in Chrome DevTools.
+--
+-- Default Value: @False@
+--
+enableDebug_ :: Bool -> Attribute model action
+enableDebug_ = boolProp "enable-debug"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#html
+--
+-- *Lynx 3.6+*. A string of HTML content to load. Automatically refreshes when
+-- the HTML changes. Lower priority than @src_@.
+--
+html_ :: MisoString -> Attribute model action
+html_ = textProp "html"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#initjs
+--
+-- *Desktop, Lynx 3.5+*. Executes JavaScript when the document is ready.
+--
+initjs_ :: MisoString -> Attribute model action
+initjs_ = textProp "initjs"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#params
+--
+-- Params for the external webview implementation.
+--
+params_ :: Value -> Attribute model action
+params_ = prop "params"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#scroll-bar-enable
+--
+-- *iOS* only. Enables the scrollbar.
+--
+-- Default Value: @False@
+--
+scrollBarEnable_ :: Bool -> Attribute model action
+scrollBarEnable_ = boolProp "scroll-bar-enable"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#src
+--
+-- The location of a resource on a remote server.
+--
+-- > src_ "https://url.com"
+--
+src_ :: MisoString -> Attribute model action
+src_ = textProp "src"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#use-osr
+--
+-- *Desktop, Lynx 3.5+*. Whether to enable offscreen rendering mode.
+--
+-- Default Value: @False@
+--
+useOsr_ :: Bool -> Attribute model action
+useOsr_ = boolProp "use-osr"
+-----------------------------------------------------------------------------
+-- | https://lynxjs.org/api/elements/built-in/webview.html#webview-type
+--
+-- Specifies the type of webview; it can be an implementation of a webview
+-- injected from @LynxService@.
+--
+-- Default Value: @\"default\"@
+--
+webviewType_ :: MisoString -> Attribute model action
+webviewType_ = textProp "webview-type"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Navigator.hs b/src/Miso/Navigator.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Navigator.hs
@@ -0,0 +1,221 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE RecordWildCards     #-}
+{-# LANGUAGE LambdaCase          #-}
+{-# LANGUAGE CPP                 #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Navigator
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Navigator" wraps the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator Navigator>
+-- API as 'Miso.Effect.Effect' combinators that integrate directly into the
+-- Model-View-Update loop. Each function returns an 'Miso.Effect.Effect' and
+-- feeds its result back as an action via 'Miso.Effect.withSink' or
+-- 'Miso.Effect.io'.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Navigator"
+--
+-- data Action
+--   = RequestLocation
+--   | GotLocation t'Geolocation'
+--   | LocationError t'GeolocationError'
+--   | RequestCamera
+--   | GotStream t'Stream'
+--   | MediaError 'Miso.DSL.JSVal'
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update RequestLocation =
+--   'geolocation' GotLocation LocationError
+-- update RequestCamera =
+--   'getUserMedia' ('userMedia' { audio = False }) GotStream MediaError
+-- update _ = pure ()
+-- @
+--
+-- = API groups
+--
+-- * __Camera \/ microphone__ ('Navigator.mediaDevices.getUserMedia'):
+--   'getUserMedia', 'userMedia', t'UserMedia', t'Stream'
+-- * __Clipboard__ ('Navigator.clipboard.writeText'):
+--   'copyClipboard'
+-- * __Online status__ ('Navigator.onLine'):
+--   'isOnLine'
+-- * __Geolocation__ ('Navigator.geolocation.getCurrentPosition'):
+--   'geolocation', t'Geolocation', t'GeolocationError', 'GeolocationErrorCode'
+--
+-- = Error handling
+--
+-- Geolocation errors are decoded from the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError GeolocationPositionError>
+-- object into t'GeolocationError', which carries a 'GeolocationErrorCode'
+-- (@'PERMISSION_DENIED'@, @'POSITION_UNAVAILABLE'@, @'TIMEOUT'@) and a
+-- human-readable message string.
+--
+-- = See also
+--
+-- * "Miso.FFI.Internal" — 'Miso.FFI.Internal.getUserMedia', 'Miso.FFI.Internal.copyClipboard',
+--   'Miso.FFI.Internal.geolocation', 'Miso.FFI.Internal.isOnLine' — the raw IO primitives
+-- * "Miso.Subscription.OnLine" — subscription-based online\/offline monitoring
+-- * "Miso.Effect" — 'Miso.Effect.withSink', 'Miso.Effect.io'
+-----------------------------------------------------------------------------
+module Miso.Navigator
+  ( -- ** User media
+    getUserMedia
+  , userMedia
+  , UserMedia (..)
+  , Stream
+  -- ** Clipboard
+  , copyClipboard
+  -- ** OnLine
+  , isOnLine
+  -- ** Geolocation
+  , geolocation
+  , Geolocation (..)
+  , GeolocationError (..)
+  , GeolocationErrorCode (..)
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad ((<=<))
+import           Prelude hiding ((!!))
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.String
+import           Miso.Effect
+import qualified Miso.FFI.Internal as FFI
+----------------------------------------------------------------------------
+-- | A media stream
+type Stream = JSVal
+----------------------------------------------------------------------------
+-- | Get access to user's media devices.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia>
+--
+getUserMedia
+  :: UserMedia
+  -- ^ Options
+  -> (Stream -> action)
+  -- ^ Successful callback
+  -> (JSVal -> action)
+  -- ^ Errorful callback
+  -> Effect context props model action
+getUserMedia UserMedia {..} successful errorful =
+  withSink $ \sink ->
+    FFI.getUserMedia audio video
+      (sink . successful)
+      (sink . errorful)
+-----------------------------------------------------------------------------
+-- | Get access to the user's clipboard.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/clipboard>
+--
+copyClipboard
+  :: MisoString
+  -- ^ Options
+  -> action
+  -- ^ Successful callback
+  -> (JSVal -> action)
+  -- ^ Errorful callback
+  -> Effect context props model action
+copyClipboard txt successful errorful =
+  withSink $ \sink ->
+    FFI.copyClipboard txt
+      (sink successful)
+      (sink . errorful)
+-----------------------------------------------------------------------------
+-- | Get user's online status
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine>
+--
+isOnLine
+  :: (Bool -> action)
+  -- ^ Successful callback
+  -> Effect context props model action
+isOnLine action = io (action <$> FFI.isOnLine)
+-----------------------------------------------------------------------------
+-- | Type for dealing with 'navigator.mediaDevices.getUserMedia'
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/mediaDevices>
+--
+data UserMedia
+  = UserMedia
+  { audio :: Bool
+  -- ^ Request access to the user's microphone
+  , video :: Bool
+  -- ^ Request access to the user's camera
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Default t'UserMedia'
+userMedia :: UserMedia
+userMedia = UserMedia True True
+-----------------------------------------------------------------------------
+-- | Geolocation fetching
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/geolocation>
+--
+geolocation
+  :: (Geolocation -> action)
+  -- ^ Success callback; receives the device's current position
+  -> (GeolocationError -> action)
+  -- ^ Error callback; receives a t'GeolocationError' with code and message
+  -> Effect context props model action
+geolocation successful errorful = do
+  withSink $ \sink ->
+    FFI.geolocation
+      (sink . successful <=< fromJSValUnchecked)
+      (sink . errorful <=< fromJSValUnchecked)
+-----------------------------------------------------------------------------
+-- | Geolocation errors
+data GeolocationError = GeolocationError GeolocationErrorCode MisoString
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal GeolocationError where
+  fromJSVal v = do
+    code <- fromJSVal =<< (v ! "code")
+    msg <- fromJSVal =<< (v ! "message")
+    pure (GeolocationError <$> code <*> msg)
+-----------------------------------------------------------------------------
+-- | Geolocation error code
+data GeolocationErrorCode
+  = PERMISSION_DENIED
+  | POSITION_UNAVAILABLE
+  | TIMEOUT
+  deriving (Enum, Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal GeolocationErrorCode where
+  fromJSVal code =
+    fromJSValUnchecked code >>= \case
+      (1 :: Int) -> pure (Just PERMISSION_DENIED)
+      2 -> pure (Just POSITION_UNAVAILABLE)
+      3 -> pure (Just TIMEOUT)
+      _ -> pure Nothing
+-----------------------------------------------------------------------------
+-- | Geolocation holds latitude, longitude and accuracy, among others.
+data Geolocation
+  = Geolocation
+  { latitude :: Double
+  -- ^ Latitude in decimal degrees
+  , longitude :: Double
+  -- ^ Longitude in decimal degrees
+  , accuracy :: Double
+  -- ^ Accuracy of the position in metres (95% confidence radius)
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance FromJSVal Geolocation where
+  fromJSVal geo = do
+    lat <- fromJSVal =<< geo ! "coords" ! "latitude"
+    lon <- fromJSVal =<< geo ! "coords" ! "longitude"
+    acc <- fromJSVal =<< geo ! "coords" ! "accuracy"
+    pure (Geolocation <$> lat <*> lon <*> acc)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Prelude.hs b/src/Miso/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Prelude.hs
@@ -0,0 +1,59 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Prelude
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Prelude" is a batteries-included custom prelude for miso
+-- applications. It re-exports:
+--
+-- * The entirety of "Miso" — all view, update, and subscription
+--   combinators are available without a qualified import.
+-- * The standard "Prelude" — familiar Haskell functions remain in scope,
+--   with @'(!!)'@ hidden to avoid the clash with miso's index operator.
+-- * @'Control.Category.(.)'@ — replaces 'Prelude.(.)' so it works for any
+--   'Control.Category.Category', not just @(->)@.
+--
+-- = Usage
+--
+-- __Option 1 — explicit import__ (simplest):
+--
+-- @
+-- import "Miso.Prelude"
+-- @
+--
+-- __Option 2 — Cabal mixin__ (replaces @Prelude@ project-wide, zero
+-- per-file boilerplate):
+--
+-- @
+-- executable app
+--   main-is:         Main.hs
+--   build-depends:   base, miso
+--   mixins:
+--     miso,
+--     miso (Miso.Prelude as Prelude),
+--     base hiding (Prelude)
+--   default-language: Haskell2010
+-- @
+--
+-- = See also
+--
+-- * "Miso" — the main miso re-export hub
+-- * "Miso.Effect" — 'Miso.Effect.Effect', 'Miso.Effect.Sub', 'Miso.Effect.io_'
+-- * "Miso.Html" — HTML element and event combinators
+-----------------------------------------------------------------------------
+module Miso.Prelude
+  ( module Miso
+  , module Prelude
+  , (.)
+  ) where
+----------------------------------------------------------------------------
+import Control.Category ((.))
+import Prelude hiding ((.), (!!))
+import Miso
+----------------------------------------------------------------------------
diff --git a/src/Miso/Property.hs b/src/Miso/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Property.hs
@@ -0,0 +1,177 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Property" provides the low-level primitives for constructing
+-- 'Miso.Types.Attribute' values that set DOM properties on virtual nodes.
+-- All higher-level property combinators in "Miso.Html.Property",
+-- "Miso.Svg.Property", and "Miso.Mathml.Property" are built on top of
+-- these.
+--
+-- The central combinator is 'prop':
+--
+-- @
+-- 'prop' :: 'Miso.JSON.ToJSON' a => 'Miso.String.MisoString' -> a -> 'Miso.Types.Attribute' action
+-- @
+--
+-- It wraps any JSON-serialisable value as a 'Miso.Types.Property' node,
+-- which the virtual DOM diffs and writes to the DOM node only when the
+-- value changes.
+--
+-- = Typed convenience wrappers
+--
+-- ['textProp'] 'Miso.String.MisoString' — @'textProp' \"placeholder\" \"…\"@
+-- ['stringProp'] 'String' — @'stringProp' \"lang\" \"en\"@
+-- ['boolProp'] 'Bool' — @'boolProp' \"checked\" True@
+-- ['intProp'] 'Int' — @'intProp' \"tabIndex\" 3@
+-- ['integerProp'] 'Integer' — @'integerProp' \"size\" 10@
+-- ['doubleProp'] 'Double' — @'doubleProp' \"volume\" 0.8@
+-- ['objectProp'] 'Miso.JSON.Types.Object' — @'objectProp' \"dataset\" obj@
+--
+-- = Class list
+--
+-- 'classList' stores CSS class names as a deduplicated list rather than a
+-- single concatenated string. The virtual DOM diffing engine handles the
+-- list directly so individual class additions and removals are efficient:
+--
+-- @
+-- 'classList' [\"btn\", \"btn-primary\"]
+-- @
+--
+-- = Virtual DOM keys
+--
+-- 'key_' (alias 'keyProp') attaches a reconciliation key to a node, telling
+-- the differ which old and new nodes correspond to each other in a dynamic
+-- list:
+--
+-- @
+-- 'Miso.Html.Element.ul_' []
+--   [ 'Miso.Html.Element.li_' [ 'key_' item.id ] [ 'Miso.text' item.label ]
+--   | item <- items
+--   ]
+-- @
+--
+-- = See also
+--
+-- * "Miso.Html.Property" — named HTML property combinators built on this module
+-- * "Miso.Svg.Property" — SVG property combinators
+-- * "Miso.Mathml.Property" — MathML property combinators
+-- * "Miso.Types" — 'Miso.Types.Attribute', 'Miso.Types.Key', 'Miso.Types.ToKey'
+-----------------------------------------------------------------------------
+module Miso.Property
+  ( -- *** Smart constructors
+    prop
+  , classList
+  , textProp
+  , stringProp
+  , boolProp
+  , intProp
+  , integerProp
+  , doubleProp
+  , objectProp
+  , keyProp
+  , key_
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.JSON (ToJSON(..), Object)
+-----------------------------------------------------------------------------
+import           Miso.Types
+-----------------------------------------------------------------------------
+-- | @prop k v@ is an attribute that will set the attribute @k@ of the DOM
+-- node associated with the vnode to @v@.
+prop
+  :: ToJSON a
+  => MisoString
+  -- ^ DOM property name (e.g. @\"value\"@, @\"className\"@)
+  -> a
+  -- ^ Property value; serialised to JSON before diffing
+  -> Attribute model action
+prop k v = Property k (toJSON v)
+-----------------------------------------------------------------------------
+-- | Set field to 'Bool' value
+boolProp
+  :: MisoString
+  -- ^ DOM property name
+  -> Bool
+  -- ^ Property value
+  -> Attribute model action
+boolProp = prop
+-----------------------------------------------------------------------------
+-- | Set field to 'String' value
+stringProp
+  :: MisoString
+  -- ^ DOM property name
+  -> String
+  -- ^ Property value
+  -> Attribute model action
+stringProp = prop
+-----------------------------------------------------------------------------
+-- | Set field to 'MisoString' value
+textProp
+  :: MisoString
+  -- ^ DOM property name
+  -> MisoString
+  -- ^ Property value
+  -> Attribute model action
+textProp = prop
+-----------------------------------------------------------------------------
+-- | Set field to t'Object' value
+objectProp
+  :: MisoString
+  -- ^ DOM property name
+  -> Object
+  -- ^ JSON object value
+  -> Attribute model action
+objectProp = prop
+-----------------------------------------------------------------------------
+-- | Set field to 'Int' value
+intProp
+  :: MisoString
+  -- ^ DOM property name
+  -> Int
+  -- ^ Property value
+  -> Attribute model action
+intProp = prop
+-----------------------------------------------------------------------------
+-- | Set field to 'Integer' value
+integerProp
+  :: MisoString
+  -- ^ DOM property name
+  -> Integer
+  -- ^ Property value
+  -> Attribute model action
+integerProp = prop
+-----------------------------------------------------------------------------
+-- | Set field to 'Double' value
+doubleProp
+  :: MisoString
+  -- ^ DOM property name
+  -> Double
+  -- ^ Property value
+  -> Attribute model action
+doubleProp = prop
+-----------------------------------------------------------------------------
+-- | Set 'Miso.Types.Key' on 'VNode'.
+keyProp :: ToKey key => key -> Attribute model action
+keyProp key = prop "key" (toKey key)
+-----------------------------------------------------------------------------
+-- | Synonym for 'keyProp'
+-- Allows a user to specify a t'Key' inside of an '[Attribute model action]'
+key_ :: ToKey key => key -> Attribute model action
+key_ = keyProp
+-----------------------------------------------------------------------------
+-- | Smart constructor for specifying 'class'
+--
+-- @since 1.9.0.0
+classList :: [MisoString] -> Attribute model action
+classList = ClassList
+-----------------------------------------------------------------------------
diff --git a/src/Miso/PubSub.hs b/src/Miso/PubSub.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/PubSub.hs
@@ -0,0 +1,64 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.PubSub
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.PubSub" provides a lightweight publish\/subscribe channel for
+-- passing messages between independent t'Miso.Types.Component' trees that
+-- do not share a parent-child relationship.
+--
+-- A t'Topic' is an untyped broadcast channel. Any component can
+-- 'publish' a message to it; every component that has called 'subscribe'
+-- on that topic will receive the message as an action.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.PubSub"
+--
+-- -- 1. Create a shared topic (typically at the top level or in a shared module)
+-- chatTopic :: IO t'Topic'
+-- chatTopic = 'topic'
+--
+-- -- 2. Subscribe in a component's subs list
+-- myChatSub :: t'Topic' -> 'Miso.Effect.Sub' Action
+-- myChatSub t = 'subscribe' t GotMessage
+--
+-- -- 3. Publish from any component's update function
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update (SendMessage msg) =
+--   'Miso.Effect.io_' ('publish' chatTopic msg)
+-- update (GotMessage msg) = do
+--   ...
+-- @
+--
+-- = API
+--
+-- * 'topic' — create a new broadcast channel
+-- * 'subscribe' — register a component subscription that receives published values
+-- * 'unsubscribe' — deregister a subscription
+-- * 'publish' — broadcast a value to all current subscribers
+--
+-- = See also
+--
+-- * "Miso.Effect" — 'Miso.Effect.Sub', 'Miso.Effect.withSink'
+-- * "Miso.Runtime" — where t'Topic', 'subscribe', 'publish' are defined
+----------------------------------------------------------------------------
+module Miso.PubSub
+  ( -- * Pub\/Sub
+    Topic
+  , topic
+  , subscribe
+  , unsubscribe
+  , publish
+  ) where
+----------------------------------------------------------------------------
+import Miso.Runtime
+----------------------------------------------------------------------------
diff --git a/src/Miso/Random.hs b/src/Miso/Random.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Random.hs
@@ -0,0 +1,143 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP               #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Random
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Random" provides a pseudo-random number generator for miso
+-- components and their test infrastructure. It is built on the
+-- <https://prng.di.unimi.it/ SplitMix32> algorithm, implemented as a
+-- stateful JavaScript function stored in a 'Miso.DSL.Function'.
+--
+-- Two usage styles are available:
+--
+-- * __Explicit generator__ — pass a t'StdGen' through your code using
+--   'next' (analogous to @System.Random@).
+-- * __Global generator__ — use 'replicateRM' or access 'globalStdGen'
+--   directly for fire-and-forget random values.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso.Random"
+--
+-- -- Explicit generator
+-- example :: IO ()
+-- example = do
+--   gen         <- 'newStdGen'
+--   let (v, g') = 'next' gen     -- v :: Double in [0, 1)
+--   print v
+--
+-- -- Global generator (convenience)
+-- tenValues :: IO [Double]
+-- tenValues = 'replicateRM' 10
+--
+-- -- Reproducible seed for tests
+-- deterministicGen :: t'StdGen'
+-- deterministicGen = 'mkStdGen' 42
+-- @
+--
+-- = Seeding
+--
+-- * 'newStdGen' seeds from @crypto.getRandomValues()@ — cryptographically
+--   random, non-reproducible.
+-- * 'mkStdGen' takes an explicit 'Seed' (@Int@) — reproducible, useful for
+--   property tests or simulations.
+-- * 'globalStdGen' is seeded once at module load time from @Math.random()@.
+--
+-- = See also
+--
+-- * 'Miso.FFI.Internal.splitmix32' — the raw JS PRNG primitive
+-- * 'Miso.FFI.Internal.getRandomValue' — @crypto.getRandomValues()@ used for seeding
+----------------------------------------------------------------------------
+module Miso.Random
+  ( -- ** Types
+    StdGen (..)
+  , Seed
+    -- ** Functions
+  , newStdGen
+  , mkStdGen
+  , next
+  , replicateRM
+  , getStdGen
+  , setStdGen
+    -- ** Globals
+  , globalStdGen
+  ) where
+-----------------------------------------------------------------------------
+import           Data.Tuple (swap)
+import           Control.Monad.State (state, runState)
+import           Control.Monad (replicateM)
+import           Data.IORef
+import           System.IO.Unsafe (unsafePerformIO)
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import qualified Miso.FFI.Internal as FFI
+-----------------------------------------------------------------------------
+-- | t'StdGen' holds a JS t'Function'.
+newtype StdGen = StdGen Function
+-----------------------------------------------------------------------------
+-- | An initial 'Seed' value, useful for simulations or reproducing test failures
+type Seed = Int
+-----------------------------------------------------------------------------
+-- | Like 'Miso.Random.newStdGen' but takes a t'Seed' as an argument and is pure.
+mkStdGen
+  :: Seed
+  -- ^ Initial seed value; identical seeds produce identical sequences
+  -> StdGen
+mkStdGen seed = StdGen $ Function $ unsafePerformIO $ FFI.splitmix32 (fromIntegral seed)
+-----------------------------------------------------------------------------
+-- | Create a new t'StdGen', defaulting to a random t'Seed'.
+newStdGen :: IO StdGen
+newStdGen = do
+  seed <- FFI.getRandomValue
+  StdGen . Function <$> FFI.splitmix32 seed
+-----------------------------------------------------------------------------
+-- | Get the next t'StdGen', extracting the value, useful with 'State'.
+next
+  :: StdGen
+  -- ^ Current generator state
+  -> (Double, StdGen)
+next (StdGen func) = unsafePerformIO $ do
+  result <- apply func ()
+  pure (result, StdGen func)
+-----------------------------------------------------------------------------
+-- | Global t'StdGen', used by 'replicateRM' and others.
+globalStdGen :: IORef StdGen
+{-# NOINLINE globalStdGen #-}
+globalStdGen = unsafePerformIO $ do
+  seed <- floor . (*1e7) <$> FFI.mathRandom
+  newIORef (mkStdGen seed)
+-----------------------------------------------------------------------------
+-- | Read the `globalStdGen`
+getStdGen :: IO StdGen
+getStdGen = readIORef globalStdGen
+-----------------------------------------------------------------------------
+-- | Set the `globalStdGen`
+setStdGen
+  :: StdGen
+  -- ^ New generator to install as the global PRNG
+  -> IO ()
+setStdGen = atomicWriteIORef globalStdGen
+-----------------------------------------------------------------------------
+-- | Generate n amount of random numbers. Uses the global PRNG 'globalStdGen'.
+--
+-- @
+-- replicateRM 10 :: IO [Double]
+-- @
+--
+replicateRM
+  :: Int
+  -- ^ Number of random 'Double' values to generate in @[0, 1)@
+  -> IO [Double]
+replicateRM n = do
+  atomicModifyIORef globalStdGen $ \gen -> do
+    swap $ flip runState gen $ replicateM n (state next)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Reload.hs b/src/Miso/Reload.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Reload.hs
@@ -0,0 +1,272 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP                 #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Reload
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Reload" supports hot-reloading of miso applications during
+-- interactive development with GHC WASM browser mode (@ghciwatch@ +
+-- WASM GHCi). It provides two entry points that replace @startApp@ in
+-- your @main@:
+--
+-- ['reload'] clears @\<head\>@ and @\<body\>@ — full reset on every @:r@; model is lost
+-- ['live'] clears @\<body\>@ only — model state survives @:r@
+--
+-- If your top-level t'Component' uses a non-trivial app-global @context@ (see
+-- 'Miso.startAppWithContext'), use 'reloadWithContext' \/ 'liveWithContext',
+-- which seed the @context@ just as 'Miso.startAppWithContext' does.
+--
+-- = reload
+--
+-- Clears both @\<head\>@ and @\<body\>@, kills any running scheduler thread,
+-- and re-mounts the component from scratch. All application state is lost.
+-- Use this when you are actively changing the @model@ type.
+--
+-- @
+-- main :: IO ()
+-- main = 'reload' 'Miso.Event.Types.defaultEvents' app
+-- @
+--
+-- = live
+--
+-- Clears only @\<body\>@, then re-mounts the component using the __old
+-- model__ value recovered from the previous GHCi session via a C-heap
+-- stable pointer. @\<head\>@ injections (stylesheets, scripts) from the
+-- previous session are preserved.
+--
+-- @
+-- main :: IO ()
+-- main = 'live' 'Miso.Event.Types.defaultEvents' app
+-- @
+--
+-- __Warning__: 'live' is unsafe if you change the @model@ type between
+-- reloads (adding, removing, or changing a field's type). Such a change
+-- will produce a segfault because the old in-memory model is coerced
+-- directly into the new type. Use 'reload' whenever you alter the model
+-- schema.
+--
+-- = See also
+--
+-- * <https://github.com/haskell-miso/miso-sampler miso-sampler> — reference project demonstrating 'live'
+-- * "Miso.Runtime" — 'Miso.Runtime.initComponent' and component lifecycle
+-- * "Miso.Event.Types" — 'Miso.Event.Types.defaultEvents' used as first argument
+----------------------------------------------------------------------------
+module Miso.Reload
+  ( -- ** Functions
+    reload
+  , reloadWithContext
+  , live
+  , liveWithContext
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Concurrent
+import           Control.Monad
+-----------------------------------------------------------------------------
+import           Miso.DSL ((!), jsg, setField)
+import qualified Miso.FFI.Internal as FFI
+import           Miso.Types (Component(..), Events)
+import           Miso.String (MisoString)
+import           Miso.Runtime (componentModel, initComponent, topLevelComponentId, globalContext, Hydrate(..))
+import           Miso.Runtime.Internal (components, schedulerThread)
+-----------------------------------------------------------------------------
+import           Miso.Lens
+-----------------------------------------------------------------------------
+import qualified Data.IntMap.Strict as IM
+import           Data.IORef
+import           Foreign hiding (void)
+import           Foreign.C.Types
+#ifdef NATIVE
+import           Miso.JSON
+#endif
+-----------------------------------------------------------------------------
+foreign import ccall unsafe "miso_x_store"
+  x_store :: StablePtr a -> IO ()
+-----------------------------------------------------------------------------
+foreign import ccall unsafe "miso_x_get"
+  x_get :: IO (StablePtr a)
+-----------------------------------------------------------------------------
+foreign import ccall unsafe "miso_x_exists"
+  x_exists :: IO CInt
+-----------------------------------------------------------------------------
+foreign import ccall unsafe "miso_x_clear"
+  x_clear :: IO ()
+-----------------------------------------------------------------------------
+#define MISO_JS_PATH "js/miso.js"
+-----------------------------------------------------------------------------
+-- | Clears the \<body\> and \<head\> on each 'reload'.
+--
+-- Meant to be used with WASM browser mode.
+--
+-- @
+-- main :: IO ()
+-- main = 'reload' 'Miso.Event.Types.defaultEvents' app
+-- @
+--
+-- N.B. This also resets the internal 'Miso.Types.component' state. This means all currently
+-- mounted components become unmounted and @ComponentId@ are reset to their
+-- original form factory.
+--
+-- If you'd like to preserve application state between calls to GHCi `:r`, see 'live'.
+--
+-- @since 1.9.0.0
+reload
+#ifdef NATIVE
+  :: (FromJSON action, ToJSON model, ToJSON action, Eq model)
+#else
+  :: (Eq model)
+#endif
+  => Events
+  -- ^ Event delegation map (typically 'Miso.Event.Types.defaultEvents')
+  -> Component () () model action
+  -- ^ Top-level application component to (re-)mount
+  -> IO ()
+reload events = reloadWithContext events ()
+-----------------------------------------------------------------------------
+-- | Like 'reload', but seeds the app-global React-style @context@ with an
+-- initial value (see 'Miso.startAppWithContext').
+--
+-- Use this instead of 'reload' when your top-level t'Component' uses a
+-- non-trivial @context@, since 'reload' fixes the @context@ to @()@.
+--
+-- @
+-- main :: IO ()
+-- main = 'reloadWithContext' 'Miso.Event.Types.defaultEvents' Light (static (mount_ app))
+-- @
+--
+-- @since 1.13.0.0
+reloadWithContext
+#ifdef NATIVE
+  :: (FromJSON action, ToJSON model, Eq context, Eq model, ToJSON action)
+#else
+  :: (Eq context, Eq model)
+#endif
+  => Events
+  -- ^ Event delegation map (typically 'Miso.Event.Types.defaultEvents')
+  -> context
+  -- ^ Initial app-global @context@
+  -> Component context () model action
+  -- ^ Top-level application component to (re-)mount
+  -> IO ()
+reloadWithContext events initialContext comp = do
+   exists <- x_exists
+   when (exists == 1) $ do
+     (_, oldSchedulerRef, _) <- deRefStablePtr =<< x_get
+     killThread =<< readIORef oldSchedulerRef
+     x_clear
+   clearPage
+   -- 'reload' is a full reset: seed the freshly-supplied context.
+   -- ('initComponent' writes 'globalContext' with the value we pass it.)
+   void (initComponent events Draw False initialContext comp Nothing () Nothing)
+   x_store =<< newStablePtr (components, schedulerThread, globalContext :: IORef context)
+-----------------------------------------------------------------------------
+-- | Live reloading. Persists all t'Component' @model@ between successive GHCi reloads.
+--
+-- This means application state should persist between GHCi reloads
+--
+-- Schema changes to @model@ are currently unsupported. If you're
+-- changing fields in @model@ (adding, removing, changing a field's type), this
+-- will more than likely segfault. If you change the 'Miso.Lens.view' or @update@ functions
+-- it will be fine.
+--
+-- Use 'reload' if you're changing the @model@ frequently and 'live'
+-- if you're adjusting the 'Miso.Lens.view' / @update@ function logic.
+--
+-- @
+-- main :: IO ()
+-- main = 'live' 'Miso.Event.Types.defaultEvents' app
+-- @
+--
+-- @since 1.9.0.0
+live
+#ifdef NATIVE
+  :: (Eq model, ToJSON model, ToJSON action, FromJSON action)
+#else
+  :: Eq model
+#endif
+  => Events
+  -- ^ Event delegation map (typically 'Miso.Event.Types.defaultEvents')
+  -> Component () () model action
+  -- ^ Top-level application component to (re-)mount with preserved model state
+  -> IO ()
+live events vcomp_ = liveWithContext events () vcomp_
+-----------------------------------------------------------------------------
+-- | Like 'live', but seeds the app-global React-style @context@ with an
+-- initial value (see 'Miso.startAppWithContext').
+--
+-- Use this instead of 'live' when your top-level t'Component' uses a
+-- non-trivial @context@, since 'live' fixes the @context@ to @()@.
+--
+-- The seeded @context@ is only used on the initial load; on subsequent reloads
+-- the preserved @model@ is recovered exactly as with 'live'.
+--
+-- @
+-- main :: IO ()
+-- main = 'liveWithContext' 'Miso.Event.Types.defaultEvents' Light (static (mount_ app))
+-- @
+--
+-- @since 1.13.0.0
+liveWithContext
+#ifdef NATIVE
+  :: (Eq context, Eq model, ToJSON model, ToJSON action, FromJSON action)
+#else
+  :: (Eq context, Eq model)
+#endif
+  => Events
+  -- ^ Event delegation map (typically 'Miso.Event.Types.defaultEvents')
+  -> context
+  -- ^ Initial app-global @context@
+  -> Component context () model action
+  -- ^ Top-level application component to (re-)mount with preserved model state
+  -> IO ()
+liveWithContext events initialContext vcomp_ = do
+      exists <- x_exists
+      if exists == 1
+        then do
+          -- clearBody (only clear the body)
+          clearBody
+
+          -- Deref old state, update new state, set pointer in C heap.
+          (oldComponentsRef, oldSchedulerRef, oldContextRef) <- deRefStablePtr =<< x_get
+          oldContext <- readIORef oldContextRef
+          killThread =<< readIORef oldSchedulerRef
+
+          _oldState <- readIORef oldComponentsRef
+          let oldModel = (_oldState IM.! topLevelComponentId) ^. componentModel
+              initialVComp = vcomp_ { model = oldModel }
+
+          -- Overwrite new components state with old components state.
+          atomicWriteIORef components _oldState
+
+          -- Perform initial draw, recovering the old model and the old context.
+          -- ('initComponent' seeds 'globalContext' with the context we pass it.)
+          initComponent events Draw True oldContext initialVComp Nothing () Nothing
+
+          -- Don't forget to flush (native mobile needs this too)
+          FFI.flush
+
+          -- Clear and set static ptr to use new state (new CAF state)
+          x_clear
+          x_store =<< newStablePtr (components, schedulerThread, globalContext :: IORef context)
+        else do
+          -- This means it is initial load, just store the pointer.
+          void (initComponent events Draw False initialContext vcomp_ Nothing () Nothing)
+          x_store =<< newStablePtr (components, schedulerThread, globalContext :: IORef context)
+-----------------------------------------------------------------------------
+clearPage, clearBody, clearHead :: IO ()
+clearPage = clearBody >> clearHead
+clearBody = do
+  body_ <- jsg "document" ! ("body" :: MisoString)
+  setField body_ "innerHTML" ("" :: MisoString)
+clearHead = do
+  head_ <- jsg "document" ! ("head" :: MisoString)
+  setField head_ "innerHTML" ("" :: MisoString)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Router.hs b/src/Miso/Router.hs
--- a/src/Miso/Router.hs
+++ b/src/Miso/Router.hs
@@ -1,196 +1,631 @@
-{-# LANGUAGE DeriveFunctor #-}
+-----------------------------------------------------------------------------
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE UndecidableInstances  #-}
-{-# LANGUAGE DataKinds             #-}
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE GADTs                 #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE PolyKinds             #-}
-{-# LANGUAGE ScopedTypeVariables   #-}
-{-# LANGUAGE TypeFamilies          #-}
-{-# LANGUAGE TypeOperators         #-}
-{-# OPTIONS_GHC -fno-warn-orphans  #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE DerivingStrategies         #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE DefaultSignatures          #-}
+{-# LANGUAGE TypeApplications           #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE RecordWildCards            #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE LambdaCase                 #-}
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE PolyKinds                  #-}
 -----------------------------------------------------------------------------
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Router
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
-----------------------------------------------------------------------------
+--
+-- = Overview
+--
+-- "Miso.Router" provides a type-safe, bidirectional client-side router.
+-- A Haskell sum type represents your application's routes; the 'Router'
+-- class encodes and decodes between that type and URL strings. The router
+-- is used together with 'Miso.Subscription.History.uriSub' or
+-- 'Miso.Subscription.History.routerSub' to react to browser navigation.
+--
+-- = Approach 1 — Generic deriving (recommended)
+--
+-- @
+-- {-\# LANGUAGE DeriveGeneric, DeriveAnyClass, DerivingStrategies \#-}
+-- import GHC.Generics (Generic)
+-- import "Miso.Router"
+--
+-- data Route
+--   = Index                                                    -- \"\/\"
+--   | About                                                    -- \"\/about\"
+--   | User (Capture \"id\" Int)                                 -- \"\/user\/42\"
+--   | Search (QueryParam \"q\" 'Miso.String.MisoString')         -- \"\/search?q=foo\"
+--   deriving stock (Show, Eq, Generic)
+--   deriving anyclass 'Router'
+-- @
+--
+-- Decoding:
+--
+-- @
+-- 'toRoute' \"\/user\/42\"  -- Right (User (Capture 42))
+-- 'toRoute' \"\/search?q=hello\" -- Right (Search (QueryParam (Just \"hello\")))
+-- @
+--
+-- Encoding (type-safe links):
+--
+-- @
+-- 'prettyRoute' (User (Capture 42))       -- \"\/user\/42\"
+-- button_ [ 'href_' (User (Capture 42)) ] [ text \"Profile\" ]
+-- @
+--
+-- = Approach 2 — Manual instance
+--
+-- @
+-- data Route = Widget Int deriving (Show, Eq)
+--
+-- instance 'Router' Route where
+--   routeParser = 'routes' [ Widget \<$\> ('path' \"widget\" *\> 'capture') ]
+--   fromRoute (Widget n) = [ 'toPath' \"widget\", 'toCapture' n ]
+-- @
+--
+-- = Generic naming rules
+--
+-- * __Constructor name__ becomes the lowercase path segment:
+--   @About@ → @\/about@, @UserProfile@ → @\/user@ (first camel-case hump only).
+-- * The special name __@Index@__ encodes the root path @\/@.
+-- * The position of t'Capture' and t'Path' fields in the constructor
+--   determines their order in the URL path. The position of
+--   t'QueryParam' and t'QueryFlag' does not matter.
+--
+-- = URL types
+--
+-- [@'Capture' sym a@] dynamic path segment — @Capture 42@ → @\/42@
+-- [@'Path' sym@] fixed path segment — @Path \"foo\"@ → @\/foo@
+-- [@'QueryParam' sym a@] optional query key — @QueryParam (Just 1)@ → @?sym=1@
+-- [@'QueryFlag' sym@] boolean query flag — @QueryFlag True@ → @?sym@
+-- [@'Fragment' sym@] hash fragment — @Fragment@ → @#sym@
+--
+-- = Integration with history subscription
+--
+-- @
+-- import "Miso.Subscription.History" ('Miso.Subscription.History.routerSub')
+--
+-- subs :: ['Miso.Effect.Sub' Action]
+-- subs = [ 'Miso.Subscription.History.routerSub' RouteChanged ]
+-- @
+--
+-- = See also
+--
+-- * "Miso.Subscription.History" — 'Miso.Subscription.History.uriSub', 'Miso.Subscription.History.routerSub', 'Miso.Subscription.History.pushURI'
+-- * "Miso.Html.Property" — 'Miso.Html.Property.href_' (plain string version)
+-----------------------------------------------------------------------------
 module Miso.Router
-  ( runRoute
+  ( -- ** Classes
+    Router (..)
+  , RouteParser
+  , GRouter (..)
+    -- ** Types
+  , Capture (..)
+  , Path (..)
+  , QueryParam (..)
+  , QueryFlag (..)
+  , Fragment (..)
+  , Token (..)
+  , URI (..)
+    -- ** Errors
   , RoutingError (..)
+    -- ** Functions
+  , parseURI
+  , prettyURI
+  , prettyQueryString
+    -- ** Manual Routing
+  , runRouter
+  , routes
+    -- ** Construction
+  , toQueryParam
+  , toCapture
+  , toPath
+  , emptyURI
+    -- ** Parser combinators
+  , queryFlag
+  , queryParam
+  , capture
+  , path
+  , fragment
+    -- ** Lexing
+  , lexTokens
+  , tokensToURI
   ) where
-
-import qualified Data.ByteString.Char8 as BS
+-----------------------------------------------------------------------------
+import qualified Data.Map.Strict as M
+import           Data.Maybe
+import           Data.Bifunctor (first)
+import           Data.Functor
 import           Data.Proxy
-import           Data.Text             (Text)
-import qualified Data.Text             as T
-import           Data.Text.Encoding
+import qualified Data.Char as C
+import           Data.String
+import           Control.Applicative
+import           Control.Monad
+import           GHC.Generics
 import           GHC.TypeLits
-import           Network.HTTP.Types
-import           Network.URI
-import           Servant.API
-import           Web.HttpApiData
-
-import           Miso.Html             hiding (text)
-
--- | Router terminator.
--- The 'HasRouter' instance for 'View' finalizes the router.
---
--- Example:
---
--- > type MyApi = "books" :> Capture "bookId" Int :> View
-
--- | 'Location' is used to split the path and query of a URI into components.
-data Location = Location
-  { locPath  :: [Text]
-  , locQuery :: Query
-  } deriving (Show, Eq, Ord)
-
--- | When routing, the router may fail to match a location.
-data RoutingError = Fail
-  deriving (Show, Eq, Ord)
-
--- | A 'Router' contains the information necessary to execute a handler.
-data Router a where
-  RChoice       :: Router a -> Router a -> Router a
-  RCapture      :: FromHttpApiData x => (x -> Router a) -> Router a
-  RQueryParam   :: (FromHttpApiData x, KnownSymbol sym)
-                   => Proxy sym -> (Maybe x -> Router a) -> Router a
-  RQueryParams  :: (FromHttpApiData x, KnownSymbol sym)
-                   => Proxy sym -> ([x] -> Router a) -> Router a
-  RQueryFlag    :: KnownSymbol sym
-                   => Proxy sym -> (Bool -> Router a) -> Router a
-  RPath         :: KnownSymbol sym => Proxy sym -> Router a -> Router a
-  RPage         :: a -> Router a
-
--- | This is similar to the @HasServer@ class from @servant-server@.
--- It is the class responsible for making API combinators routable.
--- 'RouteT' is used to build up the handler types.
--- 'Router' is returned, to be interpretted by 'routeLoc'.
-class HasRouter model layout where
-  -- | A route handler.
-  type RouteT model layout a :: *
-  -- | Transform a route handler into a 'Router'.
-  route :: Proxy layout -> Proxy a -> RouteT model layout a -> model -> Router a
-
--- | Alternative
-instance (HasRouter m x, HasRouter m y) => HasRouter m (x :<|> y) where
-  type RouteT m (x :<|> y) a = RouteT m x a :<|> RouteT m y a
-  route _ (a :: Proxy a) ((x :: RouteT m x a) :<|> (y :: RouteT m y a)) m
-    = RChoice (route (Proxy :: Proxy x) a x m) (route (Proxy :: Proxy y) a y m)
-
--- | Capture
-instance (HasRouter m sublayout, FromHttpApiData x) =>
-  HasRouter m (Capture sym x :> sublayout) where
-  type RouteT m (Capture sym x :> sublayout) a = x -> RouteT m sublayout a
-  route _ a f m = RCapture (\x -> route (Proxy :: Proxy sublayout) a (f x) m)
+-----------------------------------------------------------------------------
+import           Miso.Types hiding (model, fragment, fragment_)
+import           Miso.JSON (FromJSON (..))
+import           Miso.Util
+import qualified Miso.Html.Property as P
+import           Miso.Util.Parser hiding (NoParses)
+import qualified Miso.Util.Lexer as L
+import           Miso.Util.Lexer (Lexer)
+import           Miso.String (ToMisoString, FromMisoString, fromMisoStringEither)
+import qualified Miso.String as MS
+-----------------------------------------------------------------------------
+-- | Type used for representing capture variables
+newtype Capture sym a = Capture a
+  deriving stock (Eq, Show)
+  deriving newtype (ToMisoString, FromMisoString)
+-----------------------------------------------------------------------------
+-- | Type used for representing URL paths
+newtype Path (path :: Symbol) = Path MisoString
+  deriving stock (Eq, Show)
+  deriving newtype (ToMisoString, IsString)
+-----------------------------------------------------------------------------
+-- | Type used for representing query flags
+newtype QueryFlag (path :: Symbol) = QueryFlag Bool
+  deriving stock (Eq, Show)
+-----------------------------------------------------------------------------
+-- | Type used for representing query parameters
+newtype QueryParam (path :: Symbol) a = QueryParam (Maybe a)
+  deriving stock (Eq, Show)
+-----------------------------------------------------------------------------
+-- | Type used for representing fragments
+data Fragment (path :: Symbol) = Fragment
+  deriving stock (Eq, Show)
+-----------------------------------------------------------------------------
+instance (KnownSymbol frag) => ToMisoString (Fragment frag) where
+  toMisoString Fragment = "#" <> ms (symbolVal (Proxy @frag))
+-----------------------------------------------------------------------------
+instance (ToMisoString a, KnownSymbol path) => ToMisoString (QueryParam path a) where
+  toMisoString (QueryParam maybeVal) =
+    maybe mempty (\param -> "?" <> ms param <> "=" <> val) maybeVal
+      where
+        val = ms $ symbolVal (Proxy @path)
+-----------------------------------------------------------------------------
+instance (FromMisoString a, KnownSymbol path) => FromMisoString (QueryParam path a) where
+  fromMisoStringEither x =
+    case fromMisoStringEither @a x of
+      Right r -> Right $ QueryParam (Just r)
+      Left v -> Left v
+-----------------------------------------------------------------------------
+instance KnownSymbol name => ToMisoString (QueryFlag name) where
+  toMisoString = \case
+    QueryFlag True ->
+      "?" <> ms (symbolVal (Proxy @name))
+    QueryFlag False ->
+      mempty
+-----------------------------------------------------------------------------
+-- | A list of tokens are returned from a successful lex of a t'URI'
+data Token
+  = QueryParamTokens [(MisoString, Maybe MisoString)]
+  | QueryParamToken MisoString (Maybe MisoString)
+  | CaptureOrPathToken MisoString
+  | FragmentToken MisoString
+  | IndexToken
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Smart constructor for building a 'QueryParamToken'
+toQueryParam
+  :: ToMisoString s
+  => MisoString
+  -- ^ Query parameter key
+  -> s
+  -- ^ Query parameter value
+  -> Token
+toQueryParam k v = QueryParamToken k (Just (ms v))
+-----------------------------------------------------------------------------
+-- | Smart constructor for building a capture variable
+toCapture :: ToMisoString string => string -> Token
+toCapture = CaptureOrPathToken . ms
+-----------------------------------------------------------------------------
+-- | Smart constructor for building a path fragment
+toPath :: MisoString -> Token
+toPath = CaptureOrPathToken
+-----------------------------------------------------------------------------
+-- | Converts a list of @[Token]@ into an actual @URI@.
+tokensToURI :: [Token] -> URI
+tokensToURI tokens = URI
+  { uriPath =
+      case tokens of
+        IndexToken : _ -> ""
+        _ ->
+          MS.intercalate "/"
+          [ x
+          | CaptureOrPathToken x <- filter isPathRelated tokens
+          ]
+  , uriQueryString =
+      M.unions
+        [ case queryToken of
+            QueryParamTokens queryParams_ ->
+              M.fromList queryParams_
+            QueryParamToken k v ->
+              M.singleton k v
+            _ ->
+              mempty
+        | queryToken <- filter isQuery tokens
+        ]
+  , uriFragment =
+      foldMap ms (filter isFragment tokens)
+  } where
+      isFragment = \case
+        FragmentToken{} -> True
+        _ -> False
+      isQuery = \case
+        QueryParamToken{} -> True
+        _ -> False
+      isPathRelated = \case
+        CaptureOrPathToken {} -> True
+        IndexToken {} -> True
+        _ -> False
+-----------------------------------------------------------------------------
+instance ToMisoString Token where
+  toMisoString = \case
+    CaptureOrPathToken x -> "/" <> x
+    FragmentToken x -> "#" <> x
+    QueryParamTokens params ->
+      "?" <> MS.intercalate "&"
+        [ case value of
+            Nothing -> key
+            Just v -> key <> "=" <> v
+        | (key, value) <- params
+        ]
+    QueryParamToken k (Just v) ->
+      "?" <> k <> "=" <> v
+    QueryParamToken k Nothing ->
+      "?" <> k
+    IndexToken -> "/"
+-----------------------------------------------------------------------------
+-- | An error that can occur during lexing / parsing of a URI into a user-defined
+-- data type
+data RoutingError
+  = ParseError MisoString [Token]
+  | AmbiguousParse MisoString [Token]
+  | LexError MisoString MisoString
+  | LexErrorEOF MisoString
+  | NoParses MisoString
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | State monad for parsing URI
+type RouteParser = ParserT URI [Token] []
+-----------------------------------------------------------------------------
+-- | Combinator for parsing a capture variable out of a URI
+capture :: FromMisoString value => RouteParser value
+capture = do
+  CaptureOrPathToken capture_ <- captureOrPathToken
+  case fromMisoStringEither capture_ of
+    Left msg -> fail (fromMisoString (ms msg))
+    Right token -> pure token
+-----------------------------------------------------------------------------
+-- | Combinator for parsing a path out of a URI
+path :: MisoString -> RouteParser MisoString
+path specified = do
+  CaptureOrPathToken parsed <- captureOrPathToken
+  when (specified /= parsed) (fail "path")
+  pure specified
+-----------------------------------------------------------------------------
+index :: MisoString -> RouteParser MisoString
+index specified = do
+  IndexToken <- indexToken
+  when (specified /= "index") (fail "index")
+  pure "/"
+-----------------------------------------------------------------------------
+-- | Matches a literal URI fragment (the part after @#@), failing the parse if
+-- it differs. Returns the matched fragment.
+fragment :: MisoString -> RouteParser MisoString
+fragment specified = do
+  FragmentToken frag <- indexToken
+  when (specified /= frag) (fail "fragment")
+  pure frag
+-----------------------------------------------------------------------------
+-- | URI parsing
+parseURI :: MisoString -> Either MisoString URI
+parseURI txt =
+  case lexTokens txt of
+    Left (L.LexerError err _) -> Left err
+    Left (L.UnexpectedEOF eof) -> Left ("EOF: " <> ms (show eof))
+    Right tokens -> Right (tokensToURI tokens)
+-----------------------------------------------------------------------------
+instance FromMisoString URI where
+    fromMisoStringEither = first fromMisoString . parseURI
+-----------------------------------------------------------------------------
+instance FromJSON URI where
+    parseJSON = either fail pure . fromMisoStringEither <=< parseJSON
+-----------------------------------------------------------------------------
+-- | Class used to facilitate routing for miso applications
+class Router route where
+  fromRoute :: route -> [Token]
+  default fromRoute :: (Generic route, GRouter (Rep route)) => route -> [Token]
+  fromRoute = gFromRoute . from
 
--- | QueryParam
-instance (HasRouter m sublayout, FromHttpApiData x, KnownSymbol sym)
-         => HasRouter m (QueryParam sym x :> sublayout) where
-  type RouteT m (QueryParam sym x :> sublayout) a = Maybe x -> RouteT m sublayout a
-  route _ a f m = RQueryParam (Proxy :: Proxy sym)
-    (\x -> route (Proxy :: Proxy sublayout) a (f x) m)
+  -- | Convert a 'Router route => route' into a t'URI'
+  toURI :: route -> URI
+  toURI = tokensToURI . fromRoute
 
--- | QueryParams
-instance (HasRouter m sublayout, FromHttpApiData x, KnownSymbol sym)
-         => HasRouter m (QueryParams sym x :> sublayout) where
-  type RouteT m (QueryParams sym x :> sublayout) a = [x] -> RouteT m sublayout a
-  route _ a f m = RQueryParams
-    (Proxy :: Proxy sym)
-    (\x -> route (Proxy :: Proxy sublayout) a (f x) m)
+  -- | Map a URI back to a route
+  route :: URI -> Either RoutingError route
+  route = toRoute . prettyURI
 
--- | QueryFlag
-instance (HasRouter m sublayout, KnownSymbol sym)
-         => HasRouter m (QueryFlag sym :> sublayout) where
-  type RouteT m (QueryFlag sym :> sublayout) a = Bool -> RouteT m sublayout a
-  route _ a f m = RQueryFlag
-    (Proxy :: Proxy sym)
-    (\x -> route (Proxy :: Proxy sublayout) a (f x) m)
+  -- | Convenience for specifying a URL as a hyperlink reference in 'Miso.Types.View'
+  href_ :: route -> Attribute model action
+  href_ = P.href_ . prettyRoute
 
--- | Path
-instance (HasRouter m sublayout, KnownSymbol path)
-         => HasRouter m (path :> sublayout) where
-  type RouteT m (path :> sublayout) a = RouteT m sublayout a
-  route _ a page m = RPath
-    (Proxy :: Proxy path)
-    (route (Proxy :: Proxy sublayout) a page m)
+  -- | Route pretty printing
+  prettyRoute :: route -> MisoString
+  prettyRoute = prettyURI . tokensToURI . fromRoute
 
--- | View
-instance HasRouter m (View a) where
-  type RouteT m (View a) x = m -> x
-  route _ _ a m = RPage (a m)
+  -- | Route debugging
+  dumpURI :: route -> MisoString
+  dumpURI = ms . show . tokensToURI . fromRoute
 
--- | Use a handler to route a 'Location'.
--- Normally 'runRoute' should be used instead, unless you want custom
--- handling of string failing to parse as 'URI'.
-runRouteLoc :: forall m layout a. HasRouter m layout
-            => Location -> Proxy layout -> RouteT m layout a -> m -> Either RoutingError a
-runRouteLoc loc layout page m =
-  let routing = route layout (Proxy :: Proxy a) page m
-  in routeLoc loc routing m
+  -- | Route parsing from a 'MisoString'
+  toRoute :: MisoString -> Either RoutingError route
+  toRoute input = parseRoute input routeParser
 
--- | Use a handler to route a location, represented as a 'String'.
--- All handlers must, in the end, return @m a@.
--- 'routeLoc' will choose a route and return its result.
-runRoute
-  :: HasRouter m layout
-  => Proxy layout
-  -> RouteT m layout a
-  -> (m -> URI)
-  -> m
-  -> Either RoutingError a
-runRoute layout page getURI m =
-  runRouteLoc (uriToLocation uri) layout page m
+  routeParser :: RouteParser route
+  default routeParser :: (Generic route, GRouter (Rep route)) => RouteParser route
+  routeParser = to <$> gRouteParser
+-----------------------------------------------------------------------------
+-- | Smart constructor for building a @RouteParser@
+--
+-- @
+--
+-- data Route = Widget MisoString Int
+--
+-- instance Router Route where
+--   routeParser = routes [ Widget \<$\> path "widget" \<*\> capture ]
+--   fromRoute (Widget path value) = [ toPath path, toCapture value ]
+--
+-- router :: Router router => RouteParser router
+-- router = routes [ Widget \<$\> path "widget" \<*\> capture ]
+--
+-- > Right (Widget "widget" 10)
+-- @
+--
+-----------------------------------------------------------------------------
+runRouter
+  :: MisoString
+  -- ^ The raw URL string to parse
+  -> RouteParser route
+  -- ^ Parser to apply against the tokenised URL
+  -> Either RoutingError route
+runRouter = parseRoute
+-----------------------------------------------------------------------------
+-- | Convenience for specifying multiple routes
+routes :: [ RouteParser route ] -> RouteParser route
+routes = foldr (<|>) empty
+-----------------------------------------------------------------------------
+-- | Generic deriving for 'Router'
+class GRouter f where
+  gFromRoute :: f route -> [Token]
+  gRouteParser :: RouteParser (f route)
+-----------------------------------------------------------------------------
+instance GRouter next => GRouter (D1 m next) where
+  gFromRoute (M1 x) = gFromRoute x
+  gRouteParser = M1 <$> gRouteParser
+-----------------------------------------------------------------------------
+instance (KnownSymbol name, GRouter next) => GRouter (C1 ('MetaCons name x y) next) where
+  gFromRoute (M1 x) =
+    case name of
+      "index" -> [IndexToken]
+      _ -> CaptureOrPathToken name : gFromRoute x
+      where
+        name = lowercaseStrip $ symbolVal (Proxy @name)
+  gRouteParser = do
+    case name of
+      "index" -> do
+        void (index name)
+        M1 <$> gRouteParser
+      _ -> do
+        void (path name)
+        M1 <$> gRouteParser
+      where
+        name = lowercaseStrip $ symbolVal (Proxy @name)
+-----------------------------------------------------------------------------
+instance GRouter next => GRouter (S1 m next) where
+  gFromRoute (M1 x) = gFromRoute x
+  gRouteParser = M1 <$> gRouteParser
+-----------------------------------------------------------------------------
+instance {-# OVERLAPS #-} forall path m . KnownSymbol path => GRouter (K1 m (Path path)) where
+  gFromRoute (K1 x) = pure $ CaptureOrPathToken (ms x)
+  gRouteParser = K1 (Path chunk) <$ path chunk
     where
-      uri = getURI m
-
--- | Use a computed 'Router' to route a 'Location'.
-routeLoc :: Location -> Router a -> m -> Either RoutingError a
-routeLoc loc r m = case r of
-  RChoice a b -> do
-    case routeLoc loc a m of
-      Left Fail -> routeLoc loc b m
-      Right x -> Right x
-  RCapture f -> case locPath loc of
-    [] -> Left Fail
-    capture:paths ->
-      case parseUrlPieceMaybe capture of
-        Nothing -> Left Fail
-        Just x -> routeLoc loc { locPath = paths } (f x) m
-  RQueryParam sym f -> case lookup (BS.pack $ symbolVal sym) (locQuery loc) of
-    Nothing -> routeLoc loc (f Nothing) m
-    Just Nothing -> Left Fail
-    Just (Just text) -> case parseQueryParamMaybe (decodeUtf8 text) of
-      Nothing -> Left Fail
-      Just x -> routeLoc loc (f (Just x)) m
-  RQueryParams sym f -> maybe (Left Fail) (\x -> routeLoc loc (f x) m) $ do
-    ps <- sequence $ snd <$> Prelude.filter
-      (\(k, _) -> k == BS.pack (symbolVal sym)) (locQuery loc)
-    sequence $ (parseQueryParamMaybe . decodeUtf8) <$> ps
-  RQueryFlag sym f -> case lookup (BS.pack $ symbolVal sym) (locQuery loc) of
-    Nothing -> routeLoc loc (f False) m
-    Just Nothing -> routeLoc loc (f True) m
-    Just (Just _) -> Left Fail
-  RPath sym a -> case locPath loc of
-    [] -> Left Fail
-    p:paths -> if p == T.pack (symbolVal sym)
-      then routeLoc (loc { locPath = paths }) a m
-      else Left Fail
-  RPage a ->
-    case locPath loc of
-      [] -> Right a
-      _ -> Left Fail
-
--- | Convert a 'URI' to a 'Location'.
-uriToLocation :: URI -> Location
-uriToLocation uri = Location
-  { locPath = decodePathSegments $ BS.pack (uriPath uri)
-  , locQuery = parseQuery $ BS.pack (uriQuery uri)
-  }
+      chunk = ms $ symbolVal (Proxy :: Proxy path)
+-----------------------------------------------------------------------------
+instance {-# OVERLAPS #-} (FromMisoString a, ToMisoString a) => GRouter (K1 m (Capture sym a)) where
+  gFromRoute (K1 x) = pure $ CaptureOrPathToken (ms x)
+  gRouteParser = K1 <$> capture
+-----------------------------------------------------------------------------
+instance {-# OVERLAPS #-} KnownSymbol frag => GRouter (K1 m (Fragment frag)) where
+  gFromRoute (K1 x) = pure $ FragmentToken (ms x)
+  gRouteParser = K1 Fragment <$ fragment frag
+    where
+      frag = ms (symbolVal (Proxy :: Proxy frag))
+-----------------------------------------------------------------------------
+instance {-# OVERLAPS #-} forall param m a . (ToMisoString a, FromMisoString a, KnownSymbol param) =>
+  GRouter (K1 m (QueryParam param a)) where
+    gFromRoute (K1 (QueryParam maybeParam)) = do
+      let key = ms (symbolVal (Proxy @param))
+      case maybeParam of
+        Nothing -> [QueryParamToken key Nothing]
+        Just v -> [QueryParamToken key (Just (ms v))]
+    gRouteParser = K1 <$> queryParam
+-----------------------------------------------------------------------------
+-- | Query parameter parser from a route
+queryParam
+  :: forall param a . (FromMisoString a, KnownSymbol param)
+  => RouteParser (QueryParam param a)
+queryParam = do
+  URI {..} <- askParser
+  QueryParam <$> do
+    case M.lookup (ms (symbolVal (Proxy @param))) uriQueryString of
+      Just (Just value) ->
+        case fromMisoStringEither value of
+          Left _ -> pure Nothing
+          Right parsed -> pure (Just parsed)
+      _ -> pure Nothing
+-----------------------------------------------------------------------------
+instance {-# OVERLAPS #-} forall flag m . KnownSymbol flag => GRouter (K1 m (QueryFlag flag)) where
+  gFromRoute (K1 (QueryFlag specified))
+    | specified = [ QueryParamToken flag Nothing ]
+    | otherwise = []
+        where
+          flag = ms (symbolVal (Proxy @flag))
+  gRouteParser = K1 <$> queryFlag
+-----------------------------------------------------------------------------
+-- | Query flag parser from a route
+queryFlag :: forall flag . KnownSymbol flag => RouteParser (QueryFlag flag)
+queryFlag = do
+  URI {..} <- askParser
+  pure $ QueryFlag $ isJust (M.lookup flag uriQueryString)
+    where
+      flag = ms $ symbolVal (Proxy @flag)
+-----------------------------------------------------------------------------
+instance Router a => GRouter (K1 m a) where
+  gFromRoute (K1 x) = fromRoute x
+  gRouteParser = K1 <$> routeParser
+-----------------------------------------------------------------------------
+instance GRouter U1 where
+  gFromRoute U1 = []
+  gRouteParser = pure U1
+-----------------------------------------------------------------------------
+instance (GRouter left, GRouter right) => GRouter (left :*: right) where
+  gFromRoute (left :*: right) = gFromRoute left <> gFromRoute right
+  gRouteParser = liftA2 (:*:) gRouteParser gRouteParser
+-----------------------------------------------------------------------------
+instance (GRouter left, GRouter right) => GRouter (left :+: right) where
+  gFromRoute = \case
+    L1 m1 -> gFromRoute m1
+    R1 m1 -> gFromRoute m1
+  gRouteParser = foldr (<|>) empty
+    [ L1 <$> gRouteParser
+    , R1 <$> gRouteParser
+    ]
+-----------------------------------------------------------------------------
+captureOrPathToken :: RouteParser Token
+captureOrPathToken = satisfy $ \case
+  CaptureOrPathToken {} -> True
+  _ -> False
+-----------------------------------------------------------------------------
+indexToken :: RouteParser Token
+indexToken = satisfy $ \case
+  IndexToken {} -> True
+  _ -> False
+-----------------------------------------------------------------------------
+-- | Lexing for a URI
+uriLexer :: Lexer [Token]
+uriLexer = do
+  tokens <- some lexer
+  void $ optional (L.char '/')
+  pure (postProcess tokens)
+    where
+      postProcess :: [Token] -> [Token]
+      postProcess = concatMap $ \case
+        QueryParamTokens queryParams_ ->
+          [ QueryParamToken k v
+          | (k,v) <- queryParams_
+          ]
+        x -> pure x
+      lexer = msum
+        [ captureOrPathLexer
+        , queryParamLexer
+        , fragmentLexer
+        , indexLexer
+        ] where
+            indexLexer =
+              IndexToken <$ L.char '/'
+            captureOrPathLexer = do
+              void (L.char '/')
+              CaptureOrPathToken <$> chars
+            fragmentLexer = do
+              void (L.char '#')
+              FragmentToken <$> query
+            queryParamLexer = QueryParamTokens <$> do
+              void (L.char '?')
+              sepBy (L.char '&') $ do
+                key <- query
+                maybeValue <-
+                  optional $ do
+                    void (L.char '=')
+                    query
+                pure (key, maybeValue)
+-----------------------------------------------------------------------------
+chars :: Lexer MisoString
+chars = MS.concat <$> some pchar
+-----------------------------------------------------------------------------
+pchar :: Lexer MisoString
+pchar = unreserved <|> pctEncoded <|> subDelims <|> L.string ":" <|> L.string "@"
+-----------------------------------------------------------------------------
+query :: Lexer MisoString
+query = foldr (<|>) empty
+  [ MS.concat <$> some pchar
+  ]
+-----------------------------------------------------------------------------
+subDelims :: Lexer MisoString
+subDelims = fmap ms <$> L.satisfy $ \x -> x `elem` ("!$'()*+,;" :: String)
+-----------------------------------------------------------------------------
+unreserved :: Lexer MisoString
+unreserved = ms <$> do
+  L.satisfy $ \x -> or
+    [ C.isAlphaNum x
+    , x == '-'
+    , x == '.'
+    , x == '_'
+    , x == '~'
+    ]
+-----------------------------------------------------------------------------
+pctEncoded :: Lexer MisoString
+pctEncoded = do
+  pct <- L.char '%'
+  d1 <- hexDig
+  d2 <- hexDig
+  pure (ms pct <> ms d1 <> ms d2)
+-----------------------------------------------------------------------------
+hexDig :: Lexer Char
+hexDig = L.satisfy C.isHexDigit
+-----------------------------------------------------------------------------
+-- | Lexes a URI into route t'Token's, or reports where lexing failed.
+lexTokens :: MisoString -> Either L.LexerError [Token]
+lexTokens input =
+  case L.runLexer uriLexer (L.mkStream input) of
+    Right (tokens, _) -> Right tokens
+    Left x -> Left x
+-----------------------------------------------------------------------------
+parseRoute :: MisoString -> RouteParser a -> Either RoutingError a
+parseRoute input parser =
+  case L.runLexer uriLexer (L.mkStream input) of
+    Left (L.LexerError lexErrorMessage _) ->
+      Left (LexError input lexErrorMessage)
+    Left (L.UnexpectedEOF _) ->
+      Left (LexErrorEOF input)
+    Right (tokens, _) -> do
+      let
+        uri = tokensToURI tokens
+        isCapturePathOrIndex = \case
+          CaptureOrPathToken{} -> True
+          IndexToken{} -> True
+          _ -> False
+      case runParserT parser uri (filter isCapturePathOrIndex tokens) of
+        [(x, [])]  ->
+          Right x
+        [(_, leftovers)]  ->
+          Left $ ParseError input leftovers
+        []  ->
+          Left $ NoParses input
+        (_, leftovers) : _  ->
+          Left $ AmbiguousParse input leftovers
+-----------------------------------------------------------------------------
+lowercaseStrip :: String -> MisoString
+lowercaseStrip (x:xs) = ms (C.toLower x : takeWhile C.isLower xs)
+lowercaseStrip x = ms x
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Runtime.hs b/src/Miso/Runtime.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Runtime.hs
@@ -0,0 +1,2835 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE LambdaCase                 #-}
+{-# LANGUAGE DeriveGeneric              #-}
+{-# LANGUAGE DeriveAnyClass             #-}
+{-# LANGUAGE KindSignatures             #-}
+{-# LANGUAGE BlockArguments             #-}
+{-# LANGUAGE TemplateHaskell            #-}
+{-# LANGUAGE RecordWildCards            #-}
+{-# LANGUAGE TypeApplications           #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE DerivingStrategies         #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE DuplicateRecordFields      #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -fno-warn-orphans       #-}
+-----------------------------------------------------------------------------
+#ifdef PRODUCTION
+#define MISO_JS_PATH "js/miso.prod.js"
+#else
+#define MISO_JS_PATH "js/miso.js"
+#endif
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Runtime
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+-----------------------------------------------------------------------------
+module Miso.Runtime
+  ( -- * Internal functions
+    initialize
+  , freshComponentId
+  , buildVTree
+  , registerEventHandler
+  , renderStyles
+  , renderScripts
+  , Hydrate(..)
+  -- * Subscription
+  , startSub
+  , stopSub
+  -- * Pub / Sub
+  , subscribe
+  , unsubscribe
+  , publish
+  , Topic (..)
+  , topic
+  -- * Component
+  , ComponentState (..)
+  , ComponentIds
+  -- ** Communication
+  , mail
+  , checkMail
+  , broadcast
+  , mailParent
+  , mailChildren
+  , mailAncestors
+  , mailDescendants
+  -- ** WebSocket
+  , websocketConnect
+  , websocketConnectJSON
+  , websocketConnectText
+  , websocketConnectArrayBuffer
+  , websocketConnectBLOB
+  , websocketSend
+  , websocketClose
+  , socketState
+  , emptyWebSocket
+  , WebSocket (..)
+  , URL
+  , SocketState (..)
+  , CloseCode (..)
+  , Closed (..)
+  -- ** EventSource
+  , eventSourceConnectText
+  , eventSourceConnectJSON
+  , eventSourceClose
+  , emptyEventSource
+  , EventSource (..)
+  -- ** Payload
+  , Payload (..)
+  , json
+  , blob
+  , arrayBuffer
+  -- ** Internal Component state
+  , components
+  , globalContext
+  , setContext
+  , schedulerThread
+  , componentIds
+  , rootComponentId
+  , componentId
+  , modifyComponent
+  , unmountComponent
+  , freeLifecycleHooks
+  , componentModel
+  -- ** Scheduler
+  , scheduler
+#ifdef WASM
+  , evalFile
+#endif
+  , topLevelComponentId
+  , initComponent
+  , withJS
+  -- * Lynx cross-thread
+  , MTS (..)
+  , BTS (..)
+  , getMTSContext
+  , getBTSContext
+  , dispatchEvent
+  , mts
+  , bts
+  , web
+  -- ** Protocol types
+  , ComponentType (..)
+  , COMPONENT (..)
+  , EFFECT (..)
+  ) where
+-----------------------------------------------------------------------------
+import qualified Data.IntSet as IS
+import           Data.IntSet (IntSet)
+#ifdef NATIVE
+import qualified Data.Set as Set
+#endif
+import           Data.Proxy (Proxy(Proxy))
+import           Control.Category ((.))
+import           Control.Concurrent
+import           Control.Exception (SomeException, catch)
+import           Control.Monad (forM, forM_, when, void, (<=<), zipWithM_, forever, foldM, unless)
+import           Control.Monad.Reader (ask, asks)
+import           Control.Monad.State hiding (state)
+import qualified Miso.JSON as JSON
+import           Miso.JSON (FromJSON, ToJSON, Result(..), Value, encode, fromJSON, jsonStringify, toJSON, parseEither)
+import           Miso.Event.Decoder (Decoder(decoder, decodeAt))
+
+#if __GLASGOW_HASKELL__ < 910
+import           Data.Foldable (foldl')
+#endif
+import           Data.Maybe
+import           Data.Map.Strict (Map)
+import qualified Data.Map.Strict as M
+import           Data.IntMap.Strict (IntMap)
+import qualified Data.IntMap.Strict as IM
+import           Data.IORef (IORef, newIORef, atomicModifyIORef', readIORef, atomicWriteIORef)
+import qualified Data.Sequence as S
+import           Data.Sequence (Seq)
+import           GHC.Conc (ThreadStatus(ThreadDied, ThreadFinished), threadStatus)
+import           Data.Word (Word64)
+import           GHC.Fingerprint (Fingerprint(..))
+import           Numeric (readHex)
+import           GHC.StaticPtr (StaticKey, staticKey, deRefStaticPtr)
+#ifdef NATIVE
+import           GHC.StaticPtr (unsafeLookupStaticPtr)
+#endif
+import           Prelude hiding ((.))
+import           System.IO.Unsafe (unsafePerformIO)
+import           System.Mem.StableName (makeStableName)
+import           System.Mem (performMajorGC)
+#ifdef BENCH
+import           Text.Printf
+#endif
+-----------------------------------------------------------------------------
+import           Miso.Concurrent (Waiter(..), waiter)
+#ifdef NATIVE
+import           Miso.Concurrent (oneshot)
+#endif
+import           Miso.CSS (renderStyleSheet)
+import           Miso.Delegate (delegator)
+import qualified Miso.Diff as Diff
+import           Miso.DSL
+#ifdef WASM
+import           Miso.DSL.TH.File (evalFile)
+#endif
+import           Miso.Effect
+  ( ComponentInfo(..), Sub, Sink, Effect, Schedule(..), runEffect
+  , io_, withSink, Synchronicity(..)
+  )
+import qualified Miso.Effect as E (Thread(..))
+import qualified Miso.FFI.Internal as FFI
+import           Miso.FFI.Internal (Blob(..), ArrayBuffer(..))
+import qualified Miso.Hydrate as Hydrate
+import           Miso.Lens hiding (view)
+import           Miso.String (ToMisoString(..), FromMisoString(..))
+import           Miso.Types
+import           Miso.Util
+-----------------------------------------------------------------------------
+-- | Helper function to abstract out initialization of t'Miso.Types.Component' between top-level API functions.
+initialize
+#ifdef NATIVE
+  :: (Eq context, Eq model, Eq props, ToJSON model, ToJSON props, ToJSON action, FromJSON action)
+#else
+  :: (Eq context, Eq model, Eq props)
+#endif
+  => Events
+  -> ComponentId
+  -> Hydrate
+  -> Bool
+  -- ^ Is the root node being rendered?
+  -> props
+  -- ^ Initial props for this component
+  -> Maybe Key
+  -- ^ Optional key for stable hot-reload model recovery
+  -> Maybe StaticKey
+  -- ^ 'StaticPtr' key for cross-thread (Lynx) child component lifecycle
+  -> Component context props model action
+  -> IO DOMRef
+  -- ^ Callback function is used for obtaining the t'Miso.Types.Component' @DOMRef@.
+  -> IO (ComponentState context props model action)
+initialize events _componentParentId hydrate isRoot initialProps maybeKey _componentStaticKey comp@Component {..} getComponentMountPoint = do
+  _componentId <- freshComponentId
+  let
+    _componentProps = initialProps
+    _componentSink = \action -> do
+      atomicModifyIORef' globalQueue (\q -> (enqueue _componentId action q, ()))
+      notify globalWaiter
+
+  initializedModel <-
+    case (hydrate, hydrateModel) of
+      (Hydrate, Just m) -> m
+      (Draw, _) -> do
+        live <- readIORef liveMode
+        case (live, maybeKey) of
+          (True, Just k) -> do
+            vcomps <- readIORef components
+            pure $ fromMaybe model $ listToMaybe
+              [ cs ^. componentModel
+              | cs <- IM.elems vcomps
+              , cs ^. componentKey == Just k
+              ]
+          _ -> pure model
+      _ -> pure model
+  _componentScripts <-
+    if web
+    then
+      IM.lookup _componentId <$> readIORef components >>= \case
+        Nothing -> (++) <$> renderScripts scripts <*> renderStyles styles
+        Just cs -> pure (_componentScripts cs) -- hot reload scenario, reuse already mounted scripts
+    else
+      pure []
+
+  _componentDOMRef <- getComponentMountPoint
+  _componentVTree <- newIORef (VTree (Object jsNull))
+  _componentSubThreads <- newIORef M.empty
+
+  frame <- newEmptyMVar :: IO (MVar Double)
+  let _componentMailbox = S.empty
+
+  rAFCallback <-
+    asyncCallback1 $ \jsval -> do
+      putMVar frame =<< fromJSValUnchecked jsval
+
+  let _componentDraw = \newModel -> do
+        currentProps <- (^. componentProps) . (IM.! _componentId) <$> readIORef components
+        currentContext <- readIORef globalContext
+        newVTree <-
+          buildVTree events _componentParentId _componentId Draw
+            _componentSink logLevel newModel (view currentContext currentProps newModel)
+        newHandlers <- collectEventHandlers
+        oldVTree <- readIORef _componentVTree
+        _frame <- requestAnimationFrame rAFCallback
+        _timestamp :: Double <- takeMVar frame
+        Diff.diff (Just oldVTree) (Just newVTree) _componentDOMRef
+        FFI.updateRef oldVTree newVTree
+        atomicWriteIORef _componentVTree newVTree
+        -- The old tree can no longer dispatch; free its handler callbacks.
+        -- See Note [Freeing event handler callbacks].
+        swapEventHandlers _componentId newHandlers
+        FFI.flush
+
+#ifdef NATIVE
+  -- N.B. all three cross-thread dispatch functions below wrap their FFI call
+  -- in 'catch' / 'exception': the underlying 'postComponent' \/ 'postEffect'
+  -- calls do a raw 'getMTSContext' \/ 'getBTSContext' round-trip, and an
+  -- uncaught exception there (e.g. a transient bridge hiccup) would otherwise
+  -- propagate out of the scheduler's 'forever' loop and silently kill it.
+  let _componentHydrate = \newModel -> do
+        when bts $ (postComponent MODEL_HYDRATE _componentStaticKey _componentId _componentParentId
+          (Just (toJSON newModel)) Nothing) `catch` exception
+
+  let _componentPostEffect = \action ->
+        postEffect _componentStaticKey _componentId (toJSON action) `catch` exception
+#else
+  let _componentHydrate = \_ -> pure ()
+  let _componentPostEffect = \_ -> pure ()
+#endif
+
+  let _componentApplyActions = \(actions :: Seq action) model_ currentProps ctx -> do
+        let info = ComponentInfo _componentId _componentParentId _componentDOMRef currentProps ctx
+        foldl' (\(m, ss) action ->
+          case runEffect (update action) info m of
+            (n, sss) -> (n, ss <> sss))
+          (model_, []) actions
+
+  let vcomponent = ComponentState
+        { _componentEvents = events
+        , _componentKey = maybeKey
+        , _componentMailbox = mailbox
+        , _componentUseContext = useContext
+        , _componentTopics = mempty
+        , _componentModelDirty = dirtyCheck
+        , _componentChildren = mempty
+        , _componentModel = initializedModel
+        , _prevComponentProps = _componentProps
+        , _componentPropsPhase = \oldProps newProps ->
+            case onPropsChanged of
+              Just f -> _componentSink (f oldProps newProps)
+              _ -> pure ()
+        , ..
+        }
+
+  when isRoot (delegator _componentDOMRef _componentVTree events (logLevel `elem` [DebugEvents, DebugAll]))
+  registerComponent vcomponent
+  getModel <- mkGetModel _componentId initializedModel
+  initSubs getModel subs _componentSubThreads _componentSink
+  -- Runs on every thread. On Lynx the MTS paints the initial frame directly
+  -- (fast first frame) while the BTS builds the same VTree but suppresses its
+  -- create-patches (deterministic nodeId parity keeps both trees addressable) —
+  -- both governed by the global 'initialDraw' latch in the drawing contexts,
+  -- which 'initComponent' clears ONCE the whole root mount finishes (see the note
+  -- there).
+  initialDraw initializedModel events hydrate isRoot comp vcomponent
+  forM_ mount _componentSink
+#ifdef NATIVE
+  -- Ship the child's initial @props@ so the MTS can rebuild the mirror
+  -- component by applying the @Props@ constructor recovered from the
+  -- 'StaticKey'. The no-props case serializes @()@ (JSON @null@).
+  when (bts && not isRoot) $ do
+    -- 'mount()' runs synchronously mid-diff (see @ts/miso/dom.ts@
+    -- 'mountComponent'), so this fires before the enclosing 'Diff.diff'
+    -- call's own end-of-render 'FFI.flush' — meaning, without shipping
+    -- what's accumulated so far right here, MOUNT (dispatched immediately
+    -- below) can reach MTS before the "Miso.patches" batch containing the
+    -- 'createElement' patch for @_componentDOMRef@ itself, this component's
+    -- own mount point. MTS's 'resolveNodeRef' would then miss
+    -- @runtime.nodes[nodeId]@ (a silent JS property-read failure, not an
+    -- exception) and mount this child against a bogus parent. Flushing here
+    -- guarantees the patch creating this mount point is already applied on
+    -- MTS by the time MOUNT arrives (both travel the same cross-thread
+    -- queue, so send-order is preserved) — cheap since it only fires on an
+    -- actual new mount, not on every render.
+    FFI.flush
+    postComponent MOUNT _componentStaticKey _componentId _componentParentId
+      (Just (toJSON initialProps)) (Just _componentDOMRef)
+#endif
+  pure vcomponent
+-----------------------------------------------------------------------------
+initSubs :: IO model -> [Sub model action] -> IORef (Map MisoString ThreadId) -> Sink action -> IO ()
+initSubs getModel subs_ _componentSubThreads _componentSink = do
+  forM_ subs_ $ \sub_ -> do
+    threadId <- forkIO (sub_ _componentSink getModel)
+    subKey <- freshSubId
+    atomicModifyIORef' _componentSubThreads $ \m ->
+      (M.insert subKey threadId m, ())
+-----------------------------------------------------------------------------
+-- | Builds the @IO model@ handed to each 'Sub': a total lookup of the
+-- component's current model. A 'Sub' is normally killed before its component
+-- is deleted from 'components', but teardown is not atomic — 'killThread'
+-- returns on exception delivery, before the 'Sub' finalizer has run, so e.g.
+-- a still-queued requestAnimationFrame callback can fire after the component
+-- is gone. In that window the last observed model is returned rather than
+-- crashing on a missing key.
+mkGetModel :: ComponentId -> model -> IO (IO model)
+mkGetModel vcompId initialModel = do
+  lastModel <- newIORef initialModel
+  pure $
+    IM.lookup vcompId <$> readIORef components >>= \case
+      Nothing -> readIORef lastModel
+      Just ComponentState { _componentModel = currentModel } -> do
+        atomicWriteIORef lastModel currentModel
+        pure currentModel
+-----------------------------------------------------------------------------
+-- | Diffs two values (models, props, context), returning True if they differ
+-- and a redraw / propagation is necessary. Pointer equality via 'StableName'
+-- is used as a fast path before falling back to 'Eq'.
+dirtyCheck :: Eq a => a -> a -> Bool
+dirtyCheck c n = unsafePerformIO $ do
+  currentName <- c `seq` makeStableName c
+  updatedName <- n `seq` makeStableName n
+  pure (currentName /= updatedName && c /= n)
+-----------------------------------------------------------------------------
+-- | Checks if the Component is mounted before executing actions
+isMounted :: ComponentId -> IO Bool
+isMounted vcompId = isJust . IM.lookup vcompId <$> readIORef components
+-----------------------------------------------------------------------------
+-- | The scheduler processes all events in the system and is responsible
+-- for propagating changes across model states both asynchronously
+-- and synchronously. It also is responsible for
+-- top-down rendering of the UI Component tree.
+scheduler
+  :: forall context . Eq context => Proxy context -> IO ()
+scheduler Proxy =
+  forever $ do
+#ifdef NATIVE
+    when mts (wait btsReady)
+#endif
+    getBatch >>= \case
+      Nothing -> wait globalWaiter
+      Just (vcompId, S.Empty)
+        | vcompId == minBound -> do
+            -- context propagation, 'minBound' sentinel indicates a global
+            -- context change: re-render every t'Miso.Types.Component' with 'useContext' set.
+            -- 'minBound' is the one 'Int' that can be neither a real (positive)
+            -- @ComponentId@ nor a negated one, so it never collides.
+            vcomps <- readIORef components
+            forM_ (IM.elems vcomps) $ \ComponentState {..} ->
+              -- On the MTS, context-driven redraws are suppressed: the BTS ships
+              -- DOM patches via the JS patch protocol, so drawing here would be a
+              -- redundant second paint.
+              when (_componentUseContext && not mts) (_componentDraw _componentModel)
+        | vcompId < 0 -> do
+            -- props propagation, negated @ComponentId@ indicates render-phase only.
+            vcomps <- readIORef components
+            forM_ (IM.lookup (negate vcompId) vcomps) $ \ComponentState {..} -> do
+              -- The MTS never paints from the scheduler: props (and context) are
+              -- read-only there and the BTS drives all drawing via DOM patches.
+              -- Suppress the redraw.
+              when (not mts) $ _componentDraw _componentModel
+              _componentPropsPhase _prevComponentProps _componentProps
+
+      Just (vcompId, actions) -> do
+        mounted <- isMounted vcompId
+        when mounted (run vcompId actions)
+  where
+    -----------------------------------------------------------------------------
+    -- | Execute the commit phase against the model, perform top-down render
+    -- of the entire Component tree.
+    --
+    -- On the MTS the commit phase still runs (its 'IO' effects — e.g. main-thread
+    -- event handlers imperatively mutating a @DOMRef@ — must fire), but the
+    -- subsequent draw is suppressed: the BTS is the sole paint authority and the
+    -- MTS never diffs\/patches from the scheduler.
+    run :: ComponentId -> Seq action -> IO ()
+    run vcompId actions = do
+      rendered <- commit vcompId actions
+      when (not mts) (mapM_ renderComponent rendered)
+    -----------------------------------------------------------------------------
+    -- | Apply the actions across the model, evaluate async and sync IO.
+    commit :: ComponentId -> Seq action -> IO (Maybe ComponentId)
+    commit vcompId events = do
+      currentContext <- readIORef @context globalContext
+      vcomps <- readIORef components
+      let ComponentState {..} = vcomps IM.! vcompId
+          (updatedModel, schedules) =
+            _componentApplyActions events _componentModel _componentProps currentContext
+      -- Route each scheduled effect. A plain t'Schedule' runs its 'IO' here, on
+      -- the thread that produced it. A 'CrossThread' effect targets a specific
+      -- Lynx thread: if that's the current thread it dispatches @action@ locally
+      -- (same as 'issue'); otherwise it forwards @action@ to the peer thread via
+      -- 'postEffect', where @action@'s @update@ runs. Only the tagged @action@
+      -- crosses — sibling effects in the same @update@ stay put, so nothing is
+      -- double-executed.
+      forM_ schedules $ \case
+        ContextModify f ->
+          atomicModifyIORef' globalContext $ \ctx -> (f ctx, ())
+        CrossThread targetThread action
+          | crossThread targetThread -> _componentPostEffect action
+          | otherwise                -> _componentSink action
+        Schedule synch effect -> evalScheduled synch (effect _componentSink)
+      updatedContext <- readIORef globalContext
+      -- 'not mts': the sentinel this enqueues is a no-op there (see the
+      -- 'minBound' scheduler case) — MTS never draws context-driven changes
+      -- itself (BTS ships DOM patches), so enqueueing from MTS would just be
+      -- dequeued and discarded a moment later.
+      when (not mts && dirtyCheck currentContext updatedContext) enqueueContextPropagation
+      -- BTS is the sole owner of the shared model (mirrors ReactLynx, where
+      -- React state is background-thread-only). On MTS the model is a read-only
+      -- replica maintained purely by 'MODEL_HYDRATE' from BTS: 'commit' here
+      -- still fires the actions' 'IO' effects (e.g. main-thread event handlers
+      -- mutating a @DOMRef@), but never writes 'componentModel'. An MTS handler
+      -- that needs to change shared state dispatches the change to BTS with
+      -- 'Miso.Effect.runOnBG' (the analog of ReactLynx's 'runOnBackground'), so
+      -- the state action's @update@ runs on the BTS where the write commits; for
+      -- MTS-local state that never belongs on BTS, use a 'MainThreadRef'.
+      if not mts && _componentModelDirty _componentModel updatedModel
+        then do
+          modifyComponent _componentId (componentModel .= updatedModel)
+          pure (Just vcompId)
+        else
+          pure Nothing
+-----------------------------------------------------------------------------
+-- | Perform a top-down rendering of the t'Miso.Types.Component' tree.
+--
+-- We lookup the components each time to account for unmounting.
+--
+renderComponent :: ComponentId -> IO ()
+renderComponent vcompId = IM.lookup vcompId <$> readIORef components >>= mapM_ \ComponentState {..} -> do
+  _componentDraw _componentModel
+  _componentHydrate _componentModel
+-----------------------------------------------------------------------------
+-- | Modify a single t'Component p m a' at a @ComponentId@.
+--
+-- Auxiliary function
+modifyComponent
+  :: ComponentId
+  -> State (ComponentState context props model action) a
+  -> IO ()
+modifyComponent vcompId go =
+  atomicModifyIORef' components $ \vcomps ->
+    (IM.adjust (execState go) vcompId vcomps, ())
+-----------------------------------------------------------------------------
+-- | The set of child t'Miso.Effect.ComponentId's a component currently has
+-- mounted (the @_componentChildren@ field of 'ComponentState').
+type ComponentIds = IntSet
+-----------------------------------------------------------------------------
+initialDraw
+  :: (Eq m, Eq props, Eq context)
+  => m
+  -> Events
+  -> Hydrate
+  -> Bool
+  -> Component context props m a
+  -> ComponentState context props m a
+  -> IO ()
+initialDraw initializedModel events hydrate isRoot Component {..} ComponentState {..} = do
+#ifdef BENCH
+  start <- FFI.now
+#endif
+  currentContext <- readIORef globalContext
+  vtree <- buildVTree events _componentParentId _componentId hydrate _componentSink logLevel
+    initializedModel (view currentContext _componentProps initializedModel)
+  vtreeHandlers0 <- collectEventHandlers
+#ifdef BENCH
+  end <- FFI.now
+  when isRoot $ FFI.consoleLog $ ms (printf "buildVTree: %.3f ms" (end - start) :: String)
+#endif
+  case hydrate of
+    Draw -> do
+      Diff.diff Nothing (Just vtree) _componentDOMRef
+      atomicWriteIORef _componentVTree vtree
+      swapEventHandlers _componentId vtreeHandlers0
+    Hydrate -> do
+      if isRoot
+        then do
+          hydrated <- Hydrate.hydrate logLevel _componentDOMRef vtree
+          if hydrated
+            then do
+              atomicWriteIORef _componentVTree vtree
+              swapEventHandlers _componentId vtreeHandlers0
+            else do
+              newTree <-
+                buildVTree events _componentParentId _componentId Draw
+                  _componentSink logLevel initializedModel (view currentContext _componentProps initializedModel)
+              newHandlers <- collectEventHandlers
+              -- the discarded hydration tree's callbacks are unreachable
+              mapM_ freeFunction vtreeHandlers0
+              Diff.diff Nothing (Just newTree) _componentDOMRef
+              atomicWriteIORef _componentVTree newTree
+              swapEventHandlers _componentId newHandlers
+        else do
+          atomicWriteIORef _componentVTree vtree
+          swapEventHandlers _componentId vtreeHandlers0
+-----------------------------------------------------------------------------
+-- | Pulls the next Component for processing out of the queue, along with
+-- its events.
+getBatch :: IO (Maybe (ComponentId, Seq action))
+getBatch = do
+  atomicModifyIORef' globalQueue $ \q ->
+    case dequeue q of
+      Nothing -> (q, Nothing)
+      Just (vcompId, actions, newQueue) ->
+        (newQueue, Just (vcompId, actions))
+-----------------------------------------------------------------------------
+-- | Helper for event extraction at a specific @ComponentId@
+drainQueueAt :: ComponentId -> IO (Seq a)
+drainQueueAt vcompId = atomicModifyIORef' globalQueue (dequeueAt vcompId)
+-----------------------------------------------------------------------------
+-- | Data type for holding the events in the system along with
+-- the schedule of what events should be processed next.
+--
+-- Actions enter here from two sources — a local '_componentSink' and the
+-- @Miso.effects@ cross-thread transport (see 'effectListener') — but the
+-- scheduler treats them identically: both are handled on /this/ thread, keeping
+-- it the single writer of every model. A cross-thread 'CrossThread' effect
+-- carries a distinct @action@, so a forwarded action never bounces back on its
+-- own (only a genuine user-authored cross-thread cycle would).
+data Queue action
+  = Queue
+  { _queue :: IntMap (Seq action)
+  , _queueSchedule :: Seq ComponentId
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+emptyQueue :: Queue action
+emptyQueue = mempty
+-----------------------------------------------------------------------------
+instance Semigroup (Queue action) where
+  Queue q1 s1 <> Queue q2 s2 = Queue (q1 <> q2) (s1 <> s2)
+-----------------------------------------------------------------------------
+instance Monoid (Queue action) where
+  mempty = Queue mempty mempty
+-----------------------------------------------------------------------------
+queue :: Lens (Queue action) (IntMap (Seq action))
+queue = lens _queue $ \r f -> r { _queue = f }
+-----------------------------------------------------------------------------
+queueSchedule :: Lens (Queue action) (Seq ComponentId)
+queueSchedule = lens _queueSchedule $ \r f -> r { _queueSchedule = f }
+-----------------------------------------------------------------------------
+enqueue :: ComponentId -> action -> Queue action -> Queue action
+enqueue vcompId action q =
+  q & queue %~ IM.insertWith (flip (<>)) vcompId (S.singleton action)
+    & queueSchedule %~ (S.|> vcompId)
+-----------------------------------------------------------------------------
+-- | Used to fast track to render phase, bypassing commit phase. Used in 'Miso.Effect.props'
+-- feature.
+enqueueSchedule :: ComponentId -> IO ()
+enqueueSchedule vcompId =
+  atomicModifyIORef' globalQueue $ \q ->
+     (q & queueSchedule %~ (S.|> negate vcompId), ())
+-----------------------------------------------------------------------------
+-- | Enqueues the context-propagation sentinel (@'minBound' :: 'Int'@). When the
+-- scheduler dequeues it, every t'Miso.Types.Component' with @useContext@ enabled
+-- is re-rendered against the updated global context. Used by the @context@
+-- feature (see 'Miso.Effect.modifyContext').
+enqueueContextPropagation :: IO ()
+enqueueContextPropagation =
+  atomicModifyIORef' globalQueue $ \q ->
+     (q & queueSchedule %~ (S.|> minBound), ())
+-----------------------------------------------------------------------------
+-- | Case on queue schedule, get first item, span on the rest of queueSchedule, get length.
+-- set schedule with whatever remains.
+--
+-- Take the length of the queue schedule found, looking up with vcompId (from first element)
+-- in the queue, splitAt the queue.
+--
+dequeue
+  :: forall action
+   . Queue action
+  -> Maybe (ComponentId, Seq action, Queue action)
+dequeue q =
+  case q ^. queueSchedule of
+    S.Empty -> Nothing
+    sched@(vcompId S.:<| _) ->
+      case q ^. queue . at vcompId of
+        Nothing ->
+          let (_, remaining) = S.spanl (== vcompId) sched
+          in Just (vcompId, S.empty, q & queueSchedule .~ remaining)
+        Just actions ->
+          case S.spanl (==vcompId) sched of
+            (scheduled, remaining) ->
+              case S.splitAt (length scheduled) actions of
+                (process, rest) -> do
+                  let updated =
+                        q & queueSchedule .~ remaining
+                          & queue.at vcompId .~ do if null rest then Nothing else Just rest
+                  Just (vcompId, process, updated)
+-----------------------------------------------------------------------------
+-- | Dequeues everything from the Queue at a specific @ComponentId@, draining
+-- both the queue events and the queue schedule.
+dequeueAt
+  :: forall action
+   . ComponentId
+  -> Queue action
+  -> (Queue action, Seq action)
+dequeueAt vcompId q =
+  case q ^. queue . at vcompId of
+    Nothing -> (q, S.empty)
+    Just actions -> do
+      -- dmj: remove from schedule, extract all events
+      let updated = q & queueSchedule %~ S.filter (/=vcompId)
+                      & queue.at vcompId .~ Nothing
+      (updated, actions)
+-----------------------------------------------------------------------------
+globalWaiter :: Waiter
+{-# NOINLINE globalWaiter #-}
+globalWaiter = unsafePerformIO waiter
+-----------------------------------------------------------------------------
+-- Note [Freeing event handler callbacks]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-- Every 'On' attribute exports a fresh Haskell callback to JavaScript on
+-- every draw ('Miso.Event.onWithOptions'). On the WASM backend an exported
+-- callback pins its closure with a stable pointer that is only released
+-- when JavaScript's FinalizationRegistry notices the function is
+-- unreachable -- which requires a JavaScript GC and in practice lags far
+-- behind, so redrawing components leak callbacks (and everything their
+-- closures capture, including the model of the frame they were built in).
+--
+-- Instead we track ownership explicitly: 'Miso.Event.onWithOptions' calls
+-- 'registerEventHandler' for every callback it exports, collecting them
+-- into 'handlerCollector' for the duration of one 'buildVTree'. After the
+-- new tree has been diffed in, the previous tree's callbacks can never be
+-- dispatched again (event delegation always consults the current vtree),
+-- so 'swapEventHandlers' frees them and records the new set. Unmounting a
+-- component frees its recorded set.
+--
+-- Draws are serialized by the scheduler and the collector is harvested
+-- before the draw awaits the next animation frame, so a child component
+-- mounting synchronously mid-diff collects into an empty collector and
+-- harvests it before returning.
+-----------------------------------------------------------------------------
+-- | Callbacks exported to JavaScript during the current 'buildVTree'.
+{-# NOINLINE handlerCollector #-}
+handlerCollector :: IORef [Function]
+handlerCollector = unsafePerformIO (newIORef [])
+-----------------------------------------------------------------------------
+-- | Event handler callbacks owned by each mounted component's current vtree.
+{-# NOINLINE vtreeHandlers #-}
+vtreeHandlers :: IORef (IntMap [Function])
+vtreeHandlers = unsafePerformIO (newIORef mempty)
+-----------------------------------------------------------------------------
+-- | Called by 'Miso.Event.onWithOptions' for every callback it exports.
+-- See Note [Freeing event handler callbacks].
+registerEventHandler :: JSVal -> IO ()
+registerEventHandler cb =
+  atomicModifyIORef' handlerCollector $ \cbs -> (Function cb : cbs, ())
+-----------------------------------------------------------------------------
+-- | Take ownership of the callbacks exported by the 'buildVTree' that just
+-- finished. See Note [Freeing event handler callbacks].
+collectEventHandlers :: IO [Function]
+collectEventHandlers = atomicModifyIORef' handlerCollector (\cbs -> ([], cbs))
+-----------------------------------------------------------------------------
+-- | Record @new@ as the component's current handler set and free the
+-- previous one. Call only after the new vtree has replaced the old one.
+-- See Note [Freeing event handler callbacks].
+swapEventHandlers :: ComponentId -> [Function] -> IO ()
+swapEventHandlers vcompId newHandlers = do
+  oldHandlers <- atomicModifyIORef' vtreeHandlers $ \m ->
+    (IM.insert vcompId newHandlers m, IM.findWithDefault [] vcompId m)
+  mapM_ freeFunction oldHandlers
+-----------------------------------------------------------------------------
+-- | Free and forget a component's handler set (on unmount).
+-- See Note [Freeing event handler callbacks].
+freeEventHandlers :: ComponentId -> IO ()
+freeEventHandlers vcompId = do
+  oldHandlers <- atomicModifyIORef' vtreeHandlers $ \m ->
+    (IM.delete vcompId m, IM.findWithDefault [] vcompId m)
+  mapM_ freeFunction oldHandlers
+-----------------------------------------------------------------------------
+#ifdef NATIVE
+btsReady :: Waiter
+{-# NOINLINE btsReady #-}
+btsReady = unsafePerformIO oneshot
+-----------------------------------------------------------------------------
+-- | __MTS-side.__ Read \/ written only from 'componentListener', which only
+-- ever runs on MTS. Set once 'READY' has been handled at least once, so a
+-- retried 'READY' (BTS resends until acked — see 'sendReadyUntilAcked') only
+-- ever 'notify's 'btsReady' a single time. 'notify' on a 'oneshot' t'Waiter'
+-- is a blocking @putMVar@ on an already-full 'MVar' the second time around,
+-- so without this guard a retried 'READY' would deadlock the MTS listener
+-- callback instead of being the harmless no-op it should be.
+readyReceived :: IORef Bool
+{-# NOINLINE readyReceived #-}
+readyReceived = unsafePerformIO (newIORef False)
+-----------------------------------------------------------------------------
+-- | __BTS-side.__ Read \/ written only from 'sendReadyUntilAcked' and
+-- 'readyAckListener', which only ever run on BTS. Set once MTS's
+-- 'READY_ACK' arrives, stopping 'sendReadyUntilAcked' from resending
+-- 'READY' any further — otherwise BTS would blast the full retry budget on
+-- every boot, even in the common case where the very first 'READY' lands
+-- immediately.
+readyAcked :: IORef Bool
+{-# NOINLINE readyAcked #-}
+readyAcked = unsafePerformIO (newIORef False)
+#endif
+-----------------------------------------------------------------------------
+globalQueue :: IORef (Queue action)
+{-# NOINLINE globalQueue #-}
+globalQueue = unsafePerformIO (newIORef emptyQueue)
+-----------------------------------------------------------------------------
+-- | The global React-style @context@. Seeded in 'initComponent' (via
+-- 'Miso.startAppWithContext', defaulting to @()@) and mutated by
+-- 'Miso.Effect.modifyContext' during the scheduler's commit phase.
+--
+-- N.B. like 'components', this holds a single value whose type is fixed for the
+-- lifetime of the application; it is written before any draw occurs.
+globalContext :: IORef context
+{-# NOINLINE globalContext #-}
+globalContext = unsafePerformIO (newIORef undefined)
+-----------------------------------------------------------------------------
+-- | Seed the global @context@ 'IORef' with a value.
+--
+-- 'Miso.startAppWithContext' seeds this before the first draw, so client
+-- applications never call it. It exists for __server-side rendering__, where a
+-- t'Miso.Types.View' is serialized to HTML without ever starting the runtime
+-- and the global @context@ cell would otherwise still hold @undefined@. See
+-- 'Miso.setContext' for the full explanation.
+--
+-- @since 1.13.0.0
+setContext :: Eq context => context -> IO ()
+setContext = atomicWriteIORef globalContext
+-----------------------------------------------------------------------------
+componentId :: Lens (ComponentState context props model action) ComponentId
+componentId = lens _componentId $ \record field -> record { _componentId = field }
+-----------------------------------------------------------------------------
+componentKey :: Lens (ComponentState context props model action) (Maybe Key)
+componentKey = lens _componentKey $ \record field -> record { _componentKey = field }
+-----------------------------------------------------------------------------
+children :: Lens (ComponentState context props model action) ComponentIds
+children = lens _componentChildren $ \record field -> record { _componentChildren = field }
+-----------------------------------------------------------------------------
+componentTopics :: Lens (ComponentState context props model action) (Map MisoString (Value -> IO ()))
+componentTopics = lens _componentTopics $ \record field -> record { _componentTopics = field }
+-----------------------------------------------------------------------------
+componentModel :: Lens (ComponentState context props model action) model
+componentModel = lens _componentModel $ \record field -> record { _componentModel = field }
+-----------------------------------------------------------------------------
+componentProps :: Lens (ComponentState context props model action) props
+componentProps = lens _componentProps $ \record field -> record { _componentProps = field }
+-----------------------------------------------------------------------------
+prevComponentProps :: Lens (ComponentState context props model action) props
+prevComponentProps = lens _prevComponentProps $ \record field -> record { _prevComponentProps = field }
+-----------------------------------------------------------------------------
+-- | t'Miso.Types.Component' state, data associated with the lifetime of a t'Miso.Types.Component'
+data ComponentState context props model action
+  = ComponentState
+  { _componentId :: ComponentId
+  -- ^ The ID of the current t'Miso.Types.Component'
+  , _componentKey :: Maybe Key
+  -- ^ Optional key for stable hot-reload model recovery
+  , _componentStaticKey :: Maybe StaticKey
+  -- ^ 'StaticPtr' key of the originating @VComp@, used to instruct the MTS
+  -- to mount, hydrate, or unmount this child across the Lynx thread boundary.
+  -- 'Nothing' for the root (each thread mounts the root locally).
+  , _componentParentId :: ComponentId
+  -- ^ The ID of the t'Miso.Types.Component''s parent
+  , _componentProps :: props
+  -- ^ The current props passed to this t'Miso.Types.Component'
+  , _prevComponentProps :: props
+  -- ^ The previous Component props passed to this t'Miso.Types.Component'
+  , _componentSubThreads :: IORef (Map MisoString ThreadId)
+  -- ^ Mapping of all 'Sub' in use by t'Miso.Types.Component'
+  , _componentDOMRef :: DOMRef
+  -- ^ The DOM reference the t'Miso.Types.Component' is mounted on
+  , _componentVTree :: IORef VTree
+  -- ^ A reference to the current virtual DOM (i.e. t'VTree')
+  , _componentSink :: action -> IO ()
+  -- ^ t'Miso.Types.Component' t'Sink' used to enter events into the system
+  , _componentPostEffect :: Sink action
+  -- ^ Cross-thread (Lynx) t'Sink': serializes the @action@ and ships it to the
+  -- opposite thread via @postEffect@. Captures the t'Miso.Types.Component''s
+  -- 'ToJSON' instance at initialization time. Used by 'CrossThread' effects
+  -- ('Miso.Effect.runOnMain' \/ 'Miso.Effect.runOnBG').
+  , _componentModel :: model
+  -- ^ t'Miso.Types.Component' state
+  , _componentScripts :: [DOMRef]
+  -- ^ DOM references for \<script\> and \<style\> appended to \<head\>
+  , _componentEvents :: Events
+  -- ^ List of events a t'Miso.Types.Component' listens on
+  , _componentUseContext :: Bool
+  -- ^ Whether this t'Miso.Types.Component' re-renders when the global
+  --   @context@ changes.
+  , _componentMailbox :: Value -> Maybe action
+  -- ^ Mailbox for asynchronous t'Miso.Types.Component' communication
+  , _componentDraw :: model -> IO ()
+  -- ^ Helper function for t'Miso.Types.Component' rendering
+  , _componentHydrate :: model -> IO ()
+  -- ^ Posts the model to the MTS for cross-thread (Lynx) hydration via
+  -- @MODEL_HYDRATE@. Captures the t'Miso.Types.Component''s 'ToJSON' instance at
+  -- initialization time; a no-op unless running on the background thread ('bts').
+  , _componentPropsPhase :: props -> props -> IO ()
+  -- ^ Helper function for t'Miso.Types.Component' props changed phase.
+  , _componentModelDirty :: model -> model -> Bool
+  -- ^ Model diffing
+  , _componentApplyActions
+      :: Seq action
+      -> model
+      -> props
+      -> context
+      -> (model, [Schedule context action])
+  -- ^ t'Miso.Types.Component' actions application. Given the pending actions,
+  --   current @model@ and @props@, returns the updated @model@ and the
+  --   t'Schedule's to run (async \/ sync IO, cross-thread effects, and
+  --   'ContextModify's).
+  , _componentTopics :: Map MisoString (Value -> IO ())
+  -- ^ t'Miso.Types.Component' topics using for Pub Sub async communication.
+  , _componentChildren :: ComponentIds
+  -- ^ 'IntSet' of children t'Miso.Types.ComponentId'
+  }
+-----------------------------------------------------------------------------
+-- | A @Topic@ represents a place to send and receive messages. @Topic@ is used to facilitate
+-- communication between t'Miso.Types.Component'. t'Miso.Types.Component' can 'subscribe' to or 'publish' to any @Topic@,
+-- within the same t'Miso.Types.Component' or across t'Miso.Types.Component'.
+--
+-- This requires creating a custom 'ToJSON' / 'FromJSON'. Any other t'Miso.Types.Component'
+-- can 'publish' or 'subscribe' to this @Topic message@. It is a way to provide
+-- loosely-coupled communication between @Components@.
+--
+-- See 'publish', 'subscribe', 'unsubscribe' for more details.
+--
+-- When distributing t'Miso.Types.Component' for third-party use, it is recommended to export
+-- the @Topic@, where message is the JSON protocol.
+--
+--
+-- @since 1.9.0.0
+newtype Topic a = Topic MisoString
+  deriving stock (Ord, Eq, Show)
+-----------------------------------------------------------------------------
+instance ToMisoString (Topic a) where
+  toMisoString (Topic x) = x
+-----------------------------------------------------------------------------
+-- | Smart constructor for creating a @Topic message@ to write to
+--
+-- @
+--
+-- data Message
+--   = Increment
+--   | Decrement
+--   deriving (Show, Eq, Generic, ToJSON, FromJSON)
+--
+-- arithmetic :: Topic Message
+-- arithmetic = topic "arithmetic"
+--
+-- data Action
+--   = Notification (Result Message)
+--   | Subscribe
+--   | Unsubscribe
+--
+-- update_ :: Action -> Effect context props Int Action
+-- update_ = \case
+--   Unsubscribe ->
+--     unsubscribe arithmetic
+--   Subscribe ->
+--     subscribe arithmetic Notification
+--   Notification (Success Increment) ->
+--     update_ AddOne
+--   Notification (Success Decrement) ->
+--     update_ SubtractOne
+--   Notification (Error msg) ->
+--     io_ $ consoleError ("Decode failure: " <> ms msg)
+--
+-- @
+--
+-- @since 1.9.0.0
+topic :: MisoString -> Topic a
+topic = Topic
+-----------------------------------------------------------------------------
+-- | Subscribes a t'Miso.Types.Component' to a t'Topic'.
+--
+-- Registers a callback in the component that decodes incoming messages
+-- using its own 'FromJSON' instance and dispatches them to the component's
+-- 'Sink'. If the component is already subscribed to the named topic the
+-- previous callback is replaced.
+--
+-- Because each subscriber uses its own 'FromJSON', components can use
+-- different Haskell types for the same topic as long as the underlying
+-- JSON is compatible, enabling loose coupling between t'Miso.Types.Component'.
+--
+-- @
+--
+-- data Message = Increment | Decrement
+--   deriving (Show, Eq, Generic, ToJSON, FromJSON)
+--
+-- arithmetic :: Topic Message
+-- arithmetic = topic "arithmetic"
+--
+-- data Action
+--   = Notify Message
+--   | NotifyError MisoString
+--   | Subscribe
+--   | Unsubscribe
+--   | AddOne
+--   | SubtractOne
+--
+-- update_ :: Action -> Effect context props Int Action
+-- update_ = \\case
+--   Subscribe ->
+--     subscribe arithmetic Notify NotifyError
+--   Unsubscribe ->
+--     unsubscribe arithmetic
+--   Notify Increment -> update_ AddOne
+--   Notify Decrement -> update_ SubtractOne
+--   NotifyError msg ->
+--     io_ $ consoleError ("Decode failure: " <> msg)
+--   AddOne -> _count += 1
+--   SubtractOne -> _count -= 1
+--
+-- @
+--
+-- @since 1.9.0.0
+subscribe
+  :: FromJSON message
+  => Topic message
+  -> (message -> action)
+  -> (MisoString -> action)
+  -> Effect context props model action
+subscribe (Topic topicName) successful errorful = do
+  ComponentInfo {..} <- ask
+  withSink $ \sink ->
+    modifyComponent _componentInfoId $ do
+      componentTopics %= do
+        M.insert topicName $ \value ->
+          sink (case fromJSON value of
+                  Success s -> successful s
+                  Error e -> errorful e)
+-----------------------------------------------------------------------------
+-- | Unsubscribes a t'Miso.Types.Component' from a t'Topic'.
+--
+-- Removes the callback registered by 'subscribe' so the component no longer
+-- receives messages published to the topic. If the component is not
+-- currently subscribed this is a no-op.
+--
+-- See 'subscribe' for example usage.
+--
+-- @since 1.9.0.0
+unsubscribe :: Topic message -> Effect context props model action
+unsubscribe (Topic topicName) = do
+  ComponentInfo {..} <- ask
+  io_ $ modifyComponent _componentInfoId $ do
+    componentTopics %= M.delete topicName
+-----------------------------------------------------------------------------
+-- | Publish to a t'Topic message'
+--
+-- t'Topic message' are generated dynamically if they do not exist. When using 'publish'
+-- all subscribers are immediately notified of a new message. A message is distributed as a 'Value'
+-- The underlying 'ToJSON' instance is used to construct this 'Value'.
+--
+-- We recommend documenting a public API for the JSON protocol message when distributing a t'Miso.Types.Component'
+-- downstream to end users for consumption (be it inside a single cabal project or across multiple
+-- cabal projects).
+--
+-- @
+--
+-- arithmetic :: Topic Message
+-- arithmetic = topic "arithmetic"
+--
+-- server :: Component context props () Action
+-- server = component () update_ $ \() ->
+--   div_
+--   []
+--   [ "Server component"
+--   , button_ [ onClick AddOne ] [ "+" ]
+--   , button_ [ onClick SubtractOne ] [ "-" ]
+--   , component_ (client_ "client 1")
+--   , component_ (client_ "client 2")
+--   ] where
+--       update_ :: Action -> Effect context props () Action
+--       update_ = \case
+--         AddOne ->
+--           publish arithmetic Increment
+--         SubtractOne ->
+--           publish arithemtic Decrement
+--
+-- @
+--
+-- @since 1.9.0.0
+publish
+  :: ToJSON message
+  => Topic message
+  -> message
+  -> IO ()
+publish (Topic topicName) message = mapM_ go . IM.elems =<< readIORef components
+  where
+    go ComponentState {..} =
+      case M.lookup topicName _componentTopics of
+        Nothing ->
+          pure ()
+        Just f ->
+          f (toJSON message)
+-----------------------------------------------------------------------------
+subIds :: IORef Int
+{-# NOINLINE subIds #-}
+subIds = unsafePerformIO $ newIORef 0
+-----------------------------------------------------------------------------
+freshSubId :: IO MisoString
+freshSubId = do
+  x <- atomicModifyIORef' subIds $ \y -> (y + 1, y)
+  pure ("miso-sub-id-" <> ms x)
+-----------------------------------------------------------------------------
+-- | This is used to demarcate the ROOT of a page. This ID will *never*
+-- exist in the `components` map.
+rootComponentId :: ComponentId
+rootComponentId = 0
+-----------------------------------------------------------------------------
+-- | This is the top-level ComponentId, hardcoded
+topLevelComponentId :: ComponentId
+topLevelComponentId = 1
+-----------------------------------------------------------------------------
+-- | The global store of @ComponentId@, for internal-use only.
+--
+-- Used internally @freshComponentId@ to allocate new @ComponentId@ on
+-- mount.
+--
+componentIds :: IORef Int
+{-# NOINLINE componentIds #-}
+componentIds = unsafePerformIO $ newIORef topLevelComponentId
+-----------------------------------------------------------------------------
+freshComponentId :: IO ComponentId
+freshComponentId = atomicModifyIORef' componentIds $ \y -> (y + 1, y)
+-----------------------------------------------------------------------------
+-- | 'cleanup' is used to remove previous application state (when using miso w/ GHCi).
+--
+-- As seen in <https://try.haskell-miso.org>
+--
+-- * Detect if previous t'Miso.Types.Component' tree is present.
+-- * Unmount in descending order (top-level t'Miso.Types.Component' removed last), invoking finalizers
+-- * Kill the scheduler thread (a new one is created on ':r').
+-- * Erase all t'Miso.Types.Component'
+-- * Erase t'Queue'
+-- * Reset 'componentId'
+-- * Recreate @DOMRef@, GCs previous event listeners in JS.
+-- * Yield to the scheduler (unwind thread stacks).
+-- * Perform major garbage collection (cleans out old state).
+--
+-- This GC should remove the previous @Notify@ / 'MVar' as well since the @sink@
+-- closure should go out of scope.
+--
+cleanup :: forall context. Eq context => Proxy context -> Bool -> DOMRef -> IO ()
+cleanup Proxy live domRef = do
+  vcomps <- readIORef components
+  when (IM.size vcomps > 0) $ do
+    killThread =<< readIORef schedulerThread
+    if live
+      then do
+        -- In hot reload we want to reset subs and connections, and free lifecycle hooks
+        forM_ (IM.toDescList vcomps) $ \(_, cs@ComponentState{..}) -> do
+          mapM_ killThread =<< readIORef _componentSubThreads
+          finalizeWebSockets _componentId
+          finalizeEventSources _componentId
+          freeLifecycleHooks cs
+      else do
+        -- We can do a full unmount if we're not doing hot reload
+        forM_ (IM.toDescList vcomps) $ \(_, _vcomp_) ->
+          unmountComponent @context _vcomp_
+    atomicWriteIORef componentIds topLevelComponentId
+    atomicWriteIORef globalQueue mempty
+    unless live (atomicWriteIORef components mempty)
+    abort <- domRef ! "abort"
+    isnull <- isNull abort
+    unless isnull $ do
+      void $ (domRef # "abort") ()
+    yield
+    performMajorGC
+-----------------------------------------------------------------------------
+-- | componentMap
+--
+-- This is a global t'Miso.Types.Component' @Map@ that holds the state of all currently
+-- mounted t'Miso.Types.Component's
+components :: IORef (IntMap (ComponentState context props model action))
+{-# NOINLINE components #-}
+components = unsafePerformIO (newIORef mempty)
+-----------------------------------------------------------------------------
+-- | Set once in 'initComponent' from its @live@ argument. Gates key-based
+-- model recovery in 'initialize' — outside hot reload, a keyed component
+-- must never inherit a previous (possibly unrelated) component's model just
+-- because it shares a t'Key'.
+liveMode :: IORef Bool
+{-# NOINLINE liveMode #-}
+liveMode = unsafePerformIO (newIORef False)
+-----------------------------------------------------------------------------
+-- | This function evaluates effects according to 'Synchronicity'.
+evalScheduled :: Synchronicity -> IO () -> IO ()
+evalScheduled Sync x = x `catch` (void . exception)
+evalScheduled Async x = void (forkIO (x `catch` (void . exception)))
+-----------------------------------------------------------------------------
+exception :: SomeException -> IO ()
+exception ex = FFI.consoleError ("[EXCEPTION]: " <> ms ex)
+-----------------------------------------------------------------------------
+-- | Drains the event queue before unmounting, executed synchronously.
+drain
+  :: forall context props model action . Eq context
+  => ComponentState context props model action
+  -> IO ()
+drain ComponentState {..} = do
+  drainQueueAt _componentId >>= \case
+    S.Empty -> pure ()
+    actions -> do
+       currentContext <- readIORef @context globalContext
+       case _componentApplyActions actions _componentModel _componentProps currentContext of
+         (_, schedules) -> do
+           forM_ schedules $ \case
+             -- dmj: process all actions synchronously during unmount. A
+             -- 'CrossThread' effect targeting the peer thread is forwarded via
+             -- 'postEffect' (its @action@'s @update@ runs there); one targeting
+             -- this thread is dispatched locally. Plain t'Schedule's run here.
+             CrossThread targetThread action
+               | crossThread targetThread -> _componentPostEffect action
+               | otherwise                -> _componentSink action
+             Schedule _ effect ->
+               effect _componentSink
+                 `catch` exception
+             ContextModify f ->
+               atomicModifyIORef' globalContext $ \ctx -> (f ctx, ())
+           newContext <- readIORef globalContext
+           when (not mts && dirtyCheck currentContext newContext) enqueueContextPropagation
+           -- dmj: One last context propagation before aborting.
+           -- Don't recurse on drain, we only fire-off the last set
+           -- of events for 'onBeforeUnmounted' hooks. The queue will
+           -- ignore the rest of these.
+-----------------------------------------------------------------------------
+-- | Post unmount call to drop the <style> and <script> in <head>
+unloadScripts :: ComponentState context props model action -> IO ()
+unloadScripts ComponentState {..} = do
+  head_ <- FFI.getHead
+  forM_ _componentScripts $ \domRef -> do
+    contains <- fromJSValUnchecked =<< do head_ # "contains" $ [domRef]
+    when contains (FFI.removeChild head_ domRef)
+-----------------------------------------------------------------------------
+-- | Helper to drop all lifecycle and mounting hooks if defined.
+freeLifecycleHooks :: ComponentState context props model action -> IO ()
+freeLifecycleHooks ComponentState {..} = do
+  VTree (Object vtree) <- readIORef _componentVTree
+  -- The root Component's VTree never gets a "parent" link (only buildComp
+  -- sets one, for a mounted child's content root) -- mirrors the "at root,
+  -- do nothing" guard in ts/miso/util.ts's updateRef. FromJSVal Object
+  -- returns Nothing for undefined/null, so this naturally skips the root.
+  maybeComp <- fromJSVal =<< vtree ! ("parent" :: MisoString)
+  forM_ maybeComp $ \(Object comp) -> do
+    mapM_ freeFunction =<< fromJSVal =<< comp ! ("mount" :: MisoString)
+    mapM_ freeFunction =<< fromJSVal =<< comp ! ("unmount" :: MisoString)
+-----------------------------------------------------------------------------
+-- | Helper function for cleanly destroying a t'Miso.Types.Component'
+unmountComponent
+  :: Eq context
+  => ComponentState context props model action
+  -> IO ()
+unmountComponent cs@ComponentState {..} = do
+  mapM_ killThread =<< readIORef _componentSubThreads
+  drain cs
+  finalizeWebSockets _componentId
+  finalizeEventSources _componentId
+  unloadScripts cs
+  freeLifecycleHooks cs
+  freeEventHandlers _componentId
+  modifyComponent _componentParentId $ do
+    children.at _componentId .= Nothing
+  atomicModifyIORef' components $ \m -> (IM.delete _componentId m, ())
+#ifdef NATIVE
+  when bts $ do
+    postComponent UNMOUNT _componentStaticKey _componentId _componentParentId Nothing Nothing
+#endif
+-----------------------------------------------------------------------------
+-- | Internal function for construction of a Virtual DOM.
+--
+-- Component mounting should be synchronous.
+-- Mounting causes a recursive diffing to occur
+-- (creating sub components as detected), setting up
+-- infrastructure for each sub-component. During this
+-- process we go between the Haskell heap and the JS heap.
+buildVTree
+  :: forall context model action . Eq context
+  => Events
+  -> ComponentId
+  -> ComponentId
+  -> Hydrate
+  -> Sink action
+  -> LogLevel
+  -> model
+  -> View context model action
+  -> IO VTree
+buildVTree events_ parentId_ vcompId hydrate snk logLevel_ model_ = \case
+  VComp someComp -> buildComp Nothing someComp
+
+  VCompStatic ptr props -> case deRefStaticPtr ptr of
+    SomeStaticComponent mk -> buildComp (Just (staticKey ptr)) (mk props)
+
+  VNode ns tag attrs kids _directEvents -> do
+    vnode_ <- createNode "vnode" ns tag
+    setAttrs vnode_ attrs snk vcompId logLevel_ events_ model_
+#ifdef NATIVE
+    -- Only the Lynx native runtime consumes directEvents; the web/WASM diff
+    -- never reads it (all HTML/SVG/MathML nodes carry an empty set anyway).
+    FFI.set "directEvents" (Set.toList _directEvents) vnode_
+#endif
+    children_ <- procreate vnode_
+    vchildren <- toJSVal (map snd children_)
+    FFI.set "children" vchildren vnode_
+    nodeType <- toJSVal VNodeType
+    FFI.set "type" nodeType vnode_
+    -- The children are now linked into the tree on the JS side; release the
+    -- handles we no longer need. See Note [Freeing VTree handles].
+    freeJSVal nodeType
+    freeJSVal vchildren
+    mapM_ freeKid children_
+    pure (VTree vnode_)
+      where
+        procreate parentVTree = do
+          kidsViews <- foldM (buildKid parentVTree) [] kids
+          let ordered = reverse kidsViews
+          setNextSibling (map snd ordered)
+          pure ordered
+            where
+              setNextSibling xs =
+                zipWithM_ (flip setField "nextSibling")
+                  xs (drop 1 xs)
+              buildKid _ acc (VFrag _ []) = pure acc
+              buildKid p acc kid = do
+                VTree child <- buildVTree events_ parentId_ vcompId hydrate snk logLevel_ model_ kid
+                FFI.set "parent" p child
+                pure ((kid, child) : acc)
+  VText key t -> do
+    vtree <- create
+    flip (FFI.set "type") vtree =<< toJSVal VTextType
+    forM_ key $ \k -> FFI.set "key" (ms k) vtree
+    FFI.set "ns" ("text" :: MisoString) vtree
+    FFI.set "text" t vtree
+    pure (VTree vtree)
+  VFrag maybeKey kids -> do
+    frag <- create
+    FFI.set "type" VFragType frag
+    forM_ maybeKey $ \(Key k) -> FFI.set "key" k frag
+    children_ <- procreateFragChildren frag
+    vchildren <- toJSVal (map snd children_)
+    FFI.set "children" vchildren frag
+    freeJSVal vchildren
+    mapM_ freeKid children_
+    pure (VTree frag)
+      where
+        procreateFragChildren parentVTree = do
+          kidsViews <- foldM buildKid [] kids
+          let ordered = reverse kidsViews
+          zipWithM_ (flip setField "nextSibling") (map snd ordered) (drop 1 (map snd ordered))
+          pure ordered
+            where
+              buildKid acc (VFrag _ []) = pure acc
+              buildKid acc kid = do
+                VTree child <- buildVTree events_ parentId_ vcompId hydrate snk logLevel_ model_ kid
+                FFI.set "parent" parentVTree child
+                pure ((kid, child) : acc)
+  where
+    -- Note [Freeing VTree handles]
+    -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    -- On WASM each 'JSVal' handle carries a weak pointer that every GC must
+    -- evacuate before it can discover the handle is dead, so the hundreds of
+    -- short-lived handles created per frame while building a vtree make GC
+    -- pauses scale with the size of the tree (see 'freeJSVal'). Once a child
+    -- has been linked into its parent on the JS side the JavaScript object is
+    -- kept alive by the tree and the Haskell handle is dead weight, so we free
+    -- it -- unless something on the Haskell side can still reach it:
+    --
+    --  * Nodes with event handlers: the handler closure captures the node
+    --    ('onWithOptions' reads @pendingComponentId@ from it at event time).
+    --  * Components: 'buildComp' installs callbacks that close over the
+    --    component object.
+    --
+    -- The root handle is returned to the caller and is never freed here.
+    freeKid :: (View context model action, Object) -> IO ()
+    freeKid (kid, Object child) = when (freeable kid) (freeJSVal child)
+
+    freeable :: View context model action -> Bool
+    freeable = \case
+      VNode _ _ attrs _ _ -> not (any isEvent attrs)
+      VText {} -> True
+      VFrag {} -> True
+      VComp {} -> False
+      VCompStatic {} -> False
+
+    isEvent :: Attribute model action -> Bool
+    isEvent = \case
+      On {} -> True
+      OnStatic {} -> True
+      _ -> False
+
+    -- Shared construction for @VComp@ and @VCompStatic@. The only difference is
+    -- the 'StaticKey' passed to 'initialize': 'Nothing' for dynamic components,
+    -- @Just (staticKey ptr)@ for statically-referenced ones.
+    buildComp :: Maybe StaticKey -> SomeComponent context -> IO VTree
+    buildComp maybeStaticKey (SomeComponent maybeKey newProps app) = do
+      comp <- create
+      mountCallback <- do
+        syncCallback1' $ \parent_ -> do
+          ComponentState {..} <- initialize events_ vcompId hydrate False newProps maybeKey maybeStaticKey app (pure parent_)
+          modifyComponent vcompId (children %= IS.insert _componentId)
+          vtree <- toJSVal =<< readIORef _componentVTree
+          FFI.set "parent" comp (Object vtree)
+          obj <- create
+          setProp "componentId" _componentId obj
+          setProp "componentTree" vtree obj
+          toJSVal obj
+      unmountCallback <- toJSVal =<< do
+        FFI.syncCallback1 $ \vcompId_ -> do
+          componentId_ <- fromJSValUnchecked vcompId_
+          IM.lookup componentId_ <$> readIORef components >>= \case
+            Nothing -> pure ()
+            Just componentState -> do
+              forM_ (unmount app) (_componentSink componentState)
+              unmountComponent @context componentState
+      -- When props are present, install a diffProps callback.
+      -- Comparison happens in Haskell against _componentLastProps — no round-trip.
+      -- TypeScript calls diffProps() unconditionally; Haskell decides whether to dispatch.
+      diffPropsCallback <- toJSVal =<< do
+        syncCallback $ do
+          componentId_ <- fromJSValUnchecked =<< comp ! ("componentId" :: MisoString)
+          currentProps <- _componentProps . (IM.! componentId_) <$> readIORef components
+          when (dirtyCheck currentProps newProps) $ do
+            modifyComponent componentId_ $ do
+              componentProps .= newProps
+              prevComponentProps .= currentProps
+            enqueueSchedule componentId_
+      FFI.set "diffProps" diffPropsCallback comp
+      FFI.set "child" jsNull comp
+      forM_ maybeKey (\key -> FFI.set "key" key comp)
+      FFI.set "mount" mountCallback comp
+      FFI.set "unmount" unmountCallback comp
+      FFI.set "eventPropagation" (eventPropagation app) comp
+      FFI.set "type" VCompType comp
+      pure (VTree comp)
+-----------------------------------------------------------------------------
+-- | @createNode@
+-- A helper function for constructing a vtree (used for @vcomp@ and @vnode@)
+-- Doesn't handle children
+createNode :: MisoString -> Namespace -> MisoString -> IO Object
+createNode typ ns tag = do
+  vnode_ <- create
+  cssObj <- create
+  propsObj <- create
+  eventsObj <- create
+  captures <- create
+  bubbles <- create
+  FFI.set "css" cssObj vnode_
+  FFI.set "type" typ vnode_
+  FFI.set "props" propsObj vnode_
+  FFI.set "events" eventsObj vnode_
+  FFI.set "captures" captures eventsObj
+  FFI.set "bubbles" bubbles eventsObj
+  FFI.set "ns" ns vnode_
+  FFI.set "tag" tag vnode_
+  -- All five scratch objects are now reachable from the vnode on the JS
+  -- side; release the Haskell handles. See Note [Freeing VTree handles].
+  mapM_ (freeJSVal . unObject) [cssObj, propsObj, eventsObj, captures, bubbles]
+  pure vnode_
+-----------------------------------------------------------------------------
+-- | Helper function for populating "props" and "css" fields on a virtual
+-- DOM node
+setAttrs
+  :: Object
+  -> [Attribute model action]
+  -> Sink action
+  -> ComponentId
+  -> LogLevel
+  -> Events
+  -> model
+  -> IO ()
+setAttrs vnode_@(Object jval) attrs snk vcompId logLevel events model_ = do
+  forM_ attrs $ \case
+    Property "key" v -> do
+      value <- toJSVal v
+      FFI.set "key" value vnode_
+    ClassList classes ->
+      FFI.populateClass jval classes
+    Property k v -> do
+      value <- toJSVal v
+      o <- getProp "props" vnode_
+      FFI.set k value (Object o)
+      freeJSVal o
+      -- Only handles created by 'toJSVal' itself are ours to free: a
+      -- 'String' shares the handle of its 'MisoString' and 'Null' is a
+      -- shared constant. See Note [Freeing VTree handles].
+      when (freshValue v) (freeJSVal value)
+    On callback -> do
+      -- Reset any 'pendingStaticKey' \/ 'pendingMainThread' left behind by an
+      -- earlier 'OnStatic' attribute on this same node — otherwise a plain
+      -- 'On' handler processed after an 'OnStatic' one would inherit its
+      -- sibling's stale main-thread flag and staticKey (see 'onWithOptions').
+      FFI.set "pendingComponentId" vcompId vnode_
+      FFI.set "pendingStaticKey" jsNull vnode_
+      FFI.set "pendingMainThread" False vnode_
+      callback model_ snk (VTree vnode_) logLevel events
+    OnStatic ptr ->
+      -- Stash the handler's 'StaticKey' and owning @ComponentId@ on the node
+      -- so 'onWithOptions' can attach them to the per-event object; the native
+      -- PATCH protocol ships them to the MTS for main-thread ('MTS') dispatch.
+      -- Browser\/WASM never dereferences them. 'pendingMainThread' starts
+      -- @False@; 'Miso.Event.mainThread' (part of @callback@) flips it 'True'
+      -- so only marked handlers opt in.
+      case deRefStaticPtr ptr of
+        EventHandler {..} -> do
+          FFI.set "pendingStaticKey" (staticKey ptr) vnode_
+          FFI.set "pendingComponentId" vcompId vnode_
+          FFI.set "pendingMainThread" False vnode_
+          eventHandlerInstall model_ snk (VTree vnode_) logLevel events
+    Styles styles -> do
+      cssObj <- getProp "css" vnode_
+      forM_ (M.toList styles) $ \(k,v) -> do
+        FFI.set k v (Object cssObj)
+      freeJSVal cssObj
+  where
+    freshValue :: Value -> Bool
+    freshValue = \case
+      JSON.String {} -> False
+      JSON.Null -> False
+      _ -> True
+-----------------------------------------------------------------------------
+-- | Registers components in the global state
+registerComponent :: MonadIO m => ComponentState context props model action -> m ()
+registerComponent componentState = liftIO $
+  atomicModifyIORef' components $ \vcomps' ->
+    (IM.insert (_componentId componentState) componentState vcomps', ())
+-----------------------------------------------------------------------------
+-- | Renders styles
+--
+-- Meant for development purposes
+-- Appends CSS to <head>
+--
+renderStyles :: [CSS] -> IO [DOMRef]
+renderStyles styles =
+  forM styles $ \case
+    Href url cacheBust -> FFI.addStyleSheet url cacheBust
+    Style css -> FFI.addStyle css
+    Sheet sheet -> FFI.addStyle (renderStyleSheet sheet)
+-----------------------------------------------------------------------------
+-- | Renders scripts
+--
+-- Meant for development purposes
+-- Appends JS to <head>
+--
+renderScripts :: [JS] -> IO [DOMRef]
+renderScripts scripts =
+  forM scripts $ \case
+    Src src cacheBust ->
+      FFI.addSrc src cacheBust
+    Script script ->
+      FFI.addScript False script
+    Module src ->
+      FFI.addScript True src
+    ImportMap importMap -> do
+      o <- create
+      imports <- create
+      forM_ importMap $ \(k,v) ->
+        FFI.set k v imports
+      FFI.set "imports" imports o
+      FFI.addScriptImportMap
+        =<< jsonStringify
+        =<< toJSVal o
+-----------------------------------------------------------------------------
+-- | Starts a named 'Sub' dynamically, during the life of a t'Miso.Types.Component'.
+-- The 'Sub' can be stopped by calling @Ord subKey => stop subKey@ from the @update@ function.
+-- All 'Sub' started will be stopped if a t'Miso.Types.Component' is unmounted.
+--
+-- @
+-- data SubType = LoggerSub | TimerSub
+--   deriving (Eq, Ord)
+--
+-- update Action =
+--   startSub LoggerSub $ \\sink -> forever (threadDelay (secs 1) >> consoleLog "test")
+-- @
+--
+-- @since 1.9.0.0
+startSub
+  :: ToMisoString subKey
+  => subKey
+  -- ^ The key used to track the 'Sub'
+  -> Sub model action
+  -- ^ The 'Sub'
+  -> Effect context props model action
+startSub subKey sub = do
+  ComponentInfo {..} <- ask
+  io_ $ do
+    IM.lookup _componentInfoId <$> liftIO (readIORef components) >>= \case
+      Nothing -> pure ()
+      Just compState@ComponentState {..} -> do
+        mtid <- liftIO (M.lookup (ms subKey) <$> readIORef _componentSubThreads)
+        case mtid of
+          Nothing ->
+            startThread compState
+          Just tid -> do
+            status <- threadStatus tid
+            case status of
+              ThreadFinished -> startThread compState
+              ThreadDied -> startThread compState
+              _ -> pure ()
+  where
+    startThread ComponentState
+      { _componentId = vcompId
+      , _componentSink = vcompSink
+      , _componentSubThreads = subThreads
+      , _componentModel = currentModel
+      } = do
+        getModel <- mkGetModel vcompId currentModel
+        tid <- forkIO (sub vcompSink getModel)
+        atomicModifyIORef' subThreads $ \m ->
+          (M.insert (ms subKey) tid m, ())
+-----------------------------------------------------------------------------
+-- | Stops a named 'Sub' dynamically, during the life of a t'Miso.Types.Component'.
+-- All 'Sub' started will be stopped automatically if a t'Miso.Types.Component' is unmounted.
+--
+-- @
+-- data SubType = LoggerSub | TimerSub
+--   deriving (Eq, Ord)
+--
+-- update Action = do
+--   stopSub LoggerSub
+-- @
+--
+-- @since 1.9.0.0
+stopSub
+  :: ToMisoString subKey
+  => subKey
+  -- ^ The key used to stop the 'Sub'
+  -> Effect context props model action
+stopSub subKey = do
+  vcompId <- asks _componentInfoId
+  io_ $ do
+    IM.lookup vcompId <$> readIORef components >>= \case
+      Nothing -> do
+        pure ()
+      Just ComponentState {..} -> do
+        mtid <- liftIO (M.lookup (ms subKey) <$> readIORef _componentSubThreads)
+        forM_ mtid $ \tid ->
+          liftIO $ do
+            atomicModifyIORef' _componentSubThreads $ \m -> (M.delete (ms subKey) m, ())
+            killThread tid
+-----------------------------------------------------------------------------
+-- | Send any @ToJSON message => message@ to a t'Miso.Types.Component' mailbox, by @ComponentId@
+--
+-- @
+-- io_ $ mail componentId ("test message" :: MisoString) :: Effect context props model action
+-- @
+--
+-- @since 1.9.0.0
+mail
+  :: ToJSON message
+  => ComponentId
+  -- ^ @ComponentId@ to receive 'mail'
+  -> message
+  -- ^ The message to send
+  -> IO ()
+mail vcompId msg =
+  IM.lookup vcompId <$> readIORef components >>= \case
+    Nothing -> pure ()
+    Just ComponentState{..} ->
+      case _componentMailbox (toJSON msg) of
+        Nothing -> pure ()
+        Just action ->
+          _componentSink action
+-----------------------------------------------------------------------------
+-- | Send any @ToJSON message => message@ to the parent's t'Miso.Types.Component' mailbox
+--
+-- @
+-- mailParent ("test message" :: MisoString) :: Effect context props model action
+-- @
+--
+-- @since 1.9.0.0
+mailParent
+  :: ToJSON message
+  => message
+  -- ^ Message to send
+  -> Effect context props model action
+mailParent msg = do
+  ComponentInfo {..} <- ask
+  io_ (mail _componentInfoParentId msg)
+-----------------------------------------------------------------------------
+-- | Send any @ToJSON message => message@ to all ancestor t'Miso.Types.Component' 'mailbox'.
+--
+-- This function walks the t'Miso.Types.Component' ancestor hierarchy, delivering mail
+-- along the way.
+--
+-- @
+-- mailAncestors ("test message" :: MisoString) :: Effect context props model action
+-- @
+--
+-- @since 1.11.0.0
+mailAncestors
+  :: ToJSON message
+  => message
+  -- ^ Message to send
+  -> Effect context props model action
+mailAncestors msg = do
+  ComponentInfo {..} <- ask
+  io_ (climb _componentInfoParentId)
+    where
+      climb vcompId = do
+        mail vcompId msg
+        IM.lookup vcompId <$> readIORef components >>= \case
+          Nothing -> pure ()
+          Just cs -> climb (_componentParentId cs)
+-----------------------------------------------------------------------------
+-- | Send any @ToJSON message => message@ to the children's t'Miso.Types.Component' mailbox
+--
+-- N.B. this is only relevant for immediate descendants (not all descendants).
+--
+-- @
+-- mailChildren ("test message" :: MisoString) :: Effect context props model action
+-- @
+--
+-- @since 1.9.0.0
+mailChildren
+  :: ToJSON message
+  => message
+  -- ^ Message to send
+  -> Effect context props model action
+mailChildren msg = do
+  ComponentInfo {..} <- ask
+  io_ $ do
+    ComponentState {..} <- (IM.! _componentInfoId) <$> readIORef components
+    forM_ (IS.toList _componentChildren) (flip mail msg)
+-----------------------------------------------------------------------------
+-- | Send any @ToJSON message => message@ to all descendants t'Miso.Types.Component' mailbox
+--
+-- Unlike 'mailChildren', this is relevant for all descendants t'Miso.Types.Component'.
+--
+-- @
+-- mailDescendants ("test message" :: MisoString) :: Effect context props model action
+-- @
+--
+-- @since 1.12.0.0
+mailDescendants
+  :: ToJSON message
+  => message
+  -- ^ Message to send
+  -> Effect context props model action
+mailDescendants msg = do
+  ComponentInfo {..} <- ask
+  io_ $ do
+    cs <- (IM.! _componentInfoId) <$> readIORef components
+    forM_ (IS.toList (_componentChildren cs)) $ \child -> do
+      walk . (IM.! child) =<< readIORef components
+  where
+    walk ComponentState {..} = do
+      mail _componentId msg
+      forM_ (IS.toList _componentChildren) $ \child -> do
+        walk . (IM.! child) =<< readIORef components
+----------------------------------------------------------------------------
+-- | Helper function for processing @Mail@ from 'mail'.
+--
+-- @
+--
+-- data Action
+--   = ParsedMail Message
+--   | ErrorMail MisoString
+--
+-- main :: IO ()
+-- main = app { mailbox = checkMail ParsedMail ErrorMail }
+-- @
+--
+-- @since 1.9.0.0
+checkMail
+  :: FromJSON value
+  => (value -> action)
+  -- ^ Successful callback
+  -> (MisoString -> action)
+  -- ^ Errorful callback
+  -> Value
+  -- ^ The message received to parse.
+  -> Maybe action
+checkMail successful errorful value =
+  pure $ case fromJSON value of
+    Success x -> successful x
+    Error err -> errorful (ms err)
+-----------------------------------------------------------------------------
+-- | Sends a message to all t'Miso.Types.Component' 'mailbox', excluding oneself.
+--
+-- @
+--
+-- update :: action -> Effect context props model action
+-- update _ = broadcast (String "public service announcement")
+-- @
+--
+-- @since 1.9.0.0
+broadcast
+  :: Eq model
+  => ToJSON message
+  => message
+  -- ^ Message to broadcast to all other t'Miso.Types.Component'
+  -> Effect context props model action
+broadcast msg = do
+  ComponentInfo {..} <- ask
+  io_ $ do
+    vcompIds <- IM.keys <$> readIORef components
+    forM_ vcompIds $ \vcompId ->
+      when (_componentInfoId /= vcompId) $ do
+        IM.lookup vcompId <$> readIORef components >>= \case
+          Nothing -> pure ()
+          Just ComponentState{..} ->
+            case _componentMailbox (toJSON msg) of
+              Nothing -> pure ()
+              Just action -> _componentSink action
+-----------------------------------------------------------------------------
+type Socket = JSVal
+-----------------------------------------------------------------------------
+type WebSockets = IM.IntMap (IM.IntMap Socket)
+-----------------------------------------------------------------------------
+type EventSources = IM.IntMap (IM.IntMap Socket)
+-----------------------------------------------------------------------------
+websocketConnections :: IORef WebSockets
+{-# NOINLINE websocketConnections #-}
+websocketConnections = unsafePerformIO (newIORef IM.empty)
+-----------------------------------------------------------------------------
+websocketConnectionIds :: IORef Int
+{-# NOINLINE websocketConnectionIds #-}
+websocketConnectionIds = unsafePerformIO (newIORef (0 :: Int))
+-----------------------------------------------------------------------------
+websocketConnectText
+  :: URL
+  -- ^ t'WebSocket' 'URL'
+  -> (WebSocket -> action)
+  -- ^ onOpen
+  -> (Closed -> action)
+  -- ^ onClosed
+  -> (MisoString -> action)
+  -- ^ onMessage
+  -> (MisoString -> action)
+  -- ^ onError
+  -> Effect context props model action
+websocketConnectText url onOpen onClosed onMessage onError =
+  websocketCore $ \webSocketId sink ->
+    FFI.websocketConnect url
+      (sink $ onOpen webSocketId)
+      (sink . onClosed <=< fromJSValUnchecked)
+      (pure (sink . onMessage <=< fromJSValUnchecked))
+      Nothing
+      Nothing
+      Nothing
+      (sink . onError <=< fromJSValUnchecked)
+      True
+-----------------------------------------------------------------------------
+websocketConnectBLOB
+  :: URL
+  -- ^ t'WebSocket' 'URL'
+  -> (WebSocket -> action)
+  -- ^ onOpen
+  -> (Closed -> action)
+  -- ^ onClosed
+  -> (Blob -> action)
+  -- ^ onMessage
+  -> (MisoString -> action)
+  -- ^ onError
+  -> Effect context props model action
+websocketConnectBLOB url onOpen onClosed onMessage onError =
+  websocketCore $ \webSocketId sink ->
+    FFI.websocketConnect url
+      (sink $ onOpen webSocketId)
+      (sink . onClosed <=< fromJSValUnchecked)
+      Nothing
+      Nothing
+      (pure (sink . onMessage . Blob))
+      Nothing
+      (sink . onError <=< fromJSValUnchecked)
+      False
+-----------------------------------------------------------------------------
+websocketConnectArrayBuffer
+  :: URL
+  -- ^ t'WebSocket' 'URL'
+  -> (WebSocket -> action)
+  -- ^ onOpen
+  -> (Closed -> action)
+  -- ^ onClosed
+  -> (ArrayBuffer -> action)
+  -- ^ onMessage
+  -> (MisoString -> action)
+  -- ^ onError
+  -> Effect context props model action
+websocketConnectArrayBuffer url onOpen onClosed onMessage onError =
+  websocketCore $ \webSocketId sink ->
+    FFI.websocketConnect url
+      (sink $ onOpen webSocketId)
+      (sink . onClosed <=< fromJSValUnchecked)
+      Nothing
+      Nothing
+      Nothing
+      (pure (sink . onMessage . ArrayBuffer))
+      (sink . onError <=< fromJSValUnchecked)
+      False
+-----------------------------------------------------------------------------
+websocketConnectJSON
+  :: FromJSON json
+  => URL
+  -- ^ WebSocket URL
+  -> (WebSocket -> action)
+  -- ^ onOpen
+  -> (Closed -> action)
+  -- ^ onClosed
+  -> (json -> action)
+  -- ^ onMessage
+  -> (MisoString -> action)
+  -- ^ onError
+  -> Effect context props model action
+websocketConnectJSON url onOpen onClosed onMessage onError =
+  websocketCore $ \webSocketId sink ->
+    FFI.websocketConnect url
+      (sink $ onOpen webSocketId)
+      (sink . onClosed <=< fromJSValUnchecked)
+      Nothing
+      (pure (\bytes -> do
+          value :: Value <- fromJSValUnchecked bytes
+          case fromJSON value of
+            Error msg -> sink $ onError (ms msg)
+            Success x -> sink $ onMessage x))
+      Nothing
+      Nothing
+      (sink . onError <=< fromJSValUnchecked)
+      False
+-----------------------------------------------------------------------------
+websocketConnect
+  :: FromJSON json
+  => URL
+  -- ^ WebSocket URL
+  -> (WebSocket -> action)
+  -- ^ onOpen
+  -> (Closed -> action)
+  -- ^ onClosed
+  -> (Payload json -> action)
+  -- ^ onMessage
+  -> (MisoString -> action)
+  -- ^ onError
+  -> Effect context props model action
+websocketConnect url onOpen onClosed onMessage onError =
+  websocketCore $ \webSocketId sink ->
+    FFI.websocketConnect url
+      (sink $ onOpen webSocketId)
+      (sink . onClosed <=< fromJSValUnchecked)
+      (pure (sink . onMessage . TEXT <=< fromJSValUnchecked))
+      (pure (\bytes -> do
+          value :: Value <- fromJSValUnchecked bytes
+          case fromJSON value of
+            Error msg -> sink $ onError (ms msg)
+            Success x -> sink $ onMessage (JSON x)))
+      (pure (sink . onMessage . BLOB . Blob))
+      (pure (sink . onMessage . BUFFER . ArrayBuffer))
+      (sink . onError <=< fromJSValUnchecked)
+      False
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket>
+websocketCore
+  :: (WebSocket -> Sink action -> IO Socket)
+  -> Effect context props model action
+websocketCore core = do
+  ComponentInfo {..} <- ask
+  withSink $ \sink -> do
+    webSocketId <- freshWebSocket
+    socket <- core webSocketId sink
+    insertWebSocket _componentInfoId webSocketId socket
+  where
+    insertWebSocket :: ComponentId -> WebSocket -> Socket -> IO ()
+    insertWebSocket componentId_ (WebSocket socketId) socket =
+      atomicModifyIORef' websocketConnections $ \websockets ->
+          (update websockets, ())
+      where
+        update websockets =
+          IM.unionWith IM.union websockets
+            $ IM.singleton componentId_
+            $ IM.singleton socketId socket
+
+    freshWebSocket :: IO WebSocket
+    freshWebSocket = WebSocket <$>
+      atomicModifyIORef' websocketConnectionIds (\x -> (x + 1, x))
+-----------------------------------------------------------------------------
+getWebSocket :: ComponentId -> WebSocket -> WebSockets -> Maybe Socket
+getWebSocket vcompId (WebSocket websocketId) =
+  IM.lookup websocketId <=< IM.lookup vcompId
+-----------------------------------------------------------------------------
+finalizeWebSockets :: ComponentId -> IO ()
+finalizeWebSockets vcompId = do
+  mapM_ (mapM_ FFI.websocketClose . IM.elems) .
+    IM.lookup vcompId =<< readIORef websocketConnections
+  dropComponentWebSockets
+    where
+      dropComponentWebSockets :: IO ()
+      dropComponentWebSockets =
+        atomicModifyIORef' websocketConnections $ \websockets ->
+          (IM.delete vcompId websockets, ())
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close>
+websocketClose :: WebSocket -> Effect context props model action
+websocketClose socketId = do
+  ComponentInfo {..} <- ask
+  io_ $ do
+    result <-
+      atomicModifyIORef' websocketConnections $ \imap ->
+        dropWebSocket _componentInfoId socketId imap =:
+          getWebSocket _componentInfoId socketId imap
+    case result of
+      Nothing ->
+        pure ()
+      Just socket ->
+        FFI.websocketClose socket
+  where
+    dropWebSocket :: ComponentId -> WebSocket -> WebSockets -> WebSockets
+    dropWebSocket vcompId (WebSocket websocketId) websockets = do
+      case IM.lookup vcompId websockets of
+        Nothing ->
+          websockets
+        Just componentSockets ->
+          IM.insert vcompId (IM.delete websocketId componentSockets) websockets
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>
+websocketSend
+  :: ToJSON value
+  => WebSocket
+  -> Payload value
+  -> Effect context props model action
+websocketSend socketId msg = do
+  ComponentInfo {..} <- ask
+  io_ $ do
+    getWebSocket _componentInfoId socketId <$> readIORef websocketConnections >>= \case
+      Nothing -> pure ()
+      Just socket ->
+        case msg of
+          JSON json_ ->
+            FFI.websocketSend socket =<< toJSVal (encode json_)
+          BUFFER arrayBuffer_ -> do
+            FFI.websocketSend socket =<< toJSVal arrayBuffer_
+          TEXT txt ->
+            FFI.websocketSend socket =<< toJSVal txt
+          BLOB blob_ ->
+            FFI.websocketSend socket =<< toJSVal blob_
+-----------------------------------------------------------------------------
+-- | Retrieves current status of t'WebSocket'
+--
+-- If the t'WebSocket' identifier does not exist a 'CLOSED' is returned.
+--
+socketState :: WebSocket -> (SocketState -> action) -> Effect context props model action
+socketState socketId callback = do
+  ComponentInfo {..} <- ask
+  withSink $ \sink -> do
+     getWebSocket _componentInfoId socketId <$> readIORef websocketConnections >>= \case
+      Just socket -> do
+        x <- socket ! ("socketState" :: MisoString)
+        socketstate <- toEnum <$> fromJSValUnchecked x
+        sink (callback socketstate)
+      Nothing ->
+        sink (callback CLOSED)
+-----------------------------------------------------------------------------
+codeToCloseCode :: Int -> CloseCode
+codeToCloseCode = \case
+  1000 -> CLOSE_NORMAL
+  1001 -> CLOSE_GOING_AWAY
+  1002 -> CLOSE_PROTOCOL_ERROR
+  1003 -> CLOSE_UNSUPPORTED
+  1005 -> CLOSE_NO_STATUS
+  1006 -> CLOSE_ABNORMAL
+  1007 -> Unsupported_Data
+  1008 -> Policy_Violation
+  1009 -> CLOSE_TOO_LARGE
+  1010 -> Missing_Extension
+  1011 -> Internal_Error
+  1012 -> Service_Restart
+  1013 -> Try_Again_Later
+  1015 -> TLS_Handshake
+  n    -> OtherCode n
+-----------------------------------------------------------------------------
+-- | Closed message is sent when a t'WebSocket' has closed
+data Closed
+  = Closed
+  { closedCode :: CloseCode
+    -- ^ The code used to indicate why a socket closed
+  , wasClean :: Bool
+    -- ^ If the connection was closed cleanly, or forcefully.
+  , reason :: MisoString
+    -- ^ The reason for socket closure.
+  } deriving (Eq, Show)
+-----------------------------------------------------------------------------
+instance FromJSVal Closed where
+  fromJSVal o = do
+    closed_ <- fmap codeToCloseCode <$> do fromJSVal =<< o ! ("code" :: MisoString)
+    wasClean_ <- fromJSVal =<< o ! ("wasClean" :: MisoString)
+    reason_ <- fromJSVal =<< o ! ("reason" :: MisoString)
+    pure (Closed <$> closed_ <*> wasClean_ <*> reason_)
+-----------------------------------------------------------------------------
+-- | URL that the t'WebSocket' will @connect@ to
+type URL = MisoString
+-----------------------------------------------------------------------------
+-- | 'SocketState' corresponding to current t'WebSocket' connection
+data SocketState
+  = CONNECTING -- ^ 0
+  | OPEN       -- ^ 1
+  | CLOSING    -- ^ 2
+  | CLOSED     -- ^ 3
+  deriving (Show, Eq, Ord, Enum)
+-----------------------------------------------------------------------------
+-- | Code corresponding to a closed connection
+-- https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
+data CloseCode
+  = CLOSE_NORMAL
+   -- ^ 1000, Normal closure; the connection successfully completed whatever purpose for which it was created.
+  | CLOSE_GOING_AWAY
+   -- ^ 1001, The endpoint is going away, either because of a server failure or because the browser is navigating away from the page that opened the connection.
+  | CLOSE_PROTOCOL_ERROR
+   -- ^ 1002, The endpoint is terminating the connection due to a protocol error.
+  | CLOSE_UNSUPPORTED
+   -- ^ 1003, The connection is being terminated because the endpoint received data of a type it cannot accept (for example, a textonly endpoint received binary data).
+  | CLOSE_NO_STATUS
+   -- ^ 1005, Reserved.  Indicates that no status code was provided even though one was expected.
+  | CLOSE_ABNORMAL
+   -- ^ 1006, Reserved. Used to indicate that a connection was closed abnormally (that is, with no close frame being sent) when a status code is expected.
+  | Unsupported_Data
+   -- ^ 1007, The endpoint is terminating the connection because a message was received that contained inconsistent data (e.g., nonUTF8 data within a text message).
+  | Policy_Violation
+   -- ^ 1008, The endpoint is terminating the connection because it received a message that violates its policy. This is a generic status code, used when codes 1003 and 1009 are not suitable.
+  | CLOSE_TOO_LARGE
+   -- ^ 1009, The endpoint is terminating the connection because a data frame was received that is too large.
+  | Missing_Extension
+   -- ^ 1010, The client is terminating the connection because it expected the server to negotiate one or more extension, but the server didn't.
+  | Internal_Error
+   -- ^ 1011, The server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.
+  | Service_Restart
+   -- ^ 1012, The server is terminating the connection because it is restarting.
+  | Try_Again_Later
+   -- ^ 1013, The server is terminating the connection due to a temporary condition, e.g. it is overloaded and is casting off some of its clients.
+  | TLS_Handshake
+   -- ^ 1015, Reserved. Indicates that the connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).
+  | OtherCode Int
+   -- ^ OtherCode that is reserved and not in the range 0999
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Type for holding a t'WebSocket' file descriptor.
+newtype WebSocket = WebSocket Int
+  deriving stock Eq
+  deriving newtype (ToJSVal, Num)
+-----------------------------------------------------------------------------
+-- | A null t'WebSocket' is one with a negative descriptor.
+emptyWebSocket :: WebSocket
+emptyWebSocket = -1
+-----------------------------------------------------------------------------
+-- | A type for holding an t'EventSource' descriptor.
+newtype EventSource = EventSource Int
+  deriving stock Eq
+  deriving newtype (Num, ToJSVal)
+-----------------------------------------------------------------------------
+-- | A null t'EventSource' is one with a negative descriptor.
+emptyEventSource :: EventSource
+emptyEventSource = -1
+-----------------------------------------------------------------------------
+eventSourceConnections :: IORef EventSources
+{-# NOINLINE eventSourceConnections #-}
+eventSourceConnections = unsafePerformIO (newIORef IM.empty)
+-----------------------------------------------------------------------------
+eventSourceConnectionIds :: IORef Int
+{-# NOINLINE eventSourceConnectionIds #-}
+eventSourceConnectionIds = unsafePerformIO (newIORef (0 :: Int))
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource>
+eventSourceConnectText
+  :: URL
+  -- ^ EventSource URL
+  -> (EventSource -> action)
+  -- ^ onOpen
+  -> (MisoString -> action)
+  -- ^ onMessage
+  -> (MisoString -> action)
+  -- ^ onError
+  -> Effect context props model action
+eventSourceConnectText url onOpen onMessage onError =
+  eventSourceCore $ \eventSourceId sink -> do
+    FFI.eventSourceConnect url
+      (sink $ onOpen eventSourceId)
+      (pure $ \e -> do
+          txt <- fromJSValUnchecked e
+          sink (onMessage txt))
+      Nothing
+      (sink . onError <=< fromJSValUnchecked)
+      True
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource>
+eventSourceConnectJSON
+  :: FromJSON json
+  => URL
+  -- ^ EventSource URL
+  -> (EventSource -> action)
+  -- ^ onOpen
+  -> (json -> action)
+  -- ^ onMessage
+  -> (MisoString -> action)
+  -- ^ onError
+  -> Effect context props model action
+eventSourceConnectJSON url onOpen onMessage onError =
+  eventSourceCore $ \eventSourceId sink -> do
+    FFI.eventSourceConnect url
+      (sink $ onOpen eventSourceId)
+      Nothing
+      (pure $ \e ->
+         fromJSON <$> fromJSValUnchecked e >>= \case
+            Error errMsg -> sink (onError (ms errMsg))
+            Success json_ -> sink $ onMessage json_)
+      (sink . onError <=< fromJSValUnchecked)
+      False
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource>
+eventSourceCore
+  :: (EventSource -> Sink action -> IO Socket)
+  -> Effect context props model action
+eventSourceCore core = do
+  ComponentInfo {..} <- ask
+  withSink $ \sink -> do
+    eventSourceId <- freshEventSource
+    socket <- core eventSourceId sink
+    insertEventSource _componentInfoId eventSourceId socket
+  where
+    insertEventSource :: ComponentId -> EventSource -> Socket -> IO ()
+    insertEventSource componentId_ (EventSource socketId) socket =
+      atomicModifyIORef' eventSourceConnections $ \eventSources ->
+        (update eventSources, ())
+      where
+        update eventSources =
+          IM.unionWith IM.union eventSources
+            $ IM.singleton componentId_
+            $ IM.singleton socketId socket
+
+    freshEventSource :: IO EventSource
+    freshEventSource = EventSource <$>
+      atomicModifyIORef' eventSourceConnectionIds (\x -> (x + 1, x))
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/close>
+eventSourceClose :: EventSource -> Effect context props model action
+eventSourceClose socketId = do
+  ComponentInfo {..} <- ask
+  io_ $ do
+    result <-
+      atomicModifyIORef' eventSourceConnections $ \imap ->
+        dropEventSource _componentInfoId socketId imap =:
+          getEventSource _componentInfoId socketId imap
+    case result of
+      Nothing ->
+        pure ()
+      Just socket ->
+        FFI.eventSourceClose socket
+  where
+    dropEventSource :: ComponentId -> EventSource -> EventSources -> EventSources
+    dropEventSource vcompId (EventSource eventSourceId) eventSources = do
+      case IM.lookup vcompId eventSources of
+        Nothing ->
+          eventSources
+        Just componentSockets ->
+          IM.insert vcompId (IM.delete eventSourceId componentSockets) eventSources
+
+    getEventSource :: ComponentId -> EventSource -> EventSources -> Maybe Socket
+    getEventSource vcompId (EventSource eventSourceId) =
+      IM.lookup eventSourceId <=< IM.lookup vcompId
+-----------------------------------------------------------------------------
+finalizeEventSources :: ComponentId -> IO ()
+finalizeEventSources vcompId = do
+  mapM_ (mapM_ FFI.eventSourceClose . IM.elems) .
+    IM.lookup vcompId =<< readIORef eventSourceConnections
+  dropComponentEventSources
+    where
+      dropComponentEventSources :: IO ()
+      dropComponentEventSources =
+        atomicModifyIORef' eventSourceConnections $ \eventSources ->
+          (IM.delete vcompId eventSources, ())
+-----------------------------------------------------------------------------
+-- | Payload is used as the potential source of data when working with t'EventSource'
+data Payload value
+  = JSON value
+  -- ^ JSON-encoded data
+  | BLOB Blob
+  -- ^ Binary encoded data
+  | TEXT MisoString
+  -- ^ Text encoded data
+  | BUFFER ArrayBuffer
+  -- ^ Buffered data
+-----------------------------------------------------------------------------
+-- | Smart constructor for sending JSON encoded data via an t'EventSource'
+json :: ToJSON value => value -> Payload value
+json = JSON
+-----------------------------------------------------------------------------
+-- | Smart constructor for sending binary encoded data via an t'EventSource'
+blob :: Blob -> Payload value
+blob = BLOB
+-----------------------------------------------------------------------------
+-- | Smart constructor for sending an @ArrayBuffer@ via an t'EventSource'
+arrayBuffer :: ArrayBuffer -> Payload value
+arrayBuffer = BUFFER
+-----------------------------------------------------------------------------
+#ifdef WASM
+loadedJS :: IORef Bool
+{-# NOINLINE loadedJS #-}
+loadedJS = unsafePerformIO (newIORef False)
+#endif
+-----------------------------------------------------------------------------
+initComponent
+#ifdef NATIVE
+  :: forall context props model action . (Eq context, Eq model, Eq props, ToJSON model, ToJSON props, ToJSON action, FromJSON action)
+#else
+  :: forall context props model action . (Eq context, Eq model, Eq props)
+#endif
+  => Events
+  -> Hydrate
+  -> Bool
+  -> context
+  -- ^ Initial global @context@
+  -> Component context props model action
+  -> Maybe Key
+  -> props
+  -> Maybe StaticKey
+  -> IO ()
+initComponent events hydrate live initialContext comp_@Component {..} key props sk = do
+#ifdef WASM
+      $(evalFile MISO_JS_PATH)
+      atomicWriteIORef loadedJS True
+#endif
+      withJS $ do
+        let proxy = Proxy :: Proxy context
+#ifdef NATIVE
+        when bts $ do
+          effectListener proxy =<< getMTSContext
+          readyAckListener =<< getMTSContext
+          void $ forkIO (sendReadyUntilAcked sk)
+        when mts $ do
+          effectListener proxy =<< getBTSContext
+          componentListener proxy =<< getBTSContext
+          registerMainThreadDispatch
+#endif
+        atomicWriteIORef liveMode live
+        root <- Diff.mountElement (getMountPoint mountPoint)
+        when web (cleanup proxy live root)
+        atomicWriteIORef globalContext initialContext
+        -- dmj: top-level Component always responsive to Context changes
+        let comp_' = comp_ { useContext = True }
+        void $ initialize events rootComponentId hydrate True props key sk comp_' (pure root)
+#ifdef NATIVE
+        -- The root mount (root + every nested component drawn synchronously above)
+        -- is now complete on this thread, so clear the global 'initialDraw' latch
+        -- exactly ONCE. This flips the drawing contexts out of initial-frame mode:
+        -- the MTS stops self-assigning nodeIds (later nodes arrive via update
+        -- patches carrying their id) and the BTS stops suppressing patch emission
+        -- and starts shipping updates. Doing this here — rather than inside the
+        -- contexts' 'flush' — is the fix for the doubled render: the initial draw
+        -- performs one 'flush' per mounted component, so a per-'flush' flip tripped
+        -- on the first nested child and leaked the rest of the frame as patches.
+        do gt <- jsg ("globalThis" :: MisoString)
+           FFI.set "initialDraw" False (Object gt)
+#endif
+        atomicWriteIORef schedulerThread =<< forkIO (scheduler proxy)
+----------------------------------------------------------------------------
+-- | Placeholder passed to a @Props@ constructor when only the resulting
+-- t'SomeComponent'\'s /types/ (@model@ \/ @props@ \/ @action@) are needed, not a
+-- real @props@ value — e.g. to recover the @action@ type for decoding. Safe
+-- because every @Props@ built by @mount_@ \/ @mountWithProps@ \/ @(+>)@ is lazy
+-- in its @props@ argument, so applying it never forces this.
+#ifdef NATIVE
+propsTypeOnly :: props
+propsTypeOnly = error "Miso.Runtime: props forced during type-only Props application"
+-----------------------------------------------------------------------------
+-- | Used for bidirectional cross-thread communication.
+effectListener :: forall context jsval . (Eq context, ToJSVal jsval) => Proxy context -> jsval -> IO ()
+effectListener Proxy jsval = void $ do
+  ctx <- toJSVal jsval
+  FFI.addEventListener ctx "Miso.effects" $ \msgEvent ->
+    flip catch (\(e :: SomeException) ->
+        FFI.consoleError ("[effectListener]: exception in callback: " <> ms (show e))) $ do
+      msg <- Object msgEvent ! "data"
+      EFFECT {..} <- fromJSValUnchecked msg :: IO EFFECT
+      case effectStaticKey of
+        Nothing -> FFI.consoleError "[effectListener]: must use 'static' keyword when mounting Component w/ native"
+        Just key_ -> do
+          unsafeLookupStaticPtr key_ >>= \case
+            Nothing ->
+              FFI.consoleError "[effectListener]: staticPtr NOT found for effectStaticKey"
+            Just ptr ->
+              case deRefStaticPtr ptr of
+               SomeStaticComponent mk -> case mk propsTypeOnly of
+                SomeComponent _key _props (_ :: Component context props model action) ->
+                  case fromJSON effectAction :: Result action of
+                    Success action -> do
+                      comps <- readIORef components
+                      case IM.lookup effectComponentId comps of
+                        Nothing ->
+                          FFI.consoleError $ ms $
+                            "[effectListener]: ComponentId NOT registered:" <> ms effectComponentId
+                        Just _ -> do
+                          FFI.consoleLog "[effectListener]: Sinking action into Component"
+                          -- dmj: enqueue the cross-thread action onto the ordinary
+                          -- 'globalQueue' rather than replaying @update@ inline here.
+                          -- This keeps the scheduler the sole writer of every model
+                          -- (no read-modify-write race with the scheduler's own
+                          -- 'commit') and preserves ordering relative to any actions
+                          -- already queued for this component. The action's @update@
+                          -- runs only on this thread; it does not ping-pong back
+                          -- because only an explicit 'CrossThread' effect crosses.
+                          atomicModifyIORef' globalQueue $ \q ->
+                            (enqueue effectComponentId action q, ())
+                          notify globalWaiter
+                    Error e ->
+                      FFI.consoleError ("[effectListener]: action decode error: " <> ms e)
+#endif
+----------------------------------------------------------------------------
+#ifdef NATIVE
+-- | BTS -> MTS 'READY' dispatch is fire-and-forget over an async cross-thread
+-- transport, and BTS's bootstrap (which sends 'READY') and MTS's bootstrap
+-- (which registers the listener that receives it) run on independently
+-- scheduled threads with no ordering guarantee between them — a genuine race
+-- where 'READY' can arrive before anything on MTS is listening, in which case
+-- it is lost for good (no re-delivery to a listener that registers later).
+-- Since MTS's scheduler blocks on 'wait btsReady' until 'READY' arrives, a
+-- lost message hangs the MTS scheduler forever.
+--
+-- Retried here on a short interval, capped, until MTS's 'READY_ACK' (sent
+-- from 'componentListener'\'s 'READY' case) sets 'readyAcked' — so the common
+-- case, where MTS's listener is already up, costs one round-trip and stops,
+-- not the full retry budget. Runs on its own forked thread so it never
+-- blocks 'initComponent'\'s own startup, and that thread exits as soon as
+-- acked rather than lingering for the whole retry window.
+sendReadyUntilAcked :: Maybe StaticKey -> IO ()
+sendReadyUntilAcked sk = go (0 :: Int)
+  where
+    maxAttempts = 20    -- ~1s of retrying at 50ms intervals
+    intervalMicros = 50000
+    go attempts = do
+      postComponent READY sk topLevelComponentId rootComponentId Nothing Nothing
+      threadDelay intervalMicros
+      acked <- readIORef readyAcked -- BTS-side flag, set by 'readyAckListener'
+      if acked
+        then pure ()
+        else if attempts < maxAttempts
+          then go (attempts + 1)
+          -- Budget exhausted without an ack. Under the current boot profile this
+          -- should never happen (MTS registers its listener well under the ~1s
+          -- window), so treat it as a diagnosable fault rather than a silent
+          -- hang: the MTS scheduler is now blocked on 'wait btsReady' forever
+          -- with no re-delivery. Surface it so a boot regression (larger bundle,
+          -- slower device) is obvious in the log instead of a mystery freeze.
+          else FFI.consoleError $ ms $
+            "[sendReadyUntilAcked]: MTS never acked READY after "
+              <> ms (show maxAttempts) <> " attempts (~1s); MTS scheduler is "
+              <> "likely blocked on 'wait btsReady'. MTS boot exceeded the retry budget."
+-----------------------------------------------------------------------------
+-- | Registered on BTS to receive MTS's 'READY_ACK'. The only message BTS
+-- ever receives via the 'postComponent' \/ 'componentListener' machinery,
+-- since that protocol is otherwise BTS -> MTS only; every other
+-- 'ComponentType' is ignored here.
+readyAckListener :: MTS -> IO ()
+readyAckListener (MTS ctx) = void $ do
+  FFI.addEventListener ctx "Miso.components" $ \msgEvent -> do
+    msg <- Object msgEvent ! "data"
+    COMPONENT {..} <- fromJSValUnchecked msg :: IO COMPONENT
+    case componentComponentType of
+      READY_ACK -> atomicWriteIORef readyAcked True
+      _ -> pure ()
+#endif
+----------------------------------------------------------------------------
+-- | Used for unidirectional BTS -> MTS communication
+--
+-- dmj: This only runs on the MTS.
+--
+#ifdef NATIVE
+-- | Resolves a BTS-supplied @{ nodeId }@ @DOMRef@ to the live MTS element
+-- registered at @globalThis.runtime.nodes[nodeId]@ (see @ts/miso/native/mts.ts@).
+resolveNodeRef :: DOMRef -> IO DOMRef
+resolveNodeRef domRef = do
+  nodeId <- fromJSValUnchecked =<< domRef ! "nodeId" :: IO Int
+  nodes  <- jsg "runtime" >>= (! "nodes")
+  nodes ! ms nodeId
+-----------------------------------------------------------------------------
+componentListener :: forall context . Eq context => Proxy context -> BTS -> IO ()
+componentListener Proxy (BTS ctx) = void $ do
+  FFI.addEventListener ctx "Miso.components" $ \msgEvent ->
+    flip catch (\(e :: SomeException) ->
+        FFI.consoleError ("[componentListener]: exception in callback: " <> ms (show e))) $ do
+    msg <- Object msgEvent ! "data"
+    COMPONENT {..} <- fromJSValUnchecked msg :: IO COMPONENT
+    case componentComponentStaticKey of
+      Nothing -> FFI.consoleError "[COMPONENT]: must use 'static' keyword for Component mounting"
+      Just key_ ->
+        -- 'READY' never needs the 'StaticPtr' and must be handled BEFORE the
+        -- lookup: it only unblocks the MTS scheduler and rides no component
+        -- 'StaticKey', so it can't (and mustn't) do the deref the other
+        -- messages require.
+        case componentComponentType of
+          READY -> do
+            -- dmj: BTS retries 'READY' until acked (see 'sendReadyUntilAcked'),
+            -- so this can fire more than once. Guard 'notify' — a second
+            -- 'putMVar' on the already-full 'oneshot' 'btsReady' would block
+            -- this listener callback forever instead of being a no-op — and
+            -- always ack in response, even on a repeat, since BTS can't know
+            -- whether an earlier ack of ours reached it.
+            already <- atomicModifyIORef' readyReceived (\r -> (True, r)) -- MTS-side flag
+            unless already (notify btsReady) -- dmj: unblocks main thread scheduler
+            dispatchEvent ctx "Miso.components"
+              (COMPONENT READY_ACK Nothing minBound minBound Nothing Nothing)
+          _ ->
+            unsafeLookupStaticPtr key_ >>= \case
+              Nothing ->
+                FFI.consoleError "[COMPONENT]: staticPtr NOT found for componentStaticKey"
+              Just ptr ->
+                case deRefStaticPtr ptr of
+                 SomeStaticComponent mk -> case mk propsTypeOnly of
+                  SomeComponent _key _props (comp_ :: Component context props model action) ->
+                    case componentComponentType of
+                      MOUNT ->
+                        -- The MTS paints the initial frame itself, so any child that is part
+                        -- of that frame is already mounted+registered here by the root
+                        -- 'initialDraw' (nodeIds in lockstep with the BTS, so updates land on
+                        -- it). The BTS still posts @MOUNT@ for every non-root child; re-running
+                        -- 'initialize' for one we already have would paint a SECOND, orphaned
+                        -- copy — the doubled 'vcomp'. So mount only children we don't yet know:
+                        -- that is exactly the components created later, during a BTS update,
+                        -- which the MTS learns about solely through this message.
+                        IM.member componentComponentId <$> readIORef components >>= \case
+                          True -> pure ()
+                          False ->
+                            -- The BTS always ships its @{ nodeId }@ @DOMRef@ alongside @MOUNT@
+                            -- (see 'postComponent' MOUNT); 'Nothing' here means the wire
+                            -- invariant broke, so error out rather than silently mounting
+                            -- against a bogus synthesized parent.
+                            case componentComponentDOMRef of
+                              Nothing ->
+                                FFI.consoleError "[COMPONENT]: MOUNT missing domRef payload"
+                              Just domRef -> do
+                                -- Resolve the shipped @DOMRef@ to the real native element via
+                                -- @globalThis.runtime.nodes[nodeId]@ so the MTS t'ComponentInfo'
+                                -- Reader ('componentInfoDOMRef') holds a live ref.
+                                parent_ <- resolveNodeRef domRef
+                                -- Recover the child's initial @props@ from the wire (the BTS ships
+                                -- them on @MOUNT@), decoded at the @props@ type recovered above.
+                                case componentComponentPayload of
+                                  Just pv | Success initProps <- (fromJSON pv :: Result props) ->
+                                    void $ initialize mempty componentComponentId Draw False initProps
+                                      Nothing (Just (staticKey ptr)) comp_ (pure parent_)
+                                  _ ->
+                                    FFI.consoleError "[COMPONENT]: MOUNT missing/invalid props payload"
+                      UNMOUNT ->
+                        IM.lookup componentComponentId <$> readIORef components >>= \case
+                          Nothing ->
+                            FFI.consoleError $ "[COMPONENT]: Couldn't find Component to unmount " <>
+                              ms (show componentComponentId)
+                          Just c -> unmountComponent @context c
+                      MODEL_HYDRATE -> do
+                        case componentComponentPayload of
+                          Nothing ->
+                            FFI.consoleError "[COMPONENT]: No model to hydrate"
+                          Just m ->
+                            case fromJSON m :: Result model of
+                              Success newModel ->
+                                modifyComponent componentComponentId $ do
+                                  componentModel .= newModel
+                              Error e ->
+                                FFI.consoleError ("[COMPONENT]: Could not decode model: " <> e)
+                      -- 'READY' handled above (no deref), so GHC's long-distance
+                      -- info knows it can't reach here — no catch-all needed.
+                      -- 'READY_ACK' flows MTS -> BTS only (see 'readyAckListener');
+                      -- 'componentListener' only runs on MTS, so this never
+                      -- actually fires — kept as a no-op so the match stays total.
+                      READY_ACK -> pure ()
+#endif
+----------------------------------------------------------------------------
+-- | Dispatch a main-thread ('MTS') event on the Haskell layer.
+--
+-- Invoked synchronously by the MTS delegator (see @ts\/miso\/native\/mts\/context.ts@)
+-- with a @{ componentId, staticKey, event, target }@ object. Recovers the event
+-- handler by its 'StaticKey', runs it against the owning component's 'Sink' to
+-- install its decode+dispatch closure on a scratch node, then invokes that
+-- closure with the live event and target @DOMRef@. No BTS round-trip — the
+-- handler runs entirely on the main thread, and its @update@\/effects run there
+-- (the scheduler suppresses the redraw; see 'scheduler').
+--
+-- N.B. 'unsafeLookupStaticPtr' recovers the handler at the component's @action@
+-- type. This is sound because the @(componentId, staticKey)@ pair is emitted
+-- together from the same component's 'setAttrs'; the handler's @action@ unifies
+-- with the sink's via the quantified 'components' CAF (no @unsafeCoerce@).
+#ifdef NATIVE
+dispatchMainThreadEvent :: JSVal -> IO ()
+dispatchMainThreadEvent arg =
+  flip catch (\(e :: SomeException) ->
+      FFI.consoleError ("[MTS dispatch] exception: " <> ms (show e))) $ do
+    let o = Object arg
+    compId    <- fromJSValUnchecked =<< o ! "componentId" :: IO ComponentId
+    skHex     <- fromJSValUnchecked =<< o ! "staticKey"   :: IO MisoString
+    eventVal  <- o ! "event"
+    targetVal <- o ! "target"
+    unsafeLookupStaticPtr (fromMisoString skHex) >>= \case
+      Nothing ->
+        FFI.consoleError ("[MTS dispatch] no handler for staticKey " <> skHex)
+      -- Fully-applied 'On' handlers resolve to a runnable t'EventHandler', so the
+      -- MTS rebuilds them from the 'StaticKey' alone. An 'OnWith' handler's key
+      -- resolves to a @payload -> EventHandler@ constructor; running it on the
+      -- MTS additionally requires the forwarded @pendingPayload@ decoded at the
+      -- @payload@ type — see note below (not yet wired end-to-end).
+      Just ehPtr -> case deRefStaticPtr ehPtr of
+        EventHandler {..} -> do
+          comps <- readIORef components
+          case IM.lookup compId comps of
+            Nothing ->
+              FFI.consoleError ("[MTS dispatch] no component " <> ms (show compId))
+            Just ComponentState {..} -> do
+              -- Decode + dispatch directly from the captured t'Decoder' \/
+              -- convert pair — no JS installer round-trip (no scratch node,
+              -- no throwaway 'asyncCallback2') needed on this, the hot path
+              -- for every main-thread event.
+              decodeAtVal <- toJSVal (decodeAt eventHandlerDecoder)
+              mv <- fromJSVal =<< FFI.eventJSON decodeAtVal eventVal
+              case mv of
+                Nothing ->
+                  FFI.consoleError "[MTS dispatch] eventJSON returned no value"
+                Just v -> case parseEither (decoder eventHandlerDecoder) v of
+                  Left msg ->
+                    FFI.consoleError ("[MTS dispatch] decode error: " <> ms msg)
+                  Right result ->
+                    _componentSink (eventHandlerConvert result _componentModel targetVal)
+-----------------------------------------------------------------------------
+-- | Register 'dispatchMainThreadEvent' on @globalThis.runtime@ so the MTS
+-- delegator can invoke it synchronously. MTS only.
+registerMainThreadDispatch :: IO ()
+registerMainThreadDispatch = do
+  cb <- FFI.syncCallback1 dispatchMainThreadEvent
+  runtimeObj <- jsg "runtime"
+  FFI.set "dispatchMainThreadEvent" cb (Object runtimeObj)
+#endif
+----------------------------------------------------------------------------
+-- | Dispatches a t'COMPONENT' lifecycle message (BTS → MTS) on the
+-- @\"Miso.components\"@ channel. No-op for components without a 'StaticKey'
+-- (e.g. the root), since the MTS locates the component via 'unsafeLookupStaticPtr'.
+#ifdef NATIVE
+postComponent
+  :: ComponentType
+  -> Maybe StaticKey
+  -> ComponentId
+  -> ComponentId
+  -> Maybe Value
+  -> Maybe DOMRef
+  -> IO ()
+postComponent _ Nothing _ _ _ _ = pure ()
+postComponent componentType_ sk@(Just _) componentId_ parentId_ model_ domRef_ = do
+  ctx <- getMTSContext
+  dispatchEvent ctx "Miso.components"
+    (COMPONENT componentType_ sk componentId_ parentId_ model_ domRef_)
+#endif
+----------------------------------------------------------------------------
+-- | Dispatches an t'EFFECT' message carrying a serialized @action@ across the
+-- Lynx thread boundary on the @\"Miso.effects\"@ channel:
+--
+--   * MTS → BTS when called on the main thread ('mts').
+--   * BTS → MTS when called on the background thread ('bts').
+--
+-- A no-op on plain web builds (neither 'mts' nor 'bts').
+#ifdef NATIVE
+postEffect :: Maybe StaticKey -> ComponentId -> Value -> IO ()
+postEffect sk componentId_ action_ = do
+  when mts $ do
+    ctx <- getBTSContext
+    dispatchEvent ctx "Miso.effects" (EFFECT componentId_ action_ sk)
+  when bts $ do
+    ctx <- getMTSContext
+    dispatchEvent ctx "Miso.effects" (EFFECT componentId_ action_ sk)
+#endif
+----------------------------------------------------------------------------
+-- | Global variable to hold the scheduler thread
+--
+-- N.B. 'undefined' is safe here, it will always get populated.
+-- Also, we use this in @cleanup@ when interactive mode (GHCi) is detected
+-- in that circumstance 'schedulerThread' will always be populated. It's an
+-- invariant.
+--
+schedulerThread :: IORef ThreadId
+{-# NOINLINE schedulerThread #-}
+schedulerThread = unsafePerformIO (newIORef undefined)
+----------------------------------------------------------------------------
+-- | Whether this JS execution context is the Lynx main thread, background
+-- thread, or a plain web build.
+--
+-- N.B. this is invariant for the lifetime of a given JS context, so it's
+-- safe to compute once and cache via 'unsafePerformIO' rather than making
+-- an FFI call on every component initialization.
+--
+mts, bts, web :: Bool
+{-# NOINLINE mts #-}
+{-# NOINLINE bts #-}
+{-# NOINLINE web #-}
+(mts, bts, web) = unsafePerformIO FFI.getThreads
+-----------------------------------------------------------------------------
+-- | 'True' when a 'CrossThread' effect targets the /opposite/ Lynx thread and
+-- must therefore be forwarded (via 'postEffect') rather than dispatched locally.
+-- @False@ when the target is the current thread, or on a plain web build (where
+-- there is a single thread), so the action is handled here.
+crossThread :: E.Thread -> Bool
+crossThread = \case
+  E.BTS -> mts   -- want BTS, currently on MTS
+  E.MTS -> bts   -- want MTS, currently on BTS
+-----------------------------------------------------------------------------
+instance FromJSVal Fingerprint where
+  fromJSVal x = fmap (fmap fromMisoString) (fromJSVal x :: IO (Maybe MisoString))
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | Serializes a 'StaticKey' as a 32-character hex string (two zero-padded 'Word64' values).
+instance ToMisoString Fingerprint where
+  toMisoString fp = ms (show fp)
+  {-# INLINE toMisoString #-}
+-----------------------------------------------------------------------------
+-- | Parses a 'StaticKey' from its 32-character hex 'MisoString' representation.
+instance FromMisoString Fingerprint where
+  fromMisoStringEither s =
+    let str      = fromMisoString s :: String
+        (h1, h2) = splitAt 16 str
+        parseHex h = case (readHex h :: [(Word64, String)]) of
+          [(w, "")] -> Right w
+          _         -> Left ("fromMisoString StaticKey: invalid hex chunk " <> h)
+    in Fingerprint <$> parseHex h1 <*> parseHex h2
+  {-# INLINE fromMisoStringEither #-}
+-----------------------------------------------------------------------------
+-- | Serializes a 'Fingerprint' ('StaticKey') to its 'Show' representation.
+instance ToJSVal Fingerprint where
+  toJSVal fp = toJSVal (ms fp :: MisoString)
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+-- | The operation carried by a t'COMPONENT' message.
+data ComponentType
+  = MOUNT | UNMOUNT | MODEL_HYDRATE | READY | READY_ACK
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal ComponentType where
+  toJSVal = \case
+    MOUNT -> toJSVal ("mount"   :: MisoString)
+    UNMOUNT -> toJSVal ("unmount" :: MisoString)
+    MODEL_HYDRATE -> toJSVal ("model_hydrate" :: MisoString)
+    READY -> toJSVal ("ready" :: MisoString)
+    READY_ACK -> toJSVal ("ready_ack" :: MisoString)
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal ComponentType where
+  fromJSVal x = do
+    fromJSVal x >>= \case
+      Just ("mount" :: MisoString) -> pure (Just MOUNT)
+      Just "unmount" -> pure (Just UNMOUNT)
+      Just "model_hydrate" -> pure (Just MODEL_HYDRATE)
+      Just "ready" -> pure (Just READY)
+      Just "ready_ack" -> pure (Just READY_ACK)
+      _ -> pure Nothing
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | Cross-thread component lifecycle message (BTS → MTS).
+data COMPONENT = COMPONENT
+  { componentComponentType :: ComponentType
+  , componentComponentStaticKey :: Maybe StaticKey
+  , componentComponentId :: ComponentId
+  , componentComponentParentId :: ComponentId
+  , componentComponentPayload :: Maybe Value
+  -- ^ Serialized payload carried by hydrate messages: the @model@ for
+  -- 'MODEL_HYDRATE', and the initial @props@ for @MOUNT@. 'Nothing' for
+  -- 'UNMOUNT' \/ 'READY'.
+  , componentComponentDOMRef :: Maybe DOMRef
+  -- ^ Mount point for the mirrored MTS component, carried by @MOUNT@. In Lynx
+  -- a @DOMRef@ is a JS object holding a single @nodeId@ field, so it serializes
+  -- across the thread boundary. 'Nothing' for every other message.
+  } deriving Eq
+-----------------------------------------------------------------------------
+instance ToJSVal COMPONENT where
+  toJSVal COMPONENT {..} = do
+    o <- create
+    setField o "componentType" componentComponentType
+    setField o "staticKey" componentComponentStaticKey
+    setField o "compId" componentComponentId
+    setField o "compParentId" componentComponentParentId
+    setField o "payload" componentComponentPayload
+    setField o "domRef" componentComponentDOMRef
+    toJSVal o
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal COMPONENT where
+  fromJSVal x = do
+    let o = Object x
+    mct  <- fromJSVal =<< getProp "componentType" o
+    msk  <- fromJSVal =<< getProp "staticKey" o
+    let key = fmap fromMisoString <$> msk
+    mcid <- fromJSVal =<< getProp "compId" o
+    mcpid <- fromJSVal =<< getProp "compParentId" o
+    mp   <- fromJSVal =<< getProp "payload" o
+    mdr  <- fromJSVal =<< getProp "domRef" o
+    pure (COMPONENT <$> mct <*> key <*> mcid <*> mcpid <*> mp <*> mdr)
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | Cross-thread effect message (MTS → BTS or BTS → MTS).
+data EFFECT = EFFECT
+  { effectComponentId :: ComponentId
+  , effectAction :: Value
+  , effectStaticKey :: Maybe StaticKey
+  } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal EFFECT where
+  toJSVal EFFECT {..} = do
+    o <- create
+    setField o "componentId" effectComponentId
+    setField o "action" effectAction
+    setField o "staticKey" effectStaticKey
+    toJSVal o
+  {-# INLINE toJSVal #-}
+-----------------------------------------------------------------------------
+instance FromJSVal EFFECT where
+  fromJSVal x = do
+    let o = Object x
+    mcid <- fromJSVal =<< getProp "componentId" o
+    maction <- fromJSVal =<< getProp "action" o
+    mk <- fromJSVal =<< getProp "staticKey" o
+    pure (EFFECT <$> mcid <*> maction <*> mk)
+  {-# INLINE fromJSVal #-}
+-----------------------------------------------------------------------------
+-- | Opaque handle to the Lynx Main Thread (MTS) context proxy.
+-- Obtained via 'getMTSContext' on the background thread.
+newtype MTS = MTS JSVal
+  deriving stock Eq
+  deriving newtype ToJSVal
+-----------------------------------------------------------------------------
+-- | Opaque handle to the Lynx Background Thread (BTS) context proxy.
+-- Obtained via 'getBTSContext' on the main thread.
+newtype BTS = BTS JSVal
+  deriving stock Eq
+  deriving newtype ToJSVal
+-----------------------------------------------------------------------------
+-- | The MTS context proxy (@lynx.getCoreContext()@), cached.
+--
+-- N.B. Lynx hands back a handle to the same underlying @ContextProxy@ on
+-- every call for the lifetime of a given JS context (one instance per
+-- origin\/target pair), so — like 'mts' \/ 'bts' \/ 'web' above — it's safe
+-- to compute once via 'unsafePerformIO' rather than round-tripping the FFI
+-- on every 'postComponent' \/ 'postEffect'.
+mtsContext :: MTS
+{-# NOINLINE mtsContext #-}
+mtsContext = unsafePerformIO (MTS <$> (jsg "lynx" # "getCoreContext" $ ()))
+-----------------------------------------------------------------------------
+-- | The BTS context proxy (@lynx.getJSContext()@), cached. See 'mtsContext'.
+btsContext :: BTS
+{-# NOINLINE btsContext #-}
+btsContext = unsafePerformIO (BTS <$> (jsg "lynx" # "getJSContext" $ ()))
+-----------------------------------------------------------------------------
+-- | Returns the MTS context proxy. Call from the background thread to
+-- dispatch messages to the main thread.
+getMTSContext :: IO MTS
+{-# INLINABLE getMTSContext #-}
+getMTSContext = pure mtsContext
+-----------------------------------------------------------------------------
+-- | Returns the BTS context proxy. Call from the main thread to dispatch
+-- messages to the background thread.
+getBTSContext :: IO BTS
+{-# INLINABLE getBTSContext #-}
+getBTSContext = pure btsContext
+-----------------------------------------------------------------------------
+-- | Dispatches a cross-thread message to the BTS via @context.dispatchEvent@.
+-- The @protocol@ string names the channel (e.g. @\"Miso.patches\"@).
+dispatchEvent :: (ToJSVal ctx, ToJSVal a) => ctx -> MisoString -> a -> IO ()
+{-# INLINABLE dispatchEvent #-}
+dispatchEvent ctx protocol payload = do
+  ctx_ <- toJSVal ctx
+  o <- create
+  setField o "type" protocol
+  setField o "data" =<< toJSVal payload
+  _ <- Object ctx_ # "dispatchEvent" $ [o]
+  pure ()
+----------------------------------------------------------------------------
+-- | Loads miso's JavaScript (if not already loaded) and runs an 'IO' action.
+--
+-- On WASM, @miso.js@ is evaluated once on first call and skipped on subsequent calls.
+-- It is safe to call 'withJS' directly (e.g. when implementing WASM tests in Playwright);
+-- 'Miso.startApp' \/ 'Miso.miso' call it for you.
+--
+withJS
+  :: IO a
+  -- ^ 'IO' action to execute in between 'evalFile'
+  -> IO a
+withJS action = do
+#ifdef WASM
+  loaded <- readIORef loadedJS
+  unless loaded $(evalFile MISO_JS_PATH)
+  atomicWriteIORef loadedJS True
+#endif
+  action
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Runtime/Internal.hs b/src/Miso/Runtime/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Runtime/Internal.hs
@@ -0,0 +1,57 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Runtime.Internal
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Runtime.Internal" is a __testing-only__ facade that re-exports
+-- the miso runtime's global mutable state from the internal runtime module.
+--
+-- __Do not import this module in application code.__ Mutating any of
+-- the exported 'Data.IORef.IORef' values will corrupt the component
+-- lifecycle and produce undefined behaviour. The module exists solely to
+-- give the @miso-tests@ integration-test package direct access to
+-- component state for assertions.
+--
+-- = Exported names
+--
+-- * 'components' — global 'Data.IORef.IORef' mapping 'Miso.Effect.ComponentId'
+--   to t'ComponentState' for every mounted component.
+-- * 'componentIds' — monotonically increasing 'Data.IORef.IORef' used to
+--   assign fresh component identifiers.
+-- * 'rootComponentId' — the well-known identifier of the top-level app component.
+-- * t'ComponentState' — record holding the live model, scheduler mailbox, and
+--   other per-component runtime fields.
+-- * 'schedulerThread' — 'Data.IORef.IORef' holding the 'Control.Concurrent.ThreadId'
+--   of the event-loop scheduler thread.
+-- * 'unmountComponent' / 'freeLifecycleHooks' — teardown functions normally
+--   only invoked internally, exposed here so tests can exercise unmounting a
+--   specific t'ComponentState' directly instead of going through a full
+--   diff-driven removal.
+--
+-- = See also
+--
+-- * "Miso.Reload" — uses these internals to kill and restart the scheduler on @:r@
+----------------------------------------------------------------------------
+module Miso.Runtime.Internal
+  ( components
+  , componentIds
+  , rootComponentId
+  , ComponentState(..)
+  , ComponentIds
+  , schedulerThread
+  , unmountComponent
+  , freeLifecycleHooks
+  , module FFI
+  ) where
+----------------------------------------------------------------------------
+import Miso.Runtime (components, ComponentState(..), ComponentIds, componentIds, rootComponentId, schedulerThread, unmountComponent, freeLifecycleHooks)
+import Miso.FFI.Internal as FFI
+----------------------------------------------------------------------------
diff --git a/src/Miso/State.hs b/src/Miso/State.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/State.hs
@@ -0,0 +1,73 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.State
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.State" re-exports the 'Control.Monad.RWS.RWS' combinators that are
+-- most useful inside an 'Miso.Effect.Effect' handler. Because
+-- 'Miso.Effect.Effect' is an @RWS@ monad, the full
+-- 'Control.Monad.State.Class.MonadState',
+-- 'Control.Monad.Reader.Class.MonadReader', and
+-- 'Control.Monad.Writer.Class.MonadWriter' interfaces are available
+-- without importing @mtl@ directly.
+--
+-- This module is re-exported in its entirety by "Miso", so most
+-- applications do not need to import it explicitly.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"          -- re-exports Miso.State
+-- -- or
+-- import "Miso.State"    -- explicit import
+--
+-- data Model = Model { _count :: Int } deriving (Eq)
+-- data Action = Increment | Decrement | Reset | Log
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update Increment = 'modify' (\\m -> m { _count = _count m + 1 })
+-- update Decrement = 'modify'' (\\m -> m { _count = _count m - 1 })
+-- update Reset     = 'put' (Model 0)
+-- update Log       = do
+--   n <- 'gets' _count
+--   'Miso.Effect.io_' (consoleLog ('Miso.String.ms' n))
+-- @
+--
+-- When using "Miso.Lens" or "Miso.Lens.TH", the lens update operators
+-- (@.=@, @+=@, @%=@, …) are built directly on 'modify', so
+-- explicit calls to 'modify' \/ 'put' are rarely needed.
+--
+-- = Exported combinators
+--
+-- * __Reader__ (component metadata): 'ask', 'asks'
+-- * __State__ (model): 'get', 'gets', 'modify', 'modify'', 'put'
+-- * __Writer__ (schedule IO): 'tell'
+-- * __IO lift__: 'liftIO'
+--
+-- = See also
+--
+-- * "Miso.Effect" — 'Miso.Effect.Effect', 'Miso.Effect.io', 'Miso.Effect.io_', 'Miso.Effect.sync'
+-- * "Miso.Lens" — lens operators that wrap 'modify'
+-- * "Miso.Lens.TH" — Template Haskell lens generation
+----------------------------------------------------------------------------
+module Miso.State
+  ( ask
+  , asks
+  , modify
+  , modify'
+  , get
+  , gets
+  , put
+  , tell
+  , liftIO
+  ) where
+----------------------------------------------------------------------------
+import Control.Monad.RWS (get, gets, modify, modify', tell, put, ask, asks)
+import Control.Monad.IO.Class (liftIO)
+----------------------------------------------------------------------------
diff --git a/src/Miso/Storage.hs b/src/Miso/Storage.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Storage.hs
@@ -0,0 +1,195 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Storage
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Storage" wraps the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API Web Storage API>,
+-- providing access to both
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage localStorage>
+-- and
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage sessionStorage>
+-- through symmetric 'IO' functions.
+--
+-- Both stores map 'Miso.String.MisoString' keys to 'Miso.String.MisoString'
+-- values (the Web Storage API only persists strings). Reads return
+-- @'Maybe' 'Miso.String.MisoString'@ — 'Nothing' when the key is absent.
+--
+-- * __localStorage__ — persists across browser sessions until explicitly
+--   cleared.
+-- * __sessionStorage__ — persists only for the lifetime of the current
+--   browser tab\/session; cleared automatically when the tab is closed.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso.Storage"
+-- import "Miso.String" ('Miso.String.ms')
+--
+-- -- Persist a preference
+-- saveTheme :: 'Miso.String.MisoString' -> IO ()
+-- saveTheme theme = 'setLocalStorage' \"theme\" theme
+--
+-- -- Restore it on startup
+-- loadTheme :: IO ('Maybe' 'Miso.String.MisoString')
+-- loadTheme = 'getLocalStorage' \"theme\"
+--
+-- -- Session-scoped token (cleared when tab closes)
+-- saveToken :: 'Miso.String.MisoString' -> IO ()
+-- saveToken tok = 'setSessionStorage' \"auth_token\" tok
+-- @
+--
+-- = API groups
+--
+-- * __localStorage__: 'getLocalStorage', 'setLocalStorage',
+--   'removeLocalStorage', 'clearLocalStorage', 'localStorageLength'
+-- * __sessionStorage__: 'getSessionStorage', 'setSessionStorage',
+--   'removeSessionStorage', 'clearSessionStorage', 'sessionStorageLength'
+--
+-- = See also
+--
+-- * "Miso.Effect" — schedule storage reads\/writes with 'Miso.Effect.io' \/ 'Miso.Effect.io_'
+-- * "Miso.Subscription.History" — URL-based state that survives page reloads
+----------------------------------------------------------------------------
+module Miso.Storage
+  ( -- ** Local
+    getLocalStorage
+  , setLocalStorage
+  , removeLocalStorage
+  , clearLocalStorage
+  , localStorageLength
+    -- ** Session
+  , getSessionStorage
+  , setSessionStorage
+  , removeSessionStorage
+  , clearSessionStorage
+  , sessionStorageLength
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad (void)
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.String (MisoString)
+-----------------------------------------------------------------------------
+-- | Retrieves a value stored under the given key in session storage.
+getSessionStorage
+  :: MisoString
+  -- ^ Storage key to look up
+  -> IO (Maybe MisoString)
+getSessionStorage key = do
+  fromJSValUnchecked =<< flip getItem key =<< sessionStorage
+-----------------------------------------------------------------------------
+-- | Retrieves a value stored under the given key in local storage.
+getLocalStorage
+  :: MisoString
+  -- ^ Storage key to look up
+  -> IO (Maybe MisoString)
+getLocalStorage key =
+  fromJSValUnchecked =<< flip getItem key =<< localStorage
+-----------------------------------------------------------------------------
+-- | Sets the value of a key in local storage.
+--
+-- @setLocalStorage key value@ sets the value of @key@ to @value@.
+setLocalStorage
+  :: MisoString
+  -- ^ Storage key to set
+  -> MisoString
+  -- ^ Value to store
+  -> IO ()
+setLocalStorage key value = do
+  s <- localStorage
+  setItem s key value
+-----------------------------------------------------------------------------
+-- | Sets the value of a key in session storage.
+--
+-- @setSessionStorage key value@ sets the value of @key@ to @value@.
+setSessionStorage
+  :: MisoString
+  -- ^ Storage key to set
+  -> MisoString
+  -- ^ Value to store
+  -> IO ()
+setSessionStorage key value = do
+  s <- sessionStorage
+  setItem s key value
+-----------------------------------------------------------------------------
+-- | Removes an item from local storage.
+--
+-- @removeLocalStorage key@ removes the value of @key@.
+removeLocalStorage
+  :: MisoString
+  -- ^ Storage key to remove
+  -> IO ()
+removeLocalStorage key = do
+  s <- localStorage
+  removeItem s key
+-----------------------------------------------------------------------------
+-- | Removes an item from session storage.
+--
+-- @removeSessionStorage key@ removes the value of @key@.
+removeSessionStorage
+  :: MisoString
+  -- ^ Storage key to remove
+  -> IO ()
+removeSessionStorage key = do
+  s <- sessionStorage
+  removeItem s key
+-----------------------------------------------------------------------------
+-- | Clears local storage.
+--
+-- @clearLocalStorage@ removes all values from local storage.
+clearLocalStorage :: IO ()
+clearLocalStorage = clear =<< localStorage
+-----------------------------------------------------------------------------
+-- | Clears session storage.
+--
+-- @clearSessionStorage@ removes all values from session storage.
+clearSessionStorage :: IO ()
+clearSessionStorage = clear =<< sessionStorage
+-----------------------------------------------------------------------------
+-- | Returns the number of items in local storage.
+--
+-- @localStorageLength@ returns the count of items in local storage
+localStorageLength :: IO Int
+localStorageLength = fromJSValUnchecked =<< localStorage ! "length"
+-----------------------------------------------------------------------------
+-- | Returns the number of items in session storage.
+--
+-- @sessionStorageLength@ returns the count of items in session storage
+sessionStorageLength :: IO Int
+sessionStorageLength = fromJSValUnchecked =<< sessionStorage ! "length"
+-----------------------------------------------------------------------------
+localStorage :: IO Storage
+localStorage = Storage <$> (jsg "window" ! "localStorage")
+-----------------------------------------------------------------------------
+sessionStorage :: IO Storage
+sessionStorage = Storage <$> (jsg "window" ! "sessionStorage")
+-----------------------------------------------------------------------------
+getItem :: Storage -> MisoString -> IO JSVal
+getItem (Storage s) key = s # "getItem" $ [key]
+-----------------------------------------------------------------------------
+removeItem :: Storage -> MisoString -> IO ()
+removeItem (Storage s) key = void $ s # "removeItem" $ [key]
+-----------------------------------------------------------------------------
+setItem :: Storage -> MisoString -> MisoString -> IO ()
+setItem (Storage s) key val = do
+  _ <- s # "setItem" $ (key, val)
+  pure ()
+-----------------------------------------------------------------------------
+clear :: Storage -> IO ()
+clear (Storage s) = do
+  _ <- s # "clear" $ ()
+  pure ()
+-----------------------------------------------------------------------------
+newtype Storage = Storage JSVal
+  deriving (ToObject, ToJSVal)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/String.hs b/src/Miso/String.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/String.hs
@@ -0,0 +1,207 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE LambdaCase        #-}
+{-# LANGUAGE FlexibleInstances #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.String
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- The 'MisoString' type and its conversion type classes.
+--
+-- 'MisoString' is a platform-conditional alias:
+--
+-- * On the client (WASM \/ GHC JS backend) it is @JSString@ — a zero-copy
+--   wrapper around a native JavaScript string, giving optimal interop with
+--   the DOM and JSON APIs.
+-- * On the server (@VANILLA@ build) it is 'Data.Text.Text', enabling
+--   server-side rendering without any FFI dependency.
+--
+-- Use 'ms' (short for 'toMisoString') to convert from 'String', 'T.Text',
+-- numeric types, etc. into 'MisoString'.
+----------------------------------------------------------------------------
+module Miso.String
+  ( ToMisoString (..)
+  , FromMisoString (..)
+  , fromMisoString
+  , MisoString
+#if defined(VANILLA) || defined(MISO_TEXT)
+  , module Data.Text
+#else
+  , module Data.JSString
+#endif
+  , ms
+  ) where
+----------------------------------------------------------------------------
+import           Control.Exception
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Builder as B
+import qualified Data.ByteString.Lazy as BL
+#if defined(VANILLA) || defined(MISO_TEXT)
+import           Data.Text hiding (show, elem)
+#else
+import           Data.JSString
+#ifdef GHCJS_BOTH
+import           Data.JSString.Text
+#endif
+#endif
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T
+import qualified Data.Text.Lazy as LT
+import qualified Data.Text.Lazy.Encoding as LT
+----------------------------------------------------------------------------
+import           Miso.DSL.FFI
+----------------------------------------------------------------------------
+-- | The primary string type in Miso applications.
+--
+-- * @VANILLA@ (server\/SSR build): alias for 'Data.Text.Text'
+-- * WASM \/ GHC JS backend: alias for @JSString@ — a zero-copy wrapper around
+--   a native JavaScript string, giving optimal interop with the DOM and JSON APIs
+--
+#if defined(VANILLA) || defined(MISO_TEXT)
+type MisoString = Text
+#else
+type MisoString = JSString
+#endif
+----------------------------------------------------------------------------
+-- | A type that can be converted to 'MisoString'.
+--
+-- Instances are provided for 'String', 'T.Text', 'LT.Text', 'B.ByteString',
+-- 'BL.ByteString', 'Double', 'Float', 'Int', 'Word', and others.
+-- Use 'ms' as a short alias for 'toMisoString'.
+class ToMisoString str where
+  -- | Convert a value to 'MisoString'.
+  toMisoString :: str -> MisoString
+----------------------------------------------------------------------------
+-- | A type that can be parsed from a 'MisoString'.
+-- Like a safe 'Read' that returns an error message on failure.
+class FromMisoString t where
+  -- | Parse a 'MisoString', returning @'Left' errMsg@ on failure.
+  fromMisoStringEither :: MisoString -> Either String t
+----------------------------------------------------------------------------
+-- | Parse a 'MisoString', throwing an error on failure.
+-- Use @fromMisoStringEither@ as a safe alternative.
+fromMisoString :: FromMisoString a => MisoString -> a
+fromMisoString s =
+  case fromMisoStringEither s of
+    Left error_ -> error ("fromMisoString: " <> error_)
+    Right x  -> x
+----------------------------------------------------------------------------
+-- | Short alias for 'toMisoString'. The idiomatic way to construct a 'MisoString'.
+ms :: ToMisoString str => str -> MisoString
+ms = toMisoString
+----------------------------------------------------------------------------
+instance ToMisoString a => ToMisoString (Maybe a) where
+  toMisoString = \case
+    Nothing -> mempty
+    Just x -> ms x
+----------------------------------------------------------------------------
+instance ToMisoString Char where
+  toMisoString = singleton
+----------------------------------------------------------------------------
+instance ToMisoString IOException where
+  toMisoString = ms . show
+----------------------------------------------------------------------------
+#if !defined(VANILLA) && !defined(MISO_TEXT)
+instance ToMisoString MisoString where
+  toMisoString = id
+#endif
+----------------------------------------------------------------------------
+instance ToMisoString SomeException where
+  toMisoString = ms . show
+----------------------------------------------------------------------------
+instance ToMisoString String where
+  toMisoString = pack
+----------------------------------------------------------------------------
+instance ToMisoString LT.Text where
+  toMisoString = ms . LT.toStrict
+----------------------------------------------------------------------------
+instance ToMisoString T.Text where
+#if defined(VANILLA) || defined(MISO_TEXT)
+  toMisoString = id
+#else
+  toMisoString = textToJSString
+#endif
+----------------------------------------------------------------------------
+instance ToMisoString B.ByteString where
+  toMisoString = ms . T.decodeUtf8
+----------------------------------------------------------------------------
+instance ToMisoString BL.ByteString where
+  toMisoString = ms . LT.decodeUtf8
+----------------------------------------------------------------------------
+instance ToMisoString B.Builder where
+  toMisoString = ms . B.toLazyByteString
+----------------------------------------------------------------------------
+instance ToMisoString Float where
+  toMisoString = toString_Float
+----------------------------------------------------------------------------
+instance ToMisoString Double where
+  toMisoString = toString_Double
+----------------------------------------------------------------------------
+instance ToMisoString Int where
+  toMisoString = toString_Int
+----------------------------------------------------------------------------
+instance ToMisoString Word where
+  toMisoString = toString_Word
+----------------------------------------------------------------------------
+#if !defined(VANILLA) && !defined(MISO_TEXT)
+instance FromMisoString MisoString where
+  fromMisoStringEither = Right
+#endif
+----------------------------------------------------------------------------
+instance FromMisoString T.Text where
+#if defined(VANILLA) || defined(MISO_TEXT)
+  fromMisoStringEither = Right
+#else
+  fromMisoStringEither = Right . textFromJSString
+#endif
+----------------------------------------------------------------------------
+instance FromMisoString String where
+  fromMisoStringEither = Right . unpack
+----------------------------------------------------------------------------
+instance FromMisoString LT.Text where
+#if defined(VANILLA) || defined(MISO_TEXT)
+  fromMisoStringEither = Right . LT.fromStrict
+#else
+  fromMisoStringEither = Right . LT.fromStrict . textFromJSString
+#endif
+----------------------------------------------------------------------------
+instance FromMisoString B.ByteString where
+  fromMisoStringEither = fmap T.encodeUtf8 . fromMisoStringEither
+----------------------------------------------------------------------------
+instance FromMisoString BL.ByteString where
+  fromMisoStringEither = fmap LT.encodeUtf8 . fromMisoStringEither
+----------------------------------------------------------------------------
+instance FromMisoString B.Builder where
+  fromMisoStringEither = fmap B.byteString . fromMisoStringEither
+----------------------------------------------------------------------------
+instance FromMisoString Word where
+  fromMisoStringEither string =
+    case parseWord string of
+      Nothing -> Left ("fromMisoString Word: could not parse " <> unpack string)
+      Just x -> Right x
+----------------------------------------------------------------------------
+instance FromMisoString Double where
+  fromMisoStringEither string =
+    case parseDouble string of
+      Nothing -> Left ("fromMisoString Double: could not parse " <> unpack string)
+      Just x -> Right x
+----------------------------------------------------------------------------
+instance FromMisoString Int where
+  fromMisoStringEither string =
+    case parseInt string of
+      Nothing -> Left ("fromMisoString Int: could not parse " <> unpack string)
+      Just x -> Right x
+----------------------------------------------------------------------------
+instance FromMisoString Float where
+  fromMisoStringEither string =
+    case parseFloat string of
+      Nothing -> Left ("fromMisoString Float: could not parse " <> unpack string)
+      Just x -> Right x
+----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription.hs b/src/Miso/Subscription.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription.hs
@@ -0,0 +1,93 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Subscription" is the re-export hub for all of miso's built-in
+-- 'Miso.Effect.Sub' subscriptions. A subscription is a long-running 'IO'
+-- action of type @'Miso.Effect.Sink' action -> IO ()@ that delivers
+-- external events — mouse moves, key presses, URL changes, animation
+-- frames — into the update loop by calling its 'Miso.Effect.Sink'.
+--
+-- Register subscriptions in the 'Miso.Types.subs' field of a
+-- t'Miso.Types.Component':
+--
+-- @
+-- import "Miso"
+-- import "Miso.Subscription"
+--
+-- myComponent = ('Miso.component' model update view)
+--   { 'Miso.Types.subs' =
+--       [ 'mouseSub'    MouseMoved
+--       , 'keyboardSub' KeyPressed
+--       , 'uriSub'      UrlChanged
+--       , 'rAFSub'      Tick
+--       ]
+--   }
+-- @
+--
+-- = Subscription catalogue
+--
+-- ['mouseSub'] global @pointermove@ — "Miso.Subscription.Mouse"
+-- ['keyboardSub'] global @keydown@ \/ @keyup@ — "Miso.Subscription.Keyboard"
+-- ['arrowsSub', 'wasdSub', 'directionSub'] arrow or WASD keys held — "Miso.Subscription.Keyboard"
+-- ['uriSub'] browser @popstate@ (back\/forward\/pushState) — "Miso.Subscription.History"
+-- ['Miso.Subscription.History.routerSub'] same, decoded via 'Miso.Router.Router' — "Miso.Subscription.History"
+-- ['windowCoordsSub'] global window @pointermove@ — "Miso.Subscription.Window"
+-- ['windowPointerMoveSub'] global window @pointermove@ — "Miso.Subscription.Window"
+-- ['windowSubWithOptions'] any window event — "Miso.Subscription.Window"
+-- ['onLineSub'] @online@ \/ @offline@ change — "Miso.Subscription.OnLine"
+-- ['rAFSub'] every @requestAnimationFrame@ tick — "Miso.Subscription.RAF"
+-- ['cookieChangeSub'] @cookieStore change@ events — "Miso.Subscription.Cookie"
+-- ['canvasSub'] canvas support — "Miso.Subscription.Canvas"
+--
+-- = History helpers
+--
+-- The "Miso.Subscription.History" module also exports imperative
+-- navigation functions usable from within 'Miso.Effect.Effect':
+--
+-- @
+-- update GoHome = 'Miso.Effect.io_' ('pushURI' ('Miso.Router.toURI' Home))
+-- update GoBack = 'Miso.Effect.io_' 'back'
+-- @
+--
+-- = See also
+--
+-- * "Miso.Effect" — 'Miso.Effect.Sub', 'Miso.Effect.Sink', 'Miso.Effect.mapSub'
+-- * "Miso.Subscription.Util" — 'Miso.Subscription.Util.createSub' for custom subscriptions
+-- * "Miso.Router" — 'Miso.Router.Router' typeclass used by 'Miso.Subscription.History.routerSub'
+----------------------------------------------------------------------------
+module Miso.Subscription
+  ( -- ** Mouse
+    module Miso.Subscription.Mouse
+    -- ** Keyboard
+  , module Miso.Subscription.Keyboard
+    -- ** History
+  , module Miso.Subscription.History
+    -- ** Window
+  , module Miso.Subscription.Window
+    -- ** OnLine
+  , module Miso.Subscription.OnLine
+    -- ** requestForAnimationFrame
+  , module Miso.Subscription.RAF
+    -- ** Cookie Store
+  , module Miso.Subscription.Cookie
+    -- ** Canvas
+  , module Miso.Subscription.Canvas
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Subscription.Mouse
+import Miso.Subscription.Keyboard
+import Miso.Subscription.History
+import Miso.Subscription.Window
+import Miso.Subscription.OnLine
+import Miso.Subscription.RAF
+import Miso.Subscription.Cookie
+import Miso.Subscription.Canvas
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription/Canvas.hs b/src/Miso/Subscription/Canvas.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription/Canvas.hs
@@ -0,0 +1,99 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription.Canvas
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-----------------------------------------------------------------------------
+module Miso.Subscription.Canvas
+  ( -- ** Subscriptions
+    canvasSub
+  ) where
+-----------------------------------------------------------------------------
+import Control.Monad.Reader (runReaderT)
+import Control.Monad (void)
+import Data.IORef
+-----------------------------------------------------------------------------
+import Miso.Canvas
+import Miso.DSL
+import Miso.Effect
+import Miso.String
+import Miso.Subscription.Util
+-----------------------------------------------------------------------------
+-- | 'Sub' for canvas operations, meant to be used with 'onCreated' / 'onDestroyed'
+--
+-- Example usage below
+--
+-- @
+-- import Miso.Canvas
+--
+-- data Action = InitCanvas DOMRef | StopCanvas
+--
+-- canvasComponent :: 'Component' context props model action
+-- canvasComponent = 'component' m u v
+--   where
+--     m = ()
+--     u = \case
+--       InitCanvas domRef ->
+--         startSub "galaxy" $ canvasSub domRef "2d" $ \_timeStamp currentModel -> do
+--           drawScene currentModel
+--       StopCanvas ->
+--         stopSub "galaxy"
+--     v _context _props () =
+--       'canvas_' [ onCreatedWith InitCanvas, onDestroyed StopCanvas ] []
+--
+-- drawScene :: Model -> 'Canvas' ()
+-- drawScene m = do
+--   'clearRect' (0, 0, 800, 480)
+--   'fillStyle' ('color' Color.'Miso.CSS.Color.cornflowerblue')
+--   'fillRect'  (0, 0, 800, 480)
+--   'fillStyle' ('color' Color.'Miso.CSS.Color.white')
+--   'font'      \"24px sans-serif\"
+--   'fillText'  (\"Hello, miso!\", 32, 48)
+-- @
+--
+-- 'canvasSub' is meant to bypass virtual DOM creation, creating a more efficient canvas
+-- draw. This works by calling requestAnimationFrame in a tight loop around a freshly
+-- initialized canvas (per 'onCreated').
+--
+-- The difference between 'canvasSub' and "Miso.Canvas" is that this operates in a tight
+-- rAF loop. The latter operates on a discrete event basis and the draw is called during
+-- the diffing process.
+--
+canvasSub
+  :: DOMRef
+  -- ^ The canvas 'JSVal' (meant to be consumed from 'onCreatedWith')
+  -> MisoString
+  -- ^ "2d", "webgpu", "webgl2"
+  -> (Double -> model -> Canvas state)
+  -- ^ Canvas callback in 60fps, high precision timestamp, model snapshot
+  -- as args to Canvas DSL templating
+  -> Sub model action
+canvasSub canvasRef dim builder snk getModel = do
+  createSub acquire release snk getModel
+    where
+      acquire = do
+        ctx <- canvasRef # "getContext" $ dim
+        cbRef <- newIORef (error "canvasSub: uninitialized, impossible")
+        idRef <- newIORef (0 :: Int)
+        callback <-
+          syncCallback1 $ \jsval -> do
+            void . flip runReaderT ctx =<<
+              builder <$> fromJSValUnchecked jsval <*> getModel
+            writeIORef idRef =<< requestAnimationFrame =<< readIORef cbRef
+        writeIORef cbRef callback
+        writeIORef idRef =<< requestAnimationFrame callback
+        pure (callback, idRef)
+  
+      -- N.B. the queued frame must be cancelled before the callback is
+      -- freed: the browser holds a reference to it, and invoking a freed
+      -- callback on the next frame crashes the runtime.
+      release (callback, idRef) = do
+        cancelAnimationFrame =<< readIORef idRef
+        freeFunction (Function callback)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription/Cookie.hs b/src/Miso/Subscription/Cookie.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription/Cookie.hs
@@ -0,0 +1,86 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription.Cookie
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Subscription.Cookie" provides 'cookieChangeSub', an optional
+-- subscription that delivers
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/change_event cookieStore change>
+-- events into the update loop. Each event carries the list of cookies that
+-- were added\/updated and the list that were deleted since the last event.
+--
+-- The subscription is optional — applications that only need one-shot reads
+-- and writes can use 'Miso.Cookie.cookieGet', 'Miso.Cookie.cookieSet', and
+-- 'Miso.Cookie.cookieDelete' directly without registering a subscription.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Subscription.Cookie"
+-- import "Miso.Cookie" ('CookieChangeEvent' (..))
+--
+-- data Action = CookiesChanged 'CookieChangeEvent'
+--
+-- subs :: ['Miso.Effect.Sub' Action]
+-- subs = [ 'cookieChangeSub' CookiesChanged ]
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update (CookiesChanged ev) =
+--   'Miso.Effect.io_' (consoleLog (ms (show (@cookiesChanged@ ev))))
+-- @
+--
+-- = Availability
+--
+-- The CookieStore API requires a
+-- <https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts secure context>
+-- (HTTPS or @localhost@) and is not yet supported in all browsers. The
+-- subscription silently does nothing when @cookieStore@ is unavailable.
+--
+-- = See also
+--
+-- * "Miso.Cookie" — 'Miso.Cookie.cookieGet', 'Miso.Cookie.cookieSet',
+--   'Miso.Cookie.cookieDelete', 'Miso.Cookie.cookieGetAll'
+-- * "Miso.Subscription.Util" — 'Miso.Subscription.Util.createSub' used internally
+-- * "Miso.Subscription" — re-export hub
+-----------------------------------------------------------------------------
+module Miso.Subscription.Cookie
+  ( -- ** Subscriptions
+    cookieChangeSub
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.Cookie (CookieChangeEvent)
+import           Miso.DSL (fromJSVal)
+import           Miso.Effect (Sub)
+import           Miso.Subscription.Util (createSub)
+import qualified Miso.FFI.Internal as FFI
+-----------------------------------------------------------------------------
+-- | Returns a 'Sub' that fires an action on every
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/change_event cookieStore change>
+-- event, carrying the decoded 'CookieChangeEvent' (changed and deleted
+-- cookie lists).
+--
+-- The subscription is self-contained: it registers the listener on mount
+-- and removes it on unmount via 'Miso.Subscription.Util.createSub'.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/CookieStore/change_event>
+--
+-- @since 1.13.0.0
+cookieChangeSub
+  :: (CookieChangeEvent -> action)
+  -- ^ Callback: receives the change event on every cookie modification
+  -> Sub model action
+cookieChangeSub f sink = createSub acquire release sink
+  where
+    acquire = FFI.cookieStoreAddEventListener $ \ev ->
+      fromJSVal ev >>= mapM_ (sink . f)
+    release = FFI.cookieStoreRemoveEventListener
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription/History.hs b/src/Miso/Subscription/History.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription/History.hs
@@ -0,0 +1,193 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription.History
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Subscription.History" wraps the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/History History API>
+-- and
+-- <https://developer.mozilla.org/en-US/docs/Web/API/PopStateEvent popstate>
+-- event, providing both a reactive subscription and imperative navigation
+-- helpers.
+--
+-- = Subscriptions
+--
+-- 'uriSub' fires whenever the URL changes — through browser back\/forward
+-- buttons or any of the imperative helpers below:
+--
+-- @
+-- subs :: ['Miso.Effect.Sub' Action]
+-- subs = [ 'uriSub' UrlChanged ]
+-- @
+--
+-- 'routerSub' is a convenience wrapper that decodes the t'URI' via a
+-- 'Miso.Router.Router' instance before delivering it as an action:
+--
+-- @
+-- subs = [ 'routerSub' (RouteChanged . 'Data.Either.fromRight' NotFound) ]
+-- @
+--
+-- = Imperative navigation
+--
+-- These functions push or replace entries on the browser history stack and
+-- simultaneously fire a synthetic @popstate@ event so that 'uriSub' and
+-- 'routerSub' are notified automatically:
+--
+-- @
+-- update GoHome     = 'Miso.Effect.io_' ('pushURI' ('Miso.Router.toURI' Home))
+-- update GoProfile  = 'Miso.Effect.io_' ('pushRoute' (User (Capture 42)))
+-- update ReplaceUrl = 'Miso.Effect.io_' ('replaceURI' newUri)
+-- update GoBack     = 'Miso.Effect.io_' 'back'
+-- update GoForward  = 'Miso.Effect.io_' 'forward'
+-- update (Jump n)   = 'Miso.Effect.io_' ('go' n)
+-- @
+--
+-- 'getURI' reads the current URL from @window.location@ without subscribing:
+--
+-- @
+-- update Init = 'Miso.Effect.io' (GotURI \<$\> 'getURI')
+-- @
+--
+-- = See also
+--
+-- * "Miso.Router" — 'Miso.Router.Router', 'Miso.Router.URI', 'Miso.Router.toURI', 'Miso.Router.prettyURI'
+-- * "Miso.Subscription" — re-export hub
+-- * "Miso.Subscription.Util" — 'Miso.Subscription.Util.createSub' used internally
+----------------------------------------------------------------------------
+module Miso.Subscription.History
+  ( -- *** Subscription
+    uriSub
+  , routerSub
+    -- *** Functions
+  , getURI
+  , pushURI
+  , pushRoute
+  , replaceURI
+  , back
+  , forward
+  , go
+   -- *** Types
+  , URI (..)
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import qualified Miso.FFI.Internal as FFI
+import           Miso.String
+import           Miso.Router
+import           Miso.Effect (Sub)
+import           Miso.Subscription.Util
+-----------------------------------------------------------------------------
+-- | Pushes a new URI onto the History stack. Also raises a @popstate@ event.
+pushURI
+  :: URI
+  -- ^ The URI to push onto the history stack
+  -> IO ()
+pushURI uri = do
+  pushState (prettyURI uri)
+  raisePopState
+-----------------------------------------------------------------------------
+-- | Pushes a new @Route@ onto the History stack. Also raises a @popstate@ event.
+--
+-- Converts the @Route@ to a t'URI' internally.
+--
+pushRoute
+  :: Router route
+  => route
+  -- ^ The route to push onto the history stack (converted to a URI internally)
+  -> IO ()
+pushRoute = pushURI . toURI
+-----------------------------------------------------------------------------
+-- | Replaces current URI on stack. Also raises a @popstate@ event.
+replaceURI
+  :: URI
+  -- ^ The URI to replace the current history entry with
+  -> IO ()
+replaceURI uri = do
+  replaceState (prettyURI uri)
+  raisePopState
+-----------------------------------------------------------------------------
+raisePopState :: IO ()
+raisePopState = do
+  event <- new (jsg "PopStateEvent") ["popstate" :: MisoString]
+  window <- jsg "window"
+  void $ window # "dispatchEvent" $ [event]
+-----------------------------------------------------------------------------
+-- | Navigates backwards.
+back :: IO ()
+back = void $ getHistory # "back" $ ()
+-----------------------------------------------------------------------------
+-- | Navigates forwards.
+forward :: IO ()
+forward = void $ getHistory # "forward" $ ()
+-----------------------------------------------------------------------------
+-- | Jumps to a specific position in history.
+go
+  :: Int
+  -- ^ Number of steps to jump; positive = forward, negative = backward
+  -> IO ()
+go n = void $ getHistory # "go" $ [n]
+-----------------------------------------------------------------------------
+-- | Subscription for t'URI' changes, uses the History API.
+--
+-- This returns a new t'URI' whenever 'go', 'back', 'forward', 'pushURI'
+-- or 'replaceURI' have been called.
+--
+uriSub
+  :: (URI -> action)
+  -- ^ Callback fired with the new t'URI' on every URL change
+  -> Sub model action
+uriSub f sink = createSub acquire release sink
+  where
+    release = FFI.windowRemoveEventListener "popstate"
+    acquire = FFI.windowAddEventListener "popstate" $ \_ ->
+      sink . f =<< getURI
+-----------------------------------------------------------------------------
+-- | Subscription for @popstate@ events, from the History API, mapped
+-- to a user-defined 'Router'.
+routerSub
+  :: Router route
+  => (Either RoutingError route -> action)
+  -- ^ Callback fired with the decoded route (or 'RoutingError') on every URL change
+  -> Sub model action
+routerSub f = uriSub $ \uri -> f (route uri)
+-----------------------------------------------------------------------------
+-- | Retrieves the current relative URI by inspecting @pathname@, @search@
+-- and @hash@.
+getURI :: IO URI
+getURI = do
+  location <- jsg "window" ! "location"
+  pathname <- fromJSValUnchecked =<< location ! "pathname"
+  search <- fromJSValUnchecked =<< location ! "search"
+  hash <- fromJSValUnchecked =<< location ! "hash"
+  let uriText =
+        mconcat
+        [ pathname
+        , search
+        , hash
+        ]
+  case parseURI uriText of
+    Left err -> do
+      FFI.consoleError ("Couldn't parse URI: " <> err)
+      pure emptyURI
+    Right uri -> do
+      pure uri
+-----------------------------------------------------------------------------
+getHistory :: IO JSVal
+getHistory = jsg "window" ! "history"
+-----------------------------------------------------------------------------
+pushState :: MisoString -> IO ()
+pushState url = void $ getHistory # "pushState" $ (jsNull, jsNull, url)
+-----------------------------------------------------------------------------
+replaceState :: MisoString -> IO ()
+replaceState url = void $ getHistory # "replaceState" $ (jsNull, jsNull, url)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription/Keyboard.hs b/src/Miso/Subscription/Keyboard.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription/Keyboard.hs
@@ -0,0 +1,164 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE BangPatterns      #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription.Keyboard
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Subscription.Keyboard" provides global keyboard subscriptions that
+-- track which keys are currently held down. All four subscriptions register
+-- @keydown@, @keyup@, and @blur@ listeners on @window@; the @blur@ handler
+-- clears the pressed-key set so keys cannot get stuck when the window loses
+-- focus.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Subscription.Keyboard"
+--
+-- -- Fire action with arrow-key state on every key change
+-- subs :: ['Miso.Effect.Sub' Action]
+-- subs = [ 'arrowsSub' ArrowsChanged ]
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update (ArrowsChanged ('Arrows' x y)) = do
+--   -- x ∈ {-1, 0, 1}, y ∈ {-1, 0, 1}
+--   'Miso.Effect.io_' (move x y)
+-- @
+--
+-- = Subscription variants
+--
+-- * 'keyboardSub' — delivers the raw @'Data.IntSet.IntSet'@ of all currently
+--   pressed
+--   <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode keyCodes>.
+--   Use this when you need to handle arbitrary key combinations.
+--
+-- * 'arrowsSub' — maps the four arrow keys (37–40) to an t'Arrows' value
+--   with @arrowX ∈ {-1, 0, 1}@ and @arrowY ∈ {-1, 0, 1}@.
+--
+-- * 'wasdSub' — same as 'arrowsSub' but for W\/A\/S\/D (keyCodes 87\/83\/65\/68).
+--
+-- * 'directionSub' — fully configurable: supply your own @(up, down, left, right)@
+--   keyCode lists and get the same t'Arrows' mapping.
+--
+-- = See also
+--
+-- * "Miso.Subscription" — re-export hub
+-- * "Miso.Event.Types" — 'Miso.Event.Types.KeyCode', 'Miso.Event.Types.KeyInfo'
+-- * "Miso.Html.Event" — per-element 'Miso.Html.Event.onKeyDown' \/ 'Miso.Html.Event.onKeyUp'
+----------------------------------------------------------------------------
+module Miso.Subscription.Keyboard
+  ( -- *** Types
+    Arrows (..)
+    -- *** Subscriptions
+  , arrowsSub
+  , directionSub
+  , keyboardSub
+  , wasdSub
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad.IO.Class
+import           Data.IORef
+import           Data.IntSet
+import qualified Data.IntSet as S
+-----------------------------------------------------------------------------
+import           Miso.DSL hiding (new)
+import           Miso.Effect (Sub)
+import           Miso.Subscription.Util (createSub)
+import qualified Miso.FFI.Internal as FFI
+-----------------------------------------------------------------------------
+-- | Type for arrow keys currently pressed.
+--
+--  * 37 left arrow  ( x = -1 )
+--  * 38 up arrow    ( y =  1 )
+--  * 39 right arrow ( x =  1 )
+--  * 40 down arrow  ( y = -1 )
+data Arrows
+ = Arrows
+ { arrowX :: !Int
+ -- ^ Horizontal direction: @-1@ (left), @0@ (neutral), @1@ (right)
+ , arrowY :: !Int
+ -- ^ Vertical direction: @-1@ (down), @0@ (neutral), @1@ (up)
+ } deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Helper function to convert keys currently pressed to @Arrows@, given a
+-- mapping for keys representing up, down, left and right respectively.
+toArrows :: ([Int], [Int], [Int], [Int]) -> IntSet -> Arrows
+toArrows (up, down, left, right) set' = Arrows
+  { arrowX =
+      case (check left, check right) of
+        (True, False) -> -1
+        (False, True) -> 1
+        (_,_) -> 0
+  , arrowY =
+      case (check down, check up) of
+        (True, False) -> -1
+        (False, True) -> 1
+        (_,_) -> 0
+  } where
+      check = any (`S.member` set')
+-----------------------------------------------------------------------------
+-- | Maps t'Arrows' onto a Keyboard subscription.
+arrowsSub :: (Arrows -> action) -> Sub model action
+arrowsSub = directionSub ([38], [40], [37], [39])
+-----------------------------------------------------------------------------
+-- | Maps t'Arrows' onto a Keyboard subscription for directions (W+A+S+D keys).
+wasdSub :: (Arrows -> action) -> Sub model action
+wasdSub = directionSub ([87], [83], [65], [68])
+-----------------------------------------------------------------------------
+-- | Maps a specified list of keys to directions (up, down, left, right).
+-- The Ints represent [keyCode](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode)s for each direction.
+directionSub
+  :: ([Int], [Int], [Int], [Int])
+  -- ^ @(up, down, left, right)@ keyCode lists for each direction
+  -> (Arrows -> action)
+  -- ^ Callback fired with the current t'Arrows' state on every key change
+  -> Sub model action
+directionSub dirs = keyboardSub . (. toArrows dirs)
+-----------------------------------------------------------------------------
+-- | Returns 'Sub' for keyboard events.
+-- The callback will be called with the Set of currently pressed @keyCode@s.
+keyboardSub :: (IntSet -> action) -> Sub model action
+keyboardSub f sink = createSub acquire release sink
+  where
+    release (cb1, cb2, cb3) = do
+      FFI.windowRemoveEventListener "keyup" cb1
+      FFI.windowRemoveEventListener "keydown" cb2
+      FFI.windowRemoveEventListener "blur" cb3
+    acquire = do
+      keySetRef <- liftIO (newIORef mempty)
+      cb1 <- FFI.windowAddEventListener "keyup" (keyUpCallback keySetRef)
+      cb2 <- FFI.windowAddEventListener "keydown" (keyDownCallback keySetRef)
+      cb3 <- FFI.windowAddEventListener "blur" (blurCallback keySetRef)
+      pure (cb1, cb2, cb3)
+        where
+          keyDownCallback keySetRef = \keyDownEvent -> do
+              key <- fromJSValUnchecked =<< getProp "keyCode" (Object keyDownEvent)
+              newKeys <- liftIO $ atomicModifyIORef' keySetRef $ \keys ->
+                 let !new = S.insert key keys
+                 in (new, new)
+              sink (f newKeys)
+
+          keyUpCallback keySetRef = \keyUpEvent -> do
+              key <- fromJSValUnchecked =<< getProp "keyCode" (Object keyUpEvent)
+              newKeys <- liftIO $ atomicModifyIORef' keySetRef $ \keys ->
+                 let !new = S.delete key keys
+                 in (new, new)
+              sink (f newKeys)
+
+          -- Assume keys are released the moment focus is lost. Otherwise going
+          -- back and forth to the app can cause keys to get stuck.
+          blurCallback keySetRef = \_ -> do
+              newKeys <- liftIO $ atomicModifyIORef' keySetRef $ \_ ->
+                let !new = S.empty
+                in (new, new)
+              sink (f newKeys)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription/Mouse.hs b/src/Miso/Subscription/Mouse.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription/Mouse.hs
@@ -0,0 +1,65 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription.Mouse
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Subscription.Mouse" provides a single global subscription,
+-- 'mouseSub', that fires on every @pointermove@ event on @window@,
+-- delivering a 'Miso.Event.Types.PointerEvent' carrying coordinates,
+-- pressure, pointer type, and other pointer metadata.
+--
+-- It is a thin convenience wrapper over
+-- @'Miso.Subscription.Window.windowSub' \"pointermove\" 'Miso.Event.Decoder.pointerDecoder'@.
+-- Use 'Miso.Subscription.Window.windowPointerMoveSub' directly if you
+-- need identical behaviour but prefer the window-level import.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Subscription.Mouse"
+-- import "Miso.Event.Types" ('Miso.Event.Types.PointerEvent'(..))
+--
+-- data Action = MouseMoved 'Miso.Event.Types.PointerEvent'
+--
+-- subs :: ['Miso.Effect.Sub' Action]
+-- subs = [ 'mouseSub' MouseMoved ]
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update (MouseMoved ev) = do
+--   let (cx, cy) = client ev   -- (clientX, clientY)
+--   ...
+-- @
+--
+-- = See also
+--
+-- * "Miso.Subscription.Window" — 'Miso.Subscription.Window.windowPointerMoveSub',
+--   'Miso.Subscription.Window.windowCoordsSub', 'Miso.Subscription.Window.windowSub'
+-- * "Miso.Event.Types" — 'Miso.Event.Types.PointerEvent', 'Miso.Event.Types.PointerType'
+-- * "Miso.Event.Decoder" — 'Miso.Event.Decoder.pointerDecoder'
+----------------------------------------------------------------------------
+module Miso.Subscription.Mouse
+  ( -- *** Subscription
+    mouseSub
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Event (pointerDecoder, PointerEvent)
+import Miso.Subscription.Window (windowSub)
+import Miso.Effect (Sub)
+-----------------------------------------------------------------------------
+-- | Captures mouse coordinates as they occur and writes them to
+-- an event sink.
+mouseSub
+  :: (PointerEvent -> action)
+  -- ^ Callback fired with the full 'PointerEvent' on every @pointermove@
+  -> Sub model action
+mouseSub = windowSub "pointermove" pointerDecoder
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription/OnLine.hs b/src/Miso/Subscription/OnLine.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription/OnLine.hs
@@ -0,0 +1,74 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings   #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription.OnLine
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Subscription.OnLine" provides 'onLineSub', a subscription that
+-- tracks the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine navigator.onLine>
+-- connectivity status. It registers @online@ and @offline@ event listeners
+-- on @window@ and fires an action with 'True' when the connection is
+-- restored and @False@ when it is lost.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Subscription.OnLine"
+--
+-- data Action = OnLineChanged Bool
+--
+-- subs :: ['Miso.Effect.Sub' Action]
+-- subs = [ 'onLineSub' OnLineChanged ]
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update (OnLineChanged isOnLine)
+--   | isOnLine  = 'Miso.Effect.io_' (consoleLog \"Back online\")
+--   | otherwise = 'Miso.Effect.io_' (consoleLog \"Offline\")
+-- @
+--
+-- To read the current status imperatively without subscribing, use
+-- 'Miso.Navigator.isOnLine' from "Miso.Navigator".
+--
+-- = See also
+--
+-- * "Miso.Navigator" — 'Miso.Navigator.isOnLine' for one-shot reads
+-- * "Miso.Subscription" — re-export hub
+-- * "Miso.Subscription.Util" — 'Miso.Subscription.Util.createSub' used internally
+----------------------------------------------------------------------------
+module Miso.Subscription.OnLine
+  ( -- *** Subscriptions
+    onLineSub
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.Effect (Sub)
+import           Miso.Subscription.Util (createSub)
+import qualified Miso.FFI.Internal as FFI
+-----------------------------------------------------------------------------
+-- | Returns 'Sub' for the navigator.onLine API.
+-- Fires action with 'True' when the browser goes online, and @False@ when it goes offline.
+--
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine>
+--
+onLineSub
+  :: (Bool -> action)
+  -- ^ Callback: 'True' when going online, @False@ when going offline
+  -> Sub model action
+onLineSub f sink = createSub acquire release sink
+  where
+    release (cb1, cb2) = do
+      FFI.windowRemoveEventListener "online" cb1
+      FFI.windowRemoveEventListener "offline" cb2
+    acquire = do
+      cb1 <- FFI.windowAddEventListener "online" (\_ -> sink (f True))
+      cb2 <- FFI.windowAddEventListener "offline" (\_ -> sink (f False))
+      pure (cb1, cb2)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription/RAF.hs b/src/Miso/Subscription/RAF.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription/RAF.hs
@@ -0,0 +1,138 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription.RAF
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Subscription.RAF" provides 'rAFSub', a subscription that hooks
+-- into the browser's
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame requestAnimationFrame>
+-- loop. On each frame the browser calls back with a
+-- <https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp DOMHighResTimeStamp>
+-- (milliseconds since page load, sub-millisecond precision), which is
+-- forwarded to the component as an action.
+--
+-- This is the recommended driver for canvas-based animations and games
+-- because the browser throttles the callback to the display refresh rate
+-- (typically 60 fps) and pauses it automatically when the tab is hidden.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Subscription.RAF"
+-- import "Miso.Canvas"
+--
+-- data Action = Tick Double   -- DOMHighResTimeStamp in ms
+--
+-- myComponent = ('Miso.component' model update view)
+--   { 'Miso.Types.subs'   = [ 'rAFSub' Tick ]
+--   , 'Miso.Types.events' = 'Miso.Event.Types.defaultEvents'
+--   }
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update (Tick t) = do
+--   'Miso.State.modify' (\\m -> m { time = t })
+-- @
+--
+-- = Lifecycle
+--
+-- Internally 'rAFSub' uses 'Miso.Subscription.Util.createSub':
+--
+-- * __Acquire__ — schedules the first @requestAnimationFrame@ callback,
+--   which re-schedules itself on every invocation.
+-- * __Release__ — calls 'Miso.DSL.freeFunction' to cancel the callback
+--   and release the JS reference when the component unmounts.
+--
+-- = See also
+--
+-- * "Miso.Canvas" — canvas drawing API driven by 'rAFSub' ticks
+-- * "Miso.Subscription.Util" — 'Miso.Subscription.Util.createSub'
+-- * "Miso.Subscription" — re-export hub
+----------------------------------------------------------------------------
+module Miso.Subscription.RAF
+  ( rAFSub
+  , rAFSubElapsed
+  ) where
+----------------------------------------------------------------------------
+import           Data.IORef
+----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.Effect (Sub)
+import           Miso.Subscription.Util (createSub)
+----------------------------------------------------------------------------
+-- | A 'Sub' for 60FPS animations when using 'requestAnimationFrame'.
+--
+-- The 'Double' returned is a [DOMHighResTimeStamp](https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp) expressed in milliseconds.
+--
+rAFSub
+  :: (Double -> action)
+  -- ^ Callback fired each frame with a @DOMHighResTimeStamp@ in milliseconds
+  -> Sub model action
+rAFSub toAction sink = createSub acquire release sink
+  where
+    acquire = do
+      cbRef <- newIORef (error "rAFSub: uninitialized, impossible")
+      idRef <- newIORef (0 :: Int)
+      callback <-
+        syncCallback1 $ \jsval -> do
+          sink . toAction =<< fromJSValUnchecked jsval
+          writeIORef idRef =<< requestAnimationFrame =<< readIORef cbRef
+
+      writeIORef cbRef callback
+      writeIORef idRef =<< requestAnimationFrame callback
+      pure (callback, idRef)
+
+    -- N.B. the queued frame must be cancelled before the callback is
+    -- freed: the browser holds a reference to it, and invoking a freed
+    -- callback on the next frame crashes the runtime.
+    release (callback, idRef) = do
+      cancelAnimationFrame =<< readIORef idRef
+      freeFunction (Function callback)
+----------------------------------------------------------------------------
+-- | Like 'rAFSub' but fires @action@ at most once per @interval@ milliseconds.
+--
+-- Elapsed time is accumulated in 'IORef's inside the subscription so the
+-- model is not touched between ticks — Miso only re-renders when a tick
+-- actually fires, rather than on every animation frame.
+--
+-- @
+-- app = defaultApp model update view
+--   { subs = [ rAFSubElapsed 175 Tick ] }
+-- @
+--
+rAFSubElapsed
+  :: Double
+  -- ^ Minimum interval between ticks in milliseconds (e.g. @175@ for ~6 fps)
+  -> action
+  -- ^ Action to dispatch each time the interval elapses
+  -> Sub model action
+rAFSubElapsed interval action sink = createSub acquire release sink
+  where
+    acquire = do
+      cbRef <- newIORef (error "rAFSubElapsed: uninitialized, impossible")
+      idRef <- newIORef (0 :: Int)
+      let go lastT elap = do
+            cb <- syncCallback1 $ \jsval -> do
+              t <- fromJSValUnchecked jsval
+              let dt      = if lastT == 0 then 0 else min interval (t - lastT)
+                  newElap = elap + dt
+              if newElap >= interval
+                then sink action *> go t (newElap - interval)
+                else go t newElap
+            writeIORef cbRef cb
+            writeIORef idRef =<< requestAnimationFrame cb
+      go 0 0
+      pure (cbRef, idRef)
+    -- N.B. cancel the queued frame before freeing the callback (see 'rAFSub')
+    release (cbRef, idRef) = do
+      cancelAnimationFrame =<< readIORef idRef
+      freeFunction . Function =<< readIORef cbRef
+----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription/Util.hs b/src/Miso/Subscription/Util.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription/Util.hs
@@ -0,0 +1,89 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE CPP #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription.Util
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Subscription.Util" provides 'createSub', the building block used
+-- by every subscription in "Miso.Subscription". It handles the
+-- acquire-use-release lifecycle of an external resource (an event
+-- listener, an animation-frame callback, etc.) using
+-- 'Control.Exception.bracket' so the resource is always cleaned up when
+-- the t'Miso.Types.Component' unmounts, even if an exception is thrown.
+--
+-- = Quick start
+--
+-- Use 'createSub' to build a custom subscription from any pair of
+-- acquire\/release actions. The subscription sleeps between polls and
+-- relies entirely on the acquire step to register whatever callbacks
+-- deliver events to the sink:
+--
+-- @
+-- import "Miso.Subscription.Util" ('createSub')
+-- import "Miso.Effect" ('Sub')
+-- import qualified "Miso.FFI.Internal" as FFI
+--
+-- -- Custom subscription: fire an action whenever the window is resized
+-- resizeSub :: (Int -> action) -> 'Sub' action
+-- resizeSub toAction sink = 'createSub' acquire release sink
+--   where
+--     acquire =
+--       FFI.'Miso.FFI.Internal.windowAddEventListener' \"resize\" $ \\_ -> do
+--         w <- FFI.'Miso.FFI.Internal.windowInnerWidth'
+--         sink (toAction w)
+--     release cb =
+--       FFI.'Miso.FFI.Internal.windowRemoveEventListener' \"resize\" cb
+-- @
+--
+-- = How it works
+--
+-- @'createSub' acquire release sink@ runs:
+--
+-- @
+-- 'Control.Exception.bracket' acquire release (\\_ -> forever (threadDelay 10000_000_000))
+-- @
+--
+-- The @forever@ loop keeps the subscription thread alive by sleeping in
+-- very long increments. All actual work is done inside callbacks
+-- registered during @acquire@, which call @sink@ directly. @release@ is
+-- guaranteed to run (via 'Control.Exception.bracket') when the component
+-- teardown kills the thread.
+--
+-- = See also
+--
+-- * "Miso.Effect" — 'Miso.Effect.Sub', 'Miso.Effect.Sink'
+-- * "Miso.FFI.Internal" — 'Miso.FFI.Internal.windowAddEventListener',
+--   'Miso.FFI.Internal.windowRemoveEventListener'
+-- * "Miso.Subscription" — all built-in subscriptions
+----------------------------------------------------------------------------
+module Miso.Subscription.Util
+   ( -- ** Utilities
+     createSub
+   ) where
+----------------------------------------------------------------------------
+import           Control.Concurrent (threadDelay)
+import           Control.Monad (forever)
+import           Control.Exception (bracket)
+-----------------------------------------------------------------------------
+import           Miso.Effect
+-----------------------------------------------------------------------------
+-- | Utility function to allow resource finalization on 'Sub'.
+createSub
+  :: IO a
+  -- ^ Acquire resource
+  -> (a -> IO b)
+  -- ^ Release resource
+  -> Sub model action
+createSub acquire release = \_ _ ->
+  bracket acquire release (\_ -> forever (threadDelay (secs 10000)))
+    where
+      secs :: Int -> Int
+      secs = (*1000000)
+----------------------------------------------------------------------------
diff --git a/src/Miso/Subscription/Window.hs b/src/Miso/Subscription/Window.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Subscription/Window.hs
@@ -0,0 +1,142 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE RecordWildCards   #-}
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Subscription.Window
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Subscription.Window" provides subscriptions that listen to
+-- <https://developer.mozilla.org/en-US/docs/Web/API/Window#events window-level events>.
+-- It also exposes 'windowSub' and 'windowSubWithOptions' as the generic
+-- primitives on which 'Miso.Subscription.Mouse.mouseSub' and other
+-- per-event wrappers are built.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Subscription.Window"
+--
+-- data Action
+--   = MouseMoved 'Miso.Canvas.Coord'         -- (clientX, clientY)
+--   | PointerMoved 'Miso.Event.Types.PointerEvent' -- full pointer data
+--
+-- subs :: ['Miso.Effect.Sub' Action]
+-- subs =
+--   [ 'windowCoordsSub'      MouseMoved    -- simple (x, y) pair
+--   , 'windowPointerMoveSub' PointerMoved  -- full PointerEvent
+--   ]
+-- @
+--
+-- = Subscription variants
+--
+-- * 'windowCoordsSub' — fires @(clientX, clientY)@ as a 'Miso.Canvas.Coord'
+--   on every @pointermove@. Simplest option when only screen position is needed.
+--
+-- * 'windowPointerMoveSub' — fires the full 'Miso.Event.Types.PointerEvent'
+--   (pressure, tilt, pointer type, …) on every @pointermove@.
+--
+-- * 'windowSub' — listen to __any named window event__ by providing an event
+--   name and a 'Miso.Event.Decoder.Decoder':
+--
+-- @
+-- resizeSub :: ('Miso.Canvas.Coord' -> action) -> 'Miso.Effect.Sub' action
+-- resizeSub f = 'windowSub' \"resize\" 'Miso.Event.Decoder.emptyDecoder' (const (f (0,0)))
+-- @
+--
+-- * 'windowSubWithOptions' — same as 'windowSub' but accepts
+--   'Miso.Event.Types.Options' to call @preventDefault@ or @stopPropagation@
+--   on the raw event before forwarding it.
+--
+-- = See also
+--
+-- * "Miso.Subscription.Mouse" — 'Miso.Subscription.Mouse.mouseSub' (thin alias over 'windowPointerMoveSub')
+-- * "Miso.Event.Decoder" — 'Miso.Event.Decoder.Decoder', 'Miso.Event.Decoder.pointerDecoder'
+-- * "Miso.Event.Types" — 'Miso.Event.Types.PointerEvent', 'Miso.Event.Types.Options'
+-- * "Miso.Subscription.Util" — 'Miso.Subscription.Util.createSub' used internally
+----------------------------------------------------------------------------
+module Miso.Subscription.Window
+  ( -- *** Subscription
+    windowSub
+  , windowCoordsSub
+  , windowPointerMoveSub
+  , windowSubWithOptions
+  -- *** Types
+  , Coord
+  ) where
+-----------------------------------------------------------------------------
+import           Control.Monad
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.Event
+import           Miso.Effect
+import qualified Miso.FFI.Internal as FFI
+import           Miso.JSON hiding (Options, defaultOptions)
+import           Miso.String
+import           Miso.Subscription.Util
+import           Miso.Canvas (Coord)
+-----------------------------------------------------------------------------
+-- | Captures window coordinates changes as they occur and writes them to
+-- an event sink.
+windowCoordsSub
+  :: (Coord -> action)
+  -- ^ Callback fired with @(clientX, clientY)@ on every @pointermove@ event
+  -> Sub model action
+windowCoordsSub f = windowPointerMoveSub (f . client)
+-----------------------------------------------------------------------------
+-- | @windowSub eventName decoder toAction@ provides a subscription
+-- to listen to [window level events](https://developer.mozilla.org/en-US/docs/Web/API/Window#events).
+windowSub
+  :: MisoString
+  -- ^ DOM event name to listen for on @window@ (e.g. @\"resize\"@, @\"pointermove\"@)
+  -> Decoder r
+  -- ^ t'Decoder' for extracting a value from the raw event object
+  -> (r -> action)
+  -- ^ Callback fired with the decoded value on each event
+  -> Sub model action
+windowSub = windowSubWithOptions defaultOptions
+-----------------------------------------------------------------------------
+-- | @windowSubWithOptions options eventName decoder toAction@ provides a
+-- subscription to listen to [window level events](https://developer.mozilla.org/en-US/docs/Web/API/Window#events).
+windowSubWithOptions
+  :: Options
+  -- ^ Propagation options (@preventDefault@, @stopPropagation@)
+  -> MisoString
+  -- ^ DOM event name to listen for on @window@
+  -> Decoder result
+  -- ^ t'Decoder' for extracting a value from the raw event object
+  -> (result -> action)
+  -- ^ Callback fired with the decoded value on each event
+  -> Sub model action
+windowSubWithOptions Options{..} eventName Decoder {..} toAction sink =
+  createSub acquire release sink
+    where
+      release =
+        FFI.windowRemoveEventListener eventName
+      acquire =
+        FFI.windowAddEventListener eventName $ \e -> do
+          decodeAtVal <- toJSVal decodeAt
+          v <- fromJSValUnchecked =<< FFI.eventJSON decodeAtVal e
+          case parseEither decoder v of
+            Left s ->
+              FFI.consoleError ("windowSubWithOptions: Parse error on " <> eventName <> ": " <> ms s)
+            Right r -> do
+              when _stopPropagation (FFI.eventStopPropagation e)
+              when _preventDefault (FFI.eventPreventDefault e)
+              sink (toAction r)
+-----------------------------------------------------------------------------
+-- | @window.addEventListener ("pointermove", (event) => handle(event))@
+-- A 'Sub' to handle t'PointerEvent's on window.
+windowPointerMoveSub
+  :: (PointerEvent -> action)
+  -- ^ Callback fired with the full t'PointerEvent' on every @pointermove@
+  -> Sub model action
+windowPointerMoveSub = windowSub "pointermove" pointerDecoder
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Svg.hs b/src/Miso/Svg.hs
--- a/src/Miso/Svg.hs
+++ b/src/Miso/Svg.hs
@@ -1,37 +1,63 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Svg
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
 --
--- Example usage:
+-- = Overview
 --
+-- "Miso.Svg" is the re-export hub for miso's SVG DSL. It re-exports
+-- "Miso.Svg.Element" (all SVG element constructors) and "Miso.Svg.Event"
+-- (SVG-specific event handlers).
+--
+-- SVG property\/attribute combinators live in "Miso.Svg.Property" and
+-- must be imported separately when needed.
+--
+-- = Quick start
+--
+-- Embed an SVG circle inside a miso view:
+--
 -- @
--- import Miso
--- import Miso.Svg
+-- import "Miso"
+-- import "Miso.Svg"
+-- import qualified "Miso.Svg.Property" as SP
 --
--- intView :: Int -> View IntAction
--- intView n = svg_ [ height_ "100", width "100" ] [
---    circle_ [ cx_ "50", cy_ "50", r_ "40", stroke_ "green", strokeWidth_ "4", fill_ "yellow" ] []
---  ]
+-- badge :: 'Miso.Types.View' model action
+-- badge =
+--   @svg_@ [ SP.'Miso.Svg.Property.width_' \"100\", SP.'Miso.Svg.Property.height_' \"100\" ]
+--     [ 'Miso.Svg.Element.circle_'
+--         [ SP.'Miso.Svg.Property.cx_' \"50\", SP.'Miso.Svg.Property.cy_' \"50\"
+--         , SP.'Miso.Svg.Property.r_' \"40\"
+--         , SP.'Miso.Svg.Property.stroke_' \"green\"
+--         , SP.'Miso.Svg.Property.strokeWidth_' \"4\"
+--         , SP.'Miso.Svg.Property.fill_' \"yellow\"
+--         ]
+--     ]
 -- @
 --
--- More information on how to use `miso` is available on GitHub
+-- = Modules
 --
--- <http://github.com/dmjio/miso>
+-- * "Miso.Svg.Element" — SVG element constructors (@svg_@, @circle_@, @path_@, @g_@, …)
+-- * "Miso.Svg.Event"   — SVG event handlers (@onBegin@, @onEnd@, @onClick@, …)
+-- * "Miso.Svg.Property" — SVG attribute combinators (@cx_@, @r_@, @fill_@, @stroke_@, …)
+--   /(not re-exported here — import separately)/
 --
+-- = See also
+--
+-- * "Miso.Html.Element" — HTML element constructors
+-- * "Miso.Mathml.Element" — MathML element constructors
+-- * <https://developer.mozilla.org/en-US/docs/Web/SVG MDN SVG reference>
 ----------------------------------------------------------------------------
 module Miso.Svg
-   ( module Miso.Svg.Element
-   , module Miso.Svg.Attribute
+   ( -- ** Element
+     module Miso.Svg.Element
+     -- ** Event
    , module Miso.Svg.Event
    ) where
-
-import Miso.Svg.Attribute hiding ( filter_, path_, title_, mask_
-                               , glyphRef_, clipPath_, colorProfile_
-                               , cursor_, style_ )
+-----------------------------------------------------------------------------
 import Miso.Svg.Element
 import Miso.Svg.Event
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Svg/Attribute.hs b/src/Miso/Svg/Attribute.hs
deleted file mode 100644
--- a/src/Miso/Svg/Attribute.hs
+++ /dev/null
@@ -1,1038 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE OverloadedStrings #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Miso.Svg.Attribute
--- Copyright   :  (C) 2016-2018 David M. Johnson
--- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
--- Stability   :  experimental
--- Portability :  non-portable
---
--- <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute>
---
-----------------------------------------------------------------------------
-module Miso.Svg.Attribute
-  ( -- * Regular attributes
-    accentHeight_
-  , accelerate_
-  , accumulate_
-  , additive_
-  , alphabetic_
-  , allowReorder_
-  , amplitude_
-  , arabicForm_
-  , ascent_
-  , attributeName_
-  , attributeType_
-  , autoReverse_
-  , azimuth_
-  , baseFrequency_
-  , baseProfile_
-  , bbox_
-  , begin_
-  , bias_
-  , by_
-  , calcMode_
-  , capHeight_
-  , class_'
-  , clipPathUnits_
-  , contentScriptType_
-  , contentStyleType_
-  , cx_
-  , cy_
-  , d_
-  , decelerate_
-  , descent_
-  , diffuseConstant_
-  , divisor_
-  , dur_
-  , dx_
-  , dy_
-  , edgeMode_
-  , elevation_
-  , end_
-  , exponent_
-  , externalResourcesRequired_
-  , filterRes_
-  , filterUnits_
-  , format_
-  , from_
-  , fx_
-  , fy_
-  , g1_
-  , g2_
-  , glyphName_
-  , glyphRef_
-  , gradientTransform_
-  , gradientUnits_
-  , hanging_
-  , height_
-  , horizAdvX_
-  , horizOriginX_
-  , horizOriginY_
-  , id_
-  , ideographic_
-  , in_'
-  , in2_
-  , intercept_
-  , k_
-  , k1_
-  , k2_
-  , k3_
-  , k4_
-  , kernelMatrix_
-  , kernelUnitLength_
-  , keyPoints_
-  , keySplines_
-  , keyTimes_
-  , lang_
-  , lengthAdjust_
-  , limitingConeAngle_
-  , local_
-  , markerHeight_
-  , markerUnits_
-  , markerWidth_
-  , maskContentUnits_
-  , maskUnits_
-  , mathematical_
-  , max_
-  , media_
-  , method_
-  , min_
-  , mode_
-  , name_
-  , numOctaves_
-  , offset_
-  , operator_
-  , order_
-  , orient_
-  , orientation_
-  , origin_
-  , overlinePosition_
-  , overlineThickness_
-  , panose1_
-  , path_
-  , pathLength_
-  , patternContentUnits_
-  , patternTransform_
-  , patternUnits_
-  , pointOrder_
-  , points_
-  , pointsAtX_
-  , pointsAtY_
-  , pointsAtZ_
-  , preserveAlpha_
-  , preserveAspectRatio_
-  , primitiveUnits_
-  , r_
-  , radius_
-  , refX_
-  , refY_
-  , renderingIntent_
-  , repeatCount_
-  , repeatDur_
-  , requiredExtensions_
-  , requiredFeatures_
-  , restart_
-  , result_
-  , rotate_
-  , rx_
-  , ry_
-  , scale_
-  , seed_
-  , slope_
-  , spacing_
-  , specularConstant_
-  , specularExponent_
-  , speed_
-  , spreadMethod_
-  , startOffset_
-  , stdDeviation_
-  , stemh_
-  , stemv_
-  , stitchTiles_
-  , strikethroughPosition_
-  , strikethroughThickness_
-  , string_
-  , style_
-  , surfaceScale_
-  , systemLanguage_
-  , tableValues_
-  , target_
-  , targetX_
-  , targetY_
-  , textLength_
-  , title_
-  , to_
-  , transform_
-  , type_'
-  , u1_
-  , u2_
-  , underlinePosition_
-  , underlineThickness_
-  , unicode_
-  , unicodeRange_
-  , unitsPerEm_
-  , vAlphabetic_
-  , vHanging_
-  , vIdeographic_
-  , vMathematical_
-  , values_
-  , version_
-  , vertAdvY_
-  , vertOriginX_
-  , vertOriginY_
-  , viewBox_
-  , viewTarget_
-  , width_
-  , widths_
-  , x_
-  , xHeight_
-  , x1_
-  , x2_
-  , xChannelSelector_
-  , xlinkActuate_
-  , xlinkArcrole_
-  , xlinkHref_
-  , xlinkRole_
-  , xlinkShow_
-  , xlinkTitle_
-  , xlinkType_
-  , xmlBase_
-  , xmlLang_
-  , xmlSpace_
-  , y_
-  , y1_
-  , y2_
-  , yChannelSelector_
-  , z_
-  , zoomAndPan_
-  -- * Presentation_ attributes
-  , alignmentBaseline_
-  , baselineShift_
-  , clipPath_
-  , clipRule_
-  , clip_
-  , colorInterpolationFilters_
-  , colorInterpolation_
-  , colorProfile_
-  , colorRendering_
-  , color_
-  , cursor_
-  , direction_
-  , display_
-  , dominantBaseline_
-  , enableBackground_
-  , fillOpacity_
-  , fillRule_
-  , fill_
-  , filter_
-  , floodColor_
-  , floodOpacity_
-  , fontFamily_
-  , fontSizeAdjust_
-  , fontSize_
-  , fontStretch_
-  , fontStyle_
-  , fontVariant_
-  , fontWeight_
-  , glyphOrientationHorizontal_
-  , glyphOrientationVertical_
-  , imageRendering_
-  , kerning_
-  , letterSpacing_
-  , lightingColor_
-  , markerEnd_
-  , markerMid_
-  , markerStart_
-  , mask_
-  , opacity_
-  , overflow_
-  , pointerEvents_
-  , shapeRendering_
-  , stopColor_
-  , stopOpacity_
-  , strokeDasharray_
-  , strokeDashoffset_
-  , strokeLinecap_
-  , strokeLinejoin_
-  , strokeMiterlimit_
-  , strokeOpacity_
-  , strokeWidth_
-  , stroke_
-  , textAnchor_
-  , textDecoration_
-  , textRendering_
-  , unicodeBidi_
-  , visibility_
-  , wordSpacing_
-  , writingMode_
-  ) where
-
-import Miso.Html.Internal ( Attribute )
-import Miso.Html.Property ( textProp )
-import Miso.String        ( MisoString )
-
-attr :: MisoString -> MisoString -> Attribute action
-attr = textProp
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/accent-height>
-accentHeight_ ::  MisoString -> Attribute action
-accentHeight_ = attr "accent-height"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/accelerate>
-accelerate_ ::  MisoString -> Attribute action
-accelerate_ = attr "accelerate"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/accumulate>
-accumulate_ ::  MisoString -> Attribute action
-accumulate_ = attr "accumulate"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/additive>
-additive_ ::  MisoString -> Attribute action
-additive_ = attr "additive"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/alphabetic>
-alphabetic_ ::  MisoString -> Attribute action
-alphabetic_ = attr "alphabetic"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/allowReorder>
-allowReorder_ ::  MisoString -> Attribute action
-allowReorder_ = attr "allowReorder"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/amplitude>
-amplitude_ ::  MisoString -> Attribute action
-amplitude_ = attr "amplitude"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/arabic-form>
-arabicForm_ ::  MisoString -> Attribute action
-arabicForm_ = attr "arabic-form"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/ascent>
-ascent_ ::  MisoString -> Attribute action
-ascent_ = attr "ascent"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/attributeName>
-attributeName_ ::  MisoString -> Attribute action
-attributeName_ = attr "attributeName"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/attributeType>
-attributeType_ ::  MisoString -> Attribute action
-attributeType_ = attr "attributeType"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/autoReverse>
-autoReverse_ ::  MisoString -> Attribute action
-autoReverse_ = attr "autoReverse"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/azimuth>
-azimuth_ ::  MisoString -> Attribute action
-azimuth_ = attr "azimuth"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/baseFrequency>
-baseFrequency_ ::  MisoString -> Attribute action
-baseFrequency_ = attr "baseFrequency"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/baseProfile>
-baseProfile_ ::  MisoString -> Attribute action
-baseProfile_ = attr "baseProfile"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/bbox>
-bbox_ ::  MisoString -> Attribute action
-bbox_ = attr "bbox"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/begin>
-begin_ ::  MisoString -> Attribute action
-begin_ = attr "begin"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/bias>
-bias_ ::  MisoString -> Attribute action
-bias_ = attr "bias"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/by>
-by_ ::  MisoString -> Attribute action
-by_ = attr "by"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/calcMode>
-calcMode_ ::  MisoString -> Attribute action
-calcMode_ = attr "calcMode"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cap-height>
-capHeight_ ::  MisoString -> Attribute action
-capHeight_ = attr "cap-height"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/class>
-class_' ::  MisoString -> Attribute action
-class_' = attr "class"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clipPathUnits>
-clipPathUnits_ ::  MisoString -> Attribute action
-clipPathUnits_ = attr "clipPathUnits"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/contentScriptType>
-contentScriptType_ ::  MisoString -> Attribute action
-contentScriptType_ = attr "contentScriptType"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/contentStyleType>
-contentStyleType_ ::  MisoString -> Attribute action
-contentStyleType_ = attr "contentStyleType"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cx>
-cx_ ::  MisoString -> Attribute action
-cx_ = attr "cx"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cy>
-cy_ ::  MisoString -> Attribute action
-cy_ = attr "cy"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d>
-d_ ::  MisoString -> Attribute action
-d_ = attr "d"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/decelerate>
-decelerate_ ::  MisoString -> Attribute action
-decelerate_ = attr "decelerate"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/descent>
-descent_ ::  MisoString -> Attribute action
-descent_ = attr "descent"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/diffuseConstant>
-diffuseConstant_ ::  MisoString -> Attribute action
-diffuseConstant_ = attr "diffuseConstant"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/divisor>
-divisor_ ::  MisoString -> Attribute action
-divisor_ = attr "divisor"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dur>
-dur_ ::  MisoString -> Attribute action
-dur_ = attr "dur"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dx>
-dx_ ::  MisoString -> Attribute action
-dx_ = attr "dx"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dy>
-dy_ ::  MisoString -> Attribute action
-dy_ = attr "dy"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/edgeMode>
-edgeMode_ ::  MisoString -> Attribute action
-edgeMode_ = attr "edgeMode"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/elevation>
-elevation_ ::  MisoString -> Attribute action
-elevation_ = attr "elevation"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/end>
-end_ ::  MisoString -> Attribute action
-end_ = attr "end"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/exponent>
-exponent_ ::  MisoString -> Attribute action
-exponent_ = attr "exponent"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/externalResourcesRequired>
-externalResourcesRequired_ ::  MisoString -> Attribute action
-externalResourcesRequired_ = attr "externalResourcesRequired"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/filterRes>
-filterRes_ ::  MisoString -> Attribute action
-filterRes_ = attr "filterRes"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/filterUnits>
-filterUnits_ ::  MisoString -> Attribute action
-filterUnits_ = attr "filterUnits"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/format>
-format_ ::  MisoString -> Attribute action
-format_ = attr "format"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/from>
-from_ ::  MisoString -> Attribute action
-from_ = attr "from"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fx>
-fx_ ::  MisoString -> Attribute action
-fx_ = attr "fx"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fy>
-fy_ ::  MisoString -> Attribute action
-fy_ = attr "fy"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/g1>
-g1_ ::  MisoString -> Attribute action
-g1_ = attr "g1"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/g2>
-g2_ ::  MisoString -> Attribute action
-g2_ = attr "g2"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/glyph-name>
-glyphName_ ::  MisoString -> Attribute action
-glyphName_ = attr "glyph-name"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/glyphRef>
-glyphRef_ ::  MisoString -> Attribute action
-glyphRef_ = attr "glyphRef"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientTransform>
-gradientTransform_ ::  MisoString -> Attribute action
-gradientTransform_ = attr "gradientTransform"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientUnits>
-gradientUnits_ ::  MisoString -> Attribute action
-gradientUnits_ = attr "gradientUnits"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/hanging>
-hanging_ ::  MisoString -> Attribute action
-hanging_ = attr "hanging"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height>
-height_ ::  MisoString -> Attribute action
-height_ = attr "height"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/horiz-adv-x>
-horizAdvX_ ::  MisoString -> Attribute action
-horizAdvX_ = attr "horiz-adv-x"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/horiz-origin-x>
-horizOriginX_ ::  MisoString -> Attribute action
-horizOriginX_ = attr "horiz-origin-x"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/horiz-origin-y>
-horizOriginY_ ::  MisoString -> Attribute action
-horizOriginY_ = attr "horiz-origin-y"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/id>
-id_ ::  MisoString -> Attribute action
-id_ = attr "id"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/ideographic>
-ideographic_ ::  MisoString -> Attribute action
-ideographic_ = attr "ideographic"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/in>
-in_' ::  MisoString -> Attribute action
-in_' = attr "in"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/in2>
-in2_ ::  MisoString -> Attribute action
-in2_ = attr "in2"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/intercept>
-intercept_ ::  MisoString -> Attribute action
-intercept_ = attr "intercept"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k>
-k_ ::  MisoString -> Attribute action
-k_ = attr "k"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k1>
-k1_ ::  MisoString -> Attribute action
-k1_ = attr "k1"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k2>
-k2_ ::  MisoString -> Attribute action
-k2_ = attr "k2"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k3>
-k3_ ::  MisoString -> Attribute action
-k3_ = attr "k3"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k4>
-k4_ ::  MisoString -> Attribute action
-k4_ = attr "k4"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kernelMatrix>
-kernelMatrix_ ::  MisoString -> Attribute action
-kernelMatrix_ = attr "kernelMatrix"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kernelUnitLength>
-kernelUnitLength_ ::  MisoString -> Attribute action
-kernelUnitLength_ = attr "kernelUnitLength"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keyPoints>
-keyPoints_ ::  MisoString -> Attribute action
-keyPoints_ = attr "keyPoints"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keySplines>
-keySplines_ ::  MisoString -> Attribute action
-keySplines_ = attr "keySplines"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keyTimes>
-keyTimes_ ::  MisoString -> Attribute action
-keyTimes_ = attr "keyTimes"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/lang>
-lang_ ::  MisoString -> Attribute action
-lang_ = attr "lang"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/lengthAdjust>
-lengthAdjust_ ::  MisoString -> Attribute action
-lengthAdjust_ = attr "lengthAdjust"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/limitingConeAngle>
-limitingConeAngle_ ::  MisoString -> Attribute action
-limitingConeAngle_ = attr "limitingConeAngle"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/local>
-local_ ::  MisoString -> Attribute action
-local_ = attr "local"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/markerHeight>
-markerHeight_ ::  MisoString -> Attribute action
-markerHeight_ = attr "markerHeight"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/markerUnits>
-markerUnits_ ::  MisoString -> Attribute action
-markerUnits_ = attr "markerUnits"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/markerWidth>
-markerWidth_ ::  MisoString -> Attribute action
-markerWidth_ = attr "markerWidth"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/maskContentUnits>
-maskContentUnits_ ::  MisoString -> Attribute action
-maskContentUnits_ = attr "maskContentUnits"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/maskUnits>
-maskUnits_ ::  MisoString -> Attribute action
-maskUnits_ = attr "maskUnits"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/mathematical>
-mathematical_ ::  MisoString -> Attribute action
-mathematical_ = attr "mathematical"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/max>
-max_ ::  MisoString -> Attribute action
-max_ = attr "max"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/media>
-media_ ::  MisoString -> Attribute action
-media_ = attr "media"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/method>
-method_ ::  MisoString -> Attribute action
-method_ = attr "method"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/min>
-min_ ::  MisoString -> Attribute action
-min_ = attr "min"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/mode>
-mode_ ::  MisoString -> Attribute action
-mode_ = attr "mode"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/name>
-name_ ::  MisoString -> Attribute action
-name_ = attr "name"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/numOctaves>
-numOctaves_ ::  MisoString -> Attribute action
-numOctaves_ = attr "numOctaves"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/offset>
-offset_ ::  MisoString -> Attribute action
-offset_ = attr "offset"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/operator>
-operator_ ::  MisoString -> Attribute action
-operator_ = attr "operator"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/order>
-order_ ::  MisoString -> Attribute action
-order_ = attr "order"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/orient>
-orient_ ::  MisoString -> Attribute action
-orient_ = attr "orient"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/orientation>
-orientation_ ::  MisoString -> Attribute action
-orientation_ = attr "orientation"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/origin>
-origin_ ::  MisoString -> Attribute action
-origin_ = attr "origin"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/overline-position>
-overlinePosition_ ::  MisoString -> Attribute action
-overlinePosition_ = attr "overline-position"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/overline-thickness>
-overlineThickness_ ::  MisoString -> Attribute action
-overlineThickness_ = attr "overline-thickness"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/panose-1>
-panose1_ ::  MisoString -> Attribute action
-panose1_ = attr "panose-1"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/path>
-path_ ::  MisoString -> Attribute action
-path_ = attr "path"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pathLength>
-pathLength_ ::  MisoString -> Attribute action
-pathLength_ = attr "pathLength"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternContentUnits>
-patternContentUnits_ ::  MisoString -> Attribute action
-patternContentUnits_ = attr "patternContentUnits"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternTransform>
-patternTransform_ ::  MisoString -> Attribute action
-patternTransform_ = attr "patternTransform"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternUnits>
-patternUnits_ ::  MisoString -> Attribute action
-patternUnits_ = attr "patternUnits"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/point-order>
-pointOrder_ ::  MisoString -> Attribute action
-pointOrder_ = attr "point-order"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/points>
-points_ ::  MisoString -> Attribute action
-points_ = attr "points"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointsAtX>
-pointsAtX_ ::  MisoString -> Attribute action
-pointsAtX_ = attr "pointsAtX"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointsAtY>
-pointsAtY_ ::  MisoString -> Attribute action
-pointsAtY_ = attr "pointsAtY"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointsAtZ>
-pointsAtZ_ ::  MisoString -> Attribute action
-pointsAtZ_ = attr "pointsAtZ"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAlpha>
-preserveAlpha_ ::  MisoString -> Attribute action
-preserveAlpha_ = attr "preserveAlpha"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio>
-preserveAspectRatio_ ::  MisoString -> Attribute action
-preserveAspectRatio_ = attr "preserveAspectRatio"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/primitiveUnits>
-primitiveUnits_ ::  MisoString -> Attribute action
-primitiveUnits_ = attr "primitiveUnits"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/r>
-r_ ::  MisoString -> Attribute action
-r_ = attr "r"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/radius>
-radius_ ::  MisoString -> Attribute action
-radius_ = attr "radius"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/refX>
-refX_ ::  MisoString -> Attribute action
-refX_ = attr "refX"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/refY>
-refY_ ::  MisoString -> Attribute action
-refY_ = attr "refY"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rendering-intent>
-renderingIntent_ ::  MisoString -> Attribute action
-renderingIntent_ = attr "rendering-intent"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/repeatCount>
-repeatCount_ ::  MisoString -> Attribute action
-repeatCount_ = attr "repeatCount"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/repeatDur>
-repeatDur_ ::  MisoString -> Attribute action
-repeatDur_ = attr "repeatDur"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/requiredExtensions>
-requiredExtensions_ ::  MisoString -> Attribute action
-requiredExtensions_ = attr "requiredExtensions"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/requiredFeatures>
-requiredFeatures_ ::  MisoString -> Attribute action
-requiredFeatures_ = attr "requiredFeatures"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/restart>
-restart_ ::  MisoString -> Attribute action
-restart_ = attr "restart"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/result>
-result_ ::  MisoString -> Attribute action
-result_ = attr "result"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rotate>
-rotate_ ::  MisoString -> Attribute action
-rotate_ = attr "rotate"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rx>
-rx_ ::  MisoString -> Attribute action
-rx_ = attr "rx"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/ry>
-ry_ ::  MisoString -> Attribute action
-ry_ = attr "ry"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/scale>
-scale_ ::  MisoString -> Attribute action
-scale_ = attr "scale"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/seed>
-seed_ ::  MisoString -> Attribute action
-seed_ = attr "seed"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/slope>
-slope_ ::  MisoString -> Attribute action
-slope_ = attr "slope"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/spacing>
-spacing_ ::  MisoString -> Attribute action
-spacing_ = attr "spacing"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/specularConstant>
-specularConstant_ ::  MisoString -> Attribute action
-specularConstant_ = attr "specularConstant"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/specularExponent>
-specularExponent_ ::  MisoString -> Attribute action
-specularExponent_ = attr "specularExponent"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/speed>
-speed_ ::  MisoString -> Attribute action
-speed_ = attr "speed"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/spreadMethod>
-spreadMethod_ ::  MisoString -> Attribute action
-spreadMethod_ = attr "spreadMethod"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/startOffset>
-startOffset_ ::  MisoString -> Attribute action
-startOffset_ = attr "startOffset"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stdDeviation>
-stdDeviation_ ::  MisoString -> Attribute action
-stdDeviation_ = attr "stdDeviation"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stemh>
-stemh_ ::  MisoString -> Attribute action
-stemh_ = attr "stemh"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stemv>
-stemv_ ::  MisoString -> Attribute action
-stemv_ = attr "stemv"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stitchTiles>
-stitchTiles_ ::  MisoString -> Attribute action
-stitchTiles_ = attr "stitchTiles"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/strikethrough-position>
-strikethroughPosition_ ::  MisoString -> Attribute action
-strikethroughPosition_ = attr "strikethrough-position"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/strikethrough-thickness>
-strikethroughThickness_ ::  MisoString -> Attribute action
-strikethroughThickness_ = attr "strikethrough-thickness"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/string>
-string_ ::  MisoString -> Attribute action
-string_ = attr "string"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/style>
-style_ ::  MisoString -> Attribute action
-style_ = attr "style"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/surfaceScale>
-surfaceScale_ ::  MisoString -> Attribute action
-surfaceScale_ = attr "surfaceScale"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/systemLanguage>
-systemLanguage_ ::  MisoString -> Attribute action
-systemLanguage_ = attr "systemLanguage"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/tableValues>
-tableValues_ ::  MisoString -> Attribute action
-tableValues_ = attr "tableValues"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/target>
-target_ ::  MisoString -> Attribute action
-target_ = attr "target"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/targetX>
-targetX_ ::  MisoString -> Attribute action
-targetX_ = attr "targetX"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/targetY>
-targetY_ ::  MisoString -> Attribute action
-targetY_ = attr "targetY"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/textLength>
-textLength_ ::  MisoString -> Attribute action
-textLength_ = attr "textLength"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/title>
-title_ ::  MisoString -> Attribute action
-title_ = attr "title"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/to>
-to_ ::  MisoString -> Attribute action
-to_ = attr "to"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform>
-transform_ ::  MisoString -> Attribute action
-transform_ = attr "transform"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/type>
-type_' ::  MisoString -> Attribute action
-type_' = attr "type"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/u1>
-u1_ ::  MisoString -> Attribute action
-u1_ = attr "u1"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/u2>
-u2_ ::  MisoString -> Attribute action
-u2_ = attr "u2"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/underline-position>
-underlinePosition_ ::  MisoString -> Attribute action
-underlinePosition_ = attr "underline-position"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/underline-thickness>
-underlineThickness_ ::  MisoString -> Attribute action
-underlineThickness_ = attr "underline-thickness"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/unicode>
-unicode_ ::  MisoString -> Attribute action
-unicode_ = attr "unicode"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/unicode-range>
-unicodeRange_ ::  MisoString -> Attribute action
-unicodeRange_ = attr "unicode-range"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/units-per-em>
-unitsPerEm_ ::  MisoString -> Attribute action
-unitsPerEm_ = attr "units-per-em"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/v-alphabetic>
-vAlphabetic_ ::  MisoString -> Attribute action
-vAlphabetic_ = attr "v-alphabetic"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/v-hanging>
-vHanging_ ::  MisoString -> Attribute action
-vHanging_ = attr "v-hanging"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/v-ideographic>
-vIdeographic_ ::  MisoString -> Attribute action
-vIdeographic_ = attr "v-ideographic"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/v-mathematical>
-vMathematical_ ::  MisoString -> Attribute action
-vMathematical_ = attr "v-mathematical"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/values>
-values_ ::  MisoString -> Attribute action
-values_ = attr "values"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/version>
-version_ ::  MisoString -> Attribute action
-version_ = attr "version"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/vert-adv-y>
-vertAdvY_ ::  MisoString -> Attribute action
-vertAdvY_ = attr "vert-adv-y"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/vert-origin-x>
-vertOriginX_ ::  MisoString -> Attribute action
-vertOriginX_ = attr "vert-origin-x"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/vert-origin-y>
-vertOriginY_ ::  MisoString -> Attribute action
-vertOriginY_ = attr "vert-origin-y"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox>
-viewBox_ ::  MisoString -> Attribute action
-viewBox_ = attr "viewBox"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewTarget>
-viewTarget_ ::  MisoString -> Attribute action
-viewTarget_ = attr "viewTarget"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width>
-width_ ::  MisoString -> Attribute action
-width_ = attr "width"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/widths>
-widths_ ::  MisoString -> Attribute action
-widths_ = attr "widths"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x>
-x_ ::  MisoString -> Attribute action
-x_ = attr "x"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x-height>
-xHeight_ ::  MisoString -> Attribute action
-xHeight_ = attr "x-height"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x1>
-x1_ ::  MisoString -> Attribute action
-x1_ = attr "x1"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x2>
-x2_ ::  MisoString -> Attribute action
-x2_ = attr "x2"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xChannelSelector>
-xChannelSelector_ ::  MisoString -> Attribute action
-xChannelSelector_ = attr "x-channel-selector"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkActuate>
-xlinkActuate_ ::  MisoString -> Attribute action
-xlinkActuate_ = attr "xlinkActuate"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkArcrole>
-xlinkArcrole_ ::  MisoString -> Attribute action
-xlinkArcrole_ = attr "xlinkArcrole"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkHref>
-xlinkHref_ ::  MisoString -> Attribute action
-xlinkHref_ = attr "xlinkHref"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkRole>
-xlinkRole_ ::  MisoString -> Attribute action
-xlinkRole_ = attr "xlinkRole"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkShow>
-xlinkShow_ ::  MisoString -> Attribute action
-xlinkShow_ = attr "xlinkShow"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkTitle>
-xlinkTitle_ ::  MisoString -> Attribute action
-xlinkTitle_ = attr "xlinkTitle"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkType>
-xlinkType_ ::  MisoString -> Attribute action
-xlinkType_ = attr "xlinkType"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xmlBase>
-xmlBase_ ::  MisoString -> Attribute action
-xmlBase_ = attr "xmlBase"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xmlLang>
-xmlLang_ ::  MisoString -> Attribute action
-xmlLang_ = attr "xmlLang"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xmlSpace>
-xmlSpace_ ::  MisoString -> Attribute action
-xmlSpace_ = attr "xmlSpace"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y>
-y_ ::  MisoString -> Attribute action
-y_ = attr "y"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y1>
-y1_ ::  MisoString -> Attribute action
-y1_ = attr "y1"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y2>
-y2_ ::  MisoString -> Attribute action
-y2_ = attr "y2"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/yChannelSelector>
-yChannelSelector_ ::  MisoString -> Attribute action
-yChannelSelector_ = attr "yChannelSelector"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/z>
-z_ ::  MisoString -> Attribute action
-z_ = attr "z"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/zoomAndPan>
-zoomAndPan_ ::  MisoString -> Attribute action
-zoomAndPan_ = attr "zoomAndPan"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/alignment-baseline>
-alignmentBaseline_ ::  MisoString -> Attribute action
-alignmentBaseline_ = attr "alignment-baseline"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/baseline-shift>
-baselineShift_ ::  MisoString -> Attribute action
-baselineShift_ = attr "baseline-shift"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clip-path>
-clipPath_ ::  MisoString -> Attribute action
-clipPath_ = attr "clip-path"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clip-rule>
-clipRule_ ::  MisoString -> Attribute action
-clipRule_ = attr "clip-rule"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clip>
-clip_ ::  MisoString -> Attribute action
-clip_ = attr "clip"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color-interpolation-filters>
-colorInterpolationFilters_ ::  MisoString -> Attribute action
-colorInterpolationFilters_ = attr "color-interpolation-filters"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color-interpolation>
-colorInterpolation_ ::  MisoString -> Attribute action
-colorInterpolation_ = attr "color-interpolation"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color-profile>
-colorProfile_ ::  MisoString -> Attribute action
-colorProfile_ = attr "color-profile"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color-rendering>
-colorRendering_ ::  MisoString -> Attribute action
-colorRendering_ = attr "color-rendering"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color>
-color_ ::  MisoString -> Attribute action
-color_ = attr "color"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cursor>
-cursor_ ::  MisoString -> Attribute action
-cursor_ = attr "cursor"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/direction>
-direction_ ::  MisoString -> Attribute action
-direction_ = attr "direction"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display>
-display_ ::  MisoString -> Attribute action
-display_ = attr "display"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dominant-baseline>
-dominantBaseline_ ::  MisoString -> Attribute action
-dominantBaseline_ = attr "dominant-baseline"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/enable-background>
-enableBackground_ ::  MisoString -> Attribute action
-enableBackground_ = attr "enable-background"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-opacity>
-fillOpacity_ ::  MisoString -> Attribute action
-fillOpacity_ = attr "fill-opacity"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule>
-fillRule_ ::  MisoString -> Attribute action
-fillRule_ = attr "fill-rule"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill>
-fill_ ::  MisoString -> Attribute action
-fill_ = attr "fill"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/filter>
-filter_ ::  MisoString -> Attribute action
-filter_ = attr "filter"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/flood-color>
-floodColor_ ::  MisoString -> Attribute action
-floodColor_ = attr "flood-color"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/flood-opacity>
-floodOpacity_ ::  MisoString -> Attribute action
-floodOpacity_ = attr "flood-opacity"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-family>
-fontFamily_ ::  MisoString -> Attribute action
-fontFamily_ = attr "font-family"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-size-adjust>
-fontSizeAdjust_ ::  MisoString -> Attribute action
-fontSizeAdjust_ = attr "font-size-adjust"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-size>
-fontSize_ ::  MisoString -> Attribute action
-fontSize_ = attr "font-size"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-stretch>
-fontStretch_ ::  MisoString -> Attribute action
-fontStretch_ = attr "font-stretch"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-style>
-fontStyle_ ::  MisoString -> Attribute action
-fontStyle_ = attr "font-style"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-variant>
-fontVariant_ ::  MisoString -> Attribute action
-fontVariant_ = attr "font-variant"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-weight>
-fontWeight_ ::  MisoString -> Attribute action
-fontWeight_ = attr "font-weight"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/glyph-orientation-horizontal>
-glyphOrientationHorizontal_ ::  MisoString -> Attribute action
-glyphOrientationHorizontal_ = attr "glyph-orientation-horizontal"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/glyph-orientation-vertical>
-glyphOrientationVertical_ ::  MisoString -> Attribute action
-glyphOrientationVertical_ = attr "glyph-orientation-vertical"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering>
-imageRendering_ ::  MisoString -> Attribute action
-imageRendering_ = attr "image-rendering"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kerning>
-kerning_ ::  MisoString -> Attribute action
-kerning_ = attr "kerning"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/letter-spacing>
-letterSpacing_ ::  MisoString -> Attribute action
-letterSpacing_ = attr "letter-spacing"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/lighting-color>
-lightingColor_ ::  MisoString -> Attribute action
-lightingColor_ = attr "lighting-color"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-end>
-markerEnd_ ::  MisoString -> Attribute action
-markerEnd_ = attr "marker-end"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-mid>
-markerMid_ ::  MisoString -> Attribute action
-markerMid_ = attr "marker-mid"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-start>
-markerStart_ ::  MisoString -> Attribute action
-markerStart_ = attr "marker-start"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/mask>
-mask_ ::  MisoString -> Attribute action
-mask_ = attr "mask"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/opacity>
-opacity_ ::  MisoString -> Attribute action
-opacity_ = attr "opacity"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/overflow>
-overflow_ ::  MisoString -> Attribute action
-overflow_ = attr "overflow"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointer-events>
-pointerEvents_ ::  MisoString -> Attribute action
-pointerEvents_ = attr "pointer-events"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering>
-shapeRendering_ ::  MisoString -> Attribute action
-shapeRendering_ = attr "shape-rendering"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stop-color>
-stopColor_ ::  MisoString -> Attribute action
-stopColor_ = attr "stop-color"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stop-opacity>
-stopOpacity_ ::  MisoString -> Attribute action
-stopOpacity_ = attr "stop-opacity"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray>
-strokeDasharray_ ::  MisoString -> Attribute action
-strokeDasharray_ = attr "stroke-dasharray"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dashoffset>
-strokeDashoffset_ ::  MisoString -> Attribute action
-strokeDashoffset_ = attr "stroke-dashoffset"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap>
-strokeLinecap_ ::  MisoString -> Attribute action
-strokeLinecap_ = attr "stroke-linecap"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linejoin>
-strokeLinejoin_ ::  MisoString -> Attribute action
-strokeLinejoin_ = attr "stroke-linejoin"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit>
-strokeMiterlimit_ ::  MisoString -> Attribute action
-strokeMiterlimit_ = attr "stroke-miterlimit"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-opacity>
-strokeOpacity_ ::  MisoString -> Attribute action
-strokeOpacity_ = attr "stroke-opacity"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-width>
-strokeWidth_ ::  MisoString -> Attribute action
-strokeWidth_ = attr "stroke-width"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke>
-stroke_ ::  MisoString -> Attribute action
-stroke_ = attr "stroke"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor>
-textAnchor_ ::  MisoString -> Attribute action
-textAnchor_ = attr "text-anchor"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-decoration>
-textDecoration_ ::  MisoString -> Attribute action
-textDecoration_ = attr "text-decoration"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-rendering>
-textRendering_ ::  MisoString -> Attribute action
-textRendering_ = attr "text-rendering"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/unicode-bidi>
-unicodeBidi_ ::  MisoString -> Attribute action
-unicodeBidi_ = attr "unicode-bidi"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/visibility>
-visibility_ ::  MisoString -> Attribute action
-visibility_ = attr "visibility"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/word-spacing>
-wordSpacing_ ::  MisoString -> Attribute action
-wordSpacing_ = attr "word-spacing"
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/writing-mode>
-writingMode_ ::  MisoString -> Attribute action
-writingMode_ = attr "writing-mode"
diff --git a/src/Miso/Svg/Element.hs b/src/Miso/Svg/Element.hs
--- a/src/Miso/Svg/Element.hs
+++ b/src/Miso/Svg/Element.hs
@@ -1,19 +1,88 @@
+-----------------------------------------------------------------------------
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE NoImplicitPrelude #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Svg.Element
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Svg.Element" provides smart constructors for every element in the
+-- <https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element SVG>
+-- vocabulary. All nodes are created in the @SVG@ namespace via
+-- @document.createElementNS(\"http:\/\/www.w3.org\/2000\/svg\", …)@.
+-- This module is re-exported in its entirety by "Miso.Svg".
+--
+-- __Leaf elements__ (shapes, images, stops, …) omit the children argument:
+--
+-- @
+-- circle_ :: ['Miso.Types.Attribute' action] -> 'Miso.Types.View' model action
+-- @
+--
+-- __Container elements__ accept both attributes and children:
+--
+-- @
+-- g_ :: ['Miso.Types.Attribute' action] -> ['Miso.Types.View' model action] -> 'Miso.Types.View' model action
+-- @
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Svg"
+-- import qualified "Miso.Svg.Property" as SP
+--
+-- logo :: 'Miso.Types.View' model action
+-- logo =
+--   'svg_' [ SP.'Miso.Svg.Property.viewBox_' \"0 0 200 200\", SP.'Miso.Svg.Property.width_' \"200\" ]
+--     [ 'g_' [ SP.'Miso.Svg.Property.fill_' \"none\", SP.'Miso.Svg.Property.stroke_' \"black\" ]
+--         [ 'circle_' [ SP.'Miso.Svg.Property.cx_' \"100\", SP.'Miso.Svg.Property.cy_' \"100\", SP.'Miso.Svg.Property.r_' \"80\" ]
+--         , 'line_'   [ SP.'Miso.Svg.Property.x1_' \"20\", SP.'Miso.Svg.Property.y1_' \"100\"
+--                     , SP.'Miso.Svg.Property.x2_' \"180\", SP.'Miso.Svg.Property.y2_' \"100\" ]
+--         ]
+--     , 'text_' [ SP.'Miso.Svg.Property.x_' \"100\", SP.'Miso.Svg.Property.y_' \"110\"
+--               , SP.'Miso.Svg.Property.textAnchor_' \"middle\" ]
+--               [ 'Miso.text' \"miso\" ]
+--     ]
+-- @
+--
+-- = Element groups
+--
+-- * __Root__: 'svg_'
+-- * __Graphics__ (leaf): 'circle_', 'ellipse_', 'image_', 'line_',
+--   'path_', 'polygon_', 'polyline_', 'rect_', 'use_'
+-- * __Animation__: 'animate_', 'animateMotion_', 'animateTransform_',
+--   'mpath_', 'set_'
+-- * __Descriptive__: 'desc_', 'metadata_', 'title_'
+-- * __Containers__: 'defs_', 'g_', 'marker_', 'mask_', 'pattern_',
+--   'switch_', 'symbol_'
+-- * __Text__: 'text_', 'textPath_', 'tspan_'
+-- * __Gradients__: 'linearGradient_', 'radialGradient_', 'stop_'
+-- * __Filters__: 'feBlend_', 'feColorMatrix_', 'feComponentTransfer_',
+--   'feComposite_', 'feConvolveMatrix_', 'feDiffuseLighting_',
+--   'feDisplacementMap_', 'feDropShadow_', 'feFlood_',
+--   'feFuncA_', 'feFuncB_', 'feFuncG_', 'feFuncR_',
+--   'feGaussianBlur_', 'feImage_', 'feMerge_', 'feMergeNode_',
+--   'feMorphology_', 'feOffset_', 'feSpecularLighting_',
+--   'feTile_', 'feTurbulence_'
+-- * __Light sources__: 'feDistantLight_', 'fePointLight_', 'feSpotLight_'
+-- * __Misc__: 'foreignObject_', 'clipPath_', 'filter_', 'script_',
+--   'style_', 'view_'
+--
+-- = See also
+--
+-- * "Miso.Svg.Property" — SVG attribute combinators (@cx_@, @r_@, @fill_@, …)
+-- * "Miso.Svg.Event" — SVG event handlers
+-- * "Miso.Html.Element" — HTML element constructors
 ----------------------------------------------------------------------------
 module Miso.Svg.Element
-  ( -- * HTML Embedding
+  ( -- *** SVG
     svg_
-  , foreignObject_
-    -- * Graphics Elements
+    -- *** Graphics
   , circle_
   , ellipse_
   , image_
@@ -23,51 +92,33 @@
   , polyline_
   , rect_
   , use_
-  -- * Animation Elements
+  -- *** Animation
   , animate_
-  , animateColor_
   , animateMotion_
   , animateTransform_
   , mpath_
   , set_
-  -- * Descriptive Elements
+  -- *** Descriptive
   , desc_
   , metadata_
   , title_
-  -- * Containers
-  , a_
+  -- *** Containers
   , defs_
   , g_
   , marker_
   , mask_
-  , missingGlyph_
   , pattern_
   , switch_
   , symbol_
-  -- * Text
-  , altGlyph_
-  , altGlyphDef_
-  , altGlyphItem_
-  , glyph_
-  , glyphRef_
+  -- *** Text
   , textPath_
   , text_
-  , tref_
   , tspan_
-  -- * Fonts
-  , font_
-  , fontFace_
-  , fontFaceFormat_
-  , fontFaceName_
-  , fontFaceSrc_
-  , fontFaceUri_
-  , hkern_
-  , vkern_
-  -- * Gradients
+  -- *** Gradients
   , linearGradient_
   , radialGradient_
   , stop_
-  -- * Filters
+  -- *** Filters
   , feBlend_
   , feColorMatrix_
   , feComponentTransfer_
@@ -75,6 +126,7 @@
   , feConvolveMatrix_
   , feDiffuseLighting_
   , feDisplacementMap_
+  , feDropShadow_
   , feFlood_
   , feFuncA_
   , feFuncB_
@@ -84,352 +136,282 @@
   , feImage_
   , feMerge_
   , feMergeNode_
-  , feMorhpology_
+  , feMorphology_
   , feOffset_
   , feSpecularLighting_
   , feTile_
   , feTurbulence_
-  -- * Light source elements
+  -- *** Light source
   , feDistantLight_
   , fePointLight_
   , feSpotLight_
-  -- * Miscellaneous
+  -- *** Misc.
+  , foreignObject_
   , clipPath_
-  , colorProfile_
-  , cursor_
   , filter_
   , script_
   , style_
   , view_
   ) where
-
-import           Miso.Html.Internal hiding (style_)
-import           Miso.String        (MisoString)
-import qualified Prelude            as P
-
--- | Used to construct a `VNode` with namespace "svg"
+-----------------------------------------------------------------------------
+import           Miso.Types  hiding (text_)
+-----------------------------------------------------------------------------
+-- | Used to construct a @VNode@ with namespace *"svg"*
 --
 -- > document.createElementNS('http://www.w3.org/2000/svg', 'circle');
 --
-nodeSvg_ :: MisoString -> [Attribute action] -> [View action] -> View action
-nodeSvg_ = P.flip (node SVG) P.Nothing
-
--- | Creates an svg tag
-svg_ :: [Attribute action] -> [View action] -> View action
-svg_ = nodeSvg_ "svg"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject>
-foreignObject_ :: [Attribute action] -> [View action] -> View action
-foreignObject_ = nodeSvg_ "foreignObject"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle>
-circle_ :: [Attribute action] -> [View action] -> View action
-circle_ = nodeSvg_ "circle"
-
--- | <https__://developer.mozilla.org/en-US/docs/Web/SVG/Element/ellipse>
-ellipse_ :: [Attribute action] -> [View action] -> View action
-ellipse_ = nodeSvg_ "ellipse"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image>
-image_ :: [Attribute action] -> [View action] -> View action
-image_ = nodeSvg_ "image"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image>
-line_ :: [Attribute action] -> [View action] -> View action
-line_ = nodeSvg_ "line"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path>
-path_ :: [Attribute action] -> [View action] -> View action
-path_ = nodeSvg_ "path"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polygon>
-polygon_ :: [Attribute action] -> [View action] -> View action
-polygon_ = nodeSvg_ "polygon"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polyline>
-polyline_ :: [Attribute action] -> [View action] -> View action
-polyline_ = nodeSvg_ "polyline"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/rect>
-rect_ :: [Attribute action] -> [View action] -> View action
-rect_ = nodeSvg_ "rect"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use>
-use_ :: [Attribute action] -> [View action] -> View action
-use_ = nodeSvg_ "use"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animate>
-animate_ :: [Attribute action] -> [View action] -> View action
-animate_ = nodeSvg_ "animate"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animateColor>
-animateColor_ :: [Attribute action] -> [View action] -> View action
-animateColor_ = nodeSvg_ "animateColor"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animateMotion>
-animateMotion_ :: [Attribute action] -> [View action] -> View action
-animateMotion_ = nodeSvg_ "animateMotion"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animateMotion>
-animateTransform_ :: [Attribute action] -> [View action] -> View action
-animateTransform_ = nodeSvg_ "animateTransform"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/mpath>
-mpath_ :: [Attribute action] -> [View action] -> View action
-mpath_ = nodeSvg_ "mpath"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/set>
-set_ :: [Attribute action] -> [View action] -> View action
-set_ = nodeSvg_ "set"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc>
-desc_ :: [Attribute action] -> [View action] -> View action
-desc_ = nodeSvg_ "desc"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/metadata>
-metadata_ :: [Attribute action] -> [View action] -> View action
-metadata_ = nodeSvg_ "metadata"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title>
-title_ :: [Attribute action] -> [View action] -> View action
-title_ = nodeSvg_ "title"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/a>
-a_ :: [Attribute action] -> [View action] -> View action
-a_ = nodeSvg_ "a"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs>
-defs_ :: [Attribute action] -> [View action] -> View action
-defs_ = nodeSvg_ "defs"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g>
-g_ :: [Attribute action] -> [View action] -> View action
-g_ = nodeSvg_ "g"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/marker>
-marker_ :: [Attribute action] -> [View action] -> View action
-marker_ = nodeSvg_ "marker"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/mask>
-mask_ :: [Attribute action] -> [View action] -> View action
-mask_ = nodeSvg_ "mask"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/missingGlyph>
-missingGlyph_ :: [Attribute action] -> [View action] -> View action
-missingGlyph_ = nodeSvg_ "missingGlyph"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/pattern>
-pattern_ :: [Attribute action] -> [View action] -> View action
-pattern_ = nodeSvg_ "pattern"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/switch>
-switch_ :: [Attribute action] -> [View action] -> View action
-switch_ = nodeSvg_ "switch"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/symbol>
-symbol_ :: [Attribute action] -> [View action] -> View action
-symbol_ = nodeSvg_ "symbol"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/altGlyph>
-altGlyph_ :: [Attribute action] -> [View action] -> View action
-altGlyph_ = nodeSvg_ "altGlyph"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/altGlyphDef>
-altGlyphDef_ :: [Attribute action] -> [View action] -> View action
-altGlyphDef_ = nodeSvg_ "altGlyphDef"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/altGlyphItem>
-altGlyphItem_ :: [Attribute action] -> [View action] -> View action
-altGlyphItem_ = nodeSvg_ "altGlyphItem"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/glyph>
-glyph_ :: [Attribute action] -> [View action] -> View action
-glyph_ = nodeSvg_ "glyph"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/glyphRef>
-glyphRef_ :: [Attribute action] -> [View action] -> View action
-glyphRef_ = nodeSvg_ "glyphRef"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/glyphRef>
-textPath_ :: [Attribute action] -> [View action] -> View action
-textPath_ = nodeSvg_ "textPath"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text>
-text_ :: [Attribute action] -> [View action] -> View action
-text_ = nodeSvg_ "text"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/tref>
-tref_ :: [Attribute action] -> [View action] -> View action
-tref_ = nodeSvg_ "tref"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/tspan>
-tspan_ :: [Attribute action] -> [View action] -> View action
-tspan_ = nodeSvg_ "tspan"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font>
-font_ :: [Attribute action] -> [View action] -> View action
-font_ = nodeSvg_ "font"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face>
-fontFace_ :: [Attribute action] -> [View action] -> View action
-fontFace_ = nodeSvg_ "font-face"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face-format>
-fontFaceFormat_ :: [Attribute action] -> [View action] -> View action
-fontFaceFormat_ = nodeSvg_ "font-face-format"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face-name>
-fontFaceName_ :: [Attribute action] -> [View action] -> View action
-fontFaceName_ = nodeSvg_ "font-face-name"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face-src>
-fontFaceSrc_ :: [Attribute action] -> [View action] -> View action
-fontFaceSrc_ = nodeSvg_ "font-face-src"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face-uri>
-fontFaceUri_ :: [Attribute action] -> [View action] -> View action
-fontFaceUri_ = nodeSvg_ "font-face-uri"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/hkern>
-hkern_ :: [Attribute action] -> [View action] -> View action
-hkern_ = nodeSvg_ "hkern"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/vkern>
-vkern_ :: [Attribute action] -> [View action] -> View action
-vkern_ = nodeSvg_ "vkern"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient>
-linearGradient_ :: [Attribute action] -> [View action] -> View action
-linearGradient_ = nodeSvg_ "linearGradient"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient>
-radialGradient_ :: [Attribute action] -> [View action] -> View action
-radialGradient_ = nodeSvg_ "radialGradient"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/stop>
-stop_ :: [Attribute action] -> [View action] -> View action
-stop_ = nodeSvg_ "stop"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feBlend>
-feBlend_ :: [Attribute action] -> [View action] -> View action
-feBlend_ = nodeSvg_ "feBlend"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feColorMatrix>
-feColorMatrix_ :: [Attribute action] -> [View action] -> View action
-feColorMatrix_ = nodeSvg_ "feColorMatrix"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComponentTransfer>
-feComponentTransfer_ :: [Attribute action] -> [View action] -> View action
-feComponentTransfer_ = nodeSvg_ "feComponentTransfer"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComposite>
-feComposite_ :: [Attribute action] -> [View action] -> View action
-feComposite_ = nodeSvg_ "feComposite"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feConvolveMatrix>
-feConvolveMatrix_ :: [Attribute action] -> [View action] -> View action
-feConvolveMatrix_ = nodeSvg_ "feConvolveMatrix"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDiffuseLighting>
-feDiffuseLighting_ :: [Attribute action] -> [View action] -> View action
-feDiffuseLighting_ = nodeSvg_ "feDiffuseLighting"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDisplacementMap>
-feDisplacementMap_ :: [Attribute action] -> [View action] -> View action
-feDisplacementMap_ = nodeSvg_ "feDisplacementMap"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFlood>
-feFlood_ :: [Attribute action] -> [View action] -> View action
-feFlood_ = nodeSvg_ "feFlood"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncA>
-feFuncA_ :: [Attribute action] -> [View action] -> View action
-feFuncA_ = nodeSvg_ "feFuncA"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncB>
-feFuncB_ :: [Attribute action] -> [View action] -> View action
-feFuncB_ = nodeSvg_ "feFuncB"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncG>
-feFuncG_ :: [Attribute action] -> [View action] -> View action
-feFuncG_ = nodeSvg_ "feFuncG"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncR>
-feFuncR_ :: [Attribute action] -> [View action] -> View action
-feFuncR_ = nodeSvg_ "feFuncR"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feGaussianBlur>
-feGaussianBlur_ :: [Attribute action] -> [View action] -> View action
-feGaussianBlur_ = nodeSvg_ "feGaussianBlur"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feImage>
-feImage_ :: [Attribute action] -> [View action] -> View action
-feImage_ = nodeSvg_ "feImage"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feMerge>
-feMerge_ :: [Attribute action] -> [View action] -> View action
-feMerge_ = nodeSvg_ "feMerge"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feMergeNode>
-feMergeNode_ :: [Attribute action] -> [View action] -> View action
-feMergeNode_ = nodeSvg_ "feMergeNode"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feMorhpology>
-feMorhpology_ :: [Attribute action] -> [View action] -> View action
-feMorhpology_ = nodeSvg_ "feMorhpology"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feOffset>
-feOffset_ :: [Attribute action] -> [View action] -> View action
-feOffset_ = nodeSvg_ "feOffset"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feSpecularLighting>
-feSpecularLighting_ :: [Attribute action] -> [View action] -> View action
-feSpecularLighting_ = nodeSvg_ "feSpecularLighting"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feTile>
-feTile_ :: [Attribute action] -> [View action] -> View action
-feTile_ = nodeSvg_ "feTile"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feTurbulence>
-feTurbulence_ :: [Attribute action] -> [View action] -> View action
-feTurbulence_ = nodeSvg_ "feTurbulence"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDistantLight>
-feDistantLight_ :: [Attribute action] -> [View action] -> View action
-feDistantLight_ = nodeSvg_ "feDistantLight"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/fePointLight>
-fePointLight_ :: [Attribute action] -> [View action] -> View action
-fePointLight_ = nodeSvg_ "fePointLight"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feSpotLight>
-feSpotLight_ :: [Attribute action] -> [View action] -> View action
-feSpotLight_ = nodeSvg_ "feSpotLight"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/clipPath>
-clipPath_ :: [Attribute action] -> [View action] -> View action
-clipPath_ = nodeSvg_ "clipPath"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/color-profile>
-colorProfile_ :: [Attribute action] -> [View action] -> View action
-colorProfile_ = nodeSvg_ "color-profile"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/cursor>
-cursor_ :: [Attribute action] -> [View action] -> View action
-cursor_ = nodeSvg_ "cursor"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/filter>
-filter_ :: [Attribute action] -> [View action] -> View action
-filter_ = nodeSvg_ "filter"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/script>
-script_ :: [Attribute action] -> [View action] -> View action
-script_ = nodeSvg_ "script"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/style>
-style_ :: [Attribute action] -> [View action] -> View action
-style_ = nodeSvg_ "style"
-
--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/view>
-view_ :: [Attribute action] -> [View action] -> View action
-view_ = nodeSvg_ "view"
+nodeSvg :: MisoString -> [Attribute model action] -> [View context model action] -> View context model action
+nodeSvg nodeName = node SVG nodeName
+-----------------------------------------------------------------------------
+-- | [\<svg\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/svg)
+svg_ :: [Attribute model action] -> [View context model action] -> View context model action
+svg_ = nodeSvg "svg"
+-----------------------------------------------------------------------------
+-- | [\<foreignObject\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/foreignObject)
+foreignObject_ :: [Attribute model action] -> [View context model action] -> View context model action
+foreignObject_ = nodeSvg "foreignObject"
+-----------------------------------------------------------------------------
+-- | [\<circle\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/circle)
+circle_ :: [Attribute model action] -> View context model action
+circle_ = flip (nodeSvg "circle") []
+-----------------------------------------------------------------------------
+-- | [\<ellipse\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/ellipse)
+ellipse_ :: [Attribute model action] -> View context model action
+ellipse_ = flip (nodeSvg "ellipse") []
+-----------------------------------------------------------------------------
+-- | [\<image\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/image)
+image_ :: [Attribute model action] -> View context model action
+image_ = flip (nodeSvg "image") []
+-----------------------------------------------------------------------------
+-- | [\<line\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/line)
+line_ :: [Attribute model action] -> View context model action
+line_ = flip (nodeSvg "line") []
+-----------------------------------------------------------------------------
+-- | [\<path\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/path)
+path_ :: [Attribute model action] -> View context model action
+path_ = flip (nodeSvg "path") []
+-----------------------------------------------------------------------------
+-- | [\<polygon\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polygon)
+polygon_ :: [Attribute model action] -> View context model action
+polygon_ = flip (nodeSvg "polygon") []
+-----------------------------------------------------------------------------
+-- | [\<polyline\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polyline)
+polyline_ :: [Attribute model action] -> View context model action
+polyline_ = flip (nodeSvg "polyline") []
+-----------------------------------------------------------------------------
+-- | [\<rect\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/rect)
+rect_ :: [Attribute model action] -> View context model action
+rect_ = flip (nodeSvg "rect") []
+-----------------------------------------------------------------------------
+-- | [\<use\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/use)
+use_ :: [Attribute model action] -> View context model action
+use_ = flip (nodeSvg "use") []
+-----------------------------------------------------------------------------
+-- | [\<animate\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/animate)
+animate_ :: [Attribute model action] -> View context model action
+animate_ = flip (nodeSvg "animate") []
+-----------------------------------------------------------------------------
+-- | [\<animateMotion\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/animateMotion)
+animateMotion_ :: [Attribute model action] -> View context model action
+animateMotion_ = flip (nodeSvg "animateMotion") []
+-----------------------------------------------------------------------------
+-- | [\<animateTransform\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/animateTransform)
+animateTransform_ :: [Attribute model action] -> View context model action
+animateTransform_ = flip (nodeSvg "animateTransform") []
+-----------------------------------------------------------------------------
+-- | [\<mpath\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/mpath)
+mpath_ :: [Attribute model action] -> View context model action
+mpath_ = flip (nodeSvg "mpath") []
+-----------------------------------------------------------------------------
+-- | [\<set\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/set)
+set_ :: [Attribute model action] -> View context model action
+set_ = flip (nodeSvg "set") []
+-----------------------------------------------------------------------------
+-- | [\<desc\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/desc)
+desc_ :: [Attribute model action] -> [View context model action] -> View context model action
+desc_ = nodeSvg "desc"
+-----------------------------------------------------------------------------
+-- | [\<metadata\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/metadata)
+metadata_ :: [Attribute model action] -> [View context model action] -> View context model action
+metadata_ = nodeSvg "metadata"
+-----------------------------------------------------------------------------
+-- | [\<title\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/title)
+title_ :: [Attribute model action] -> [View context model action] -> View context model action
+title_ = nodeSvg "title"
+-----------------------------------------------------------------------------
+-- | [\<defs\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/defs)
+defs_ :: [Attribute model action] -> [View context model action] -> View context model action
+defs_ = nodeSvg "defs"
+-----------------------------------------------------------------------------
+-- | [\<g\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/g)
+g_ :: [Attribute model action] -> [View context model action] -> View context model action
+g_ = nodeSvg "g"
+-----------------------------------------------------------------------------
+-- | [\<marker\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/marker)
+marker_ :: [Attribute model action] -> [View context model action] -> View context model action
+marker_ = nodeSvg "marker"
+-----------------------------------------------------------------------------
+-- | [\<mask\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/mask)
+mask_ :: [Attribute model action] -> [View context model action] -> View context model action
+mask_ = nodeSvg "mask"
+-----------------------------------------------------------------------------
+-- | [\<pattern\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/pattern)
+pattern_ :: [Attribute model action] -> [View context model action] -> View context model action
+pattern_ = nodeSvg "pattern"
+-----------------------------------------------------------------------------
+-- | [\<switch\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/switch)
+switch_ :: [Attribute model action] -> [View context model action] -> View context model action
+switch_ = nodeSvg "switch"
+-----------------------------------------------------------------------------
+-- | [\<symbol\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/symbol)
+symbol_ :: [Attribute model action] -> [View context model action] -> View context model action
+symbol_ = nodeSvg "symbol"
+-----------------------------------------------------------------------------
+-- | [\<textPath\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/textPath)
+textPath_ :: [Attribute model action] -> [View context model action] -> View context model action
+textPath_ = nodeSvg "textPath"
+-----------------------------------------------------------------------------
+-- | [\<text\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/text)
+text_ :: [Attribute model action] -> [View context model action] -> View context model action
+text_ = nodeSvg "text"
+-----------------------------------------------------------------------------
+-- | [\<tspan\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/tspan)
+tspan_ :: [Attribute model action] -> [View context model action] -> View context model action
+tspan_ = nodeSvg "tspan"
+-----------------------------------------------------------------------------
+-- | [\<linearGradient\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/linearGradient)
+linearGradient_ :: [Attribute model action] -> [View context model action] -> View context model action
+linearGradient_ = nodeSvg "linearGradient"
+-----------------------------------------------------------------------------
+-- | [\<radialGradient\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/radialGradient)
+radialGradient_ :: [Attribute model action] -> [View context model action] -> View context model action
+radialGradient_ = nodeSvg "radialGradient"
+-----------------------------------------------------------------------------
+-- | [\<stop\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/stop)
+stop_ :: [Attribute model action] -> View context model action
+stop_ = flip (nodeSvg "stop") []
+-----------------------------------------------------------------------------
+-- | [\<feBlend\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feBlend)
+feBlend_ :: [Attribute model action] -> View context model action
+feBlend_ = flip (nodeSvg "feBlend") []
+-----------------------------------------------------------------------------
+-- | [\<feColorMatrix\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feColorMatrix)
+feColorMatrix_ :: [Attribute model action] -> View context model action
+feColorMatrix_ = flip (nodeSvg "feColorMatrix") []
+-----------------------------------------------------------------------------
+-- | [\<feComponentTransfer\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feComponentTransfer)
+feComponentTransfer_ :: [Attribute model action] -> [View context model action] -> View context model action
+feComponentTransfer_ = nodeSvg "feComponentTransfer"
+-----------------------------------------------------------------------------
+-- | [\<feComposite\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feComposite)
+feComposite_ :: [Attribute model action] -> View context model action
+feComposite_ = flip (nodeSvg "feComposite") []
+-----------------------------------------------------------------------------
+-- | [\<feConvolveMatrix\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feConvolveMatrix)
+feConvolveMatrix_ :: [Attribute model action] -> View context model action
+feConvolveMatrix_ = flip (nodeSvg "feConvolveMatrix") []
+-----------------------------------------------------------------------------
+-- | [\<feDiffuseLighting\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feDiffuseLighting)
+feDiffuseLighting_ :: [Attribute model action] -> [View context model action] -> View context model action
+feDiffuseLighting_ = nodeSvg "feDiffuseLighting"
+-----------------------------------------------------------------------------
+-- | [\<feDisplacementMap\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feDisplacementMap)
+feDisplacementMap_ :: [Attribute model action] -> View context model action
+feDisplacementMap_ = flip (nodeSvg "feDisplacementMap") []
+-----------------------------------------------------------------------------
+-- | [\<feDropShadow\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feDropShadow)
+--
+-- @since 1.9.0.0
+feDropShadow_ :: [Attribute model action] -> View context model action
+feDropShadow_ = flip (nodeSvg "feDropShadow") []
+-----------------------------------------------------------------------------
+-- | [\<feFlood\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFlood)
+feFlood_ :: [Attribute model action] -> View context model action
+feFlood_ = flip (nodeSvg "feFlood") []
+-----------------------------------------------------------------------------
+-- | [\<feFuncA\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFuncA)
+feFuncA_ :: [Attribute model action] -> [View context model action] -> View context model action
+feFuncA_ = nodeSvg "feFuncA"
+-----------------------------------------------------------------------------
+-- | [\<feFuncB\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFuncB)
+feFuncB_ :: [Attribute model action] -> [View context model action] -> View context model action
+feFuncB_ = nodeSvg "feFuncB"
+-----------------------------------------------------------------------------
+-- | [\<feFuncG\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFuncG)
+feFuncG_ :: [Attribute model action] -> [View context model action] -> View context model action
+feFuncG_ = nodeSvg "feFuncG"
+-----------------------------------------------------------------------------
+-- | [\<feFuncR\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFuncR)
+feFuncR_ :: [Attribute model action] -> [View context model action] -> View context model action
+feFuncR_ = nodeSvg "feFuncR"
+-----------------------------------------------------------------------------
+-- | [\<feGaussianBlur\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feGaussianBlur)
+feGaussianBlur_ :: [Attribute model action] -> View context model action
+feGaussianBlur_ = flip (nodeSvg "feGaussianBlur") []
+-----------------------------------------------------------------------------
+-- | [\<feImage\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feImage)
+feImage_ :: [Attribute model action] -> View context model action
+feImage_ = flip (nodeSvg "feImage") []
+-----------------------------------------------------------------------------
+-- | [\<feMerge\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feMerge)
+feMerge_ :: [Attribute model action] -> [View context model action] -> View context model action
+feMerge_ = nodeSvg "feMerge"
+-----------------------------------------------------------------------------
+-- | [\<feMergeNode\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feMergeNode)
+feMergeNode_ :: [Attribute model action] -> View context model action
+feMergeNode_ = flip (nodeSvg "feMergeNode") []
+-----------------------------------------------------------------------------
+-- | [\<feMorphology\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feMorphology)
+--
+-- @since 1.9.0.0
+feMorphology_ :: [Attribute model action] -> View context model action
+feMorphology_ = flip (nodeSvg "feMorphology") []
+-----------------------------------------------------------------------------
+-- | [\<feOffset\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feOffset)
+feOffset_ :: [Attribute model action] -> View context model action
+feOffset_ = flip (nodeSvg "feOffset") []
+-----------------------------------------------------------------------------
+-- | [\<feSpecularLighting\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feSpecularLighting)
+feSpecularLighting_ :: [Attribute model action] -> [View context model action] -> View context model action
+feSpecularLighting_ = nodeSvg "feSpecularLighting"
+-----------------------------------------------------------------------------
+-- | [\<feTile\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feTile)
+feTile_ :: [Attribute model action] -> View context model action
+feTile_ = flip (nodeSvg "feTile") []
+-----------------------------------------------------------------------------
+-- | [\<feTurbulence\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feTurbulence)
+feTurbulence_ :: [Attribute model action] -> View context model action
+feTurbulence_ = flip (nodeSvg "feTurbulence") []
+-----------------------------------------------------------------------------
+-- | [\<feDistantLight\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feDistantLight)
+feDistantLight_ :: [Attribute model action] -> [View context model action] -> View context model action
+feDistantLight_ = nodeSvg "feDistantLight"
+-----------------------------------------------------------------------------
+-- | [\<fePointLight\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/fePointLight)
+fePointLight_ :: [Attribute model action] -> View context model action
+fePointLight_ = flip (nodeSvg "fePointLight") []
+-----------------------------------------------------------------------------
+-- | [\<feSpotLight\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feSpotLight)
+feSpotLight_ :: [Attribute model action] -> View context model action
+feSpotLight_ = flip (nodeSvg "feSpotLight") []
+-----------------------------------------------------------------------------
+-- | [\<clipPath\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/clipPath)
+clipPath_ :: [Attribute model action] -> [View context model action] -> View context model action
+clipPath_ = nodeSvg "clipPath"
+-----------------------------------------------------------------------------
+-- | [\<filter\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/filter)
+filter_ :: [Attribute model action] -> [View context model action] -> View context model action
+filter_ = nodeSvg "filter"
+-----------------------------------------------------------------------------
+-- | [\<script\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/script)
+script_ :: [Attribute model action] -> [View context model action] -> View context model action
+script_ = nodeSvg "script"
+-----------------------------------------------------------------------------
+-- | [\<style\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/style)
+style_ :: [Attribute model action] -> [View context model action] -> View context model action
+style_ = nodeSvg "style"
+-----------------------------------------------------------------------------
+-- | [\<view\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/view)
+view_ :: [Attribute model action] -> View context model action
+view_ = flip (nodeSvg "view") []
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Svg/Event.hs b/src/Miso/Svg/Event.hs
--- a/src/Miso/Svg/Event.hs
+++ b/src/Miso/Svg/Event.hs
@@ -1,31 +1,84 @@
+-----------------------------------------------------------------------------
 {-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE TypeFamilies          #-}
 {-# LANGUAGE DataKinds             #-}
 {-# LANGUAGE OverloadedStrings     #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 -----------------------------------------------------------------------------
 -- |
--- Module      :  Miso.Svg.Events
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Module      :  Miso.Svg.Event
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Svg.Event" provides event-handler 'Miso.Types.Attribute' values
+-- for SVG-specific DOM events. All handlers use 'Miso.Event.emptyDecoder'
+-- — they fire a fixed action with no payload extracted from the event
+-- object. This module is re-exported by "Miso.Svg".
+--
+-- For pointer and keyboard events on SVG elements, use the handlers from
+-- "Miso.Html.Event" directly — they work on any DOM element regardless of
+-- namespace.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.Svg"
+--
+-- data Action = AnimDone | Zoomed
+--
+-- view :: Model -> 'Miso.Types.View' Model Action
+-- view _ =
+--   @svg_@ []
+--     [ 'Miso.Svg.Element.animate_'
+--         [ 'onEnd'  AnimDone
+--         , 'onZoom' Zoomed
+--         ]
+--     , 'Miso.Svg.Element.circle_'
+--         [ 'onClick'    Toggle
+--         , 'onMouseOver' Highlight
+--         ]
+--     ]
+-- @
+--
+-- = Event groups
+--
+-- * __Animation__ (@\<animate\>@, @\<animateTransform\>@, …):
+--   'onBegin', 'onEnd', 'onRepeat'
+--
+-- * __Document__ (fires on @\<svg\>@ root):
+--   'onAbort', 'onError', 'onResize', 'onScroll', 'onZoom'
+--
+-- * __Graphical__ (fires on any visible SVG element):
+--   'onActivate', 'onClick', 'onFocusIn', 'onFocusOut',
+--   'onMouseDown', 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp'
+--
+-- Note: 'onClick' is re-exported from "Miso.Html.Event" and is identical
+-- to the HTML version.
+--
+-- = See also
+--
+-- * "Miso.Html.Event" — 'Miso.Html.Event.onPointerDown', 'Miso.Html.Event.onKeyDown', …
+--   work on SVG elements too
+-- * "Miso.Svg.Element" — SVG element constructors
+-- * "Miso.Event" — 'Miso.Event.on', 'Miso.Event.emptyDecoder' primitives
 ----------------------------------------------------------------------------
 module Miso.Svg.Event
-  ( -- * Animation event handlers
+  ( -- *** Animation
     onBegin
   , onEnd
   , onRepeat
-    -- * Document event attributes
+    -- *** Document
   , onAbort
   , onError
   , onResize
   , onScroll
-  , onLoad
-  , onUnload
   , onZoom
-    -- * Graphical Event Attributes
+    -- *** Graphical
   , onActivate
   , onClick
   , onFocusIn
@@ -36,81 +89,72 @@
   , onMouseOver
   , onMouseUp
   ) where
-
-import Miso.Event 
+-----------------------------------------------------------------------------
+import Miso.Event (on, emptyDecoder)
 import Miso.Html.Event (onClick)
-import Miso.Html.Internal
-
+import Miso.Types (Attribute)
+-----------------------------------------------------------------------------
 -- | onBegin event
-onBegin :: action -> Attribute action
-onBegin action = on "begin" emptyDecoder $ \() -> action
-
+onBegin :: action -> Attribute model action
+onBegin action = on "begin" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onEnd event
-onEnd :: action -> Attribute action
-onEnd action = on "end" emptyDecoder $ \() -> action
-
+onEnd :: action -> Attribute model action
+onEnd action = on "end" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onRepeat event
-onRepeat :: action -> Attribute action
-onRepeat action = on "repeat" emptyDecoder $ \() -> action
-
+onRepeat :: action -> Attribute model action
+onRepeat action = on "repeat" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onAbort event
-onAbort :: action -> Attribute action
-onAbort action = on "abort" emptyDecoder $ \() -> action
-
+onAbort :: action -> Attribute model action
+onAbort action = on "abort" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onError event
-onError :: action -> Attribute action
-onError action = on "error" emptyDecoder $ \() -> action
-
+onError :: action -> Attribute model action
+onError action = on "error" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onResize event
-onResize :: action -> Attribute action
-onResize action = on "resize" emptyDecoder $ \() -> action
-
+onResize :: action -> Attribute model action
+onResize action = on "resize" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onScroll event
-onScroll :: action -> Attribute action
-onScroll action = on "scroll" emptyDecoder $ \() -> action
-
--- | onLoad event
-onLoad :: action -> Attribute action
-onLoad action = on "load" emptyDecoder $ \() -> action
-
--- | onUnload event
-onUnload :: action -> Attribute action
-onUnload action = on "unload" emptyDecoder $ \() -> action
-
+onScroll :: action -> Attribute model action
+onScroll action = on "scroll" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onZoom event
-onZoom :: action -> Attribute action
-onZoom action = on "zoom" emptyDecoder $ \() -> action
-
+onZoom :: action -> Attribute model action
+onZoom action = on "zoom" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onActivate event
-onActivate :: action -> Attribute action
-onActivate action = on "activate" emptyDecoder $ \() -> action
-
+onActivate :: action -> Attribute model action
+onActivate action = on "activate" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onFocusIn event
-onFocusIn :: action -> Attribute action
-onFocusIn action = on "focusin" emptyDecoder $ \() -> action
-
+onFocusIn :: action -> Attribute model action
+onFocusIn action = on "focusin" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onFocusOut event
-onFocusOut :: action -> Attribute action
-onFocusOut action = on "focusout" emptyDecoder $ \() -> action
-
+onFocusOut :: action -> Attribute model action
+onFocusOut action = on "focusout" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onMouseDown event
-onMouseDown :: action -> Attribute action
-onMouseDown action = on "mousedown" emptyDecoder $ \() -> action
+onMouseDown :: action -> Attribute model action
+onMouseDown action = on "mousedown" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onMouseMove event
-onMouseMove :: action -> Attribute action
-onMouseMove action = on "mousemove" emptyDecoder $ \() -> action
-
+onMouseMove :: action -> Attribute model action
+onMouseMove action = on "mousemove" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onMouseOut event
-onMouseOut :: action -> Attribute action
-onMouseOut action = on "mouseout" emptyDecoder $ \() -> action
-
+onMouseOut :: action -> Attribute model action
+onMouseOut action = on "mouseout" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onMouseOver event
-onMouseOver :: action -> Attribute action
-onMouseOver action = on "mouseover" emptyDecoder $ \() -> action
-
+onMouseOver :: action -> Attribute model action
+onMouseOver action = on "mouseover" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
 -- | onMouseUp event
-onMouseUp :: action -> Attribute action
-onMouseUp action = on "mouseup" emptyDecoder $ \() -> action
-
-
-
+onMouseUp :: action -> Attribute model action
+onMouseUp action = on "mouseup" emptyDecoder $ \() _ _ -> action
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Svg/Property.hs b/src/Miso/Svg/Property.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Svg/Property.hs
@@ -0,0 +1,989 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE OverloadedStrings #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Svg.Property
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Svg.Property" provides 'Miso.Types.Attribute' smart constructors
+-- for all
+-- <https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute SVG attributes>.
+-- Every combinator takes a 'Miso.String.MisoString' value and produces an
+-- 'Miso.Types.Attribute' that is set on the SVG element by the virtual DOM.
+--
+-- This module is __not__ re-exported by "Miso.Svg" and must be imported
+-- separately. Qualify it to avoid clashing with same-named combinators
+-- from "Miso.Html.Property":
+--
+-- @
+-- import qualified "Miso.Svg.Property" as SP
+-- @
+--
+-- = Quick start
+--
+-- @
+-- import "Miso.Svg"
+-- import qualified "Miso.Svg.Property" as SP
+--
+-- arrow :: 'Miso.Types.View' model action
+-- arrow =
+--   'Miso.Svg.Element.svg_' [ SP.'viewBox_' \"0 0 100 100\", SP.'width_' \"100\" ]
+--     [ 'Miso.Svg.Element.path_'
+--         [ SP.'d_'           \"M 10 50 L 90 50 M 70 30 L 90 50 L 70 70\"
+--         , SP.'stroke_'      \"black\"
+--         , SP.'strokeWidth_' \"4\"
+--         , SP.'fill_'        \"none\"
+--         , SP.'strokeLinecap_' \"round\"
+--         ]
+--     ]
+-- @
+--
+-- = Attribute groups
+--
+-- * __Geometry__: 'cx_', 'cy_', 'r_', 'rx_', 'ry_', 'x_', 'y_',
+--   'x1_', 'y1_', 'x2_', 'y2_', @width_@, @height_@, 'd_', 'points_',
+--   'viewBox_', 'preserveAspectRatio_', 'pathLength_', 'textLength_'
+--
+-- * __Paint__: 'fill_', 'fillOpacity_', 'fillRule_', 'stroke_',
+--   'strokeWidth_', 'strokeOpacity_', 'strokeDasharray_',
+--   'strokeDashoffset_', 'strokeLinecap_', 'strokeLinejoin_',
+--   'strokeMiterlimit_', 'color_', 'opacity_', 'stopColor_', 'stopOpacity_'
+--
+-- * __Transform__: 'transform_', 'transformOrigin_', 'gradientTransform_',
+--   'patternTransform_', 'rotate_', 'scale_'
+--
+-- * __Text__: 'textAnchor_', 'textDecoration_', 'textRendering_',
+--   'fontFamily_', 'fontSize_', 'fontSizeAdjust_', 'fontStyle_',
+--   'fontVariant_', 'fontWeight_', 'letterSpacing_', 'wordSpacing_',
+--   'direction_', 'writingMode_', 'unicodeBidi_', 'dominantBaseline_',
+--   'alignmentBaseline_', 'baselineShift_', 'dx_', 'dy_'
+--
+-- * __Gradients__: 'gradientUnits_', 'spreadMethod_', 'fr_', 'fx_', 'fy_',
+--   'offset_', 'x1_', 'y1_', 'x2_', 'y2_'
+--
+-- * __Filters__: 'in_\'', 'in2_', 'result_', 'mode_', 'operator_',
+--   'order_', 'kernelMatrix_', 'edgeMode_', 'stdDeviation_',
+--   'bias_', 'divisor_', 'amplitude_', 'exponent_', 'intercept_',
+--   'slope_', 'tableValues_', 'numOctaves_', 'seed_', 'baseFrequency_',
+--   'stitchTiles_', 'filterUnits_', 'primitiveUnits_',
+--   'diffuseConstant_', 'specularConstant_', 'specularExponent_',
+--   'surfaceScale_', 'azimuth_', 'elevation_', 'pointsAtX_',
+--   'pointsAtY_', 'pointsAtZ_', 'limitingConeAngle_', 'k1_',
+--   'k2_', 'k3_', 'k4_', 'xChannelSelector_', 'yChannelSelector_',
+--   'preserveAlpha_', 'radius_', 'scale_'
+--
+-- * __Markers__: 'markerHeight_', 'markerWidth_', 'markerUnits_',
+--   'markerEnd_', 'markerMid_', 'markerStart_', 'orient_', 'refX_', 'refY_'
+--
+-- * __Masks \/ Clips__: 'maskContentUnits_', 'maskUnits_', 'mask_',
+--   'clipPath_', 'clipRule_', 'clipPathUnits_'
+--
+-- * __Pattern__: 'patternContentUnits_', 'patternUnits_'
+--
+-- * __Animation__: 'begin_', 'dur_', 'end_', 'by_', 'from_', 'to_',
+--   'values_', 'calcMode_', 'keyTimes_', 'keySplines_', 'keyPoints_',
+--   'repeatCount_', 'repeatDur_', 'restart_', 'additive_',
+--   'accumulate_', 'attributeName_', 'type_\'', 'path_'
+--
+-- * __Misc__: 'cursor_', 'display_', 'filter_', 'imageRendering_',
+--   'lightingColor_', 'overflow_', 'paintOrder_', 'pointerEvents_',
+--   'shapeRendering_', 'vectorEffect_', 'visibility_',
+--   'colorInterpolation_', 'colorInterpolationFilters_',
+--   'floodColor_', 'floodOpacity_', 'crossorigin_', 'decoding_',
+--   'media_', 'method_', 'side_', 'spacing_', 'startOffset_',
+--   'systemLanguage_', 'target_', 'targetX_', 'targetY_', 'z_'
+--
+-- __Note__: Two SVG attributes clash with Haskell keywords and are given
+-- disambiguated names: @'in_\''@ (for the @in@ attribute) and @'type_\''@
+-- (for the @type@ attribute).
+--
+-- = See also
+--
+-- * "Miso.Svg.Element" — SVG element constructors
+-- * "Miso.Html.Property" — HTML property combinators (different namespace)
+-- * <https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute MDN SVG attribute reference>
+----------------------------------------------------------------------------
+module Miso.Svg.Property
+  ( -- *** Regular Attributes
+    accumulate_
+  , additive_
+  , amplitude_
+  , attributeName_
+  , azimuth_
+  , baseFrequency_
+  , begin_
+  , bias_
+  , by_
+  , calcMode_
+  , clipPathUnits_
+  , cx_
+  , cy_
+  , d_
+  , decoding_
+  , diffuseConstant_
+  , divisor_
+  , dur_
+  , dx_
+  , dy_
+  , edgeMode_
+  , elevation_
+  , end_
+  , exponent_
+  , filterUnits_
+  , fr_
+  , from_
+  , fx_
+  , fy_
+  , gradientTransform_
+  , gradientUnits_
+  , in_'
+  , in2_
+  , intercept_
+  , k1_
+  , k2_
+  , k3_
+  , k4_
+  , kernelMatrix_
+  , keyPoints_
+  , keySplines_
+  , keyTimes_
+  , lengthAdjust_
+  , limitingConeAngle_
+  , markerHeight_
+  , markerUnits_
+  , markerWidth_
+  , maskContentUnits_
+  , maskUnits_
+  , max_
+  , media_
+  , method_
+  , min_
+  , mode_
+  , numOctaves_
+  , offset_
+  , operator_
+  , order_
+  , orient_
+  , origin_
+  , paintOrder_
+  , path_
+  , pathLength_
+  , patternContentUnits_
+  , patternTransform_
+  , patternUnits_
+  , points_
+  , pointsAtX_
+  , pointsAtY_
+  , pointsAtZ_
+  , preserveAlpha_
+  , preserveAspectRatio_
+  , primitiveUnits_
+  , r_
+  , radius_
+  , refX_
+  , refY_
+  , repeatCount_
+  , repeatDur_
+  , restart_
+  , result_
+  , rotate_
+  , rx_
+  , ry_
+  , scale_
+  , seed_
+  , side_
+  , slope_
+  , spacing_
+  , specularConstant_
+  , specularExponent_
+  , spreadMethod_
+  , startOffset_
+  , stdDeviation_
+  , stitchTiles_
+  , surfaceScale_
+  , systemLanguage_
+  , tableValues_
+  , target_
+  , targetX_
+  , targetY_
+  , textLength_
+  , to_
+  , transform_
+  , transformOrigin_
+  , type_'
+  , values_
+  , vectorEffect_
+  , viewBox_
+  , x_
+  , x1_
+  , x2_
+  , xChannelSelector_
+  , y_
+  , y1_
+  , y2_
+  , yChannelSelector_
+  , z_
+  -- *** Presentation attributes
+  --
+  -- | All SVG presentation attributes can be used as CSS properties.
+  , alignmentBaseline_
+  , baselineShift_
+  , clipPath_
+  , clipRule_
+  , color_
+  , colorInterpolation_
+  , colorInterpolationFilters_
+  , crossorigin_
+  , cursor_
+  , direction_
+  , display_
+  , dominantBaseline_
+  , fill_
+  , fillOpacity_
+  , fillRule_
+  , filter_
+  , floodColor_
+  , floodOpacity_
+  , fontFamily_
+  , fontSize_
+  , fontSizeAdjust_
+  , fontStyle_
+  , fontVariant_
+  , fontWeight_
+  , imageRendering_
+  , letterSpacing_
+  , lightingColor_
+  , markerEnd_
+  , markerMid_
+  , markerStart_
+  , mask_
+  , opacity_
+  , overflow_
+  , pointerEvents_
+  , shapeRendering_
+  , stopColor_
+  , stopOpacity_
+  , stroke_
+  , strokeDasharray_
+  , strokeDashoffset_
+  , strokeLinecap_
+  , strokeLinejoin_
+  , strokeMiterlimit_
+  , strokeOpacity_
+  , strokeWidth_
+  , textAnchor_
+  , textDecoration_
+  , textRendering_
+  , unicodeBidi_
+  , visibility_
+  , wordSpacing_
+  , writingMode_
+  ) where
+-----------------------------------------------------------------------------
+import Miso.Property ( textProp )
+import Miso.String ( MisoString )
+import Miso.Types ( Attribute )
+-----------------------------------------------------------------------------
+attr :: MisoString -> MisoString -> Attribute model action
+attr = textProp
+-----------------------------------------------------------------------------
+-- | [accumulate](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/accumulate) attribute
+accumulate_ ::  MisoString -> Attribute model action
+accumulate_ = attr "accumulate"
+-----------------------------------------------------------------------------
+-- | [additive](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/additive) attribute
+additive_ ::  MisoString -> Attribute model action
+additive_ = attr "additive"
+-----------------------------------------------------------------------------
+-- | [amplitude](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/amplitude) attribute
+amplitude_ ::  MisoString -> Attribute model action
+amplitude_ = attr "amplitude"
+-----------------------------------------------------------------------------
+-- | [attributeName](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/attributeName) attribute
+attributeName_ ::  MisoString -> Attribute model action
+attributeName_ = attr "attributeName"
+-----------------------------------------------------------------------------
+-- | [azimuth](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/azimuth) attribute
+azimuth_ ::  MisoString -> Attribute model action
+azimuth_ = attr "azimuth"
+-----------------------------------------------------------------------------
+-- | [baseFrequency](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/baseFrequency) attribute
+baseFrequency_ ::  MisoString -> Attribute model action
+baseFrequency_ = attr "baseFrequency"
+-----------------------------------------------------------------------------
+-- | [begin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/begin) attribute
+begin_ ::  MisoString -> Attribute model action
+begin_ = attr "begin"
+-----------------------------------------------------------------------------
+-- | [bias](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/bias) attribute
+bias_ ::  MisoString -> Attribute model action
+bias_ = attr "bias"
+-----------------------------------------------------------------------------
+-- | [by](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/by) attribute
+by_ ::  MisoString -> Attribute model action
+by_ = attr "by"
+-----------------------------------------------------------------------------
+-- | [calcMode](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/calcMode) attribute
+calcMode_ ::  MisoString -> Attribute model action
+calcMode_ = attr "calcMode"
+-----------------------------------------------------------------------------
+-- | [clipPathUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/clipPathUnits) attribute
+clipPathUnits_ ::  MisoString -> Attribute model action
+clipPathUnits_ = attr "clipPathUnits"
+-----------------------------------------------------------------------------
+-- | [cx](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/cx) attribute
+cx_ ::  MisoString -> Attribute model action
+cx_ = attr "cx"
+-----------------------------------------------------------------------------
+-- | [cy](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/cy) attribute
+cy_ ::  MisoString -> Attribute model action
+cy_ = attr "cy"
+-----------------------------------------------------------------------------
+-- | [d](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/d) attribute
+d_ ::  MisoString -> Attribute model action
+d_ = attr "d"
+-----------------------------------------------------------------------------
+-- | [decoding](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/decoding) attribute
+--
+-- @since 1.9.0.0
+decoding_ ::  MisoString -> Attribute model action
+decoding_ = attr "decoding"
+-----------------------------------------------------------------------------
+-- | [diffuseConstant](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/diffuseConstant) attribute
+diffuseConstant_ ::  MisoString -> Attribute model action
+diffuseConstant_ = attr "diffuseConstant"
+-----------------------------------------------------------------------------
+-- | [divisor](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/divisor) attribute
+divisor_ ::  MisoString -> Attribute model action
+divisor_ = attr "divisor"
+-----------------------------------------------------------------------------
+-- | [dur](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/dur) attribute
+dur_ ::  MisoString -> Attribute model action
+dur_ = attr "dur"
+-----------------------------------------------------------------------------
+-- | [dx](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/dx) attribute
+dx_ ::  MisoString -> Attribute model action
+dx_ = attr "dx"
+-----------------------------------------------------------------------------
+-- | [dy](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/dy) attribute
+dy_ ::  MisoString -> Attribute model action
+dy_ = attr "dy"
+-----------------------------------------------------------------------------
+-- | [edgeMode](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/edgeMode) attribute
+edgeMode_ ::  MisoString -> Attribute model action
+edgeMode_ = attr "edgeMode"
+-----------------------------------------------------------------------------
+-- | [elevation](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/elevation) attribute
+elevation_ ::  MisoString -> Attribute model action
+elevation_ = attr "elevation"
+-----------------------------------------------------------------------------
+-- | [end](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/end) attribute
+end_ ::  MisoString -> Attribute model action
+end_ = attr "end"
+-----------------------------------------------------------------------------
+-- | [exponent](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/exponent) attribute
+exponent_ ::  MisoString -> Attribute model action
+exponent_ = attr "exponent"
+-----------------------------------------------------------------------------
+-- | [filterUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/filterUnits) attribute
+filterUnits_ ::  MisoString -> Attribute model action
+filterUnits_ = attr "filterUnits"
+-----------------------------------------------------------------------------
+-- | [fr](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fr) attribute
+--
+-- @since 1.9.0.0
+fr_ ::  MisoString -> Attribute model action
+fr_ = attr "fr"
+-----------------------------------------------------------------------------
+-- | [from](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/from) attribute
+from_ ::  MisoString -> Attribute model action
+from_ = attr "from"
+-----------------------------------------------------------------------------
+-- | [fx](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fx) attribute
+fx_ ::  MisoString -> Attribute model action
+fx_ = attr "fx"
+-----------------------------------------------------------------------------
+-- | [fy](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fy) attribute
+fy_ ::  MisoString -> Attribute model action
+fy_ = attr "fy"
+-----------------------------------------------------------------------------
+-- | [gradientTransform](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/gradientTransform) attribute
+gradientTransform_ ::  MisoString -> Attribute model action
+gradientTransform_ = attr "gradientTransform"
+-----------------------------------------------------------------------------
+-- | [gradientUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/gradientUnits) attribute
+gradientUnits_ ::  MisoString -> Attribute model action
+gradientUnits_ = attr "gradientUnits"
+-----------------------------------------------------------------------------
+-- | [in](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/in) attribute
+in_' ::  MisoString -> Attribute model action
+in_' = attr "in"
+-----------------------------------------------------------------------------
+-- | [in2](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/in2) attribute
+in2_ ::  MisoString -> Attribute model action
+in2_ = attr "in2"
+-----------------------------------------------------------------------------
+-- | [intercept](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/intercept) attribute
+intercept_ ::  MisoString -> Attribute model action
+intercept_ = attr "intercept"
+-----------------------------------------------------------------------------
+-- | [k1](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/k1) attribute
+k1_ ::  MisoString -> Attribute model action
+k1_ = attr "k1"
+-----------------------------------------------------------------------------
+-- | [k2](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/k2) attribute
+k2_ ::  MisoString -> Attribute model action
+k2_ = attr "k2"
+-----------------------------------------------------------------------------
+-- | [k3](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/k3) attribute
+k3_ ::  MisoString -> Attribute model action
+k3_ = attr "k3"
+-----------------------------------------------------------------------------
+-- | [k4](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/k4) attribute
+k4_ ::  MisoString -> Attribute model action
+k4_ = attr "k4"
+-----------------------------------------------------------------------------
+-- | [kernelMatrix](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/kernelMatrix) attribute
+kernelMatrix_ ::  MisoString -> Attribute model action
+kernelMatrix_ = attr "kernelMatrix"
+-----------------------------------------------------------------------------
+-- | [keyPoints](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/keyPoints) attribute
+keyPoints_ ::  MisoString -> Attribute model action
+keyPoints_ = attr "keyPoints"
+-----------------------------------------------------------------------------
+-- | [keySplines](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/keySplines) attribute
+keySplines_ ::  MisoString -> Attribute model action
+keySplines_ = attr "keySplines"
+-----------------------------------------------------------------------------
+-- | [keyTimes](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/keyTimes) attribute
+keyTimes_ ::  MisoString -> Attribute model action
+keyTimes_ = attr "keyTimes"
+-----------------------------------------------------------------------------
+-- | [lengthAdjust](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/lengthAdjust) attribute
+lengthAdjust_ ::  MisoString -> Attribute model action
+lengthAdjust_ = attr "lengthAdjust"
+-----------------------------------------------------------------------------
+-- | [limitingConeAngle](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/limitingConeAngle) attribute
+limitingConeAngle_ ::  MisoString -> Attribute model action
+limitingConeAngle_ = attr "limitingConeAngle"
+-----------------------------------------------------------------------------
+-- | [markerHeight](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/markerHeight) attribute
+markerHeight_ ::  MisoString -> Attribute model action
+markerHeight_ = attr "markerHeight"
+-----------------------------------------------------------------------------
+-- | [markerUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/markerUnits) attribute
+markerUnits_ ::  MisoString -> Attribute model action
+markerUnits_ = attr "markerUnits"
+-----------------------------------------------------------------------------
+-- | [markerWidth](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/markerWidth) attribute
+markerWidth_ ::  MisoString -> Attribute model action
+markerWidth_ = attr "markerWidth"
+-----------------------------------------------------------------------------
+-- | [maskContentUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/maskContentUnits) attribute
+maskContentUnits_ ::  MisoString -> Attribute model action
+maskContentUnits_ = attr "maskContentUnits"
+-----------------------------------------------------------------------------
+-- | [maskUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/maskUnits) attribute
+maskUnits_ ::  MisoString -> Attribute model action
+maskUnits_ = attr "maskUnits"
+-----------------------------------------------------------------------------
+-- | [max](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/max) attribute
+max_ ::  MisoString -> Attribute model action
+max_ = attr "max"
+-----------------------------------------------------------------------------
+-- | [media](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/media) attribute
+media_ ::  MisoString -> Attribute model action
+media_ = attr "media"
+-----------------------------------------------------------------------------
+-- | [method](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/method) attribute
+method_ ::  MisoString -> Attribute model action
+method_ = attr "method"
+-----------------------------------------------------------------------------
+-- | [min](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/min) attribute
+min_ ::  MisoString -> Attribute model action
+min_ = attr "min"
+-----------------------------------------------------------------------------
+-- | [mode](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/mode) attribute
+mode_ ::  MisoString -> Attribute model action
+mode_ = attr "mode"
+-----------------------------------------------------------------------------
+-- | [numOctaves](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/numOctaves) attribute
+numOctaves_ ::  MisoString -> Attribute model action
+numOctaves_ = attr "numOctaves"
+-----------------------------------------------------------------------------
+-- | [offset](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/stop) attribute
+offset_ ::  MisoString -> Attribute model action
+offset_ = attr "offset"
+-----------------------------------------------------------------------------
+-- | [operator](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/operator) attribute
+operator_ ::  MisoString -> Attribute model action
+operator_ = attr "operator"
+-----------------------------------------------------------------------------
+-- | [order](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/order) attribute
+order_ ::  MisoString -> Attribute model action
+order_ = attr "order"
+-----------------------------------------------------------------------------
+-- | [orient](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/orient) attribute
+orient_ ::  MisoString -> Attribute model action
+orient_ = attr "orient"
+-----------------------------------------------------------------------------
+-- | [origin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/origin) attribute
+origin_ ::  MisoString -> Attribute model action
+origin_ = attr "origin"
+-----------------------------------------------------------------------------
+-- | [path](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/path) attribute
+path_ ::  MisoString -> Attribute model action
+path_ = attr "path"
+-----------------------------------------------------------------------------
+-- | [paint-order](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/paint-order) attribute
+--
+-- @since 1.9.0.0
+paintOrder_ ::  MisoString -> Attribute model action
+paintOrder_ = attr "paint-order"
+-----------------------------------------------------------------------------
+-- | [pathLength](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pathLength) attribute
+pathLength_ ::  MisoString -> Attribute model action
+pathLength_ = attr "pathLength"
+-----------------------------------------------------------------------------
+-- | [patternContentUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/patternContentUnits) attribute
+patternContentUnits_ ::  MisoString -> Attribute model action
+patternContentUnits_ = attr "patternContentUnits"
+-----------------------------------------------------------------------------
+-- | [patternTransform](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/patternTransform) attribute
+patternTransform_ ::  MisoString -> Attribute model action
+patternTransform_ = attr "patternTransform"
+-----------------------------------------------------------------------------
+-- | [patternUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/patternUnits) attribute
+patternUnits_ ::  MisoString -> Attribute model action
+patternUnits_ = attr "patternUnits"
+-----------------------------------------------------------------------------
+-- | [points](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/points) attribute
+points_ ::  MisoString -> Attribute model action
+points_ = attr "points"
+-----------------------------------------------------------------------------
+-- | [pointsAtX](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pointsAtX) attribute
+pointsAtX_ ::  MisoString -> Attribute model action
+pointsAtX_ = attr "pointsAtX"
+-----------------------------------------------------------------------------
+-- | [pointsAtY](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pointsAtY) attribute
+pointsAtY_ ::  MisoString -> Attribute model action
+pointsAtY_ = attr "pointsAtY"
+-----------------------------------------------------------------------------
+-- | [pointsAtZ](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pointsAtZ) attribute
+pointsAtZ_ ::  MisoString -> Attribute model action
+pointsAtZ_ = attr "pointsAtZ"
+-----------------------------------------------------------------------------
+-- | [preserveAlpha](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/preserveAlpha) attribute
+preserveAlpha_ ::  MisoString -> Attribute model action
+preserveAlpha_ = attr "preserveAlpha"
+-----------------------------------------------------------------------------
+-- | [preserveAspectRatio](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/preserveAspectRatio) attribute
+preserveAspectRatio_ ::  MisoString -> Attribute model action
+preserveAspectRatio_ = attr "preserveAspectRatio"
+-----------------------------------------------------------------------------
+-- | [primitiveUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/primitiveUnits) attribute
+primitiveUnits_ ::  MisoString -> Attribute model action
+primitiveUnits_ = attr "primitiveUnits"
+-----------------------------------------------------------------------------
+-- | [r](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/r) attribute
+r_ ::  MisoString -> Attribute model action
+r_ = attr "r"
+-----------------------------------------------------------------------------
+-- | [radius](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/radius) attribute
+radius_ ::  MisoString -> Attribute model action
+radius_ = attr "radius"
+-----------------------------------------------------------------------------
+-- | [refX](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/refX) attribute
+refX_ ::  MisoString -> Attribute model action
+refX_ = attr "refX"
+-----------------------------------------------------------------------------
+-- | [refY](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/refY) attribute
+refY_ ::  MisoString -> Attribute model action
+refY_ = attr "refY"
+-----------------------------------------------------------------------------
+-- | [repeatCount](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/repeatCount) attribute
+repeatCount_ ::  MisoString -> Attribute model action
+repeatCount_ = attr "repeatCount"
+-----------------------------------------------------------------------------
+-- | [repeatDur](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/repeatDur) attribute
+repeatDur_ ::  MisoString -> Attribute model action
+repeatDur_ = attr "repeatDur"
+-----------------------------------------------------------------------------
+-- | [restart](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/restart) attribute
+restart_ ::  MisoString -> Attribute model action
+restart_ = attr "restart"
+-----------------------------------------------------------------------------
+-- | [result](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/result) attribute
+result_ ::  MisoString -> Attribute model action
+result_ = attr "result"
+-----------------------------------------------------------------------------
+-- | [rotate](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/rotate) attribute
+rotate_ ::  MisoString -> Attribute model action
+rotate_ = attr "rotate"
+-----------------------------------------------------------------------------
+-- | [rx](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/rx) attribute
+rx_ ::  MisoString -> Attribute model action
+rx_ = attr "rx"
+-----------------------------------------------------------------------------
+-- | [ry](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/ry) attribute
+ry_ ::  MisoString -> Attribute model action
+ry_ = attr "ry"
+-----------------------------------------------------------------------------
+-- | [scale](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/scale) attribute
+scale_ ::  MisoString -> Attribute model action
+scale_ = attr "scale"
+-----------------------------------------------------------------------------
+-- | [seed](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/seed) attribute
+seed_ ::  MisoString -> Attribute model action
+seed_ = attr "seed"
+-----------------------------------------------------------------------------
+-- | [side](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/side) attribute
+--
+-- @since 1.9.0.0
+side_ ::  MisoString -> Attribute model action
+side_ = attr "side"
+-----------------------------------------------------------------------------
+-- | [slope](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/slope) attribute
+slope_ ::  MisoString -> Attribute model action
+slope_ = attr "slope"
+-----------------------------------------------------------------------------
+-- | [spacing](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/spacing) attribute
+spacing_ ::  MisoString -> Attribute model action
+spacing_ = attr "spacing"
+-----------------------------------------------------------------------------
+-- | [specularConstant](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/specularConstant) attribute
+specularConstant_ ::  MisoString -> Attribute model action
+specularConstant_ = attr "specularConstant"
+-----------------------------------------------------------------------------
+-- | [specularExponent](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/specularExponent) attribute
+specularExponent_ ::  MisoString -> Attribute model action
+specularExponent_ = attr "specularExponent"
+-----------------------------------------------------------------------------
+-- | [spreadMethod](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/spreadMethod) attribute
+spreadMethod_ ::  MisoString -> Attribute model action
+spreadMethod_ = attr "spreadMethod"
+-----------------------------------------------------------------------------
+-- | [startOffset](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/startOffset) attribute
+startOffset_ ::  MisoString -> Attribute model action
+startOffset_ = attr "startOffset"
+-----------------------------------------------------------------------------
+-- | [stdDeviation](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stdDeviation) attribute
+stdDeviation_ ::  MisoString -> Attribute model action
+stdDeviation_ = attr "stdDeviation"
+-----------------------------------------------------------------------------
+-- | [stitchTiles](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stitchTiles) attribute
+stitchTiles_ ::  MisoString -> Attribute model action
+stitchTiles_ = attr "stitchTiles"
+-----------------------------------------------------------------------------
+-- | [surfaceScale](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/surfaceScale) attribute
+surfaceScale_ ::  MisoString -> Attribute model action
+surfaceScale_ = attr "surfaceScale"
+-----------------------------------------------------------------------------
+-- | [systemLanguage](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/systemLanguage) attribute
+systemLanguage_ ::  MisoString -> Attribute model action
+systemLanguage_ = attr "systemLanguage"
+-----------------------------------------------------------------------------
+-- | [tableValues](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/tableValues) attribute
+tableValues_ ::  MisoString -> Attribute model action
+tableValues_ = attr "tableValues"
+-----------------------------------------------------------------------------
+-- | [target](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/target) attribute
+target_ ::  MisoString -> Attribute model action
+target_ = attr "target"
+-----------------------------------------------------------------------------
+-- | [targetX](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/targetX) attribute
+targetX_ ::  MisoString -> Attribute model action
+targetX_ = attr "targetX"
+-----------------------------------------------------------------------------
+-- | [targetY](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/targetY) attribute
+targetY_ ::  MisoString -> Attribute model action
+targetY_ = attr "targetY"
+-----------------------------------------------------------------------------
+-- | [textLength](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/textLength) attribute
+textLength_ ::  MisoString -> Attribute model action
+textLength_ = attr "textLength"
+-----------------------------------------------------------------------------
+-- | [to](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/to) attribute
+to_ ::  MisoString -> Attribute model action
+to_ = attr "to"
+-----------------------------------------------------------------------------
+-- | [transform](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/transform) attribute
+transform_ ::  MisoString -> Attribute model action
+transform_ = attr "transform"
+-----------------------------------------------------------------------------
+-- | [transform-origin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/transform-origin) attribute
+--
+-- @since 1.9.0.0
+transformOrigin_ ::  MisoString -> Attribute model action
+transformOrigin_ = attr "transform-origin"
+-----------------------------------------------------------------------------
+-- | [type](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/type) attribute
+type_' ::  MisoString -> Attribute model action
+type_' = attr "type"
+-----------------------------------------------------------------------------
+-- | [values](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/values) attribute
+values_ ::  MisoString -> Attribute model action
+values_ = attr "values"
+-----------------------------------------------------------------------------
+-- | [vector-effect](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/vector-effect) attribute
+--
+-- @since 1.9.0.0
+vectorEffect_ ::  MisoString -> Attribute model action
+vectorEffect_ = attr "vector-effect"
+-----------------------------------------------------------------------------
+-- | [viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/viewBox) attribute
+viewBox_ ::  MisoString -> Attribute model action
+viewBox_ = attr "viewBox"
+-----------------------------------------------------------------------------
+-- | [x](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/x) attribute
+x_ ::  MisoString -> Attribute model action
+x_ = attr "x"
+-----------------------------------------------------------------------------
+-- | [x1](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/x1) attribute
+x1_ ::  MisoString -> Attribute model action
+x1_ = attr "x1"
+-----------------------------------------------------------------------------
+-- | [x2](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/x2) attribute
+x2_ ::  MisoString -> Attribute model action
+x2_ = attr "x2"
+-----------------------------------------------------------------------------
+-- | [xChannelSelector](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/xChannelSelector) attribute
+xChannelSelector_ ::  MisoString -> Attribute model action
+xChannelSelector_ = attr "x-channel-selector"
+-----------------------------------------------------------------------------
+-- | [y](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/y) attribute
+y_ ::  MisoString -> Attribute model action
+y_ = attr "y"
+-----------------------------------------------------------------------------
+-- | [y1](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/y1) attribute
+y1_ ::  MisoString -> Attribute model action
+y1_ = attr "y1"
+-----------------------------------------------------------------------------
+-- | [y2](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/y2) attribute
+y2_ ::  MisoString -> Attribute model action
+y2_ = attr "y2"
+-----------------------------------------------------------------------------
+-- | [yChannelSelector](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/yChannelSelector) attribute
+yChannelSelector_ ::  MisoString -> Attribute model action
+yChannelSelector_ = attr "yChannelSelector"
+-----------------------------------------------------------------------------
+-- | [z](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/z) attribute
+z_ ::  MisoString -> Attribute model action
+z_ = attr "z"
+-----------------------------------------------------------------------------
+-- | [alignment-baseline](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/alignment-baseline) attribute
+alignmentBaseline_ ::  MisoString -> Attribute model action
+alignmentBaseline_ = attr "alignment-baseline"
+-----------------------------------------------------------------------------
+-- | [baseline-shift](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/baseline-shift) attribute
+baselineShift_ ::  MisoString -> Attribute model action
+baselineShift_ = attr "baseline-shift"
+-----------------------------------------------------------------------------
+-- | [clip-path](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/clip-path) attribute
+clipPath_ ::  MisoString -> Attribute model action
+clipPath_ = attr "clip-path"
+-----------------------------------------------------------------------------
+-- | [clip-rule](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/clip-rule) attribute
+clipRule_ ::  MisoString -> Attribute model action
+clipRule_ = attr "clip-rule"
+-----------------------------------------------------------------------------
+-- | [color-interpolation](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/color-interpolation) attribute
+colorInterpolation_ ::  MisoString -> Attribute model action
+colorInterpolation_ = attr "color-interpolation"
+-----------------------------------------------------------------------------
+-- | [color-interpolation-filters](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/color-interpolation-filters) attribute
+colorInterpolationFilters_ ::  MisoString -> Attribute model action
+colorInterpolationFilters_ = attr "color-interpolation-filters"
+-----------------------------------------------------------------------------
+-- | [crossorigin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/crossorigin) attribute
+--
+-- @since 1.9.0.0
+crossorigin_ ::  MisoString -> Attribute model action
+crossorigin_ = attr "crossorigin"
+-----------------------------------------------------------------------------
+-- | [color](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/color) attribute
+color_ ::  MisoString -> Attribute model action
+color_ = attr "color"
+-----------------------------------------------------------------------------
+-- | [cursor](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/cursor) attribute
+cursor_ ::  MisoString -> Attribute model action
+cursor_ = attr "cursor"
+-----------------------------------------------------------------------------
+-- | [direction](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/direction) attribute
+direction_ ::  MisoString -> Attribute model action
+direction_ = attr "direction"
+-----------------------------------------------------------------------------
+-- | [display](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/display) attribute
+display_ ::  MisoString -> Attribute model action
+display_ = attr "display"
+-----------------------------------------------------------------------------
+-- | [dominant-baseline](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/dominant-baseline) attribute
+dominantBaseline_ ::  MisoString -> Attribute model action
+dominantBaseline_ = attr "dominant-baseline"
+-----------------------------------------------------------------------------
+-- | [fill-opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fill-opacity) attribute
+fillOpacity_ ::  MisoString -> Attribute model action
+fillOpacity_ = attr "fill-opacity"
+-----------------------------------------------------------------------------
+-- | [fill-rule](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fill-rule) attribute
+fillRule_ ::  MisoString -> Attribute model action
+fillRule_ = attr "fill-rule"
+-----------------------------------------------------------------------------
+-- | [fill](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fill) attribute
+fill_ ::  MisoString -> Attribute model action
+fill_ = attr "fill"
+-----------------------------------------------------------------------------
+-- | [filter](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/filter) attribute
+filter_ ::  MisoString -> Attribute model action
+filter_ = attr "filter"
+-----------------------------------------------------------------------------
+-- | [flood-color](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/flood-color) attribute
+floodColor_ ::  MisoString -> Attribute model action
+floodColor_ = attr "flood-color"
+-----------------------------------------------------------------------------
+-- | [flood-opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/flood-opacity) attribute
+floodOpacity_ ::  MisoString -> Attribute model action
+floodOpacity_ = attr "flood-opacity"
+-----------------------------------------------------------------------------
+-- | [font-family](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-family) attribute
+fontFamily_ ::  MisoString -> Attribute model action
+fontFamily_ = attr "font-family"
+-----------------------------------------------------------------------------
+-- | [font-size-adjust](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-size-adjust) attribute
+fontSizeAdjust_ ::  MisoString -> Attribute model action
+fontSizeAdjust_ = attr "font-size-adjust"
+-----------------------------------------------------------------------------
+-- | [font-size](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-size) attribute
+fontSize_ ::  MisoString -> Attribute model action
+fontSize_ = attr "font-size"
+-----------------------------------------------------------------------------
+-- | [font-style](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-style) attribute
+fontStyle_ ::  MisoString -> Attribute model action
+fontStyle_ = attr "font-style"
+-----------------------------------------------------------------------------
+-- | [font-variant](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-variant) attribute
+fontVariant_ ::  MisoString -> Attribute model action
+fontVariant_ = attr "font-variant"
+-----------------------------------------------------------------------------
+-- | [font-weight](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-weight) attribute
+fontWeight_ ::  MisoString -> Attribute model action
+fontWeight_ = attr "font-weight"
+-----------------------------------------------------------------------------
+-- | [image-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/image-rendering) attribute
+imageRendering_ ::  MisoString -> Attribute model action
+imageRendering_ = attr "image-rendering"
+-----------------------------------------------------------------------------
+-- | [letter-spacing](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/letter-spacing) attribute
+letterSpacing_ ::  MisoString -> Attribute model action
+letterSpacing_ = attr "letter-spacing"
+-----------------------------------------------------------------------------
+-- | [lighting-color](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/lighting-color) attribute
+lightingColor_ ::  MisoString -> Attribute model action
+lightingColor_ = attr "lighting-color"
+-----------------------------------------------------------------------------
+-- | [marker-end](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-end) attribute
+markerEnd_ ::  MisoString -> Attribute model action
+markerEnd_ = attr "marker-end"
+-----------------------------------------------------------------------------
+-- | [marker-mid](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-mid) attribute
+markerMid_ ::  MisoString -> Attribute model action
+markerMid_ = attr "marker-mid"
+-----------------------------------------------------------------------------
+-- | [marker-start](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-start) attribute
+markerStart_ ::  MisoString -> Attribute model action
+markerStart_ = attr "marker-start"
+-----------------------------------------------------------------------------
+-- | [mask](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/mask) attribute
+mask_ ::  MisoString -> Attribute model action
+mask_ = attr "mask"
+-----------------------------------------------------------------------------
+-- | [opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/opacity) attribute
+opacity_ ::  MisoString -> Attribute model action
+opacity_ = attr "opacity"
+-----------------------------------------------------------------------------
+-- | [overflow](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/overflow) attribute
+overflow_ ::  MisoString -> Attribute model action
+overflow_ = attr "overflow"
+-----------------------------------------------------------------------------
+-- | [pointer-events](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pointer-events) attribute
+pointerEvents_ ::  MisoString -> Attribute model action
+pointerEvents_ = attr "pointer-events"
+-----------------------------------------------------------------------------
+-- | [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/shape-rendering) attribute
+shapeRendering_ ::  MisoString -> Attribute model action
+shapeRendering_ = attr "shape-rendering"
+-----------------------------------------------------------------------------
+-- | [stop-color](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stop-color) attribute
+stopColor_ ::  MisoString -> Attribute model action
+stopColor_ = attr "stop-color"
+-----------------------------------------------------------------------------
+-- | [stop-opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stop-opacity) attribute
+stopOpacity_ ::  MisoString -> Attribute model action
+stopOpacity_ = attr "stop-opacity"
+-----------------------------------------------------------------------------
+-- | [stroke-dasharray](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-dasharray) attribute
+strokeDasharray_ ::  MisoString -> Attribute model action
+strokeDasharray_ = attr "stroke-dasharray"
+-----------------------------------------------------------------------------
+-- | [stroke-dashoffset](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-dashoffset) attribute
+strokeDashoffset_ ::  MisoString -> Attribute model action
+strokeDashoffset_ = attr "stroke-dashoffset"
+-----------------------------------------------------------------------------
+-- | [stroke-linecap](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-linecap) attribute
+strokeLinecap_ ::  MisoString -> Attribute model action
+strokeLinecap_ = attr "stroke-linecap"
+-----------------------------------------------------------------------------
+-- | [stroke-linejoin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-linejoin) attribute
+strokeLinejoin_ ::  MisoString -> Attribute model action
+strokeLinejoin_ = attr "stroke-linejoin"
+-----------------------------------------------------------------------------
+-- | [stroke-miterlimit](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-miterlimit) attribute
+strokeMiterlimit_ ::  MisoString -> Attribute model action
+strokeMiterlimit_ = attr "stroke-miterlimit"
+-----------------------------------------------------------------------------
+-- | [stroke-opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-opacity) attribute
+strokeOpacity_ ::  MisoString -> Attribute model action
+strokeOpacity_ = attr "stroke-opacity"
+-----------------------------------------------------------------------------
+-- | [stroke-width](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-width) attribute
+strokeWidth_ ::  MisoString -> Attribute model action
+strokeWidth_ = attr "stroke-width"
+-----------------------------------------------------------------------------
+-- | [stroke](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke) attribute
+stroke_ ::  MisoString -> Attribute model action
+stroke_ = attr "stroke"
+-----------------------------------------------------------------------------
+-- | [text-anchor](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/text-anchor) attribute
+textAnchor_ ::  MisoString -> Attribute model action
+textAnchor_ = attr "text-anchor"
+-----------------------------------------------------------------------------
+-- | [text-decoration](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/text-decoration) attribute
+textDecoration_ ::  MisoString -> Attribute model action
+textDecoration_ = attr "text-decoration"
+-----------------------------------------------------------------------------
+-- | [text-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/text-rendering) attribute
+textRendering_ ::  MisoString -> Attribute model action
+textRendering_ = attr "text-rendering"
+-----------------------------------------------------------------------------
+-- | [unicode-bidi](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/unicode-bidi) attribute
+unicodeBidi_ ::  MisoString -> Attribute model action
+unicodeBidi_ = attr "unicode-bidi"
+-----------------------------------------------------------------------------
+-- | [visibility](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/visibility) attribute
+visibility_ ::  MisoString -> Attribute model action
+visibility_ = attr "visibility"
+-----------------------------------------------------------------------------
+-- | [word-spacing](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/word-spacing) attribute
+wordSpacing_ ::  MisoString -> Attribute model action
+wordSpacing_ = attr "word-spacing"
+-----------------------------------------------------------------------------
+-- | [writing-mode](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/writing-mode) attribute
+writingMode_ ::  MisoString -> Attribute model action
+writingMode_ = attr "writing-mode"
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Trace.hs b/src/Miso/Trace.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Trace.hs
@@ -0,0 +1,286 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Trace
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Trace" provides functions for tracing values to the browser's
+-- developer console, in the spirit of "Debug.Trace" from @base@. Where
+-- "Debug.Trace" writes to @stderr@, these functions write to the browser
+-- console using
+-- <https://developer.mozilla.org/en-US/docs/Web/API/console/log_static console.log>,
+-- <https://developer.mozilla.org/en-US/docs/Web/API/console/warn_static console.warn>
+-- and
+-- <https://developer.mozilla.org/en-US/docs/Web/API/console/error_static console.error>,
+-- gaining the browser's affordances such as severity filtering and stack
+-- traces.
+--
+-- The motivation is debugging /pure/ code: places where 'IO' is
+-- unavailable or inconvenient, such as a miso application's @view@
+-- function or pure helpers called from @update@.
+--
+-- Like "Debug.Trace", these functions are implemented with
+-- 'unsafePerformIO' and are not referentially transparent: they are meant
+-- only as a debugging aid and should not be used in production code.
+-- Since Haskell is lazily evaluated, a trace fires when (and only when)
+-- the traced expression is forced, so messages can appear out of order,
+-- once, or not at all.
+--
+-- = Naming conventions
+--
+-- The functions follow the naming conventions of "Debug.Trace":
+--
+-- * @trace*@ functions log with @console.log@, @traceWarn*@ with
+--   @console.warn@, and @traceError*@ with @console.error@.
+-- * @*Show@ variants accept any 'Show'-able value instead of a string.
+-- * @*Id@ variants return the traced value itself.
+-- * @*With@ variants trace the result of applying a function to the value.
+-- * @*M@ variants trace inside an 'Applicative' (e.g. miso's
+--   'Miso.Effect.Effect' monad, or 'IO').
+--
+-- = See also
+--
+-- * "Debug.Trace" — the @base@ equivalent, on which this API is modeled
+-- * "Miso.FFI" — 'consoleLog', 'consoleWarn', 'consoleError'
+----------------------------------------------------------------------------
+module Miso.Trace
+  ( -- ** Logging (@console.log@)
+    trace
+  , traceId
+  , traceWith
+  , traceShow
+  , traceShowId
+  , traceShowWith
+  , traceM
+  , traceShowM
+    -- ** Errors (@console.error@)
+  , traceError
+  , traceErrorId
+  , traceErrorWith
+  , traceErrorShow
+  , traceErrorShowId
+  , traceErrorShowWith
+  , traceErrorM
+  , traceErrorShowM
+    -- ** Warnings (@console.warn@)
+  , traceWarn
+  , traceWarnId
+  , traceWarnWith
+  , traceWarnShow
+  , traceWarnShowId
+  , traceWarnShowWith
+  , traceWarnM
+  , traceWarnShowM
+    -- ** Generalized tracing
+  , traceTo
+  ) where
+-----------------------------------------------------------------------------
+import           System.IO.Unsafe (unsafePerformIO)
+import           Prelude
+-----------------------------------------------------------------------------
+import           Miso.FFI
+import           Miso.String
+-----------------------------------------------------------------------------
+-- | Outputs a message to the browser console with @console.log@ when the
+-- result is forced, then returns the second argument. The browser
+-- analogue of 'Debug.Trace.trace'.
+trace
+  :: ToMisoString s
+  => s
+  -- ^ Message to log
+  -> a
+  -- ^ Value to return
+  -> a
+trace = traceTo consoleLog
+-----------------------------------------------------------------------------
+-- | Like 'trace', but returns the message itself:
+-- @'traceId' x = 'trace' x x@.
+traceId :: ToMisoString s => s -> s
+traceId = traceWith id
+-----------------------------------------------------------------------------
+-- | Traces the result of applying a function to a value, then returns the
+-- original value. Useful for logging a projection of a larger structure
+-- while leaving the structure untouched.
+traceWith
+  :: ToMisoString s
+  => (a -> s)
+  -- ^ Function producing the message from the value
+  -> a
+  -- ^ Value to trace and return
+  -> a
+traceWith f a = trace (f a) a
+-----------------------------------------------------------------------------
+-- | Like 'trace', but accepts any 'Show'-able value as the message. The
+-- browser analogue of 'Debug.Trace.traceShow'.
+traceShow
+  :: Show a
+  => a
+  -- ^ Value to log
+  -> b
+  -- ^ Value to return
+  -> b
+traceShow = trace . show
+-----------------------------------------------------------------------------
+-- | Shows and traces a value, then returns it. Convenient to wrap around
+-- any sub-expression you want to inspect without restructuring the code.
+traceShowId :: Show a => a -> a
+traceShowId = traceWith show
+-----------------------------------------------------------------------------
+-- | Traces the 'show'-n result of applying a function to a value, then
+-- returns the original value.
+traceShowWith
+  :: Show b
+  => (a -> b)
+  -- ^ Function producing the value to show from the value
+  -> a
+  -- ^ Value to trace and return
+  -> a
+traceShowWith f = traceWith (show . f)
+-----------------------------------------------------------------------------
+-- | Traces a message in an 'Applicative' context, such as miso's
+-- 'Miso.Effect.Effect' monad or 'IO'. The browser analogue of
+-- 'Debug.Trace.traceM'.
+traceM :: (ToMisoString s, Applicative f) => s -> f ()
+traceM s = trace s $ pure ()
+-----------------------------------------------------------------------------
+-- | Like 'traceM', but accepts any 'Show'-able value. Useful for logging
+-- every action that flows through an update function.
+traceShowM :: (Show a, Applicative f) => a -> f ()
+traceShowM = traceM . show
+-----------------------------------------------------------------------------
+-- | Like 'trace', but logs with @console.error@, which browsers render
+-- prominently (typically in red, with an expandable stack trace).
+traceError
+  :: ToMisoString s
+  => s
+  -- ^ Message to log
+  -> a
+  -- ^ Value to return
+  -> a
+traceError = traceTo consoleError
+-----------------------------------------------------------------------------
+-- | Like 'traceId', but logs with @console.error@.
+traceErrorId :: ToMisoString s => s -> s
+traceErrorId = traceErrorWith id
+-----------------------------------------------------------------------------
+-- | Like 'traceWith', but logs with @console.error@.
+traceErrorWith
+  :: ToMisoString s
+  => (a -> s)
+  -- ^ Function producing the message from the value
+  -> a
+  -- ^ Value to trace and return
+  -> a
+traceErrorWith f a = traceError (f a) a
+-----------------------------------------------------------------------------
+-- | Like 'traceShow', but logs with @console.error@.
+traceErrorShow
+  :: Show a
+  => a
+  -- ^ Value to log
+  -> b
+  -- ^ Value to return
+  -> b
+traceErrorShow = traceError . show
+-----------------------------------------------------------------------------
+-- | Like 'traceShowId', but logs with @console.error@.
+traceErrorShowId :: Show a => a -> a
+traceErrorShowId = traceErrorWith show
+-----------------------------------------------------------------------------
+-- | Like 'traceShowWith', but logs with @console.error@.
+traceErrorShowWith
+  :: Show b
+  => (a -> b)
+  -- ^ Function producing the value to show from the value
+  -> a
+  -- ^ Value to trace and return
+  -> a
+traceErrorShowWith f = traceErrorWith (show . f)
+-----------------------------------------------------------------------------
+-- | Like 'traceM', but logs with @console.error@.
+traceErrorM :: (ToMisoString s, Applicative f) => s -> f ()
+traceErrorM s = traceError s $ pure ()
+-----------------------------------------------------------------------------
+-- | Like 'traceShowM', but logs with @console.error@.
+traceErrorShowM :: (Show a, Applicative f) => a -> f ()
+traceErrorShowM = traceErrorM . show
+-----------------------------------------------------------------------------
+-- | Like 'trace', but logs with @console.warn@, which browsers render as
+-- a warning (typically in yellow) and can be filtered by severity.
+traceWarn
+  :: ToMisoString s
+  => s
+  -- ^ Message to log
+  -> a
+  -- ^ Value to return
+  -> a
+traceWarn = traceTo consoleWarn
+-----------------------------------------------------------------------------
+-- | Like 'traceId', but logs with @console.warn@.
+traceWarnId :: ToMisoString s => s -> s
+traceWarnId = traceWarnWith id
+-----------------------------------------------------------------------------
+-- | Like 'traceWith', but logs with @console.warn@.
+traceWarnWith
+  :: ToMisoString s
+  => (a -> s)
+  -- ^ Function producing the message from the value
+  -> a
+  -- ^ Value to trace and return
+  -> a
+traceWarnWith f a = traceWarn (f a) a
+-----------------------------------------------------------------------------
+-- | Like 'traceShow', but logs with @console.warn@.
+traceWarnShow
+  :: Show a
+  => a
+  -- ^ Value to log
+  -> b
+  -- ^ Value to return
+  -> b
+traceWarnShow = traceWarn . show
+-----------------------------------------------------------------------------
+-- | Like 'traceShowId', but logs with @console.warn@.
+traceWarnShowId :: Show a => a -> a
+traceWarnShowId = traceWarnWith show
+-----------------------------------------------------------------------------
+-- | Like 'traceShowWith', but logs with @console.warn@.
+traceWarnShowWith
+  :: Show b
+  => (a -> b)
+  -- ^ Function producing the value to show from the value
+  -> a
+  -- ^ Value to trace and return
+  -> a
+traceWarnShowWith f = traceWarnWith (show . f)
+-----------------------------------------------------------------------------
+-- | Like 'traceM', but logs with @console.warn@.
+traceWarnM :: (ToMisoString s, Applicative f) => s -> f ()
+traceWarnM s = traceWarn s $ pure ()
+-----------------------------------------------------------------------------
+-- | Like 'traceShowM', but logs with @console.warn@.
+traceWarnShowM :: (Show a, Applicative f) => a -> f ()
+traceWarnShowM = traceWarnM . show
+-----------------------------------------------------------------------------
+-- | The generalized tracing combinator underlying this module: traces via
+-- the given console function from "Miso.FFI". Every other function here
+-- is defined in terms of it.
+traceTo
+  :: ToMisoString s
+  => (MisoString -> IO ())
+  -- ^ Console function to log with, e.g. 'consoleLog'
+  -> s
+  -- ^ Message to log
+  -> a
+  -- ^ Value to return
+  -> a
+{-# NOINLINE traceTo #-}
+traceTo f s a = unsafePerformIO $ do
+  f (toMisoString s)
+  pure a
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Types.hs b/src/Miso/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Types.hs
@@ -0,0 +1,1196 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE ExistentialQuantification  #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE DerivingStrategies         #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE RecordWildCards            #-}
+{-# LANGUAGE DeriveAnyClass             #-}
+{-# LANGUAGE StaticPointers             #-}
+{-# LANGUAGE DeriveGeneric              #-}
+{-# LANGUAGE DeriveFunctor              #-}
+{-# LANGUAGE LambdaCase                 #-}
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE CPP                        #-}
+-----------------------------------------------------------------------------
+{-# OPTIONS_GHC -Wno-orphans #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Types
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Types" defines every core type that miso applications are built
+-- from. It is re-exported in its entirety by "Miso", so most application
+-- code never needs to import it directly.
+--
+-- = The Component record
+--
+-- @'Component' context props model action@ is the central record type. It
+-- wires together the MVU loop and all supporting runtime configuration:
+--
+-- @
+-- data t'Component' context props model action = Component
+--   { model           :: model
+--   , hydrateModel    :: Maybe (IO model)
+--   , update          :: action -> 'Miso.Effect.Effect' context props model action
+--   , view            :: context -> props -> model -> 'View' context model action
+--   , useContext      :: Bool
+--   , subs            :: ['Miso.Effect.Sub' action]
+--   , styles          :: ['CSS']
+--   , scripts         :: ['JS']
+--   , mountPoint      :: Maybe 'MountPoint'
+--   , logLevel        :: 'LogLevel'
+--   , mailbox         :: Value -> Maybe action
+--   , eventPropagation :: Bool
+--   , mount           :: Maybe action
+--   , unmount         :: Maybe action
+--   , onPropsChanged  :: Maybe (props -> props -> action)
+--   }
+-- @
+--
+-- Use the 'component' smart constructor to build one with sane defaults,
+-- then override only the fields you need:
+--
+-- @
+-- myApp :: 'App' Model Action
+-- myApp = ('component' initialModel update view)
+--   { 'subs'   = [ mySub ]
+--   , 'styles' = [ 'Href' \"style.css\" (False :: 'CacheBust') ]
+--   }
+-- @
+--
+-- = The View type
+--
+-- @'View' context model action@ is miso's virtual DOM tree. Its five
+-- constructors map to the five node kinds the runtime handles:
+--
+-- * 'VNode' — a regular DOM element (@\<div\>@, @\<svg\>@, …)
+-- * 'VText' — a text node
+-- * @VComp@ — an embedded child t'Component'
+-- * @VCompStatic@ — an embedded child t'Component' behind a 'GHC.StaticPtr.StaticPtr',
+--   so it can cross the Lynx dual-thread boundary (see 'vcomp' \/ 'mountStatic')
+-- * 'VFrag' — a group of siblings with no wrapper element, optionally keyed
+--
+-- = Key types at a glance
+--
+-- ['Component'] full MVU application\/component record
+-- ['App'] alias for @'Component' () () model action@
+-- ['View'] virtual DOM node
+-- ['Attribute'] DOM property, class list, event handler, or style
+-- ['Namespace'] @HTML@ \| @SVG@ \| @MATHML@
+-- ['Key'] reconciliation hint for list diffing
+-- ['CSS'] stylesheet reference (@Href@, @Style@, @Sheet@)
+-- ['JS'] script reference (@Src@, @Script@, @Module@, …)
+-- ['LogLevel'] debug verbosity (@Off@, @DebugHydrate@, …)
+-- ['URI'] parsed URL (path + query string + fragment)
+--
+-- = Text combinators
+--
+-- * 'text' — create a text node (HTML-escaped in SSR mode)
+-- * 'textRaw' — create a text node without HTML escaping
+-- * 'text_' — concatenate a list of strings with a space separator
+-- * 'textKey' / 'textKey_' — keyed variants for efficient list diffing
+-- * 'htmlEncode' — manually escape @< > & \" \'@
+--
+-- = Component mounting
+--
+-- * @\"key\" '+>' comp@ — mount a child component with a key
+-- * 'mount_' — mount without a key (unsafe in dynamic lists)
+-- * 'mountWithProps' / 'mountWithProps_' — mount with explicit @props@
+-- * 'mountUseContext' — mount without a key, subscribed to @context@ updates
+-- * 'vcomp' / 'vcomp_' (with 'mountStatic' \/ 'mountStaticWithProps') —
+--   static-key mounting; the compile-time
+--   'GHC.StaticPtr.StaticKey' already provides identity, so unlike the
+--   non-static combinators there is no keyed variant
+--
+-- __Under the Lynx dual-thread (@NATIVE@) backend, always use 'vcomp' \/
+-- 'vcomp_' — never '+>' \/ 'mount_' \/ 'mountWithProps' \/ 'mountWithProps_' \/
+-- 'mountUseContext'.__ The non-static combinators build a component with no
+-- 'GHC.StaticPtr.StaticKey'; anything mounted with them /after/ the initial
+-- frame (e.g. inside a list or behind a conditional) never registers a
+-- main-thread mirror on the MTS, which silently drops every @OnStatic@
+-- (main-thread) event handler inside that subtree for the component's whole
+-- lifetime. This is invisible outside of a console error — there is no type
+-- error and no runtime crash. GHC emits a warning at every use site of the
+-- non-static combinators when built with @NATIVE@ as a reminder.
+--
+-- = Fragment combinators
+--
+-- * 'fragment' / 'vfrag' — group siblings without a wrapper element
+-- * 'fragment_' / 'vfrag_' — keyed fragment
+--
+-- = Conditional view utilities
+--
+-- * 'optionalAttrs' — add attributes conditionally
+-- * 'optionalVoidAttrs' — same for void (no-children) elements
+-- * 'optionalChildren' — add children conditionally
+--
+-- = See also
+--
+-- * "Miso.Effect" — 'Miso.Effect.Effect', 'Miso.Effect.Sub', 'Miso.Effect.Sink'
+-- * "Miso.Html.Element" — element smart constructors built on 'node'
+-- * "Miso.Html.Property" — attribute constructors built on 'Attribute'
+-- * "Miso.Html.Render" — SSR serialisation via 'Miso.Html.Render.ToHtml'
+-- * "Miso.Router" — 'Miso.Router.URI' parsing and pretty-printing
+----------------------------------------------------------------------------
+module Miso.Types
+  ( -- ** Types
+    App
+  , Component     (..)
+  , ComponentId
+  , SomeComponent (..)
+  , SomeStaticComponent         (..)
+  , EventHandler  (..)
+  , View          (..)
+  , Key           (..)
+  , Attribute     (..)
+  , Namespace     (..)
+  , CSS           (..)
+  , JS            (..)
+  , LogLevel      (..)
+  , VTree         (..)
+  , VTreeType     (..)
+  , Hydrate       (..)
+  , Tag
+  , DirectEvents
+  , CacheBust
+  , MountPoint
+  , DOMRef
+  , Events
+  , Phase         (..)
+  , URI           (..)
+  -- ** Classes
+  , ToKey         (..)
+  -- ** Smart Constructors
+  , emptyURI
+  , component
+  -- ** Event handler smart constructor
+  , event
+  -- ** Component mounting
+  , vcomp
+  , vcomp_
+  , (+>)
+  , mount_
+  , mountUseContext
+  , mountWithProps_
+  , mountWithProps
+  , mountStatic
+  , mountStaticWithProps
+  -- ** Fragment combinators
+  , fragment
+  , fragment_
+  , vfrag
+  , vfrag_
+  -- ** Utils
+  , getMountPoint
+  , optionalAttrs
+  , optionalVoidAttrs
+  , optionalChildren
+  , prettyURI
+  , prettyQueryString
+  -- *** Combinators
+  , node
+  , nodeDirectEvents
+  , vnode
+  , text
+  , vtext
+  , text_
+  , textRaw
+  , textKey
+  , textKey_
+  , htmlEncode
+  -- *** MisoString
+  , MisoString
+  , toMisoString
+  , fromMisoString
+  , ms
+  ) where
+-----------------------------------------------------------------------------
+import           Data.Function
+import qualified Data.Map.Strict as M
+import           Data.Set (Set)
+import qualified Data.Set as S
+import           Data.Maybe (fromMaybe, isJust)
+import           Data.String (IsString, fromString)
+import qualified Data.Text as T
+import           GHC.Generics
+import           GHC.StaticPtr
+import           Prelude
+-----------------------------------------------------------------------------
+import           Miso.DSL
+import           Miso.Effect (Effect, Sub, Sink, DOMRef, ComponentId)
+import           Miso.Event.Types
+import qualified Miso.Event.Decoder
+import           Miso.JSON (Value, ToJSON(..), encode)
+#ifdef NATIVE
+import           Miso.JSON (FromJSON(..))
+#endif
+import qualified Miso.String as MS
+import           Miso.String (ToMisoString, MisoString, toMisoString, ms, fromMisoString)
+import           Miso.CSS.Types (StyleSheet)
+-----------------------------------------------------------------------------
+-- | Application entry point
+data Component context props model action
+  = Component
+  { model :: model
+  -- ^ Initial model
+  , hydrateModel :: Maybe (IO model)
+  -- ^ Optional 'IO' to load component @model@ state, such as reading data from page.
+  --   The resulting @model@ is only used during initial hydration, not on remounts.
+  --
+  --   __Note:__ only synchronous 'IO' should be used here (e.g. reading from
+  --   @localStorage@ via 'Miso.Storage.getLocalStorage').
+  , update :: action -> Effect context props model action
+  -- ^ Updates model, optionally providing effects.
+  , view :: context -> props -> model -> View context model action
+  -- ^ Draws 'View'. Receives the app-global @context@, the @props@ passed by the
+  --   parent, and the current @model@.
+  , useContext :: Bool
+  -- ^ Whether this t'Miso.Types.Component' should be re-rendered when the
+  --   app-global @context@ changes (see 'Miso.Effect.modifyContext').
+  --
+  --   This controls whether a component __reacts__ to context changes, not
+  --   whether it may __change__ the context. A component may call
+  --   'Miso.Effect.modifyContext' \/ 'Miso.Effect.putContext' with
+  --   @useContext = False@; it simply won't re-render in response. Enable it on
+  --   the (usually nested) components whose 'Miso.Lens.view' reads the @context@ and must
+  --   refresh when it changes.
+  --
+  --   Defaults to @False@.
+  --
+  -- @since 1.9.0.0
+  , subs :: [ Sub model action ]
+  -- ^ Subscriptions to run during application lifetime
+  , styles :: [CSS]
+  -- ^ CSS styles expressed as either a URL ('Href') or as 'Style' text.
+  -- These styles are appended dynamically to the \<head\> section of your HTML page
+  -- before the initial draw on \<body\> occurs.
+  --
+  -- __Note:__ This field should only be used in development mode.
+  --
+  -- @since 1.9.0.0
+  , scripts :: [JS]
+  -- ^ JavaScript scripts expressed as either a URL ('Src') or raw JS text.
+  -- These scripts are appended dynamically to the \<head\> section of your HTML page
+  -- before the initial draw on \<body\> occurs.
+  --
+  -- __Note:__ This field should only be used in development mode.
+  --
+  -- @since 1.9.0.0
+  , mountPoint :: Maybe MountPoint
+  -- ^ ID of the root element for DOM diff.
+  -- If 'Nothing' is provided, the entire document body is used as a mount point.
+  , logLevel :: LogLevel
+  -- ^ Debugging configuration for prerendering and event delegation
+  , mailbox :: Value -> Maybe action
+  -- ^ Receives mail from other components
+  --
+  -- @since 1.9.0.0
+  , eventPropagation :: Bool
+  -- ^ Should events bubble up past the t'Miso.Types.Component' barrier.
+  --
+  -- Defaults to @False@
+  --
+  -- @since 1.9.0.0
+  , mount :: Maybe action
+  -- ^ action to execute during t'Miso.Types.Component' mount phase.
+  --
+  -- @since 1.9.0.0
+  , unmount :: Maybe action
+  -- ^ action to execute during t'Miso.Types.Component' unmount phase.
+  --
+  -- @since 1.9.0.0
+  , onPropsChanged :: Maybe (props -> props -> action)
+  -- ^ action to execute when t'Component' @props@ have changed (a.k.a. @props@ phase).
+  -- Receives previous @props@ and current @props@ as arguments.
+  --
+  -- @since 1.11.0.0
+  }
+-----------------------------------------------------------------------------
+-- | @mountPoint@ for t'Miso.Types.Component', e.g "body"
+type MountPoint = MisoString
+-----------------------------------------------------------------------------
+-- | Allow users to express 'CSS' and append it to \<head\> before the first draw
+--
+-- > 'Href' "http://domain.com/style.css" ('True' :: 'CacheBust')
+-- > 'Style' "body { background-color: red; }"
+--
+data CSS
+  = Href MisoString CacheBust
+  -- ^ @URL@ linking to hosted 'CSS'
+  | Style MisoString
+  -- ^ Raw 'CSS' content in a 'Miso.Html.Element.style_' tag
+  | Sheet StyleSheet
+  -- ^ 'CSS' built with "Miso.CSS"
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Parameter used to indicate cache busting logic should be used.
+-- If 'True' this will append a timestamp to the query. This will force cache
+-- invalidation on the browser, causing a fetch of the resources.
+--
+type CacheBust = Bool
+-----------------------------------------------------------------------------
+-- | Allow users to express JS and append it to \<head\> before the first draw
+--
+-- This is meant to be useful in development only.
+--
+-- @
+-- 'Src' \"http:\/\/example.com\/script.js\" (@False@ :: 'CacheBust')
+-- 'Script' "alert(\"hi\");"
+-- 'ImportMap' [ "key" @=:@ "value" ]
+-- 'Module' "console.log(\"hi\");"
+-- @
+--
+-- @since 1.9.0.0
+data JS
+  = Src MisoString CacheBust
+  -- ^ URL linking to hosted JS
+  | Script MisoString
+  -- ^ Raw JS content that you would enter in a \<script\> tag
+  | Module MisoString
+  -- ^ Raw JS module content that you would enter in a \<script type="module"\> tag.
+  -- See [script type](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type)
+  | ImportMap [(MisoString,MisoString)]
+  -- ^ Import map content in a \<script type="importmap"\> tag.
+  -- See [importmap](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap)
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Convenience for extracting mount point
+getMountPoint :: Maybe MisoString -> MisoString
+getMountPoint = fromMaybe "body"
+-----------------------------------------------------------------------------
+-- | Smart constructor for t'Miso.Types.Component' with sane defaults.
+component
+  :: model
+  -- ^ model
+  -> (action -> Effect context props model action)
+  -- ^ update
+  -> (context -> props -> model -> View context model action)
+  -- ^ view
+  -> Component context props model action
+component m u v = Component
+  { model = m
+  , hydrateModel = Nothing
+  , update = u
+  , view = v
+  , useContext = False
+  , subs = []
+  , styles = []
+  , scripts = []
+  , mountPoint = Nothing
+  , logLevel = Off
+  , mailbox = const Nothing
+  , eventPropagation = False
+  , mount = Nothing
+  , unmount = Nothing
+  , onPropsChanged = Nothing
+  }
+-----------------------------------------------------------------------------
+-- | A miso application is a top-level t'Miso.Types.Component'. Its app-global
+-- @context@ defaults to @()@ (see 'Miso.startAppWithContext' to supply a
+-- non-trivial context), and its @props@ are fixed to @()@.
+--
+type App model action = Component () () model action
+-----------------------------------------------------------------------------
+-- | Logging configuration for debugging Miso internals (useful to see if prerendering is successful)
+data LogLevel
+  = Off
+  -- ^ No debug logging, the default value used in 'component'
+  | DebugHydrate
+  -- ^ Will warn if the structure or properties of the
+  -- DOM vs. Virtual DOM differ during prerendering.
+  | DebugEvents
+  -- ^ Will warn if an event cannot be routed to the Haskell event
+  -- handler that raised it. Also will warn if an event handler is
+  -- being used, yet it's not being listened for by the event
+  -- delegator mount point.
+  | DebugAll
+  -- ^ Logs on all of the above
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+-- | Tag type, (e.g. 'Miso.Html.Element.div_', 'Miso.Html.Element.p_')
+--
+-- Meant to indicate the type of element being created.
+-- Used as the first argument to @document.createElement@ for the web backend.
+--
+type Tag = MisoString
+-----------------------------------------------------------------------------
+-- | The set of events an element dispatches /directly/ on itself rather than
+-- by bubbling to the delegated mount listener. Empty for HTML\/SVG\/MathML;
+-- populated for Lynx native elements (see 'nodeDirectEvents').
+--
+-- @since 1.13.0.0
+type DirectEvents = Set MisoString
+-----------------------------------------------------------------------------
+-- | Core type for constructing a virtual DOM in Haskell
+data View context model action
+  = VNode Namespace Tag [Attribute model action] [View context model action] DirectEvents
+    -- ^ The final 'Set' names the events this element dispatches /directly/ on
+    -- itself rather than by bubbling to the delegated mount listener (Lynx
+    -- native @input@\/@scroll@\/… events). Empty for all HTML\/SVG\/MathML
+    -- elements. See 'nodeDirectEvents'.
+  | VText (Maybe Key) MisoString
+  | VComp (SomeComponent context)
+  | forall props . VCompStatic (StaticPtr (SomeStaticComponent props context)) props
+    -- ^ An embedded child t'Component'. The 'StaticPtr' holds only the closed
+    -- @props -> component@ constructor ('SomeStaticComponent'); the @props@ value — often
+    -- derived from the parent's @model@ — rides alongside and crosses the
+    -- dual-thread (Lynx) boundary as JSON. The no-props case uses @props ~ ()@
+    -- (see 'mountStatic'). This split is what lets a mount escape @static@\'s
+    -- closedness restriction. See 'vcomp'. This is necessary for lynx dual-thread
+    -- in order to transfer context, props, event handlers etc.
+  | VFrag (Maybe Key) [View context model action]
+-----------------------------------------------------------------------------
+-- | Existential wrapper allowing nesting of t'Miso.Types.Component' in t'Miso.Types.Component'.
+--
+-- The @context@ type parameter is shared with the enclosing 'View', so every
+-- nested t'Miso.Types.Component' participates in the same app-global context.
+data SomeComponent context
+#ifdef NATIVE
+   = forall model action props . (FromJSON model, ToJSON model, FromJSON action, ToJSON action, FromJSON props, ToJSON props, Eq context, Eq model, Eq props)
+#else
+   = forall model action props . (Eq context, Eq model, Eq props)
+#endif
+  => SomeComponent (Maybe Key) props (Component context props model action)
+-----------------------------------------------------------------------------
+-- | A closed @props -> component@ constructor, bundled with the serialization
+-- dictionaries needed to move @props@ across the dual-thread (Lynx) boundary.
+--
+-- Unlike t'SomeComponent', the @props@ type parameter is /preserved/ (not
+-- existential). This lets @vcompWith@ statically require the runtime @props@
+-- value to match the constructor, while the packed 'FromJSON' \/ 'ToJSON'
+-- dictionaries are recovered on the MTS after 'unsafeLookupStaticPtr' derefs
+-- the 'StaticPtr' — so the MTS can decode the wire @props@ at exactly this
+-- type and rebuild the t'SomeComponent'.
+--
+-- Built with 'mount_' \/ 'mountWithProps' \/ '(+>)'; consumed by 'vcomp'.
+--
+-- @since 1.13.0.0
+data SomeStaticComponent props context
+#ifdef NATIVE
+  = (Eq props, FromJSON props, ToJSON props)
+  => SomeStaticComponent (props -> SomeComponent context)
+#else
+  = Eq props
+  => SomeStaticComponent (props -> SomeComponent context)
+#endif
+-----------------------------------------------------------------------------
+-- | Create a fragment (keyless).
+--
+-- A fragment groups multiple sibling 'View' nodes without introducing
+-- an extra DOM element.
+--
+-- Synonym for `fragment'
+--
+-- @since 1.10.0.0
+vfrag :: [View context model action] -> View context model action
+vfrag = fragment
+-----------------------------------------------------------------------------
+-- | Create a fragment (keyless).
+--
+-- A fragment groups multiple sibling 'View' nodes without introducing
+-- an extra DOM element.
+--
+-- @since 1.10.0.0
+fragment :: [View context model action] -> View context model action
+fragment = VFrag Nothing
+-----------------------------------------------------------------------------
+-- | Like 'fragment', but keyed for efficient diffing.
+--
+-- @since 1.10.0.0
+vfrag_ :: MisoString -> [View context model action] -> View context model action
+vfrag_ key = VFrag (Just (Key key))
+-----------------------------------------------------------------------------
+-- | Like 'fragment', but keyed for efficient diffing.
+--
+-- @since 1.10.0.0
+fragment_ :: MisoString -> [View context model action] -> View context model action
+fragment_ key = VFrag (Just (Key key))
+-----------------------------------------------------------------------------
+-- | t'Miso.Types.Component' mounting combinator
+--
+-- Used in the @view@ function to mount a t'Miso.Types.Component' on any 'VNode'.
+--
+-- @
+-- "component-id" +> component model noop $ \\m ->
+--   div_ [ id_ "foo" ] [ text (ms m) ]
+-- @
+--
+-- __Warning (Lynx dual-thread \/ @NATIVE@):__ this builds a @VComp@ with no
+-- 'GHC.StaticPtr.StaticKey'. A component mounted this way as part of the
+-- /initial/ frame is fine (the MTS independently reconstructs it while
+-- painting its own first frame). But if it is mounted /later/ — e.g. inside
+-- a list or behind a conditional, appearing only after the first frame — the
+-- MTS has no other way to learn of it, so it never registers a mirror
+-- t'Miso.Types.ComponentState' for it, and any main-thread (@OnStatic@)
+-- event handler inside that subtree silently fails to dispatch for the
+-- component's whole lifetime, with only a console error as a clue. Use
+-- 'vcomp' with 'mountStaticWithProps' instead for anything that may mount
+-- after the initial frame under @NATIVE@ — the compile-time
+-- 'GHC.StaticPtr.StaticKey' already supplies the identity a manual key would,
+-- no explicit key needed.
+--
+-- @since 1.9.0.0
+(+>)
+  :: forall context childModel childAction model action .
+#ifdef NATIVE
+     (Eq context, Eq childModel, FromJSON childModel, ToJSON childModel, FromJSON childAction, ToJSON childAction)
+#else
+     (Eq context, Eq childModel)
+#endif
+  => MisoString
+  -- ^ @VComp@ @key_@
+  -> Component context () childModel childAction
+  -- ^ t'Component'
+  -> View context model action
+infixr 0 +>
+#ifdef NATIVE
+{-# WARNING (+>) "[NATIVE] '+>' has no StaticKey; a component mounted with it after the initial frame silently drops OnStatic handlers inside it. Use 'vcomp' with 'mountStaticWithProps' instead." #-}
+#endif
+key +> child = VComp (SomeComponent (Just (toKey key)) () child)
+-----------------------------------------------------------------------------
+-- | t'Miso.Types.Component' mounting combinator.
+--
+-- Note: only use this if you're certain you won't be diffing two t'Miso.Types.Component'
+-- against each other. Otherwise, you will need a key to distinguish between
+-- the two t'Miso.Types.Component', to ensure unmounting and mounting occurs.
+--
+-- It takes only the @component@ and yields a closed @props -> component@
+-- constructor ('SomeStaticComponent') suitable for @static@ — the @props@ value
+-- is /not/ supplied here, but later at the 'vcomp' site, so a parent can pass
+-- runtime @props@ (e.g. derived from its own @model@) without an explicit lambda:
+--
+-- Static mounting automatically provides the @key_@ at compile time (via 'GHC.StaticPtr.staticKey').
+-- So the user doesn't need to use the '+>' combinators.
+--
+-- @
+-- vcomp (model ^. field) (static (mountStaticWithProps child))
+-- @
+--
+-- @since 1.13.0.0
+mountStaticWithProps
+#ifdef NATIVE
+  :: (Eq context, Eq props, Eq model, FromJSON model, ToJSON model, FromJSON action, ToJSON action, FromJSON props, ToJSON props)
+#else
+  :: (Eq context, Eq props, Eq model)
+#endif
+  => Component context props model action
+  -- ^ t'Component' to mount
+  -> SomeStaticComponent props context
+mountStaticWithProps child = SomeStaticComponent (\props -> SomeComponent Nothing props child)
+-----------------------------------------------------------------------------
+-- | t'Miso.Types.Component' mounting combinator, with @props@ supplied directly.
+--
+-- __Warning (Lynx dual-thread \/ @NATIVE@):__ see the note on '(+>)' — this
+-- also builds an unkeyed @VComp@ with no 'GHC.StaticPtr.StaticKey', so the
+-- same caveat applies: components mounted with this /after/ the initial
+-- frame never get a main-thread mirror registered, silently breaking
+-- @OnStatic@ handlers inside them. Use 'vcomp' with 'mountStaticWithProps'
+-- instead for anything that may mount dynamically under @NATIVE@.
+mountWithProps
+  :: forall context props childModel childAction model action .
+#ifdef NATIVE
+     (Eq context, Eq props, Eq childModel, FromJSON childModel, ToJSON childModel, FromJSON childAction, ToJSON childAction, FromJSON props, ToJSON props)
+#else
+     (Eq context, Eq props, Eq childModel)
+#endif
+  => props
+  -> Component context props childModel childAction
+  -- ^ t'Component' to mount
+  -> View context model action
+#ifdef NATIVE
+{-# WARNING mountWithProps "[NATIVE] 'mountWithProps' has no StaticKey; a component mounted with it after the initial frame silently drops OnStatic handlers inside it. Use 'vcomp' with 'mountStaticWithProps' instead." #-}
+#endif
+mountWithProps props comp = VComp (SomeComponent Nothing props comp)
+-----------------------------------------------------------------------------
+-- | t'Miso.Types.Component' mounting combinator, keyed, with @props@ supplied directly.
+--
+-- __Warning (Lynx dual-thread \/ @NATIVE@):__ see the note on '(+>)' — this
+-- also builds a @VComp@ with no 'GHC.StaticPtr.StaticKey' (the key here is
+-- just the diffing t'Key', unrelated), so the same caveat applies: mounted
+-- /after/ the initial frame, it never gets a main-thread mirror registered,
+-- silently breaking @OnStatic@ handlers inside it. Use 'vcomp' with
+-- 'mountStaticWithProps' instead for anything that may mount dynamically
+-- under @NATIVE@ — the compile-time 'GHC.StaticPtr.StaticKey' already
+-- supplies the identity a manual key would, no explicit key needed.
+mountWithProps_
+  :: forall context props childModel childAction model action .
+#ifdef NATIVE
+     (Eq context, Eq props, Eq childModel, FromJSON childAction, FromJSON childModel, ToJSON childModel, ToJSON childAction, FromJSON props, ToJSON props)
+#else
+     (Eq context, Eq childModel, Eq props)
+#endif
+  => MisoString
+  -> props
+  -> Component context props childModel childAction
+  -- ^ t'Component' to mount
+  -> View context model action
+#ifdef NATIVE
+{-# WARNING mountWithProps_ "[NATIVE] 'mountWithProps_' has no StaticKey; a component mounted with it after the initial frame silently drops OnStatic handlers inside it. Use 'vcomp' with 'mountStaticWithProps' instead." #-}
+#endif
+mountWithProps_ key props child = VComp (SomeComponent (Just (Key key)) props child)
+-----------------------------------------------------------------------------
+-- | Static t'Miso.Types.Component' mounting combinator, for a component
+-- that takes no @props@.
+--
+-- Produces a @'SomeStaticComponent' () context@ to be wrapped in @static@ and
+-- turned into a 'View' by 'vcomp_'. Unlike 'mount_', no key is needed: the
+-- compile-time 'GHC.StaticPtr.StaticKey' already supplies identity, so this is
+-- safe to diff against another t'Miso.Types.Component'.
+--
+-- To opt the child into app-global @context@ updates, set the field directly:
+-- @mountStatic comp { useContext = True }@.
+--
+-- @
+-- div_ [] [ vcomp_ (static (mountStatic myComp)) ]
+-- @
+--
+-- @since 1.13.0.0
+mountStatic
+#ifdef NATIVE
+  :: (Eq context, Eq model, FromJSON model, ToJSON model, FromJSON action, ToJSON action)
+#else
+  :: (Eq context, Eq model)
+#endif
+  => Component context () model action
+  -- ^ t'Component' to mount
+  -> SomeStaticComponent () context
+mountStatic child = SomeStaticComponent (const (SomeComponent Nothing () child))
+-----------------------------------------------------------------------------
+-- | t'Miso.Types.Component' mounting combinator.
+--
+-- Note: only use this if you're certain you won't be diffing two t'Miso.Types.Component'
+-- against each other. Otherwise, you will need a key to distinguish between
+-- the two t'Miso.Types.Component', to ensure unmounting and mounting occurs.
+--
+-- @
+-- mount_ $ component model noop $ \\m ->
+--  div_ [ id_ "foo" ] [ text (ms m) ]
+-- @
+--
+-- __Warning (Lynx dual-thread \/ @NATIVE@):__ see the note on '(+>)' — this
+-- also builds a @VComp@ with no 'GHC.StaticPtr.StaticKey', so the same
+-- caveat applies: mounted /after/ the initial frame, it never gets a
+-- main-thread mirror registered, silently breaking @OnStatic@ handlers
+-- inside it. Use 'vcomp_' with 'mountStatic' instead for anything that may
+-- mount dynamically under @NATIVE@.
+--
+-- @since 1.9.0.0
+mount_
+  :: forall context childModel childAction model action .
+#ifdef NATIVE
+     (Eq context, Eq childModel, FromJSON childModel, ToJSON childModel, FromJSON childAction, ToJSON childAction)
+#else
+     (Eq context, Eq childModel)
+#endif
+  => Component context () childModel childAction
+  -- ^ t'Component' to mount
+  -> View context model action
+#ifdef NATIVE
+{-# WARNING mount_ "[NATIVE] 'mount_' has no StaticKey; a component mounted with it after the initial frame silently drops OnStatic handlers inside it. Use 'vcomp_' with 'mountStatic' instead." #-}
+#endif
+mount_ comp = VComp (SomeComponent Nothing () comp)
+-----------------------------------------------------------------------------
+-- | Embed a child t'Component' as a 'View'.
+--
+-- Smart constructor for @VComp@, mirroring 'vnode' \/ 'vtext' \/ 'vfrag'.
+--
+-- The 'StaticPtr' wraps only the closed @props -> component@ constructor (built
+-- with 'mountStatic' or 'mountStaticWithProps'); it must use the @static@ keyword
+-- and refer to a closed, top-level binding. The @props@ value is supplied
+-- /separately/ — so it may depend on the parent's @model@ — and is serialized
+-- across the dual-thread boundary. The no-props case passes @()@.
+--
+-- No class constraints appear here: the serialization dictionaries are
+-- discharged at the @static (mount_ child)@ site and recovered on the MTS from
+-- the @Props@.
+--
+-- @
+-- div_ [] [ vcomp_ (static (mountStatic myComp)) ]
+-- @
+--
+-- @since 1.12.0.0
+vcomp
+  :: props
+  -> StaticPtr (SomeStaticComponent props context)
+  -> View context model action
+vcomp = flip VCompStatic
+-----------------------------------------------------------------------------
+-- | Like 'vcomp', but for a t'Miso.Types.Component' that takes no @props@.
+--
+-- @'vcomp_' = 'vcomp' ()@ — pair it with 'mountStatic', which produces a
+-- @'SomeStaticComponent' () context@.
+--
+-- @
+-- div_ [] [ vcomp_ (static (mountStatic myComp)) ]
+-- @
+--
+-- @since 1.13.0.0
+vcomp_
+  :: StaticPtr (SomeStaticComponent () context)
+  -> View context model action
+vcomp_ = vcomp ()
+-----------------------------------------------------------------------------
+-- | t'Miso.Types.Component' mounting combinator that opts the child into
+-- app-global React-style @context@ updates.
+--
+-- Equivalent to 'mount_', but sets @useContext = True@ on the mounted
+-- t'Miso.Types.Component' so it re-renders whenever the @context@ changes
+-- (see 'Miso.Effect.modifyContext'). Like 'mount_', this is unkeyed and so
+-- unsafe when diffing two t'Miso.Types.Component' against each other.
+--
+-- @
+-- mountUseContext $ component model noop $ \\ctx m ->
+--  div_ [ id_ "foo" ] [ text (ms m) ]
+-- @
+--
+-- __Warning (Lynx dual-thread \/ @NATIVE@):__ see the note on 'mount_' —
+-- this also builds a @VComp@ with no 'GHC.StaticPtr.StaticKey', so the same
+-- caveat applies: mounted /after/ the initial frame, it never gets a
+-- main-thread mirror registered, silently breaking @OnStatic@ handlers
+-- inside it. Use @'vcomp_' (static ('mountStatic' comp { useContext = True }))@
+-- instead under @NATIVE@.
+--
+-- @since 1.13.0.0
+mountUseContext
+  :: forall context childModel childAction model action .
+#ifdef NATIVE
+     (Eq context, Eq childModel, FromJSON childModel, ToJSON childModel, FromJSON childAction, ToJSON childAction)
+#else
+     (Eq context, Eq childModel)
+#endif
+  => Component context () childModel childAction
+  -- ^ t'Component' to mount
+  -> View context model action
+#ifdef NATIVE
+{-# WARNING mountUseContext "[NATIVE] 'mountUseContext' has no StaticKey; a component mounted with it after the initial frame silently drops OnStatic handlers inside it. Use 'vcomp_' with 'mountStatic' on a component with useContext = True instead." #-}
+#endif
+mountUseContext comp = VComp (SomeComponent Nothing () comp { useContext = True })
+-----------------------------------------------------------------------------
+-- | DOM element namespace.
+data Namespace
+  = HTML
+  -- ^ HTML Namespace
+  | SVG
+  -- ^ SVG Namespace
+  | MATHML
+  -- ^ MATHML Namespace
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal Namespace where
+  toJSVal = \case
+    SVG -> toJSVal ("svg" :: MisoString)
+    HTML -> toJSVal ("html" :: MisoString)
+    MATHML -> toJSVal ("mathml" :: MisoString)
+-----------------------------------------------------------------------------
+-- | Unique key for a DOM node.
+--
+-- This key is only used to speed up diffing the children of a DOM
+-- node, the actual content is not important. The keys of the children
+-- of a given DOM node must be unique. Failure to satisfy this
+-- invariant gives undefined behavior at runtime.
+newtype Key = Key MisoString
+  deriving newtype (Show, Eq, IsString, ToJSON, ToMisoString)
+-----------------------------------------------------------------------------
+-- | ToJSVal instance for t'Key'
+instance ToJSVal Key where
+  toJSVal (Key x) = toJSVal x
+-----------------------------------------------------------------------------
+-- | Convert custom key types to t'Key'.
+--
+-- Instances of this class do not have to guarantee uniqueness of the
+-- generated keys, it is up to the user to do so. @toKey@ must be an
+-- injective function (different inputs must map to different outputs).
+class ToKey key where
+  -- | Converts any key into t'Key'
+  toKey :: key -> Key
+-----------------------------------------------------------------------------
+-- | Identity instance
+instance ToKey Key where toKey = id
+-----------------------------------------------------------------------------
+#if !defined(VANILLA) && !defined(MISO_TEXT)
+-- | Convert 'MisoString' to t'Key'
+instance ToKey MisoString where toKey = Key
+#endif
+-----------------------------------------------------------------------------
+-- | Convert 'T.Text' to t'Key'
+instance ToKey T.Text where toKey = Key . toMisoString
+-----------------------------------------------------------------------------
+-- | Convert 'String' to t'Key'
+instance ToKey String where toKey = Key . toMisoString
+-----------------------------------------------------------------------------
+-- | Convert 'Int' to t'Key'
+instance ToKey Int where toKey = Key . toMisoString
+-----------------------------------------------------------------------------
+-- | Convert 'Double' to t'Key'
+instance ToKey Double where toKey = Key . toMisoString
+-----------------------------------------------------------------------------
+-- | Convert 'Float' to t'Key'
+instance ToKey Float where toKey = Key . toMisoString
+-----------------------------------------------------------------------------
+-- | Convert 'Word' to t'Key'
+instance ToKey Word where toKey = Key . toMisoString
+-----------------------------------------------------------------------------
+-- | Wrapper for event handler callbacks, used for cross-thread communication.
+--
+-- Carries two independent things built from the same @(decoder, convert)@
+-- pair:
+--
+-- * 'eventHandlerInstall' — attaches a real JS listener to a live vnode.
+--   Used by the runtime's attribute diffing, on both threads.
+-- * 'eventHandlerDecoder' \/ 'eventHandlerConvert' — the decode step exposed
+--   directly, with no JS installer round-trip. Used by the MTS's
+--   @dispatchMainThreadEvent@ to decode + dispatch a main-thread event
+--   synchronously, without reconstructing (and discarding) a JS callback via
+--   a throwaway scratch node on every single event.
+--
+-- @since 1.13.0.0
+data EventHandler model action = forall result. EventHandler
+  { eventHandlerInstall :: model -> Sink action -> VTree -> LogLevel -> Events -> IO ()
+  , eventHandlerDecoder :: Miso.Event.Decoder.Decoder result
+  , eventHandlerConvert :: result -> model -> DOMRef -> action
+  }
+-----------------------------------------------------------------------------
+-- | Embed a fully-applied @static@ event handler.
+--
+-- The handler is baked into the 'StaticPtr', so the main thread can rebuild it
+-- from the 'StaticKey' alone (no payload to forward). Use this for handlers that
+-- take no injected @model@ data — including decoder handlers whose argument is a
+-- function (e.g. @onScroll HandleScroll@).
+--
+-- @
+-- button_ [ event (static (onClick AddOne)) ]
+-- div_    [ event (static (onScroll HandleScroll)) ]
+-- @
+--
+-- @since 1.13.0.0
+event :: StaticPtr (EventHandler model action) -> Attribute model action
+event = OnStatic
+-----------------------------------------------------------------------------
+-- | Attribute of a vnode in a t'View'.
+--
+data Attribute model action
+  = Property MisoString Value
+  | ClassList [MisoString]
+  | On (model -> Sink action -> VTree -> LogLevel -> Events -> IO ())
+  -- ^ A fully-applied @static@ event handler; the main thread rebuilds it from
+  -- the 'StaticKey' alone. See 'event'.
+  | OnStatic (StaticPtr (EventHandler model action))
+  -- ^ A @static@ handler /constructor/ plus a runtime @payload@ (often @model@
+  -- data) supplied separately and JSON-shipped across the dual-thread boundary,
+  -- so the handler can reach the main thread with runtime data. The @action@
+  -- stays outside the existential; only @payload@ is hidden. Handler-identity
+  -- diffing is by 'StaticKey' (JS-side, @ts\/miso\/dom.ts@). See @eventWith@.
+  | Styles (M.Map MisoString MisoString)
+-----------------------------------------------------------------------------
+instance Eq (Attribute model action) where
+  Property k1 v1 == Property k2 v2 = k1 == k2 && v1 == v2
+  ClassList x == ClassList y = x == y
+  Styles x == Styles y = x == y
+  -- Compare by handler identity ('StaticKey') only. Payload diffing is a JS
+  -- concern (@ts\/miso\/dom.ts@) over the stashed value.
+  OnStatic ptr1 == OnStatic ptr2 = on (==) staticKey ptr1 ptr2
+  _ == _ = False
+-----------------------------------------------------------------------------
+instance Show (Attribute model action) where
+  show = \case
+    Property key value ->
+      MS.unpack key <> "=" <> MS.unpack (ms (encode value))
+    ClassList classes ->
+      MS.unpack (MS.intercalate " " classes)
+    On _ ->
+      "<event-handler>"
+    OnStatic ptr ->
+      "<event-handler-with: " <> show (staticKey ptr) <> ">"
+    Styles styles ->
+      MS.unpack $ MS.concat
+        [ k <> "=" <> v <> ";"
+        | (k, v) <- M.toList styles
+        ]
+-----------------------------------------------------------------------------
+-- | 'IsString' instance
+instance IsString (View context model action) where
+  fromString = VText Nothing . fromString
+-----------------------------------------------------------------------------
+-- | Virtual DOM implemented as a JavaScript t'Object'.
+--   Used for diffing, patching and event delegation.
+--   Not meant to be constructed directly, see t'Miso.Types.View' instead.
+newtype VTree = VTree
+  { getTree :: Object
+  -- ^ Underlying JavaScript object representing the virtual DOM tree
+  } deriving newtype (ToObject, ToJSVal)
+-----------------------------------------------------------------------------
+-- | Create a new 'Miso.Types.VNode'.
+--
+-- @node ns tag attrs children@ creates a new node with tag @tag@
+-- in the namespace @ns@. All @attrs@ are called when
+-- the node is created and its children are initialized to @children@.
+node
+  :: Namespace
+  -- ^ Element namespace (@HTML@, @SVG@, or @MATHML@)
+  -> MisoString
+  -- ^ Tag name (e.g. @\"div\"@, @\"circle\"@)
+  -> [Attribute model action]
+  -- ^ Attributes, properties, and event handlers
+  -> [View context model action]
+  -- ^ Child nodes
+  -> View context model action
+node ns tag attrs kids = VNode ns tag attrs kids mempty
+-----------------------------------------------------------------------------
+-- | Like 'node', but declares the set of events this element dispatches
+-- /directly/ on itself instead of by bubbling to the delegated mount listener.
+--
+-- Only relevant to the Lynx native runtime, where component-emitted events
+-- (@input@, @scroll@, @load@, …) do not bubble and must be bound on the
+-- element. The set is a /capability/: a listener is bound only for events the
+-- element actually handles. Empty on the browser\/WASM runtime.
+--
+-- @since 1.13.0.0
+nodeDirectEvents
+  :: Namespace
+  -- ^ Element namespace (@HTML@, @SVG@, or @MATHML@)
+  -> MisoString
+  -- ^ Tag name (e.g. @\"input\"@, @\"scroll-view\"@)
+  -> [Attribute model action]
+  -- ^ Attributes, properties, and event handlers
+  -> [MisoString]
+  -- ^ Events dispatched directly on this element
+  -> [View context model action]
+  -- ^ Child nodes
+  -> View context model action
+nodeDirectEvents ns tag attrs direct kids = VNode ns tag attrs kids (S.fromList direct)
+-----------------------------------------------------------------------------
+-- | Create a new 'Miso.Types.VNode'.
+--
+-- Synonym for 'node'
+--
+vnode
+  :: Namespace
+  -- ^ Element namespace (@HTML@, @SVG@, or @MATHML@)
+  -> MisoString
+  -- ^ Tag name (e.g. @\"div\"@, @\"circle\"@)
+  -> [Attribute model action]
+  -- ^ Attributes, properties, and event handlers
+  -> [View context model action]
+  -- ^ Child nodes
+  -> View context model action
+vnode = node
+-----------------------------------------------------------------------------
+-- | Create a new v'VText' with the given content.
+text :: MisoString -> View context model action
+#ifdef SSR
+text = VText Nothing . htmlEncode
+#else
+text = VText Nothing
+#endif
+-----------------------------------------------------------------------------
+-- | Synonym for 'text'
+vtext :: MisoString -> View context model action
+vtext = text
+----------------------------------------------------------------------------
+-- | Create a new v'VText', not subject to HTML escaping.
+--
+-- Like 'text', except will not escape HTML when used on the server.
+--
+textRaw :: MisoString -> View context model action
+textRaw = VText Nothing
+----------------------------------------------------------------------------
+-- |
+-- HTML-encodes text.
+--
+-- Useful for escaping HTML when delivering on the server. Naive usage
+-- of 'text' will ensure this as well.
+--
+-- >>> Data.Text.IO.putStrLn $ text "<a href=\"\">"
+-- &lt;a href=&quot;&quot;&gt;
+htmlEncode :: MisoString -> MisoString
+htmlEncode = MS.concatMap $ \case
+  '<' -> "&lt;"
+  '>' -> "&gt;"
+  '&' -> "&amp;"
+  '"' -> "&quot;"
+  '\'' -> "&#39;"
+  x -> MS.singleton x
+-----------------------------------------------------------------------------
+-- | Create a new v'VText' containing concatenation of the given strings.
+--
+-- @
+--   view :: View context model action
+--   view = div_
+--     [ className "container" ]
+--     [ text_
+--       [ "foo"
+--       , "bar"
+--       ]
+--     ]
+-- @
+--
+-- Renders as @<div class="container">foo bar</div>@
+--
+-- A single additional space is added between elements.
+--
+text_ :: [MisoString] -> View context model action
+text_ = VText Nothing . MS.intercalate " "
+-----------------------------------------------------------------------------
+-- | Like 'text', but allow the node to be keyed for efficient diffing.
+--
+-- @
+-- view :: model -> View context model action
+-- view = \x -> div_ [] [ textKey (1 :: Int) "text here" ]
+-- @
+--
+-- @since 1.9.0.0
+textKey :: ToKey key => key -> MisoString -> View context model action
+textKey k = VText (Just (toKey k))
+-----------------------------------------------------------------------------
+-- | Like 'text_', but allow the node to be keyed for efficient diffing.
+--
+-- @
+-- view :: model -> View context model action
+-- view = \x -> div_ [] [ textKey_ (1 :: Int) [ "text", "goes", "here" ] ]
+-- @
+--
+-- @since 1.9.0.0
+textKey_ :: ToKey key => key -> [MisoString] -> View context model action
+textKey_ k xs = VText (Just (toKey k)) (MS.intercalate " " xs)
+-----------------------------------------------------------------------------
+-- | Utility function to make it easy to specify conditional attributes
+--
+-- @
+-- view :: Bool -> View context model action
+-- view danger = optionalAttrs div_ [ id_ "some-div" ] danger [ class_ "danger" ] ["child"]
+-- @
+--
+-- @since 1.9.0.0
+optionalAttrs
+  :: ([Attribute model action] -> [View context model action] -> View context model action)
+  -> [Attribute model action] -- ^ Attributes to be added unconditionally
+  -> Bool -- ^ A condition
+  -> [Attribute model action] -- ^ Additional attributes to add if the condition is True
+  -> [View context model action] -- ^ Children
+  -> View context model action
+optionalAttrs element attrs condition opts kids =
+  case element attrs kids of
+    VNode ns name _ _ de -> do
+      let newAttrs = concat [ opts | condition ] ++ attrs
+      VNode ns name newAttrs kids de
+    x -> x
+-----------------------------------------------------------------------------
+-- | Utility function to make it easy to specify conditional attributes for void elements.
+--
+-- @
+-- view :: Bool -> View context model action
+-- view shouldClear = optionalVoidAttrs textarea_ [ value_ "" ] shouldClear [ id_ "text-area-id" ]
+-- @
+--
+-- @since 1.9.0.0
+optionalVoidAttrs
+  :: ([Attribute model action] -> View context model action)
+  -> [Attribute model action] -- ^ Attributes to be added unconditionally
+  -> Bool -- ^ A condition
+  -> [Attribute model action] -- ^ Additional attributes to add if the condition is True
+  -> View context model action
+optionalVoidAttrs element attrs condition opts =
+  case element attrs of
+    VNode ns name _ kids de -> do
+      let newAttrs = concat [ opts | condition ] ++ attrs
+      VNode ns name newAttrs kids de
+    x -> x
+----------------------------------------------------------------------------
+-- | Conditionally adds children.
+--
+-- @
+-- view :: Bool -> View context model action
+-- view withChild = optionalChildren div_ [ id_ "txt" ] [] withChild [ "foo" ]
+-- @
+--
+-- @since 1.9.0.0
+optionalChildren
+  :: ([Attribute model action] -> [View context model action] -> View context model action)
+  -> [Attribute model action] -- ^ Attributes to be added unconditionally
+  -> [View context model action] -- ^ Children to be added unconditionally
+  -> Bool -- ^ A condition
+  -> [View context model action] -- ^ Additional children to add if the condition is True
+  -> View context model action
+optionalChildren element attrs kids condition opts =
+  case element attrs kids of
+    VNode ns name _ _ de -> do
+      let newKids = kids ++ concat [ opts | condition ]
+      VNode ns name attrs newKids de
+    x -> x
+----------------------------------------------------------------------------
+-- | URI type. See the official [specification](https://www.rfc-editor.org/rfc/rfc3986)
+--
+data URI
+  = URI
+  { uriPath :: MisoString
+  -- ^ Path component, e.g. @\"users\/42\"@
+  , uriFragment :: MisoString
+  -- ^ Fragment identifier (without the leading @#@), e.g. @\"section-1\"@
+  , uriQueryString :: M.Map MisoString (Maybe MisoString)
+  -- ^ Query parameters. @'Just' v@ for @?key=v@ pairs; 'Nothing' for bare flags (@?flag@).
+  } deriving stock (Show, Eq, Generic)
+    deriving anyclass (ToJSVal, ToObject)
+----------------------------------------------------------------------------
+-- | Empty t'URI'.
+emptyURI :: URI
+emptyURI = URI mempty mempty mempty
+----------------------------------------------------------------------------
+instance ToMisoString URI where
+  toMisoString = prettyURI
+----------------------------------------------------------------------------
+instance ToJSON URI where
+  toJSON = toJSON . toMisoString
+----------------------------------------------------------------------------
+-- | Pretty-prints a t'URI'.
+prettyURI :: URI -> MisoString
+prettyURI uri@URI {..} = "/" <> uriPath <> prettyQueryString uri <> uriFragment
+-----------------------------------------------------------------------------
+-- | Pretty-prints a t'URI' query string.
+prettyQueryString :: URI -> MisoString
+prettyQueryString URI {..} = queries <> flags
+  where
+    queries =
+      MS.concat
+      [ "?" <>
+        MS.intercalate "&"
+        [ k <> "=" <> v
+        | (k, Just v) <- M.toList uriQueryString
+        ]
+      | any isJust (M.elems uriQueryString)
+      ]
+    flags = mconcat
+        [ "?" <> k
+        | (k, Nothing) <- M.toList uriQueryString
+        ]
+-----------------------------------------------------------------------------
+-- | VTreeType ADT for matching TypeScript enum
+data VTreeType
+  = VCompType
+  | VNodeType
+  | VTextType
+  | VFragType
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
+instance ToJSVal VTreeType where
+  toJSVal = \case
+    VCompType -> toJSVal (0 :: Int)
+    VNodeType -> toJSVal (1 :: Int)
+    VTextType -> toJSVal (2 :: Int)
+    VFragType -> toJSVal (3 :: Int)
+-----------------------------------------------------------------------------
+-- | Hydrate avoids calling @diff@, and instead calls @hydrate@
+-- 'Draw' invokes the virtual-DOM diff
+data Hydrate
+  = Draw
+  | Hydrate
+  deriving (Show, Eq)
+-----------------------------------------------------------------------------
diff --git a/src/Miso/Util.hs b/src/Miso/Util.hs
--- a/src/Miso/Util.hs
+++ b/src/Miso/Util.hs
@@ -1,20 +1,81 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Miso.Util
--- Copyright   :  (C) 2016-2018 David M. Johnson
+-- Copyright   :  (C) 2016-2026 David M. Johnson
 -- License     :  BSD3-style (see the file LICENSE)
--- Maintainer  :  David M. Johnson <djohnson.m@gmail.com>
+-- Maintainer  :  David M. Johnson <code@dmj.io>
 -- Stability   :  experimental
 -- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Util" provides general-purpose combinators shared across miso's
+-- internal modules and available to application code. It is re-exported
+-- by "Miso".
+--
+-- = View helpers
+--
+-- * 'withFoldable' — @map@ over any 'Foldable' to produce a list of
+--   views; particularly handy for @Maybe@:
+--
+-- @
+-- 'withFoldable' (model ^. mAlert) $ \\msg ->
+--   'Miso.Html.Element.div_' [ 'Miso.Html.Property.class_' \"alert\" ] [ 'Miso.text' msg ]
+-- @
+--
+-- * 'conditionalViews' — include a list of views only when a condition
+--   is 'True'; returns @[]@ otherwise:
+--
+-- @
+-- 'conditionalViews' isLoggedIn
+--   [ 'Miso.Html.Element.button_' [ 'Miso.Html.Event.onClick' Logout ] [ 'Miso.text' \"Log out\" ] ]
+-- @
+--
+-- = Parser \/ lexer combinators
+--
+-- These 'Control.Applicative.Alternative'-polymorphic combinators work
+-- with both 'Miso.Util.Lexer.Lexer' and 'Miso.Util.Parser.Parser':
+--
+-- * 'oneOf' — try alternatives in order, succeeding on the first match
+--   (analogous to 'Data.Foldable.asum')
+-- * 'sepBy' / 'sepBy1' — parse a list interleaved with a separator
+-- * 'enclosed' — parse something between two delimiters (@l *> x \<* r@)
+-- * 'between' — parse two things separated by a third, returning a pair
+-- * 'optionalDefault' — parse with a fallback default on failure
+-- * 'exists' — test whether a combinator succeeds, returning 'Bool'
+--
+-- = Miscellaneous
+--
+-- * '(=:)' — infix tuple constructor for key-value pairs:
+--   @\"key\" @=:@ value@
+-- * 'compose' — forward function composition generalised to any
+--   'Control.Category.Category': @f \`compose\` g = g . f@
+--
+-- = See also
+--
+-- * "Miso.Util.Lexer" — the 'Miso.Util.Lexer.Lexer' combinator library
+-- * "Miso.Util.Parser" — the 'Miso.Util.Parser.Parser' combinator library
 ----------------------------------------------------------------------------
 module Miso.Util
   ( withFoldable
   , conditionalViews
+  , oneOf
+  , enclosed
+  , optionalDefault
+  , exists
+  , sepBy1
+  , sepBy
+  , between
+  , (=:)
+  , compose
   ) where
-
-import Data.Foldable
-import Miso.Html (View)
-
+-----------------------------------------------------------------------------
+import           Control.Category
+import           Data.Maybe (isJust, fromMaybe)
+import           Control.Applicative (Alternative, many, empty, (<|>), optional)
+import           Data.Foldable (toList)
+import           Prelude hiding ((.))
+-----------------------------------------------------------------------------
 -- | Generic @map@ function, useful for creating @View@s from the elements of
 -- some @Foldable@. Particularly handy for @Maybe@, as shown in the example
 -- below.
@@ -22,16 +83,139 @@
 -- @
 -- view model =
 --     div_ [] $
---      withFoldable (model ^. mSomeMaybeVal) $ \someVal ->
+--      withFoldable (model ^. mSomeMaybeVal) $ \\someVal ->
 --         p_ [] [ text $ "Hey, look at this value: " <> ms (show someVal) ]
 -- @
-withFoldable :: Foldable t => t a -> (a -> b) -> [b]
+withFoldable
+  :: Foldable t
+  => t a
+  -- ^ Container to map over (e.g. @Maybe@, @[]@)
+  -> (a -> b)
+  -- ^ Function to apply to each element
+  -> [b]
 withFoldable ta f = map f (toList ta)
-
--- | Hides the @View@s the condition is False. Shows them when the condition
+-----------------------------------------------------------------------------
+-- | Conditionally includes views.
+-- Hides the 'Miso.Types.View's if the condition is False. Shows them when the condition
 -- is True.
-conditionalViews :: Bool -> [View action] -> [View action]
+conditionalViews
+  :: Bool
+  -- ^ When 'True' the views are included; when @False@ an empty list is returned
+  -> [view]
+  -- ^ Views to include conditionally
+  -> [view]
 conditionalViews condition views =
     if condition
     then views
     else []
+-----------------------------------------------------------------------------
+-- | Selects the first 'Alternative', analogous to 'Data.Foldable.asum'.
+oneOf :: Alternative f => [f a] -> f a
+oneOf = foldr (<|>) empty
+----------------------------------------------------------------------------
+-- | Convenience function for constructing parser / lexer combinators.
+--
+-- @
+-- test :: Parser a -> Parser a
+-- test = enclosed (char '(') (char ')')
+-- @
+enclosed
+  :: Applicative f
+  => f a
+  -- ^ Opening delimiter (e.g. @char '('@)
+  -> f b
+  -- ^ Closing delimiter (e.g. @char ')'@)
+  -> f c
+  -- ^ Inner parser\/lexer whose result is returned
+  -> f c
+enclosed l r x = l *> x <* r
+----------------------------------------------------------------------------
+-- | Allow the specification of default values during parsing / lexing
+-- in the case of parser / lexer failure.
+--
+-- @
+-- test :: Parser MisoString
+-- test = optionalDefault "foo" (string "bar")
+-- @
+optionalDefault
+  :: Alternative f
+  => b
+  -- ^ Default value to use when the parser\/lexer fails
+  -> f b
+  -- ^ Parser\/lexer to attempt
+  -> f b
+optionalDefault def p = fromMaybe def <$> optional p
+----------------------------------------------------------------------------
+-- | Combinator for testing parsing / lexing failure on any input.
+--
+-- @
+-- test :: Parser Bool
+-- test = exists (string "foo")
+-- @
+exists :: Alternative f => f a -> f Bool
+exists p = isJust <$> optional p
+----------------------------------------------------------------------------
+-- | Interleaves one parser combinator with another, must have at least one
+-- successful parse.
+--
+-- @
+-- test :: Parser [Int]
+-- test = sepBy1 (char ',') number
+-- @
+sepBy1
+  :: Alternative m
+  => m sep
+  -- ^ Separator parser\/lexer (result discarded)
+  -> m a
+  -- ^ Element parser\/lexer
+  -> m [a]
+sepBy1 sep p = (:) <$> p <*> many (sep *> p)
+----------------------------------------------------------------------------
+-- | Interleaves one parser combinator with another, may not have any successful
+-- parses.
+--
+-- @
+-- test :: Parser [Int]
+-- test = sepBy (char ',') number
+-- @
+sepBy
+  :: Alternative m
+  => m sep
+  -- ^ Separator parser\/lexer (result discarded)
+  -> m a
+  -- ^ Element parser\/lexer
+  -> m [a]
+sepBy sep p = sepBy1 sep p <|> pure []
+----------------------------------------------------------------------------
+-- | Successfully parses the arguments between another combinator
+--
+-- @
+-- test :: Parser (Int, Int)
+-- test = between (char '*') number number
+-- -- 5*5
+-- @
+between
+  :: Applicative f
+  => f a
+  -- ^ Separator between the two elements (result discarded)
+  -> f b
+  -- ^ Left element parser\/lexer
+  -> f c
+  -- ^ Right element parser\/lexer
+  -> f (b, c)
+between c l r = (,) <$> l <*> (c *> r)
+----------------------------------------------------------------------------
+-- | Tuple constructor, useful for constructing key-value pairs.
+--
+(=:) :: k -> v -> (k, v)
+k =: v = (k,v)
+----------------------------------------------------------------------------
+-- | Function composition generalized to 'Category'
+--
+-- @
+-- test :: Int -> Int
+-- test = (+1) \`compose\` (+1)
+-- @
+compose :: Category cat => cat a b -> cat b c -> cat a c
+compose = flip (.)
+----------------------------------------------------------------------------
diff --git a/src/Miso/Util/Lexer.hs b/src/Miso/Util/Lexer.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Util/Lexer.hs
@@ -0,0 +1,339 @@
+{-# LANGUAGE CPP #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Util.Lexer
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Util.Lexer" is an internal lexer combinator library used by
+-- miso's JSON pipeline ("Miso.JSON.Lexer") and URI\/router tokeniser
+-- ("Miso.Router"). It is __not__ designed for general application use,
+-- but is exposed for downstream code that needs to build custom lexers.
+--
+-- The central type is t'Lexer':
+--
+-- @
+-- newtype t'Lexer' token = Lexer
+--   { 'runLexer' :: t'Stream' -> Either t'LexerError' (token, t'Stream') }
+-- @
+--
+-- t'Lexer' is a 'Monad', 'Alternative', and 'MonadFail'. Its
+-- 'Control.Applicative.Alternative' instance implements the
+-- /maximal munch/ rule: when both branches succeed, the one that
+-- consumes the most input wins.
+--
+-- = Key types
+--
+-- * t'Stream' — the remaining input text together with a t'Location'
+--   (line and column) cursor.
+-- * t'Location' — @{line :: Int, column :: (Int, Int)}@, used in error
+--   messages and t'Located' tokens.
+-- * t'Located' token — a lexed value paired with the t'Location' at which
+--   it was recognised.
+-- * t'LexerError' — either @LexerError MisoString Location@ (unexpected
+--   input) or @UnexpectedEOF Location@ (ran out of input).
+--
+-- = Primitive combinators
+--
+-- @
+-- 'satisfy'  :: (Char -> Bool) -> t'Lexer' Char   -- consume one matching char
+-- 'char'     :: Char -> t'Lexer' Char              -- consume a specific char
+-- 'string'   :: 'Miso.String.MisoString' -> t'Lexer' 'Miso.String.MisoString'   -- consume a literal prefix
+-- 'string''  :: String -> t'Lexer' String          -- same for 'String'
+-- 'peek'     :: t'Lexer' (Maybe Char)              -- look ahead without consuming
+-- 'oops'     :: t'Lexer' token                     -- always fails
+-- @
+--
+-- = Stream and location access
+--
+-- @
+-- 'getInput'     :: t'Lexer' t'Stream'
+-- 'putInput'     :: t'Stream' -> t'Lexer' ()
+-- 'modifyInput'  :: ('Stream' -> t'Stream') -> t'Lexer' ()
+-- 'getLocation'  :: t'Lexer' t'Location'
+-- 'setLocation'  :: t'Location' -> t'Lexer' ()
+-- @
+--
+-- = Running a lexer
+--
+-- @
+-- 'runLexer' :: t'Lexer' token -> t'Stream' -> Either t'LexerError' (token, t'Stream')
+-- 'mkStream' :: 'Miso.String.MisoString' -> t'Stream'   -- create initial stream
+-- @
+--
+-- = See also
+--
+-- * "Miso.Util.Parser" — parser combinator library that consumes t'Lexer' output
+-- * "Miso.JSON.Lexer" — JSON tokeniser built on this module
+-- * "Miso.Router" — URI tokeniser built on this module
+-- * "Miso.Util" — higher-level 'Miso.Util.sepBy', 'Miso.Util.oneOf', …
+----------------------------------------------------------------------------
+module Miso.Util.Lexer
+  ( -- ** Types
+    Lexer (..)
+  , Stream (..)
+  , Located (..)
+  , Location (..)
+  , LexerError (..)
+    -- ** Combinators
+  , getStartColumn
+  , zeroLocation
+  , initialLocation
+  , mkStream
+  , oops
+  , streamError
+  , string
+  , string'
+  , char
+  , satisfy
+  , peek
+  , getInput
+  , putInput
+  , getLocation
+  , setLocation
+  , modifyInput
+  , withLocation
+  ) where
+----------------------------------------------------------------------------
+import           Control.Monad
+#if __GLASGOW_HASKELL__ <= 865
+import           Control.Monad.Fail
+#endif
+import           Control.Applicative
+----------------------------------------------------------------------------
+import           Miso.String (MisoString, ToMisoString)
+import qualified Miso.String as MS
+----------------------------------------------------------------------------
+-- | Potential errors during lexing
+data LexerError
+  = LexerError MisoString Location
+  | UnexpectedEOF Location
+  deriving (Eq)
+----------------------------------------------------------------------------
+instance Show LexerError where
+  show (UnexpectedEOF loc) =
+    "Unexpected EOF at: " <> show loc
+  show (LexerError xs loc) =
+    "Unexpected \"" <> take 5 (MS.unpack xs) <> "\"... at " <> show loc
+----------------------------------------------------------------------------
+-- | Type to hold the location (line and column) of a Token
+data Location
+  = Location
+  { line :: Int
+  -- ^ Current line number (1-based)
+  , column :: (Int,Int)
+  -- ^ @(start, end)@ column offsets for the current token (1-based)
+  } deriving Eq
+----------------------------------------------------------------------------
+instance Show Location where
+  show (Location l col) = show l <> " " <> show col
+----------------------------------------------------------------------------
+-- | Helper for extracting column from t'Location'
+getStartColumn :: Location -> Int
+getStartColumn = fst . column
+----------------------------------------------------------------------------
+-- | Initial t'Location'
+initialLocation :: Location
+initialLocation = Location 1 (1,1)
+----------------------------------------------------------------------------
+-- | Empty t'Location'
+zeroLocation :: Location
+zeroLocation = Location 0 (0,0)
+----------------------------------------------------------------------------
+-- | A Lexer is a state monad with optional failure the abides by the
+-- maximal munch rule in its 'Alternative' instance.
+newtype Lexer token
+  = Lexer
+  { runLexer :: Stream -> Either LexerError (token, Stream)
+  -- ^ Run the lexer against a t'Stream'; returns the token and remaining input, or a t'LexerError'
+  }
+----------------------------------------------------------------------------
+-- | Combinator that always fails to lex
+oops :: Lexer token
+oops = Lexer $ \s -> Left (streamError s)
+----------------------------------------------------------------------------
+-- | Smart constructor for t'LexerError'
+streamError
+  :: Stream
+  -- ^ The stream at the point of failure; used to populate the error location
+  -> LexerError
+streamError (Stream xs l) = unexpected xs l
+----------------------------------------------------------------------------
+-- | Smart constructor for t'Stream'
+mkStream
+  :: MisoString
+  -- ^ Input text to lex
+  -> Stream
+mkStream xs = Stream xs initialLocation
+----------------------------------------------------------------------------
+-- | A t'Stream' of text used as input to lexing
+data Stream
+  = Stream
+  { stream :: MisoString
+    -- ^ Current t'Stream' of text
+  , currentLocation :: Location
+    -- ^ current t'Location' in the t'Stream'
+  } deriving Eq
+----------------------------------------------------------------------------
+-- | A t'Located' token holds the lexed output the t'Location' at which
+-- the successful lex occurred.
+data Located token
+  = Located
+  { token :: token
+  -- ^ The lexed token value
+  , location :: Location
+  -- ^ t'Location' in the source at which this token was recognised
+  } deriving Eq
+----------------------------------------------------------------------------
+instance Show token => Show (Located token) where
+  show (Located t l) = show l <> " " <> show t
+----------------------------------------------------------------------------
+instance Functor Lexer where
+  fmap f (Lexer l) = Lexer $ \input -> do
+    (t, x) <- l input
+    pure (f t, x)
+----------------------------------------------------------------------------
+instance Applicative Lexer where
+  pure x = Lexer $ \input -> pure (x, input)
+  Lexer l1 <*> Lexer l2 = Lexer $ \input -> do
+    (f, x) <- l1 input
+    (a, y) <- l2 x
+    pure (f a, y)
+----------------------------------------------------------------------------
+instance Monad Lexer where
+  m >>= f = Lexer $ \input -> do
+    (x, s) <- runLexer m input
+    runLexer (f x) s
+----------------------------------------------------------------------------
+instance MonadFail Lexer where
+  fail _ = oops
+----------------------------------------------------------------------------
+instance Alternative Lexer where
+  empty = Lexer $ \(Stream s l)  -> Left (unexpected s l)
+  Lexer l1 <|> Lexer l2 = Lexer $ \input ->
+    case (l1 input, l2 input) of
+      (res, Left _) -> res
+      (Left _, res) -> res
+      (Right (x, Stream s sl), Right (y,Stream t tl)) ->
+        if MS.length s <= MS.length t
+        then Right (x, Stream s sl)
+        else Right (y, Stream t tl)
+----------------------------------------------------------------------------
+instance MonadPlus Lexer where
+  mplus = (<|>)
+----------------------------------------------------------------------------
+-- | Fetches the first character in the t'Stream', does not consume input
+peek :: Lexer (Maybe Char)
+peek = Lexer $ \ys ->
+  pure $ case ys of
+    Stream xs l ->
+      case MS.uncons xs of
+        Nothing -> (Nothing, Stream mempty l)
+        Just (z,zs) -> (Just z, Stream (MS.singleton z <> zs) l)
+----------------------------------------------------------------------------
+-- | Predicate combinator that consumes matching input
+satisfy
+  :: (Char -> Bool)
+  -- ^ Predicate; the next character is consumed only if this returns 'True'
+  -> Lexer Char
+satisfy predicate = Lexer $ \ys ->
+  case ys of
+    Stream s l ->
+      case MS.uncons s of
+        Nothing -> Left (unexpected s l)
+        Just (z,zs)
+          | predicate z -> Right (z, Stream zs l)
+          | otherwise -> Left (unexpected zs l)
+----------------------------------------------------------------------------
+-- | Smart constructor for t'LexerError'
+-- If the input is empty, an 'UnexpectedEOF' is issued.
+unexpected :: MisoString -> Location -> LexerError
+unexpected xs loc | MS.null xs = UnexpectedEOF loc
+unexpected cs loc = LexerError cs loc
+----------------------------------------------------------------------------
+-- | Retrieves current input from t'Lexer'
+getInput :: Lexer Stream
+getInput = Lexer $ \s -> Right (s, s)
+----------------------------------------------------------------------------
+-- | Overrides current t'Stream' in t'Lexer' to user-specified t'Stream'.
+putInput
+  :: Stream
+  -- ^ Replacement stream; replaces the current lexer input
+  -> Lexer ()
+putInput s = Lexer $ \_ -> Right ((), s)
+----------------------------------------------------------------------------
+-- | Retrieves the current t'Stream' t'Location'
+getLocation :: Lexer Location
+getLocation = Lexer $ \(Stream s l) -> pure (l, Stream s l)
+----------------------------------------------------------------------------
+-- | Sets the current t'Stream' t'Location'
+setLocation
+  :: Location
+  -- ^ New location to record in the stream cursor
+  -> Lexer ()
+setLocation l = Lexer $ \(Stream s _) -> pure ((), Stream s l)
+----------------------------------------------------------------------------
+-- | Modifies a t'Stream'
+modifyInput
+  :: (Stream -> Stream)
+  -- ^ Transform to apply to the current lexer input
+  -> Lexer ()
+modifyInput f = do
+  s <- getInput
+  putInput (f s)
+----------------------------------------------------------------------------
+-- | Lexer combinator for matching a 'Char'
+char
+  :: Char
+  -- ^ The exact character to consume
+  -> Lexer Char
+char c = satisfy (== c)
+----------------------------------------------------------------------------
+-- | Lexer combinator for matching a 'String'
+string'
+  :: String
+  -- ^ Literal string prefix to consume character by character
+  -> Lexer String
+string' = traverse char
+----------------------------------------------------------------------------
+-- | Lexer combinator for matching a 'MisoString'
+string
+  :: MisoString
+  -- ^ Literal string prefix to consume from the input
+  -> Lexer MisoString
+string prefix = Lexer $ \s ->
+  case s of
+    Stream ys l
+      | prefix `MS.isPrefixOf` ys ->
+          Right (prefix, Stream (MS.drop (MS.length prefix) ys) l)
+      | otherwise ->
+          Left (unexpected ys l)
+----------------------------------------------------------------------------
+-- | Lexer combinator for executing a t'Lexer' with annotated t'Location' information
+withLocation
+  :: ToMisoString token
+  => Lexer token
+  -- ^ Inner lexer whose result is wrapped with its source t'Location'
+  -> Lexer (Located token)
+withLocation lexer = do
+  result <- lexer
+  let
+    adjustLoc :: Location -> MisoString -> Location
+    adjustLoc l = MS.foldl' adjust (next l)
+
+  setLocation =<< adjustLoc <$> getLocation <*> pure (MS.ms result)
+  Located result <$> getLocation
+    where
+      next :: Location -> Location
+      next (Location l (_, end)) = Location l (end, end)
+
+      adjust :: Location -> Char -> Location
+      adjust (Location l (_, _)) '\n'       = Location (l + 1) (1,1)
+      adjust (Location l (start, end)) '\t' = Location l (start, end + 8)
+      adjust (Location l (start, end))   _  = Location l (start, end + 1)
+----------------------------------------------------------------------------
diff --git a/src/Miso/Util/Parser.hs b/src/Miso/Util/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/Util/Parser.hs
@@ -0,0 +1,234 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE ScopedTypeVariables  #-}
+{-# LANGUAGE FlexibleInstances    #-}
+{-# LANGUAGE CPP                  #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.Util.Parser
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.Util.Parser" is an internal parser combinator library that
+-- operates over a token stream produced by "Miso.Util.Lexer". It is used
+-- by miso's JSON pipeline ("Miso.JSON.Parser") and the client-side router
+-- ("Miso.Router"). It is __not__ designed for general application use,
+-- but is exposed for downstream code that needs to build custom parsers.
+--
+-- = Core types
+--
+-- @
+-- newtype 'ParserT' r token m a = Parser
+--   { 'runParserT' :: r -> token -> m (a, token) }
+--
+-- type t'Parser' token a = 'ParserT' () [token] [] a
+-- @
+--
+-- 'ParserT' is a monad transformer parameterised by:
+--
+-- * @r@ — a read-only environment (accessible via 'askParser')
+-- * @token@ — the input stream type (typically @[t]@)
+-- * @m@ — the result monad; using @[]@ gives non-deterministic\/backtracking parsing
+-- * @a@ — the parsed result
+--
+-- The @'Parser' token a@ convenience alias fixes @r = ()@ and @m = []@,
+-- which gives a standard backtracking parser over a @[token]@ stream.
+--
+-- = Primitive combinators
+--
+-- @
+-- 'anyToken'    :: 'ParserT' r [a] [] a         -- consume any single token
+-- 'satisfy'     :: (a -> Bool) -> 'ParserT' r [a] [] a  -- consume if predicate holds
+-- 'token_'      :: Eq t => t -> t'Parser' t t    -- match a specific token
+-- 'peek'        :: t'Parser' a a                 -- look ahead without consuming
+-- 'endOfInput'  :: 'ParserT' r a [] ()          -- succeed only at end of stream
+-- 'allTokens'   :: 'ParserT' r a [] a           -- return the entire remaining stream
+-- 'modifyTokens' :: (t -> t) -> 'ParserT' r t [] ()  -- transform the token stream
+-- 'askParser'   :: 'ParserT' r token [] r       -- read the environment
+-- 'errorOut'    :: e -> 'ParserT' r e [] ()     -- inject a custom error token
+-- @
+--
+-- = Error type
+--
+-- @
+-- data 'ParseError' a token
+--   = UnexpectedParse [token]  -- input remained after a successful parse
+--   | LexicalError 'Miso.Util.Lexer.LexerError'  -- upstream lex failure
+--   | Ambiguous [(a, [token])] -- multiple distinct parses
+--   | NoParses token           -- no parse succeeded
+--   | EmptyStream              -- input was empty
+-- @
+--
+-- = Running a parser
+--
+-- @
+-- 'parse' :: t'Parser' token a -> [token] -> Either ('ParseError' a token) a
+-- @
+--
+-- 'parse' returns 'Right' only when exactly one parse consumes all input.
+-- Ambiguous or partial parses produce a 'Left' error.
+--
+-- = See also
+--
+-- * "Miso.Util.Lexer" — produces the token stream consumed here
+-- * "Miso.JSON.Parser" — JSON parser built on this module
+-- * "Miso.Router" — URI\/route parser built on this module
+-- * "Miso.Util" — 'Miso.Util.sepBy', 'Miso.Util.oneOf' used alongside parsers
+----------------------------------------------------------------------------
+module Miso.Util.Parser
+  ( -- ** Types
+    Parser
+  , ParserT (..)
+  , ParseError (..)
+    -- ** Combinators
+  , parse
+  , anyToken
+  , satisfy
+  , peek
+  , token_
+  , errorOut
+  , allTokens
+  , modifyTokens
+  , askParser
+  , endOfInput
+  ) where
+----------------------------------------------------------------------------
+#if __GLASGOW_HASKELL__ <= 881
+import           Control.Monad.Fail (MonadFail (..))
+#endif
+import           Control.Applicative
+import           Control.Monad
+import           Data.Maybe (isNothing)
+----------------------------------------------------------------------------
+import           Miso.Util.Lexer (LexerError)
+----------------------------------------------------------------------------
+-- | A type for expressing failure during parsing.
+data ParseError a token
+  = UnexpectedParse [token]
+  | LexicalError LexerError
+  | Ambiguous [(a, [token])]
+  | NoParses token
+  | EmptyStream
+  deriving (Show, Eq)
+----------------------------------------------------------------------------
+-- | Executes a parser against a series of tokens.
+parse
+  :: Parser token a
+  -- ^ Parser to run
+  -> [token]
+  -- ^ Input token stream
+  -> Either (ParseError a token) a
+parse _ [] = Left EmptyStream
+parse parser tokens =
+  case runParserT parser () tokens of
+    []        -> Left (NoParses (last tokens))
+    [(x, [])] -> Right x
+    [(_, xs)] -> Left (UnexpectedParse xs)
+    xs        -> Left (Ambiguous xs)
+----------------------------------------------------------------------------
+-- | Convenience synonym when defining parser combinators
+type Parser token a = ParserT () [token] [] a
+----------------------------------------------------------------------------
+-- | Core type for parsing
+newtype ParserT r token m a
+  = Parser
+  { runParserT :: r -> token -> m (a, token)
+  -- ^ Run the parser given a read-only environment @r@ and input @token@;
+  -- returns zero or more @(result, remaining-input)@ pairs in @m@
+  }
+----------------------------------------------------------------------------
+instance Functor (ParserT r token []) where
+  fmap f (Parser run) = Parser $ \r input ->
+    case run r input of
+      tokens -> [ (f x, toks) | (x, toks) <- tokens ]
+----------------------------------------------------------------------------
+instance Applicative (ParserT r token []) where
+  pure x = Parser $ \_ s -> pure (x,s)
+  Parser f <*> Parser g = Parser $ \r input -> do
+    (k, s) <- f r input
+    (x, t) <- g r s
+    pure (k x, t)
+----------------------------------------------------------------------------
+instance Alternative (ParserT r token []) where
+  empty = Parser $ \_ _ -> []
+  Parser f <|> Parser g =
+    Parser $ \r tokens ->
+      case f r tokens of
+        [] -> g r tokens
+        x  -> x
+----------------------------------------------------------------------------
+instance Monad (ParserT r token []) where
+  return = pure
+  Parser f >>= k = Parser $ \r tokens -> do
+    (x, tokens') <- f r tokens
+    runParserT (k x) r tokens'
+----------------------------------------------------------------------------
+instance MonadFail (ParserT r token []) where
+  fail _ = empty
+----------------------------------------------------------------------------
+instance MonadPlus (ParserT r token [])
+----------------------------------------------------------------------------
+-- | Match any token.
+anyToken :: ParserT r [a] [] a
+anyToken = Parser $ \_ input ->
+  case input of
+    t : ts -> [(t, ts)]
+    _ -> []
+----------------------------------------------------------------------------
+-- | Succeeds for any token for which the predicate @f@ returns 'True'.
+-- Returns the parsed token.
+satisfy
+  :: (a -> Bool)
+  -- ^ Predicate; the next token is consumed only if this returns 'True'
+  -> ParserT r [a] [] a
+satisfy f = do
+  t <- anyToken
+  guard (f t)
+  pure t
+----------------------------------------------------------------------------
+-- | Succeeds if the next token in the stream matches the given one.
+-- Returns the parsed token.
+token_
+  :: Eq token
+  => token
+  -- ^ Expected token value
+  -> Parser token token
+token_ t = satisfy (==t)
+----------------------------------------------------------------------------
+-- | Returns all input from a parser
+allTokens :: ParserT r a [] a
+allTokens = Parser $ \_ input -> [(input, input)]
+----------------------------------------------------------------------------
+-- | Modifies tokens
+modifyTokens
+  :: (t -> t)
+  -- ^ Transform to apply to the current token stream
+  -> ParserT r t [] ()
+modifyTokens f = Parser $ \_ input -> [((), f input)]
+----------------------------------------------------------------------------
+-- | Retrieves read-only state from a Parser
+askParser :: ParserT r token [] r
+askParser = Parser $ \r input -> [(r, input)]
+----------------------------------------------------------------------------
+-- | Views the next token without consuming input
+peek :: Parser a a
+peek = Parser $ \_ tokens ->
+  case tokens of
+    [] -> []
+    (x:xs) -> [(x, x:xs)]
+----------------------------------------------------------------------------
+-- | Parser combinator that always fails
+errorOut
+  :: errorToken
+  -- ^ Error token injected as the current stream (useful for error propagation)
+  -> ParserT r errorToken [] ()
+errorOut x = Parser $ \_ _ -> [((),x)]
+----------------------------------------------------------------------------
+-- | Parser combinator that only succeeds if there are no more tokens.
+endOfInput :: ParserT r [a] [] ()
+endOfInput = guard . isNothing =<< optional anyToken
+----------------------------------------------------------------------------
diff --git a/src/Miso/WebSocket.hs b/src/Miso/WebSocket.hs
new file mode 100644
--- /dev/null
+++ b/src/Miso/WebSocket.hs
@@ -0,0 +1,299 @@
+-----------------------------------------------------------------------------
+{-# LANGUAGE TypeApplications           #-}
+{-# LANGUAGE CPP                        #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Miso.WebSocket
+-- Copyright   :  (C) 2016-2026 David M. Johnson
+-- License     :  BSD3-style (see the file LICENSE)
+-- Maintainer  :  David M. Johnson <code@dmj.io>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+-- = Overview
+--
+-- "Miso.WebSocket" provides a full-duplex
+-- <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket WebSocket>
+-- client that integrates directly into the MVU loop. Every operation
+-- — connecting, sending, and closing — returns an 'Miso.Effect.Effect',
+-- making WebSocket communication a first-class citizen of the @update@
+-- function.
+--
+-- = Quick start
+--
+-- @
+-- import "Miso"
+-- import "Miso.WebSocket"
+--
+-- data Action
+--   = Connect
+--   | Connected  t'WebSocket'
+--   | Received   'Miso.String.MisoString'
+--   | Disconnected t'Closed'
+--   | WsError    'Miso.String.MisoString'
+--   | Send       'Miso.String.MisoString'
+--   | Disconnect
+--
+-- -- Hold the socket handle in the model so we can send later
+-- data Model = Model { ws :: t'WebSocket' }
+--
+-- update :: Action -> 'Miso.Effect.Effect' p props Model Action
+-- update Connect =
+--   'connectText' \"wss:\/\/echo.websocket.org\"
+--     Connected Disconnected Received WsError
+-- update (Connected sock) =
+--   'Miso.State.modify' (\\m -> m { ws = sock })
+-- update (Received msg) =
+--   'Miso.Effect.io_' (consoleLog msg)
+-- update (Send txt) = do
+--   sock <- 'Miso.State.gets' ws
+--   'sendText' sock txt
+-- update Disconnect = do
+--   sock <- 'Miso.State.gets' ws
+--   'close' sock
+-- update _ = pure ()
+-- @
+--
+-- = Connection variants
+--
+-- Five @connect@ functions cover every wire format. They all share the
+-- same callback signature — @onOpen@, @onClosed@, @onMessage@, @onError@
+-- — but differ in how the message payload is decoded:
+--
+-- ['connectText'] 'Miso.String.MisoString' — plain UTF-8 text
+-- ['connectJSON'] @json@ ('Miso.JSON.FromJSON' json) — auto-decoded from JSON
+-- ['connectBLOB'] t'Blob' — raw binary Blob
+-- ['connectArrayBuffer'] t'ArrayBuffer' — raw binary buffer
+-- ['connect'] @'Payload' json@ — mixed; caller pattern-matches the payload ADT
+--
+-- = Sending messages
+--
+-- The t'WebSocket' handle delivered to @onOpen@ must be stored in the
+-- model and passed to each send call:
+--
+-- @
+-- 'sendText'        :: t'WebSocket' -> 'Miso.String.MisoString' -> 'Miso.Effect.Effect' p props model action
+-- 'sendJSON'        :: 'Miso.JSON.ToJSON' json => t'WebSocket' -> json -> 'Miso.Effect.Effect' p props model action
+-- 'sendBLOB'        :: t'WebSocket' -> t'Blob' -> 'Miso.Effect.Effect' p props model action
+-- 'sendArrayBuffer' :: t'WebSocket' -> t'ArrayBuffer' -> 'Miso.Effect.Effect' p props model action
+-- @
+--
+-- = Lifecycle
+--
+-- * Always call 'close' when the connection is no longer needed to avoid
+--   resource leaks. It is safe to call 'close' multiple times — subsequent
+--   calls are no-ops.
+-- * 'socketState' lets you query the current 'SocketState'
+--   (@CONNECTING@, @OPEN@, @CLOSING@, @CLOSED@) asynchronously.
+-- * 'emptyWebSocket' (@= -1@) is a null sentinel you can store in the
+--   model before a connection has been established.
+--
+-- = Types
+--
+-- * t'WebSocket' — an opaque integer file descriptor returned by @onOpen@.
+-- * @URL@ — alias for 'Miso.String.MisoString'.
+-- * 'SocketState' — four-state enum mirroring the JS @readyState@ property.
+-- * t'Closed' — close event data: 'closedCode', 'wasClean', 'reason'.
+-- * 'CloseCode' — typed close codes from
+--   <https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code RFC 6455>.
+-- * 'Payload' — @JSON value | BLOB Blob | TEXT MisoString | BUFFER ArrayBuffer@.
+-- * t'Blob' / t'ArrayBuffer' — re-exported from "Miso.FFI.Internal".
+--
+-- = See also
+--
+-- * "Miso.EventSource" — Server-Sent Events (SSE), a unidirectional alternative
+-- * "Miso.Fetch" — one-shot HTTP requests
+-- * "Miso.Effect" — 'Miso.Effect.Effect', 'Miso.Effect.io_'
+----------------------------------------------------------------------------
+module Miso.WebSocket
+  ( -- *** t'WebSocket'
+    connect
+  , connectJSON
+  , connectText
+  , connectBLOB
+  , connectArrayBuffer
+  , sendText
+  , sendJSON
+  , sendBLOB
+  , sendArrayBuffer
+  , close
+  , socketState
+  -- *** Defaults
+  , emptyWebSocket
+  -- *** Types
+  , WebSocket   (..)
+  , URL
+  , SocketState (..)
+  , CloseCode   (..)
+  , Closed      (..)
+  , Payload     (..)
+  , Blob        (..)
+  , ArrayBuffer (..)
+  ) where
+-----------------------------------------------------------------------------
+import           Miso.Effect
+import           Miso.JSON
+import           Miso.Runtime
+import           Miso.String (MisoString)
+import           Miso.FFI (Blob(..), ArrayBuffer(..))
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>
+--
+-- Establishes a t'WebSocket' server that receives potentially multiple different t'Payload'.
+--
+-- It's more common to use 'connectJSON' or 'connectText'. But 'connect' can be used to received multiple
+-- different kinds of data from a t'WebSocket' server.
+--
+connect
+  :: FromJSON json
+  => URL
+  -- ^ URL endpoint for a t'WebSocket' connection
+  -> (WebSocket -> action)
+  -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.
+  -> (Closed -> action)
+  -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.
+  -> (Payload json -> action)
+  -- ^ @onMessage@ is a callback invoked when a message has been received from the t'WebSocket' server.
+  -> (MisoString -> action)
+  -- ^ Error message callback
+  -> Effect context props model action
+connect = websocketConnect
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>
+--
+-- Establishes a t'WebSocket' server that assumes a JSON-encoded protocol.
+--
+connectJSON
+  :: FromJSON json
+  => URL
+  -- ^ URL endpoint for a t'WebSocket' connection
+  -> (WebSocket -> action)
+  -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.
+  -> (Closed -> action)
+  -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.
+  -> (json -> action)
+  -- ^ @onMessage@ is a callback invoked when a JSON-encoded message has been received from the t'WebSocket' server.
+  -> (MisoString -> action)
+  -- ^ Error message callback
+  -> Effect context props model action
+connectJSON = websocketConnectJSON
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>
+--
+-- Establishes a t'WebSocket' server that assumes a text-encoded protocol.
+--
+connectText
+  :: URL
+  -- ^ URL endpoint for a t'WebSocket' connection
+  -> (WebSocket -> action)
+  -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.
+  -> (Closed -> action)
+  -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.
+  -> (MisoString -> action)
+  -- ^ @onMessage@ is a callback invoked when a text-encoded message has been received from the t'WebSocket' server.
+  -> (MisoString -> action)
+  -- ^ Error message callback
+  -> Effect context props model action
+connectText = websocketConnectText
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>
+--
+-- Establishes a t'WebSocket' server that assumes a binary-encoded protocol.
+--
+connectBLOB
+  :: URL
+  -- ^ URL endpoint for a t'WebSocket' connection
+  -> (WebSocket -> action)
+  -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.
+  -> (Closed -> action)
+  -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.
+  -> (Blob -> action)
+  -- ^ @onMessage@ is a callback invoked when a binary-encoded message has been received from the t'WebSocket' server.
+  -> (MisoString -> action)
+  -- ^ @onError@ callback
+  -> Effect context props model action
+connectBLOB = websocketConnectBLOB
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>
+--
+-- Establishes a t'WebSocket' server that assumes an t'ArrayBuffer' protocol.
+--
+connectArrayBuffer
+  :: URL
+  -- ^ URL endpoint for a t'WebSocket' connection
+  -> (WebSocket -> action)
+  -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.
+  -> (Closed -> action)
+  -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.
+  -> (ArrayBuffer -> action)
+  -- ^ @onMessage@ is a callback invoked when an t'ArrayBuffer' message has been received from the t'WebSocket' server.
+  -> (MisoString -> action)
+  -- ^ @onError@ callback
+  -> Effect context props model action
+connectArrayBuffer = websocketConnectArrayBuffer
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>
+--
+-- @
+--
+-- data Person = Person { name :: MisoString, age :: Int }
+--   deriving (Show, Eq)
+--
+-- instance ToJSON Person where
+--   toJSON (Person name age) = object [ "name" .= name, "age" .= age ]
+--
+-- test :: WebSocket -> Effect context props model action
+-- test connection = do
+--   sendJSON (connection :: WebSocket) (Person "alice" 42)
+--   sendJSON (connection :: WebSocket) (Person "bob" 42)
+--
+-- @
+--
+sendJSON
+  :: ToJSON json
+  => WebSocket
+  -- ^ t'WebSocket' descriptor required to send a message to the server.
+  -> json
+  -- ^ A JSON-encoded message
+  -> Effect context props model action
+sendJSON socket x = websocketSend socket (JSON x)
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>
+sendBLOB
+  :: WebSocket
+  -- ^ t'WebSocket' descriptor required to send a message to the server.
+  -> Blob
+  -- ^ An t'Blob' payload to send to the t'WebSocket' server
+  -> Effect context props model action
+sendBLOB socket x = websocketSend @() socket (blob x)
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>
+sendArrayBuffer
+  :: WebSocket
+  -- ^ t'WebSocket' descriptor required to send a message to the server.
+  -> ArrayBuffer
+  -- ^ An t'ArrayBuffer' payload to send to the t'WebSocket' server
+  -> Effect context props model action
+sendArrayBuffer socket x = websocketSend @() socket (arrayBuffer x)
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>
+sendText
+  :: WebSocket
+  -- ^ t'WebSocket' descriptor required to send a message to the server.
+  -> MisoString
+  -- ^ A text payload to send to t'WebSocket' server
+  -> Effect context props model action
+sendText socket x = websocketSend @() socket (TEXT x)
+-----------------------------------------------------------------------------
+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close>
+--
+-- It is very important to close the t'WebSocket', otherwise leaks can occur.
+--
+-- 'close' is a no-op if invoked multiple times.
+--
+close
+  :: WebSocket
+  -- ^ t'WebSocket' descriptor required to close the socket on the server.
+  -> Effect context props model action
+close = websocketClose
+-----------------------------------------------------------------------------
diff --git a/tests/Main.hs b/tests/Main.hs
deleted file mode 100644
--- a/tests/Main.hs
+++ /dev/null
@@ -1,92 +0,0 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE ForeignFunctionInterface #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE NamedFieldPuns #-}
-module Main where
-
-import           Control.Monad
-import           Data.Aeson
-import qualified Data.HashMap.Strict       as H
-import           Data.Scientific
-import qualified Data.Vector               as V
-import           Debug.Trace
-import           GHCJS.Marshal
-import           Test.Hspec                (it, hspec, describe, shouldSatisfy, shouldBe, Spec)
-import           Test.Hspec.Core.Runner    (hspecResult, Summary(..))
-import           Test.QuickCheck
-import           Test.QuickCheck.Instances
-
-import           Miso
-import           Miso.FFI
-import           System.IO.Unsafe
-
-instance Arbitrary Value where
-  arbitrary = sized sizedArbitraryValue
-
-sizedArbitraryValue :: Int -> Gen Value
-sizedArbitraryValue n
-  | n <= 0 = oneof [pure Null, bool, number, string]
-  | otherwise = resize n' $ oneof [pure Null, bool, string, number, array, object']
-  where
-    n' = n `div` 2
-    bool = Bool <$> arbitrary
-    number = Number <$> arbitrary
-    string = String <$> arbitrary
-    array = Array <$> arbitrary
-    object' = Object <$> arbitrary
-
-compareValue :: Value -> Value -> Bool
-compareValue (Object x) (Object y) = and $ zipWith compareValue (H.elems x) (H.elems y)
-compareValue (Array x) (Array y)   = and $ zipWith compareValue (V.toList x) (V.toList y)
-compareValue (String x) (String y) = x == y
-compareValue (Bool x) (Bool y)     = x == y
-compareValue Null Null             = True
-compareValue (Number x) (Number y) = closeEnough x y
-compareValue _ _ = False
-
-closeEnough x y
-  = let d = max (abs x) (abs y)
-        relDiff = if (d == 0.0) then d else abs (x - y) / d
-    in relDiff <= 0.00001
-
-main :: IO ()
-main = do
-  Summary { summaryFailures } <- hspecResult tests
-  phantomExit summaryFailures
-
-tests :: Spec
-tests = do
-  storageTests
-  roundTripJSVal
-
-storageTests :: Spec
-storageTests = describe "Storage tests" $ do
-  it "should write to and read from local storage" $ do
-    let obj = object [ "foo" .= ("bar" :: String) ]
-    setLocalStorage "foo" obj
-    Right r <- getLocalStorage "foo"
-    r `shouldBe` obj
-  it "should write to and read from session storage" $ do
-    let obj = object [ "foo" .= ("bar" :: String) ]
-    setSessionStorage "foo" obj
-    Right r <- getLocalStorage "foo"
-    r `shouldBe` obj
-
-roundTripJSVal =
- describe "Serialization tests" $ do
-  it "Should round trip JSVal" $ do
-    property $ (\(x :: Value) -> do
-      Just y <- jsvalToValue =<< toJSVal x
-      compareValue x y `shouldBe` True)
-
-phantomExit :: Int -> IO ()
-phantomExit x
-  | x <= 0 = phantomExitSuccess
-  | otherwise = phantomExitFail
-
-foreign import javascript unsafe "phantom.exit(0);"
-  phantomExitSuccess :: IO ()
-
-foreign import javascript unsafe "phantom.exit(1);"
-  phantomExitFail :: IO ()
