Files
microdao-daarion/site/tasks/TASK_PHASE_ASSETS_PROXY_DEBUG_v2/index.html
Apple fb4f4a16d5 🔧 Fix GitHub Actions docs workflow
- Update mkdocs dependencies to latest versions
- Add permissions for GitHub Pages deployment
- Add workflow_dispatch for manual trigger
- Fix build command with fallback
2026-01-10 07:57:36 -08:00

859 lines
26 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="canonical" href="https://IvanTytar.github.io/microdao-daarion/tasks/TASK_PHASE_ASSETS_PROXY_DEBUG_v2/">
<link rel="icon" href="../../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.18">
<title>TASK_PHASE_ASSETS_PROXY_DEBUG_v2 — MinIO Asset Proxy (логотипи/банери) - DAARION Documentation</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.66ac8b77.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#task_phase_assets_proxy_debug_v2-minio-asset-proxy" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../.." title="DAARION Documentation" class="md-header__button md-logo" aria-label="DAARION Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
DAARION Documentation
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
TASK_PHASE_ASSETS_PROXY_DEBUG_v2 — MinIO Asset Proxy (логотипи/банери)
</span>
</div>
</div>
</div>
<script>var media,input,key,value,palette=__md_get("__palette");if(palette&&palette.color){"(prefers-color-scheme)"===palette.color.media&&(media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']"),palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent"));for([key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
</button>
</nav>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="DAARION Documentation" class="md-nav__button md-logo" aria-label="DAARION Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
</a>
DAARION Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../public/" class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../public/getting-started/" class="md-nav__link">
<span class="md-ellipsis">
Getting Started
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../public/architecture-overview/" class="md-nav__link">
<span class="md-ellipsis">
Architecture
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../public/daiS_daos_overview/" class="md-nav__link">
<span class="md-ellipsis">
DAIS & DAOS
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="">
<span class="md-ellipsis">
Internal
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Internal
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_1" >
<label class="md-nav__link" for="__nav_5_1" id="__nav_5_1_label" tabindex="0">
<span class="md-ellipsis">
Infra
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_1">
<span class="md-nav__icon md-icon"></span>
Infra
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../internal/infra/INFRA_AUTOMATION_PACK_V1/" class="md-nav__link">
<span class="md-ellipsis">
Infra Automation Pack v1
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/infra/monitoring_overview/" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/infra/nodes_registry_v0/" class="md-nav__link">
<span class="md-ellipsis">
Nodes Registry v0
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_2" >
<label class="md-nav__link" for="__nav_5_2" id="__nav_5_2_label" tabindex="0">
<span class="md-ellipsis">
Specs
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_2">
<span class="md-nav__icon md-icon"></span>
Specs
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../internal/specs/matrix_presence_aggregator/" class="md-nav__link">
<span class="md-ellipsis">
Matrix Presence Aggregator
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/specs/city_map_spec/" class="md-nav__link">
<span class="md-ellipsis">
City Map Spec
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../internal/specs/node_join_protocol_draft/" class="md-nav__link">
<span class="md-ellipsis">
Node Join Protocol (Draft)
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#_1" class="md-nav__link">
<span class="md-ellipsis">
Контекст
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#_2" class="md-nav__link">
<span class="md-ellipsis">
Завдання
</span>
</a>
<nav class="md-nav" aria-label="Завдання">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1" class="md-nav__link">
<span class="md-ellipsis">
1. Перевірити, що саме зараз працює на проді
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-asset-proxy-city-service" class="md-nav__link">
<span class="md-ellipsis">
2. Перевірити конфіг маршруту Asset Proxy у city-service
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-env-minio-asset-proxy" class="md-nav__link">
<span class="md-ellipsis">
3. Перевірити ENV для доступу до MinIO в Asset Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-normalizeasseturl-asset-proxy" class="md-nav__link">
<span class="md-ellipsis">
4. Вирівняти контракт normalizeAssetUrl ↔ Asset Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5" class="md-nav__link">
<span class="md-ellipsis">
5. Перевірка на проді
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#acceptance-criteria" class="md-nav__link">
<span class="md-ellipsis">
Acceptance Criteria
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="task_phase_assets_proxy_debug_v2-minio-asset-proxy">TASK_PHASE_ASSETS_PROXY_DEBUG_v2 — MinIO Asset Proxy (логотипи/банери)<a class="headerlink" href="#task_phase_assets_proxy_debug_v2-minio-asset-proxy" title="Permanent link">&para;</a></h1>
<h2 id="_1">Контекст<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h2>
<ul>
<li>MinIO використовується для зберігання assets (логотипи, банери, зображення).</li>
<li>Раніше доступ йшов через <code>https://assets.daarion.space/...</code> (NGINX → MinIO).</li>
<li>Було додано proxy в city-service:</li>
<li>endpoint: <code>/city/assets/proxy/{path}</code> (далі — Asset Proxy).</li>
<li><code>normalizeAssetUrl</code> перетворює <code>https://assets.daarion.space/daarion-assets/...</code> у <code>/api/city/assets/proxy/...</code>.</li>
<li>Cursor повідомляв:</li>
<li>Proxy endpoint працює, локально повертає PNG.</li>
<li>Компоненти використовують <code>normalizeAssetUrl</code>.</li>
<li>На проді фактично:</li>
<li>логотипи/банери на <code>daarion.space</code> знову не відображаються,</li>
<li>у браузері видно або «биті» /api-URL, або прямі <code>assets.daarion.space</code>, які не відкриваються.</li>
</ul>
<p>Ціль — зробити так, щоб:
- на проді логотипи/банери стабільно відображалися,
- всі UI-компоненти використовували один механізм нормалізації URL,
- Asset Proxy коректно працював із MinIO в прод-оточенні.</p>
<hr />
<h2 id="_2">Завдання<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h2>
<h3 id="1">1. Перевірити, що саме зараз працює на проді<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<ol>
<li>Зайти на продовий <code>daarion.space</code> (через SSH-tunel / curl).</li>
<li>Для декількох сторінок (мікроDAO, ноди, банери):</li>
<li>подивитись <code>img.src</code> у HTML/DevTools,</li>
<li>зафіксувати: чи це <code>/api/city/assets/proxy/...</code> чи <code>https://assets.daarion.space/...</code>.</li>
<li>Якщо хоч один компонент ще використовує сирий URL:</li>
<li>знайти всі місця у фронті, де рендеряться логотипи/банери (microdao, nodes, dashboards, тощо),</li>
<li>переконатися, що всюди використовується <strong>одна</strong> функція <code>normalizeAssetUrl</code> (або аналогічний helper),</li>
<li>виправити імпорти/використання (ніяких <code>src={logoUrl}</code> напряму).</li>
</ol>
<h3 id="2-asset-proxy-city-service">2. Перевірити конфіг маршруту Asset Proxy у city-service<a class="headerlink" href="#2-asset-proxy-city-service" title="Permanent link">&para;</a></h3>
<ol>
<li>
<p>Знайти в <code>services/city-service/routes_city.py</code> (або відповідному файлі) endpoint типу:
<code>python
@router.get("/city/assets/proxy/{path:path}")</code>
Важливо: має бути <code>{path:path}</code>, щоб підтримувати вкладені шляхи з <code>/</code>.</p>
</li>
<li>
<p>Переконатися, що:</p>
</li>
<li>route справді висить під <code>/city/assets/proxy/{path}</code> (не <code>/assets/proxy</code> без <code>/city</code>),</li>
<li>в main-файлі <code>city-service</code> router змонтовано як <code>/api/city</code> (або відповідно до NGINX/Caddy маршрутизації),</li>
<li>
<p>результатом на проді стає <strong>саме той шлях</strong>, який очікує фронт (наприклад <code>/api/city/assets/proxy/...</code>).</p>
</li>
<li>
<p>Перехрестити це з проксі-конфігом NGINX/Caddy:</p>
</li>
<li><code>/api/city</code><code>city-service</code>,</li>
<li>нічого не обрізається/не додається зайве (щоб не вийшло <code>/api/api/city/...</code> або <code>/city/city/...</code>).</li>
</ol>
<h3 id="3-env-minio-asset-proxy">3. Перевірити ENV для доступу до MinIO в Asset Proxy<a class="headerlink" href="#3-env-minio-asset-proxy" title="Permanent link">&para;</a></h3>
<ol>
<li>
<p>Знайти, які ENV використовує proxy для MinIO (наприклад):
<code>python
MINIO_PUBLIC_ENDPOINT
MINIO_BUCKET
MINIO_ASSETS_PREFIX # typ. "daarion-assets"</code></p>
</li>
<li>
<p>Переконатися, що:</p>
</li>
<li>у prod-docker-compose для <code>city-service</code> ці ENV присутні й коректні,</li>
<li>
<p>в коді proxy шлях будується правильно:
<code>python
# псевдокод
target_url = f"{MINIO_PUBLIC_ENDPOINT}/{MINIO_BUCKET}/{path}"</code>
якщо <code>normalizeAssetUrl</code> відрізає <code>daarion-assets/</code>, то тут це потрібно додати вручну.</p>
</li>
<li>
<p>Написати невеликий unit/integration-тест або просто <code>curl</code> у коді:</p>
</li>
<li>викликати Asset Proxy з конкретним шляхом, який точно існує в MinIO (<code>microdao/logo/...</code>),</li>
<li>переконатися, що код отримує 200 і <code>Content-Type: image/png</code>.</li>
</ol>
<h3 id="4-normalizeasseturl-asset-proxy">4. Вирівняти контракт normalizeAssetUrl ↔ Asset Proxy<a class="headerlink" href="#4-normalizeasseturl-asset-proxy" title="Permanent link">&para;</a></h3>
<ol>
<li>В коді <code>normalizeAssetUrl</code> явно зафіксувати контракт:</li>
<li>Приклад вхідного URL з БД:
<code>text
https://assets.daarion.space/daarion-assets/microdao/logo/123.png</code></li>
<li>
<p>Вихідний URL для фронта:
<code>text
/api/city/assets/proxy/microdao/logo/123.png</code></p>
</li>
<li>
<p>В коді proxy за цим шляхом (<code>microdao/logo/123.png</code>) формувати запит до MinIO:
<code>text
&lt;MINIO_PUBLIC_ENDPOINT&gt;/daarion-assets/microdao/logo/123.png</code></p>
</li>
<li>
<p>Якщо в БД іноді зберігаються шляхи без <code>daarion-assets/</code> або без домену:</p>
</li>
<li>
<p>додати обробку в normalizeAssetUrl:</p>
<ul>
<li>якщо шлях починається з <code>https://assets.daarion.space/</code> → вирізати домен і префікс бакету,</li>
<li>якщо з <code>/daarion-assets/</code> → вирізати <code>/daarion-assets/</code>,</li>
<li>якщо просто <code>microdao/logo/...</code> → використовувати як є.</li>
</ul>
</li>
<li>
<p>Додати короткий коментар у коді normalizeAssetUrl і Asset Proxy, щоб наступні зміни не ламали цей контракт.</p>
</li>
</ol>
<h3 id="5">5. Перевірка на проді<a class="headerlink" href="#5" title="Permanent link">&para;</a></h3>
<ol>
<li>Після оновлення <code>city-service</code> і <code>web</code> (перезбір образів і <code>docker-compose up -d</code>):</li>
<li>
<p>Зайти на основні сторінки з логотипами/банерами:</p>
<ul>
<li>список MicroDAO,</li>
<li>сторінка MicroDAO,</li>
<li>сторінка нод,</li>
<li>dashboard, де є банери.</li>
</ul>
</li>
<li>
<p>У DevTools:</p>
</li>
<li>перевірити, що всі картинки ведуть на <code>/api/city/assets/proxy/...</code>,</li>
<li>статус усіх запитів 200,</li>
<li>
<p><code>Content-Type</code> відповідає типу зображення.</p>
</li>
<li>
<p>Зафіксувати в короткому звіті:</p>
</li>
<li>приклади реальних URL (до/після),</li>
<li>що саме було змінено в коді / docker-конфігах,</li>
<li>інструкцію, як додавати нові компоненти з логотипами, щоб не обійти <code>normalizeAssetUrl</code>.</li>
</ol>
<hr />
<h2 id="acceptance-criteria">Acceptance Criteria<a class="headerlink" href="#acceptance-criteria" title="Permanent link">&para;</a></h2>
<ul>
<li>На проді:</li>
<li>всі логотипи й банери на <code>daarion.space</code> завантажуються,</li>
<li>немає жодних прямих <code>https://assets.daarion.space/...</code> у HTML,</li>
<li>
<p>всі запити до зображень йдуть через <code>/api/city/assets/proxy/...</code> і повертають 200.</p>
</li>
<li>
<p>В репозиторії:</p>
</li>
<li>є один централізований helper (<code>normalizeAssetUrl</code>), який використовують усі компоненти для assets,</li>
<li>Asset Proxy має чіткий контракт з цим helper'ом і коректні ENV для MinIO,</li>
<li>
<p>коротка документація (наприклад, у <code>docs/ASSETS_DNS_SETUP.md</code> або новому <code>docs/ASSETS_PROXY.md</code>) описує поточну схему.</p>
</li>
<li>
<p>Перезапуск сервісів (web + city-service) після змін обов'язково задокументований у звіті Cursor.</p>
</li>
</ul>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../..", "features": ["navigation.sections", "navigation.instant", "content.code.copy"], "search": "../../assets/javascripts/workers/search.b8dbb3d2.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
<script src="../../assets/javascripts/bundle.3220b9d7.min.js"></script>
</body>
</html>