diff options
Diffstat (limited to 'lua.html')
| -rw-r--r-- | lua.html | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/lua.html b/lua.html new file mode 100644 index 0000000..7baeba0 --- /dev/null +++ b/lua.html @@ -0,0 +1,66 @@ +<!doctype html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>panto — Lua extensions</title> +<link rel="stylesheet" href="_ds/pantograph-design-system-56a1c74e-41c1-486b-ba3c-4eabdfacef31/styles.css"> +<link rel="stylesheet" href="_shared/components.css"> +<link rel="stylesheet" href="_shared/docs.css"> +</head> +<body> +<div class="pd-app"> +<header class="pd-header"> +<div class="pd-header__left"> +<button class="pd-menu" type="button" aria-label="Menu" data-menu-toggle><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="1em" height="1em"><path d="M4 12h16"/><path d="M4 6h16"/><path d="M4 18h16"/></svg></button> +<a class="pd-brand" href="index.html"><img src="assets/logo-mark.svg" width="28" height="28" alt=""><span class="pd-brand__word">panto</span><span class="pd-brand__div">/</span><span class="pd-brand__sub">docs</span></a> +<span class="pg-badge pg-badge--outline">CLI</span> +</div> +<nav class="pd-nav"><a href="index.html" class="pd-nav__link">Getting started</a><a href="cli.html" class="pd-nav__link">Command line</a><a href="configuration.html" class="pd-nav__link">Configuration</a><a href="keybindings.html" class="pd-nav__link">Key bindings</a><a href="lua.html" class="pd-nav__link pd-nav__link--active">Lua extensions</a></nav> +<div class="pd-header__right"><a class="pd-ghlink" href="https://code.tjp.lol/pantograph.git/" target="_blank" rel="noreferrer"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="1em" height="1em"><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 .5 5 .5 5 .5c-.3 1.15-.3 2.35 0 3.5A5.4 5.4 0 0 0 4 7.5c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/><path d="M9 18c-4.51 2-5-2-7-2"/></svg> Source</a></div> +</header> +<div class="pd-shell"> +<aside class="pd-sidebar"><div class="pd-sidebar__scroll"><div class="pd-navsec"><p class="pd-navsec__title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="1em" height="1em"><path d="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"/><circle cx="12" cy="12" r="10"/></svg>Getting started</p><ul class="pd-navsec__list"><li><a href="index.html#overview" class="pd-navsec__link">Overview</a></li><li><a href="index.html#install" class="pd-navsec__link">Install</a></li><li><a href="index.html#first-run" class="pd-navsec__link">First run</a></li><li><a href="index.html#authenticate" class="pd-navsec__link">Authenticate</a></li></ul></div><div class="pd-navsec"><p class="pd-navsec__title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="1em" height="1em"><path d="m4 17 6-6-6-6"/><path d="M12 19h8"/></svg>Command line</p><ul class="pd-navsec__list"><li><a href="cli.html#starting" class="pd-navsec__link">Starting a session</a></li><li><a href="cli.html#sessions" class="pd-navsec__link"><code>panto sessions</code></a></li><li><a href="cli.html#models" class="pd-navsec__link"><code>panto models</code></a></li><li><a href="cli.html#auth" class="pd-navsec__link"><code>panto auth</code></a></li><li><a href="cli.html#bootstrap" class="pd-navsec__link"><code>panto bootstrap</code></a></li><li><a href="cli.html#lua" class="pd-navsec__link"><code>panto lua</code></a></li><li><a href="cli.html#slash-commands" class="pd-navsec__link">Slash commands</a></li><li><a href="cli.html#environment" class="pd-navsec__link">Environment</a></li></ul></div><div class="pd-navsec"><p class="pd-navsec__title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="1em" height="1em"><path d="M3 5h11"/><path d="M19 5h2"/><path d="M3 12h6"/><path d="M14 12h7"/><path d="M3 19h10"/><path d="M18 19h3"/><circle cx="16" cy="5" r="2"/><circle cx="11" cy="12" r="2"/><circle cx="15" cy="19" r="2"/></svg>Configuration</p><ul class="pd-navsec__list"><li><a href="configuration.html#files" class="pd-navsec__link">Files & layers</a></li><li><a href="configuration.html#providers" class="pd-navsec__link"><code>[providers]</code></a></li><li><a href="configuration.html#auth" class="pd-navsec__link"><code>[auth]</code></a></li><li><a href="configuration.html#defaults" class="pd-navsec__link"><code>[defaults]</code></a></li><li><a href="configuration.html#policies" class="pd-navsec__link">Tools & extensions</a></li><li><a href="configuration.html#compaction" class="pd-navsec__link"><code>[compaction]</code></a></li><li><a href="configuration.html#models" class="pd-navsec__link"><code>models.toml</code></a></li><li><a href="configuration.html#system-prompt" class="pd-navsec__link">System prompt</a></li></ul></div><div class="pd-navsec"><p class="pd-navsec__title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="1em" height="1em"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="M6 8h.001"/><path d="M10 8h.001"/><path d="M14 8h.001"/><path d="M18 8h.001"/><path d="M8 12h.001"/><path d="M12 12h.001"/><path d="M16 12h.001"/><path d="M7 16h10"/></svg>Key bindings</p><ul class="pd-navsec__list"><li><a href="keybindings.html#editing" class="pd-navsec__link">Editing & cursor</a></li><li><a href="keybindings.html#submit" class="pd-navsec__link">Submit & newline</a></li><li><a href="keybindings.html#control" class="pd-navsec__link">Selectors & control</a></li><li><a href="keybindings.html#terminal" class="pd-navsec__link">Terminal protocol</a></li></ul></div><div class="pd-navsec pd-navsec--current"><p class="pd-navsec__title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="1em" height="1em"><path d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z"/><path d="m7 16.5-4.74-2.85"/><path d="m7 16.5 5-3"/><path d="M7 16.5v5.17"/><path d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z"/><path d="m17 16.5-5-3"/><path d="m17 16.5 4.74-2.85"/><path d="M17 16.5v5.17"/><path d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z"/><path d="M12 8 7.26 5.15"/><path d="m12 8 4.74-2.85"/><path d="M12 13.5V8"/></svg>Lua extensions</p><ul class="pd-navsec__list"><li><a href="lua.html#overview" class="pd-navsec__link pd-navsec__link--active">Overview</a></li><li><a href="lua.html#loading" class="pd-navsec__link">Loading extensions</a></li><li><a href="lua.html#tools" class="pd-navsec__link"><code>register_tool</code></a></li><li><a href="lua.html#commands" class="pd-navsec__link"><code>register_command</code></a></li><li><a href="lua.html#events" class="pd-navsec__link">Events: on & emit</a></li><li><a href="lua.html#components" class="pd-navsec__link">Lua components</a></li><li><a href="lua.html#runtime" class="pd-navsec__link">Runtime & luarocks</a></li></ul></div></div></aside> +<div class="pd-scrim"></div> +<main class="pd-main"><article class="pd-doc" data-screen-label="Lua extensions"><p class="panto-eyebrow pd-eyebrow">Reference</p><h1 class="pd-doc__h1">Lua extensions</h1><div class="pd-doc__meta"><span class="pg-badge pg-badge--neutral">require("panto")</span></div><p class="pd-lead">Everything beyond the core is a Lua extension — including the standard tools. An extension is a Lua file that calls into the <code>panto.ext</code> table to add tools, slash commands, and UI behaviour. This is how panto stays small without staying useless.</p><h2 id="overview" class="pd-h2">Overview</h2><p class="pd-body">Inside an extension, <code>local panto = require("panto")</code> gives you the API. The <code>panto.ext</code> table has three entry points:</p><div class="pd-opts"><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">register_tool</span><span class="pg-badge pg-badge--neutral">model-facing</span></div><div class="pd-opt__desc">Add a tool the model can call.</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">register_command</span><span class="pg-badge pg-badge--neutral">you-facing</span></div><div class="pd-opt__desc">Add a <code>/</code>slash command to the REPL.</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">on / emit</span><span class="pg-badge pg-badge--neutral">UI events</span></div><div class="pd-opt__desc">Hook the UI event bus to wrap or replace how things render.</div></div></div><p class="pd-body">All extensions share one long-lived Lua interpreter, so module-global state persists across calls. The <a href="#runtime">runtime</a> includes <code>luv</code> (libuv), so tool handlers can perform async I/O.</p><h2 id="loading" class="pd-h2">Loading extensions</h2><p class="pd-body">Drop a <code>.lua</code> file into an extensions directory and it loads at startup. panto discovers extensions across three layers:</p><div class="pd-table-wrap"><table class="pd-table"><thead><tr><th>Layer</th><th>Location</th></tr></thead><tbody><tr><td class="mono">base</td><td class="mono">$PANTO_HOME/agent</td></tr><tr><td class="mono">user</td><td class="mono">$XDG_CONFIG_HOME/panto/extensions/ · else ~/.config/panto/extensions/</td></tr><tr><td class="mono">project</td><td class="mono">./.panto/extensions/</td></tr></tbody></table></div><p class="pd-body">Project shadows user shadows base. Which extensions and tools actually load is gated by the <a href="configuration.html#policies"><code>[extensions]</code> and <code>[tools]</code></a> allow/deny policies.</p><div class="pg-callout pg-callout--warn"><span class="pg-callout__icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg></span><div class="pg-callout__body"><p class="pg-callout__title">Name collisions abort startup</p>If two surviving extensions register a tool (or command) with the same name, panto refuses to start rather than pick one silently. A Lua command may not shadow a builtin like <code>/compact</code>.</div></div><h2 id="tools" class="pd-h2">register_tool</h2><p class="pd-body">A tool is something the model can call. Describe it with a JSON-Schema for its arguments and a handler that returns a string result.</p><div class="pd-opts"><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">name</span><span class="pd-opt__type">string</span><span class="pg-badge pg-badge--danger">required</span></div><div class="pd-opt__desc">The tool name the model invokes.</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">description</span><span class="pd-opt__type">string</span><span class="pg-badge pg-badge--danger">required</span></div><div class="pd-opt__desc">Shown to the model; explain when to use it.</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">schema</span><span class="pd-opt__type">table</span><span class="pg-badge pg-badge--danger">required</span></div><div class="pd-opt__desc">A JSON-Schema table (<code>type = "object"</code>, <code>properties</code>, <code>required</code>) describing the arguments.</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">handler</span><span class="pd-opt__type">function(input)</span></div><div class="pd-opt__desc">Receives the decoded arguments table; returns a string result. May yield (async).</div></div></div><div class="pg-code"><div class="pg-code__bar"><span class="pg-code__name">.panto/extensions/echo.lua</span><span class="pg-code__lang">lua</span><button class="pg-code__copy" type="button" aria-label="Copy code"><svg class="pg-code__copyglyph" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg><svg class="pg-code__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m20 6-11 11-5-5"/></svg><span class="pg-code__label">Copy</span></button></div><div class="pg-code__scroll"><pre><code>local panto = require("panto") + +panto.ext.register_tool { + name = "echo", + description = "Echo back the given message.", + schema = { + type = "object", + properties = { + message = { type = "string", description = "The text to echo back." }, + }, + required = { "message" }, + }, + handler = function(input) + return "echo: " .. input.message + end, +}</code></pre></div></div><h2 id="commands" class="pd-h2">register_command</h2><p class="pd-body">A slash command runs locally when you type <code>/name</code> in the REPL. The handler runs synchronously and acts by side effect (typically writing output); its return value is ignored.</p><div class="pd-opts"><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">name</span><span class="pd-opt__type">string</span><span class="pg-badge pg-badge--danger">required</span></div><div class="pd-opt__desc">Command name, without the leading <code>/</code>.</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">description</span><span class="pd-opt__type">string</span><span class="pg-badge pg-badge--danger">required</span></div><div class="pd-opt__desc">One-line summary (for listings).</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">handler</span><span class="pd-opt__type">function(args)</span></div><div class="pd-opt__desc"><code>args</code> is the trimmed text after the command name — the empty string when none was given.</div></div></div><div class="pg-code"><div class="pg-code__bar"><span class="pg-code__name">.panto/extensions/greet.lua</span><span class="pg-code__lang">lua</span><button class="pg-code__copy" type="button" aria-label="Copy code"><svg class="pg-code__copyglyph" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg><svg class="pg-code__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m20 6-11 11-5-5"/></svg><span class="pg-code__label">Copy</span></button></div><div class="pg-code__scroll"><pre><code>local panto = require("panto") + +panto.ext.register_command { + name = "greet", + description = "Print a greeting. Optional args name who to greet.", + handler = function(args) + local who = args ~= "" and args or "world" + io.write("\n[greet] hello, " .. who .. "!\n") + end, +}</code></pre></div></div><h2 id="events" class="pd-h2">Events: on & emit</h2><p class="pd-body"><code>panto.ext.on(name, handler)</code> subscribes a handler to the UI event bus — the same bus the built-in TUI uses. Handlers fire in registration order, and can wrap or replace the component that renders a given moment of the transcript.</p><p class="pd-body">The handler receives an event object <code>e</code> that is valid <strong>only</strong> during the call (copy any field you need into a local — don’t read <code>e</code> later at render time):</p><div class="pd-opts"><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">e.name</span><span class="pd-opt__type">string</span></div><div class="pd-opt__desc">The event name.</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">e.<field></span></div><div class="pd-opt__desc">Read-only payload fields (nil when absent, so you can branch on them).</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">e:getComponent()</span></div><div class="pd-opt__desc">The current native component, as an opaque pass-through handle.</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">e:setComponent(c)</span></div><div class="pd-opt__desc">Replace the component for this boundary — pass the handle back to wrap it, or a Lua component table to replace it.</div></div></div><p class="pd-body">The events and the payload fields they carry:</p><div class="pd-table-wrap"><table class="pd-table"><thead><tr><th>Event</th><th>Payload fields</th></tr></thead><tbody><tr><td class="mono">tool</td><td class="mono">index, tool_name, id, delta, input, output</td></tr><tr><td class="mono">thinking</td><td class="mono">index, delta, text</td></tr><tr><td class="mono">assistant_text</td><td class="mono">index, delta, text</td></tr><tr><td class="mono">user_message</td><td class="mono">text</td></tr><tr><td class="mono">session_start</td><td class="mono">version, cwd, model</td></tr><tr><td class="mono">compaction</td><td class="mono">summary</td></tr><tr><td class="mono">custom</td><td class="mono">— produced by emit</td></tr></tbody></table></div><div class="pg-code"><div class="pg-code__bar"><span class="pg-code__name">.panto/extensions/skill-badge.lua</span><span class="pg-code__lang">lua</span><button class="pg-code__copy" type="button" aria-label="Copy code"><svg class="pg-code__copyglyph" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg><svg class="pg-code__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m20 6-11 11-5-5"/></svg><span class="pg-code__label">Copy</span></button></div><div class="pg-code__scroll"><pre><code>local panto = require("panto") + +-- Change how the "skill" tool renders in the transcript. +panto.ext.on("tool", function(e) + if e.tool_name ~= "skill" then return end -- ignore every other tool + local name = e.tool_name -- snapshot now: e is short-lived + e:setComponent({ + render = function(self, width) + return { "▸ running skill: " .. name } + end, + }) +end)</code></pre></div></div><p class="pd-body"><code>panto.ext.emit(name, data)</code> fires a custom event on the same bus, running both native and Lua handlers. Today <code>data</code> is surfaced as an opaque <code>custom</code> payload.</p><h2 id="components" class="pd-h2">Lua components</h2><p class="pd-body">A Lua component is a table you hand to <code>e:setComponent</code>. The one required method is <code>render</code>:</p><div class="pd-opts"><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">render</span><span class="pd-opt__type">function(self, width)</span><span class="pg-badge pg-badge--danger">required</span></div><div class="pd-opt__desc">Return an array of strings — one per line. Runs synchronously (it may <em>not</em> yield), each line is truncated to <code>width</code> columns, and any error becomes a safe fallback line so the frame never crashes. An empty array is valid (zero lines).</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">handleInput</span><span class="pd-opt__type">function(self, data)</span></div><div class="pd-opt__desc">Optional. Handle input routed to the component.</div></div><div class="pd-opt"><div class="pd-opt__key"><span class="pd-opt__name">firstLineChanged / invalidate</span><span class="pd-opt__type">function</span></div><div class="pd-opt__desc">Optional render-cache hooks.</div></div></div><h2 id="runtime" class="pd-h2">Runtime & luarocks</h2><p class="pd-body">panto embeds a pinned Lua and luarocks, and ships exactly one battery: <code>luv</code> (libuv’s event loop), the single runtime dependency. It drives panto’s coroutine scheduler and gives extensions one rich async-I/O surface. The bootstrap reconciles the installed rocks tree against panto’s manifest on every startup — installing what’s missing, removing what’s stale.</p><p class="pd-body">Anything else is yours to add. Install extra rocks into panto’s tree with the embedded luarocks, via <a href="cli.html#lua"><code>panto lua</code></a>:</p><div class="pg-code"><div class="pg-code__bar"><span class="pg-code__name">shell</span><span class="pg-code__lang">bash</span><button class="pg-code__copy" type="button" aria-label="Copy code"><svg class="pg-code__copyglyph" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></svg><svg class="pg-code__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m20 6-11 11-5-5"/></svg><span class="pg-code__label">Copy</span></button></div><div class="pg-code__scroll"><pre><code>panto lua -e 'arg[0]="luarocks"; require("luarocks.cmd").run_command("install","lpeg")'</code></pre></div></div><div class="pg-callout pg-callout--tip"><span class="pg-callout__icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"/></svg></span><div class="pg-callout__body"><p class="pg-callout__title">One-time setup</p>On a fresh machine, run <a href="cli.html#bootstrap"><code>panto bootstrap</code></a> once to build the rocks tree before your extensions need it.</div></div><nav class="pd-prevnext"><a class="pd-pn pd-pn--prev" href="keybindings.html"><span class="pd-pn__dir">← Previous</span><span class="pd-pn__title">Key bindings</span></a><span style="flex:1"></span></nav></article></main> +<aside class="pd-toc"><p class="pd-toc__title">On this page</p><ul class="pd-toc__list"><li><a href="#overview" class="pd-toc__link pd-toc__link--active">Overview</a></li><li><a href="#loading" class="pd-toc__link">Loading extensions</a></li><li><a href="#tools" class="pd-toc__link">register_tool</a></li><li><a href="#commands" class="pd-toc__link">register_command</a></li><li><a href="#events" class="pd-toc__link">Events: on & emit</a></li><li><a href="#components" class="pd-toc__link">Lua components</a></li><li><a href="#runtime" class="pd-toc__link">Runtime & luarocks</a></li></ul></aside> +</div> +</div> +<script src="_shared/docs.js"></script> +</body> +</html>
\ No newline at end of file |
