website

Personal website
git clone https://github.com/michaelneuper/website.git
README | Files | Log | Refs

commit fa5aa8cb2b713e28c75e3c0ae2884c4515c4d08e
parent e84fe2d4a9cfa411c32445c4c1ccd59d38334649
Author: Michael Neuper <michael@michaelneuper.com>
Date:   Mon, 12 Oct 2026 15:35:45 +0200

replace the hugo site with the astro site

Merges the history of the new site, which started in its own repo, and
removes Hugo. netlify.toml now builds with Astro, and the GPG key moved
from static/ to public/ so its URL stays the same.

Claude-Session: https://claude.ai/code/session_011d9ErWYG4cS8UDXfPRtwTJ

Diffstat:
M.gitignore | 14+++++++++-----
DREADME.md | 8--------
Darchetypes/default.md | 13-------------
Darchetypes/default.org | 5-----
Aastro.config.mjs | 10++++++++++
Dcategories.txt | 19-------------------
Dconfig/_default/hugo.toml | 72------------------------------------------------------------------------
Dconfig/_default/markup.toml | 12------------
Dconfig/_default/params.toml | 65-----------------------------------------------------------------
Dconfig/production/hugo.toml | 3---
Dcontent/_index.md | 24------------------------
Dcontent/pages/contact.md | 42------------------------------------------
Dcontent/pages/donate.md | 49-------------------------------------------------
Dcontent/pages/keybindings.md | 131-------------------------------------------------------------------------------
Dcontent/pages/library.md | 117-------------------------------------------------------------------------------
Dcontent/pages/software.md | 77-----------------------------------------------------------------------------
Dcontent/posts/best-firefox-extensions.md | 174-------------------------------------------------------------------------------
Dcontent/posts/buffer-overflow.md | 83-------------------------------------------------------------------------------
Dcontent/posts/efficient-latex-editing-with-emacs/abbreviations.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/accents.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/evil-tex.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/gnu-calc.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/index.md | 261-------------------------------------------------------------------------------
Dcontent/posts/efficient-latex-editing-with-emacs/latexmk.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/math-symbols.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/preview.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/snippets.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/symbols.png | 0
Dcontent/posts/efficient-latex-editing-with-emacs/tex-folding.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/xenops-paste.webm | 0
Dcontent/posts/efficient-latex-editing-with-emacs/xenops-render.webm | 0
Dcontent/posts/enable-monitor-mode-on-tp-link.md | 123-------------------------------------------------------------------------------
Dcontent/posts/how-i-use-org-roam-to-takes-notes-for-cs/graph.png | 0
Dcontent/posts/how-i-use-org-roam-to-takes-notes-for-cs/index.md | 249-------------------------------------------------------------------------------
Dcontent/posts/how-i-use-org-roam-to-takes-notes-for-cs/topic-node.png | 0
Dcontent/posts/how-to-create-your-own-website.md | 122-------------------------------------------------------------------------------
Dcontent/posts/modelling-population-growth-in-python/Figure_1.png | 0
Dcontent/posts/modelling-population-growth-in-python/Figure_1_old.png | 0
Dcontent/posts/modelling-population-growth-in-python/Figure_2.png | 0
Dcontent/posts/modelling-population-growth-in-python/Figure_2_old.png | 0
Dcontent/posts/modelling-population-growth-in-python/Figure_3.png | 0
Dcontent/posts/modelling-population-growth-in-python/Figure_3_old.png | 0
Dcontent/posts/modelling-population-growth-in-python/Figure_4.png | 0
Dcontent/posts/modelling-population-growth-in-python/Figure_4_old.png | 0
Dcontent/posts/modelling-population-growth-in-python/index.md | 344-------------------------------------------------------------------------------
Dcontent/posts/modelling-population-growth-in-python/logistic.py | 58----------------------------------------------------------
Dcontent/posts/modelling-population-growth-in-python/predator-prey.py | 67-------------------------------------------------------------------
Dcontent/posts/read-more.md | 52----------------------------------------------------
Dcontent/posts/replace-jupyter-notebook-with-emacs-org-mode.md | 293-------------------------------------------------------------------------------
Dcontent/posts/stop-using-proprietary-software.md | 50--------------------------------------------------
Dcontent/posts/turning-a-window-manager-into-a-desktop-environment.md | 228-------------------------------------------------------------------------------
Dcontent/posts/what-linux-packaging-format-to-use.md | 122-------------------------------------------------------------------------------
Dgo.mod | 5-----
Dgo.sum | 26--------------------------
Dlayouts/404.html | 8--------
Mnetlify.toml | 63++++++++-------------------------------------------------------
Mpackage-lock.json | 4140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mpackage.json | 18+++++++++++-------
Dpostcss.config.js | 3---
Apublic/favicon.svg | 12++++++++++++
Apublic/fonts/cm-italic.woff2 | 0
Apublic/fonts/cm-regular.woff2 | 0
Apublic/fonts/jetbrains-mono-regular.woff2 | 0
Apublic/fonts/jetbrains-mono-semibold.woff2 | 0
Rstatic/michaelneuper.gpg -> public/michaelneuper.gpg | 0
Apublic/notes-to-self.txt | 6++++++
Apublic/robots.txt | 3+++
Asrc/pages/index.astro | 352+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/coffee.js | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/computer.js | 608+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/contact.js | 28++++++++++++++++++++++++++++
Asrc/scripts/ctf.js | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/datasheet.js | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/decode.js | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/demos/bytecode.js | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/demos/computer.js | 1+
Asrc/scripts/demos/othello.js | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/demos/rbudp.js | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/demos/scheduler.js | 196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/gitlog.js | 226+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/main.js | 27+++++++++++++++++++++++++++
Asrc/scripts/memmap.js | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/org.js | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/shell.js | 511+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scripts/themes.js | 19+++++++++++++++++++
Asrc/scripts/util.js | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/styles/style.css | 2443+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dstatic/css/styles.css | 70----------------------------------------------------------------------
Dstatic/images/android-chrome-192x192.png | 0
Dstatic/images/android-chrome-512x512.png | 0
Dstatic/images/apple-touch-icon.png | 0
Dstatic/images/badges/ad-free-site.svg | 29-----------------------------
Dstatic/images/badges/created-with-emacs.jpg | 0
Dstatic/images/badges/emacs.gif | 0
Dstatic/images/badges/gnu.gif | 0
Dstatic/images/badges/javascript.gif | 0
Dstatic/images/badges/libreboot.gif | 0
Dstatic/images/badges/made-with-emacs.png | 0
Dstatic/images/badges/sink_animated.gif | 0
Dstatic/images/badges/suckless.gif | 0
Dstatic/images/badges/tor.gif | 0
Dstatic/images/badges/wiby.org.gif | 0
Dstatic/images/books/1984.webp | 0
Dstatic/images/books/critique-of-reason.webp | 0
Dstatic/images/books/how-linux-works.webp | 0
Dstatic/images/books/lingua-latina.webp | 0
Dstatic/images/books/republic.webp | 0
Dstatic/images/books/short-history.webp | 0
Dstatic/images/crypto/bitcoin.png | 0
Dstatic/images/crypto/btc-logo.svg | 8--------
Dstatic/images/crypto/monero.png | 0
Dstatic/images/crypto/xmr-logo.svg | 7-------
Dstatic/images/favicon-16x16.png | 0
Dstatic/images/favicon-32x32.png | 0
Dstatic/images/favicon.ico | 0
Dstatic/images/icons/blog.svg | 15---------------
Dstatic/images/icons/categories.svg | 15---------------
Dstatic/images/icons/contact.svg | 15---------------
Dstatic/images/icons/copied.svg | 5-----
Dstatic/images/icons/copy.svg | 7-------
Dstatic/images/icons/emacs-alt.svg | 286-------------------------------------------------------------------------------
Dstatic/images/icons/emacs.svg | 239-------------------------------------------------------------------------------
Dstatic/images/icons/github.svg | 15---------------
Dstatic/images/icons/hugo.svg | 14--------------
Dstatic/images/icons/rss.svg | 15---------------
Dstatic/images/icons/search.svg | 4----
Dstatic/images/icons/tags.svg | 15---------------
Dstatic/images/logo.webp | 0
Dstatic/images/redragon_mouse.webp | 0
Dstatic/images/wacom_tablet.webp | 0
Atsconfig.json | 5+++++
131 files changed, 9508 insertions(+), 4426 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,5 +1,10 @@ -public/ -resources/ +# build output +dist/ +# generated types +.astro/ +# dependencies node_modules/ -.hugo_build.lock -.DS_Store -\ No newline at end of file +# logs +npm-debug.log* +# macOS +.DS_Store diff --git a/README.md b/README.md @@ -1,7 +0,0 @@ -# Website - -[![Netlify Status](https://api.netlify.com/api/v1/badges/ef24cb24-3253-4c70-a0bf-3f1b5f326a8a/deploy-status)](https://app.netlify.com/sites/michaelneuper/deploys) - -Personal site built with the [hugo](https://gohugo.io) framework and deployed with [netlify](https://netlify.com) - -View at https://michaelneuper.com/ -\ No newline at end of file diff --git a/archetypes/default.md b/archetypes/default.md @@ -1,12 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }}" -date: {{ .Date }} -description: Generic description -categories: [] -tags: [] -toc: true -math: false -draft: false ---- -Generic summary -<!--more--> -\ No newline at end of file diff --git a/archetypes/default.org b/archetypes/default.org @@ -1,5 +0,0 @@ -#+title: {{ replace .Name "-" " " | title }} -#+date: {{ .Date }} -#+categories[]: -#+tags[]: -#+draft: false diff --git a/astro.config.mjs b/astro.config.mjs @@ -0,0 +1,10 @@ +// @ts-check +import { defineConfig } from "astro/config"; + +export default defineConfig({ + // The default ("jsx") drops line breaks between text and inline elements, which + // glues words to links. true only removes whitespace that doesn't render. + compressHTML: true, + // The toolbar would sit on top of the modeline and echo area. + devToolbar: { enabled: false }, +}); diff --git a/categories.txt b/categories.txt @@ -1,19 +0,0 @@ -Articles: These are informative and thought-provoking pieces that cover a specific topic in-depth. - -Tutorials: Step-by-step instructions or advice on how to do something, often featuring tips and best practices. - -Guides: Detailed, hands-on instructions for completing a task or learning a new skill, often accompanied by images or videos. - -Editorials: Personal perspectives on current events, issues, or trends, often featuring strong arguments and viewpoints. - -Reviews: Critical assessments of products, services, books, movies, or events, providing opinions and recommendations. - -Interviews: Conversations with experts, thought leaders, or other interesting personalities, offering unique insights and perspectives. - -Case Studies: In-depth analyses of specific examples or stories, highlighting lessons learned and practical implications. - -Listicles: Fun and easy-to-read posts that feature a list format, such as "Top 10" or "Best of" compilations. - -Anecdotes: Sharing personal experiences or stories that relate to the blog's theme, offering unique insights or lessons learned. - -Resources: Collections of helpful resources, tools, or links for your readers to explore and use. diff --git a/config/_default/hugo.toml b/config/_default/hugo.toml @@ -1,72 +0,0 @@ -baseURL = "https://michaelneuper.com" -enableEmoji = true -enableGitInfo = false -enableRobotsTXT = true -hasCJKLanguage = false -locale = "en" -rssLimit = 10 -title = "Michael" - -[params] -author = "Michael Neuper" - -[taxonomies] -tags = "tags" -categories = "categories" - -[module] - [[module.imports]] - path = "github.com/michaelneuper/hugo-texify3" - disable = false - - -[menu] - [[menu.main]] - identifier = "posts" - name = "Blog" - url = "/posts/" - pre = """ - <?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> - <svg width="1em" height="1em" viewBox="-2 -2 24 24" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin" class="jam jam-write"><path d='M5.72 14.456l1.761-.508 10.603-10.73a.456.456 0 0 0-.003-.64l-.635-.642a.443.443 0 0 0-.632-.003L6.239 12.635l-.52 1.82zM18.703.664l.635.643c.876.887.884 2.318.016 3.196L8.428 15.561l-3.764 1.084a.901.901 0 0 1-1.11-.623.915.915 0 0 1-.002-.506l1.095-3.84L15.544.647a2.215 2.215 0 0 1 3.159.016zM7.184 1.817c.496 0 .898.407.898.909a.903.903 0 0 1-.898.909H3.592c-.992 0-1.796.814-1.796 1.817v10.906c0 1.004.804 1.818 1.796 1.818h10.776c.992 0 1.797-.814 1.797-1.818v-3.635c0-.502.402-.909.898-.909s.898.407.898.91v3.634c0 2.008-1.609 3.636-3.593 3.636H3.592C1.608 19.994 0 18.366 0 16.358V5.452c0-2.007 1.608-3.635 3.592-3.635h3.592z'/></svg> - """ - weight = 1 - - # [[menu.main]] - # identifier = "rss" - # name = "RSS" - # url = "/index.xml" - # pre = """ - # <svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> - # <path d="M2.88,16.88a3,3,0,0,0,0,4.24,3,3,0,0,0,4.24,0,3,3,0,0,0-4.24-4.24Zm2.83,2.83a1,1,0,0,1-1.42-1.42,1,1,0,0,1,1.42,0A1,1,0,0,1,5.71,19.71ZM5,12a1,1,0,0,0,0,2,5,5,0,0,1,5,5,1,1,0,0,0,2,0,7,7,0,0,0-7-7ZM5,8a1,1,0,0,0,0,2,9,9,0,0,1,9,9,1,1,0,0,0,2,0,11.08,11.08,0,0,0-3.22-7.78A11.08,11.08,0,0,0,5,8Zm10.61.39A15.11,15.11,0,0,0,5,4,1,1,0,0,0,5,6,13,13,0,0,1,18,19a1,1,0,0,0,2,0A15.11,15.11,0,0,0,15.61,8.39Z"/></svg> - # """ - # weight = 2 - - [[menu.main]] - identifier = "github" - name = "GitHub" - url = "https://github.com/michaelneuper" - pre = """ - <svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"> - <path d="M10.07031,20.50291a1.00008,1.00008,0,0,0-1.18115-.9834c-1.30908.24024-2.96191.27637-3.40137-.958a5.70754,5.70754,0,0,0-1.83691-2.415,1.20073,1.20073,0,0,1-.1665-.10938,1,1,0,0,0-.93067-.64551H2.54883a.99965.99965,0,0,0-1,.99512c-.00391.81543.811,1.33789,1.1416,1.51465a4.4408,4.4408,0,0,1,.92383,1.35937c.36426,1.02344,1.42285,2.57617,4.46582,2.376.001.03516.00195.06836.00244.09863l.00439.26758a1,1,0,0,0,2,0l-.00488-.31836C10.07715,21.4951,10.07031,21.22068,10.07031,20.50291Zm10.667-15.126c.03174-.125.063-.26367.09034-.41992a6.27792,6.27792,0,0,0-.40821-3.293,1.002,1.002,0,0,0-.61572-.58007c-.356-.12012-1.67041-.35645-4.18408,1.25a13.86918,13.86918,0,0,0-6.354,0C6.76221.751,5.45459.9658,5.10205,1.07908a.99744.99744,0,0,0-.63135.584,6.3003,6.3003,0,0,0-.40332,3.35644c.02442.12793.05078.2461.07813.35449A6.26928,6.26928,0,0,0,2.89014,9.20311a8.42168,8.42168,0,0,0,.04248.92187c.334,4.60254,3.334,5.98438,5.42431,6.459-.04345.125-.083.25878-.11816.40039a1.00023,1.00023,0,0,0,1.94238.47851,1.6784,1.6784,0,0,1,.46778-.87793.99947.99947,0,0,0-.5459-1.74512c-3.4541-.39453-4.95362-1.80175-5.1792-4.89843a6.61076,6.61076,0,0,1-.03369-.73828,4.25769,4.25769,0,0,1,.91943-2.71289,3.022,3.022,0,0,1,.1958-.23145.99988.99988,0,0,0,.188-1.02441,3.3876,3.3876,0,0,1-.15527-.55567A4.09356,4.09356,0,0,1,6.1167,3.06346a7.54263,7.54263,0,0,1,2.415,1.17968,1.00877,1.00877,0,0,0,.82764.13282,11.77716,11.77716,0,0,1,6.17285.001,1.00549,1.00549,0,0,0,.83056-.13769,7.572,7.572,0,0,1,2.40528-1.19043,4.03977,4.03977,0,0,1,.0874,1.57812,3.205,3.205,0,0,1-.16895.60743.9999.9999,0,0,0,.188,1.02441c.07715.08691.1543.18066.22363.26855A4.12186,4.12186,0,0,1,20,9.20311a7.03888,7.03888,0,0,1-.0376.77734c-.22021,3.05566-1.72558,4.46387-5.1958,4.85937a1,1,0,0,0-.54541,1.7461,1.63079,1.63079,0,0,1,.46631.9082,3.06079,3.06079,0,0,1,.09229.81934v2.334C14.77,21.2949,14.77,21.78025,14.77,22.00291a1,1,0,1,0,2,0c0-.2168,0-.69238.00977-1.33984V18.31346a4.8815,4.8815,0,0,0-.15479-1.31153,4.25638,4.25638,0,0,0-.11621-.416,6.51258,6.51258,0,0,0,5.44531-6.42383A8.69677,8.69677,0,0,0,22,9.20311,6.13062,6.13062,0,0,0,20.7373,5.37693Z"/></svg> - """ - weight = 3 - - [[menu.main]] - identifier = "linkedin" - name = "LinkedIn" - url = "https://linkedin.com/in/michaelneuper" - pre = """ - <svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"> - <path d="M6 2C3.79086 2 2 3.79086 2 6V18C2 20.2091 3.79086 22 6 22H18C20.2091 22 22 20.2091 22 18V6C22 3.79086 20.2091 2 18 2H6ZM4 6C4 4.89543 4.89543 4 6 4H18C19.1046 4 20 4.89543 20 6V18C20 19.1046 19.1046 20 18 20H6C4.89543 20 4 19.1046 4 18V6ZM9 11C9 10.4477 8.55228 10 8 10C7.44772 10 7 10.4477 7 11V17C7 17.5523 7.44772 18 8 18C8.55228 18 9 17.5523 9 17V11ZM9.5 7.5C9.5 8.32843 8.82843 9 8 9C7.17157 9 6.5 8.32843 6.5 7.5C6.5 6.67157 7.17157 6 8 6C8.82843 6 9.5 6.67157 9.5 7.5ZM12 10C12.3395 10 12.6395 10.1692 12.8203 10.4279C13.3329 10.1502 13.9036 10 14.5 10C16.6594 10 18 11.9258 18 13.5714V13.579V13.5865V13.5941V13.6017V13.6093V13.617V13.6246V13.6323V13.64V13.6477V13.6555V13.6632V13.671V13.6788V13.6866V13.6944V13.7022V13.7101V13.718V13.7258V13.7338V13.7417V13.7496V13.7576V13.7655V13.7735V13.7815V13.7896V13.7976V13.8057V13.8137V13.8218V13.8299V13.838V13.8462V13.8543V13.8625V13.8706V13.8788V13.887V13.8953V13.9035V13.9117V13.92V13.9283V13.9365V13.9448V13.9532V13.9615V13.9698V13.9782V13.9866V13.9949V14.0033V14.0117V14.0201V14.0286V14.037V14.0455V14.0539V14.0624V14.0709V14.0794V14.0879V14.0964V14.1049V14.1135V14.122V14.1306V14.1392V14.1478V14.1563V14.165V14.1736V14.1822V14.1908V14.1995V14.2081V14.2168V14.2254V14.2341V14.2428V14.2515V14.2602V14.2689V14.2776V14.2864V14.2951V14.3039V14.3126V14.3214V14.3301V14.3389V14.3477V14.3565V14.3653V14.3741V14.3829V14.3917V14.4005V14.4093V14.4182V14.427V14.4359V14.4447V14.4536V14.4624V14.4713V14.4802V14.4891V14.4979V14.5068V14.5157V14.5246V14.5335V14.5424V14.5513V14.5602V14.5692V14.5781V14.587V14.5959V14.6049V14.6138V14.6227V14.6317V14.6406V14.6496V14.6585V14.6674V14.6764V14.6854V14.6943V14.7033V14.7122V14.7212V14.7302V14.7391V14.7481V14.757V14.766V14.775V14.7839V14.7929V14.8019V14.8108V14.8198V14.8288V14.8378V14.8467V14.8557V14.8647V14.8736V14.8826V14.8916V14.9005V14.9095V14.9184V14.9274V14.9363V14.9453V14.9543V14.9632V14.9722V14.9811V14.99V14.999V15.0079V15.0169V15.0258V15.0347V15.0436V15.0526V15.0615V15.0704V15.0793V15.0882V15.0971V15.106V15.1149V15.1238V15.1327V15.1416V15.1504V15.1593V15.1682V15.177V15.1859V15.1947V15.2036V15.2124V15.2213V15.2301V15.2389V15.2477V15.2565V15.2653V15.2741V15.2829V15.2917V15.3005V15.3092V15.318V15.3267V15.3355V15.3442V15.3529V15.3616V15.3703V15.379V15.3877V15.3964V15.4051V15.4138V15.4224V15.4311V15.4397V15.4483V15.457V15.4656V15.4742V15.4827V15.4913V15.4999V15.5085V15.517V15.5255V15.5341V15.5426V15.5511V15.5596V15.5681V15.5765V15.585V15.5934V15.6019V15.6103V15.6187V15.6271V15.6355V15.6439V15.6522V15.6606V15.6689V15.6772V15.6855V15.6938V15.7021V15.7104V15.7186V15.7269V15.7351V15.7433V15.7515V15.7597V15.7679V15.776V15.7842V15.7923V15.8004V15.8085V15.8166V15.8246V15.8327V15.8407V15.8487V15.8567V15.8647V15.8727V15.8806V15.8885V15.8965V15.9044V15.9122V15.9201V15.928V15.9358V15.9436V15.9514V15.9592V15.9669V15.9747V15.9824V15.9901V15.9978V16.0055V16.0131V16.0208V16.0284V16.036V16.0435V16.0511V16.0586V16.0661V16.0736V16.0811V16.0886V16.096V16.1034V16.1108V16.1182V16.1255V16.1329V16.1402V16.1475V16.1547V16.162V16.1692V16.1764V16.1836V16.1908V16.1979V16.205V16.2121V16.2192V16.2262V16.2332V16.2402V16.2472V16.2542V16.2611V16.268V16.2749V16.2818V16.2886V16.2954V16.3022V16.309V16.3157V16.3224V16.3291V16.3358V16.3425V16.3491V16.3557V16.3622V16.3688V16.3753V16.3818V16.3882V16.3947V16.4011V16.4075V16.4138V16.4202V16.4265V16.4328V16.439V16.4452V16.4514V16.4576V16.4638V16.4699V16.476V16.482V16.4881V16.4941V16.5V16.506V16.5119V16.5178V16.5237V16.5295V16.5353V16.5411V16.5468V16.5525V16.5582V16.5639V16.5695V16.5751V16.5807V16.5862V16.5917V16.5972V16.6026V16.6081V16.6134V16.6188V16.6241V16.6294V16.6347V16.6399V16.6451V16.6503V16.6554V16.6605V16.6656V16.6706V16.6756V16.6806V16.6855V16.6904V16.6953V16.7001V16.7049V16.7097V16.7144V16.7191V16.7238V16.7284V16.733V16.7376V16.7421V16.7466V16.7511V16.7555V16.7599V16.7643V16.7686V16.7729V16.7771V16.7813V16.7855V16.7897V16.7938V16.7978V16.8019V16.8059V16.8098V16.8138V16.8177V16.8215V16.8253V16.8291V16.8328V16.8365V16.8402V16.8438V16.8474V16.851V16.8545V16.858V16.8614V16.8648V16.8682V16.8715V16.8748V16.878V16.8812V16.8844V16.8875V16.8906V16.8936V16.8966V16.8996V16.9025V16.9054V16.9083V16.9111V16.9138V16.9165V16.9192V16.9219V16.9245V16.927V16.9295V16.932V16.9344V16.9368V16.9392V16.9415V16.9438V16.946V16.9481V16.9503V16.9524V16.9544V16.9564V16.9584V16.9603V16.9622V16.964V16.9658V16.9676V16.9693V16.9709V16.9725V16.9741V16.9756V16.9771V16.9785V16.9799V16.9813V16.9826V16.9838V16.985V16.9862V16.9873V16.9884V16.9894V16.9904V16.9913V16.9922V16.993V16.9938V16.9946V16.9953V16.9959V16.9965V16.9971V16.9976V16.998V16.9984V16.9988V16.9991V16.9994V16.9996V16.9998V16.9999V17C18 17 18 17 18 17C18 17.5523 17.5523 18 17 18C16.4477 18 16 17.5523 16 17C16 17 16 17 16 17V16.9999V16.9998V16.9996V16.9994V16.9991V16.9988V16.9984V16.998V16.9976V16.9971V16.9965V16.9959V16.9953V16.9946V16.9938V16.993V16.9922V16.9913V16.9904V16.9894V16.9884V16.9873V16.9862V16.985V16.9838V16.9826V16.9813V16.9799V16.9785V16.9771V16.9756V16.9741V16.9725V16.9709V16.9693V16.9676V16.9658V16.964V16.9622V16.9603V16.9584V16.9564V16.9544V16.9524V16.9503V16.9481V16.946V16.9438V16.9415V16.9392V16.9368V16.9344V16.932V16.9295V16.927V16.9245V16.9219V16.9192V16.9165V16.9138V16.9111V16.9083V16.9054V16.9025V16.8996V16.8966V16.8936V16.8906V16.8875V16.8844V16.8812V16.878V16.8748V16.8715V16.8682V16.8648V16.8614V16.858V16.8545V16.851V16.8474V16.8438V16.8402V16.8365V16.8328V16.8291V16.8253V16.8215V16.8177V16.8138V16.8098V16.8059V16.8019V16.7978V16.7938V16.7897V16.7855V16.7813V16.7771V16.7729V16.7686V16.7643V16.7599V16.7555V16.7511V16.7466V16.7421V16.7376V16.733V16.7284V16.7238V16.7191V16.7144V16.7097V16.7049V16.7001V16.6953V16.6904V16.6855V16.6806V16.6756V16.6706V16.6656V16.6605V16.6554V16.6503V16.6451V16.6399V16.6347V16.6294V16.6241V16.6188V16.6134V16.6081V16.6026V16.5972V16.5917V16.5862V16.5807V16.5751V16.5695V16.5639V16.5582V16.5525V16.5468V16.5411V16.5353V16.5295V16.5237V16.5178V16.5119V16.506V16.5V16.4941V16.4881V16.482V16.476V16.4699V16.4638V16.4576V16.4514V16.4452V16.439V16.4328V16.4265V16.4202V16.4138V16.4075V16.4011V16.3947V16.3882V16.3818V16.3753V16.3688V16.3622V16.3557V16.3491V16.3425V16.3358V16.3291V16.3224V16.3157V16.309V16.3022V16.2954V16.2886V16.2818V16.2749V16.268V16.2611V16.2542V16.2472V16.2402V16.2332V16.2262V16.2192V16.2121V16.205V16.1979V16.1908V16.1836V16.1764V16.1692V16.162V16.1547V16.1475V16.1402V16.1329V16.1255V16.1182V16.1108V16.1034V16.096V16.0886V16.0811V16.0736V16.0661V16.0586V16.0511V16.0435V16.036V16.0284V16.0208V16.0131V16.0055V15.9978V15.9901V15.9824V15.9747V15.9669V15.9592V15.9514V15.9436V15.9358V15.928V15.9201V15.9122V15.9044V15.8965V15.8885V15.8806V15.8727V15.8647V15.8567V15.8487V15.8407V15.8327V15.8246V15.8166V15.8085V15.8004V15.7923V15.7842V15.776V15.7679V15.7597V15.7515V15.7433V15.7351V15.7269V15.7186V15.7104V15.7021V15.6938V15.6855V15.6772V15.6689V15.6606V15.6522V15.6439V15.6355V15.6271V15.6187V15.6103V15.6019V15.5934V15.585V15.5765V15.5681V15.5596V15.5511V15.5426V15.5341V15.5255V15.517V15.5085V15.4999V15.4913V15.4827V15.4742V15.4656V15.457V15.4483V15.4397V15.4311V15.4224V15.4138V15.4051V15.3964V15.3877V15.379V15.3703V15.3616V15.3529V15.3442V15.3355V15.3267V15.318V15.3092V15.3005V15.2917V15.2829V15.2741V15.2653V15.2565V15.2477V15.2389V15.2301V15.2213V15.2124V15.2036V15.1947V15.1859V15.177V15.1682V15.1593V15.1504V15.1416V15.1327V15.1238V15.1149V15.106V15.0971V15.0882V15.0793V15.0704V15.0615V15.0526V15.0436V15.0347V15.0258V15.0169V15.0079V14.999V14.99V14.9811V14.9722V14.9632V14.9543V14.9453V14.9363V14.9274V14.9184V14.9095V14.9005V14.8916V14.8826V14.8736V14.8647V14.8557V14.8467V14.8378V14.8288V14.8198V14.8108V14.8019V14.7929V14.7839V14.775V14.766V14.757V14.7481V14.7391V14.7302V14.7212V14.7122V14.7033V14.6943V14.6854V14.6764V14.6674V14.6585V14.6496V14.6406V14.6317V14.6227V14.6138V14.6049V14.5959V14.587V14.5781V14.5692V14.5602V14.5513V14.5424V14.5335V14.5246V14.5157V14.5068V14.4979V14.4891V14.4802V14.4713V14.4624V14.4536V14.4447V14.4359V14.427V14.4182V14.4093V14.4005V14.3917V14.3829V14.3741V14.3653V14.3565V14.3477V14.3389V14.3301V14.3214V14.3126V14.3039V14.2951V14.2864V14.2776V14.2689V14.2602V14.2515V14.2428V14.2341V14.2254V14.2168V14.2081V14.1995V14.1908V14.1822V14.1736V14.165V14.1563V14.1478V14.1392V14.1306V14.122V14.1135V14.1049V14.0964V14.0879V14.0794V14.0709V14.0624V14.0539V14.0455V14.037V14.0286V14.0201V14.0117V14.0033V13.9949V13.9866V13.9782V13.9698V13.9615V13.9532V13.9448V13.9365V13.9283V13.92V13.9117V13.9035V13.8953V13.887V13.8788V13.8706V13.8625V13.8543V13.8462V13.838V13.8299V13.8218V13.8137V13.8057V13.7976V13.7896V13.7815V13.7735V13.7655V13.7576V13.7496V13.7417V13.7338V13.7258V13.718V13.7101V13.7022V13.6944V13.6866V13.6788V13.671V13.6632V13.6555V13.6477V13.64V13.6323V13.6246V13.617V13.6093V13.6017V13.5941V13.5865V13.579V13.5714C16 12.8032 15.3406 12 14.5 12C13.9759 12 13.3974 12.2849 13 12.9631V12.9658V12.9761V12.9864V12.9967V13.0071V13.0174V13.0278V13.0382V13.0487V13.0591V13.0695V13.08V13.0905V13.101V13.1115V13.122V13.1326V13.1432V13.1537V13.1643V13.1749V13.1855V13.1962V13.2068V13.2175V13.2282V13.2388V13.2496V13.2603V13.271V13.2817V13.2925V13.3033V13.314V13.3248V13.3356V13.3464V13.3573V13.3681V13.379V13.3898V13.4007V13.4116V13.4225V13.4334V13.4443V13.4552V13.4662V13.4771V13.4881V13.499V13.51V13.521V13.532V13.543V13.554V13.565V13.5761V13.5871V13.5981V13.6092V13.6203V13.6313V13.6424V13.6535V13.6646V13.6757V13.6868V13.6979V13.709V13.7202V13.7313V13.7424V13.7536V13.7647V13.7759V13.7871V13.7982V13.8094V13.8206V13.8318V13.8429V13.8541V13.8653V13.8765V13.8878V13.899V13.9102V13.9214V13.9326V13.9438V13.9551V13.9663V13.9775V13.9888V14V14.0113V14.0225V14.0338V14.045V14.0562V14.0675V14.0788V14.09V14.1013V14.1125V14.1238V14.135V14.1463V14.1576V14.1688V14.1801V14.1913V14.2026V14.2139V14.2251V14.2364V14.2476V14.2589V14.2701V14.2814V14.2926V14.3039V14.3151V14.3264V14.3376V14.3489V14.3601V14.3714V14.3826V14.3938V14.405V14.4163V14.4275V14.4387V14.4499V14.4611V14.4723V14.4835V14.4947V14.5059V14.5171V14.5283V14.5395V14.5506V14.5618V14.573V14.5841V14.5953V14.6064V14.6176V14.6287V14.6398V14.6509V14.662V14.6732V14.6843V14.6953V14.7064V14.7175V14.7286V14.7396V14.7507V14.7617V14.7728V14.7838V14.7948V14.8058V14.8168V14.8278V14.8388V14.8498V14.8607V14.8717V14.8826V14.8936V14.9045V14.9154V14.9263V14.9372V14.9481V14.9589V14.9698V14.9806V14.9915V15.0023V15.0131V15.0239V15.0347V15.0455V15.0562V15.067V15.0777V15.0884V15.0991V15.1098V15.1205V15.1312V15.1419V15.1525V15.1631V15.1737V15.1843V15.1949V15.2055V15.2161V15.2266V15.2371V15.2476V15.2581V15.2686V15.2791V15.2895V15.2999V15.3104V15.3208V15.3311V15.3415V15.3519V15.3622V15.3725V15.3828V15.3931V15.4033V15.4136V15.4238V15.434V15.4442V15.4544V15.4645V15.4747V15.4848V15.4949V15.5049V15.515V15.525V15.535V15.545V15.555V15.565V15.5749V15.5848V15.5947V15.6046V15.6144V15.6243V15.6341V15.6439V15.6536V15.6634V15.6731V15.6828V15.6925V15.7021V15.7118V15.7214V15.731V15.7405V15.7501V15.7596V15.7691V15.7786V15.788V15.7974V15.8068V15.8162V15.8256V15.8349V15.8442V15.8534V15.8627V15.8719V15.8811V15.8903V15.8994V15.9086V15.9177V15.9267V15.9358V15.9448V15.9538V15.9627V15.9717V15.9806V15.9895V15.9983V16.0071V16.0159V16.0247V16.0334V16.0421V16.0508V16.0595V16.0681V16.0767V16.0853V16.0938V16.1023V16.1108V16.1193V16.1277V16.1361V16.1444V16.1527V16.161V16.1693V16.1776V16.1858V16.1939V16.2021V16.2102V16.2183V16.2263V16.2343V16.2423V16.2503V16.2582V16.2661V16.2739V16.2817V16.2895V16.2973V16.305V16.3127V16.3203V16.328V16.3356V16.3431V16.3506V16.3581V16.3656V16.373V16.3803V16.3877V16.395V16.4023V16.4095V16.4167V16.4239V16.431V16.4381V16.4451V16.4522V16.4591V16.4661V16.473V16.4799V16.4867V16.4935V16.5002V16.507V16.5137V16.5203V16.5269V16.5335V16.54V16.5465V16.5529V16.5593V16.5657V16.5721V16.5783V16.5846V16.5908V16.597V16.6031V16.6092V16.6153V16.6213V16.6272V16.6332V16.6391V16.6449V16.6507V16.6565V16.6622V16.6679V16.6735V16.6791V16.6847V16.6902V16.6956V16.7011V16.7064V16.7118V16.7171V16.7223V16.7275V16.7327V16.7378V16.7429V16.7479V16.7529V16.7578V16.7627V16.7676V16.7724V16.7772V16.7819V16.7865V16.7912V16.7957V16.8003V16.8048V16.8092V16.8136V16.8179V16.8222V16.8265V16.8307V16.8348V16.839V16.843V16.847V16.851V16.8549V16.8588V16.8626V16.8664V16.8701V16.8738V16.8774V16.881V16.8845V16.888V16.8914V16.8948V16.8981V16.9014V16.9046V16.9078V16.9109V16.914V16.917V16.92V16.9229V16.9258V16.9286V16.9313V16.9341V16.9367V16.9393V16.9419V16.9444V16.9468V16.9492V16.9516V16.9539V16.9561V16.9583V16.9604V16.9625V16.9645V16.9665V16.9684V16.9703V16.9721V16.9738V16.9755V16.9771V16.9787V16.9803V16.9817V16.9831V16.9845V16.9858V16.9871V16.9883V16.9894V16.9905V16.9915V16.9925V16.9934V16.9942V16.995V16.9957V16.9964V16.997V16.9976V16.9981V16.9985V16.9989V16.9993V16.9995V16.9997V16.9999V17V17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V17V16.9999V16.9997V16.9995V16.9993V16.9989V16.9985V16.9981V16.9976V16.997V16.9964V16.9957V16.995V16.9942V16.9934V16.9925V16.9915V16.9905V16.9894V16.9883V16.9871V16.9858V16.9845V16.9831V16.9817V16.9803V16.9787V16.9771V16.9755V16.9738V16.9721V16.9703V16.9684V16.9665V16.9645V16.9625V16.9604V16.9583V16.9561V16.9539V16.9516V16.9492V16.9468V16.9444V16.9419V16.9393V16.9367V16.9341V16.9313V16.9286V16.9258V16.9229V16.92V16.917V16.914V16.9109V16.9078V16.9046V16.9014V16.8981V16.8948V16.8914V16.888V16.8845V16.881V16.8774V16.8738V16.8701V16.8664V16.8626V16.8588V16.8549V16.851V16.847V16.843V16.839V16.8348V16.8307V16.8265V16.8222V16.8179V16.8136V16.8092V16.8048V16.8003V16.7957V16.7912V16.7865V16.7819V16.7772V16.7724V16.7676V16.7627V16.7578V16.7529V16.7479V16.7429V16.7378V16.7327V16.7275V16.7223V16.7171V16.7118V16.7064V16.7011V16.6956V16.6902V16.6847V16.6791V16.6735V16.6679V16.6622V16.6565V16.6507V16.6449V16.6391V16.6332V16.6272V16.6213V16.6153V16.6092V16.6031V16.597V16.5908V16.5846V16.5783V16.5721V16.5657V16.5593V16.5529V16.5465V16.54V16.5335V16.5269V16.5203V16.5137V16.507V16.5002V16.4935V16.4867V16.4799V16.473V16.4661V16.4591V16.4522V16.4451V16.4381V16.431V16.4239V16.4167V16.4095V16.4023V16.395V16.3877V16.3803V16.373V16.3656V16.3581V16.3506V16.3431V16.3356V16.328V16.3203V16.3127V16.305V16.2973V16.2895V16.2817V16.2739V16.2661V16.2582V16.2503V16.2423V16.2343V16.2263V16.2183V16.2102V16.2021V16.1939V16.1858V16.1776V16.1693V16.161V16.1527V16.1444V16.1361V16.1277V16.1193V16.1108V16.1023V16.0938V16.0853V16.0767V16.0681V16.0595V16.0508V16.0421V16.0334V16.0247V16.0159V16.0071V15.9983V15.9895V15.9806V15.9717V15.9627V15.9538V15.9448V15.9358V15.9267V15.9177V15.9086V15.8994V15.8903V15.8811V15.8719V15.8627V15.8534V15.8442V15.8349V15.8256V15.8162V15.8068V15.7974V15.788V15.7786V15.7691V15.7596V15.7501V15.7405V15.731V15.7214V15.7118V15.7021V15.6925V15.6828V15.6731V15.6634V15.6536V15.6439V15.6341V15.6243V15.6144V15.6046V15.5947V15.5848V15.5749V15.565V15.555V15.545V15.535V15.525V15.515V15.5049V15.4949V15.4848V15.4747V15.4645V15.4544V15.4442V15.434V15.4238V15.4136V15.4033V15.3931V15.3828V15.3725V15.3622V15.3519V15.3415V15.3311V15.3208V15.3104V15.2999V15.2895V15.2791V15.2686V15.2581V15.2476V15.2371V15.2266V15.2161V15.2055V15.1949V15.1843V15.1737V15.1631V15.1525V15.1419V15.1312V15.1205V15.1098V15.0991V15.0884V15.0777V15.067V15.0562V15.0455V15.0347V15.0239V15.0131V15.0023V14.9915V14.9806V14.9698V14.9589V14.9481V14.9372V14.9263V14.9154V14.9045V14.8936V14.8826V14.8717V14.8607V14.8498V14.8388V14.8278V14.8168V14.8058V14.7948V14.7838V14.7728V14.7617V14.7507V14.7396V14.7286V14.7175V14.7064V14.6953V14.6843V14.6732V14.662V14.6509V14.6398V14.6287V14.6176V14.6064V14.5953V14.5841V14.573V14.5618V14.5506V14.5395V14.5283V14.5171V14.5059V14.4947V14.4835V14.4723V14.4611V14.4499V14.4387V14.4275V14.4163V14.405V14.3938V14.3826V14.3714V14.3601V14.3489V14.3376V14.3264V14.3151V14.3039V14.2926V14.2814V14.2701V14.2589V14.2476V14.2364V14.2251V14.2139V14.2026V14.1913V14.1801V14.1688V14.1576V14.1463V14.135V14.1238V14.1125V14.1013V14.09V14.0788V14.0675V14.0562V14.045V14.0338V14.0225V14.0113V14V13.9888V13.9775V13.9663V13.9551V13.9438V13.9326V13.9214V13.9102V13.899V13.8878V13.8765V13.8653V13.8541V13.8429V13.8318V13.8206V13.8094V13.7982V13.7871V13.7759V13.7647V13.7536V13.7424V13.7313V13.7202V13.709V13.6979V13.6868V13.6757V13.6646V13.6535V13.6424V13.6313V13.6203V13.6092V13.5981V13.5871V13.5761V13.565V13.554V13.543V13.532V13.521V13.51V13.499V13.4881V13.4771V13.4662V13.4552V13.4443V13.4334V13.4225V13.4116V13.4007V13.3898V13.379V13.3681V13.3573V13.3464V13.3356V13.3248V13.314V13.3033V13.2925V13.2817V13.271V13.2603V13.2496V13.2388V13.2282V13.2175V13.2068V13.1962V13.1855V13.1749V13.1643V13.1537V13.1432V13.1326V13.122V13.1115V13.101V13.0905V13.08V13.0695V13.0591V13.0487V13.0382V13.0278V13.0174V13.0071V12.9967V12.9864V12.9761V12.9658V12.9555V12.9452V12.9349V12.9247V12.9145V12.9043V12.8941V12.884V12.8738V12.8637V12.8536V12.8435V12.8335V12.8234V12.8134V12.8034V12.7934V12.7834V12.7735V12.7636V12.7537V12.7438V12.7339V12.7241V12.7143V12.7104V12.7064V12.7025V12.6985V12.6946V12.6906V12.6866V12.6826V12.6786V12.6746V12.6706V12.6666V12.6626V12.6586V12.6545V12.6505V12.6464V12.6423V12.6383V12.6342V12.6301V12.626V12.6219V12.6178V12.6137V12.6096V12.6055V12.6013V12.5972V12.593V12.5889V12.5847V12.5805V12.5764V12.5722V12.568V12.5638V12.5596V12.5554V12.5512V12.547V12.5427V12.5385V12.5343V12.53V12.5258V12.5215V12.5173V12.513V12.5087V12.5045V12.5002V12.4959V12.4916V12.4873V12.483V12.4787V12.4744V12.4701V12.4657V12.4614V12.4571V12.4528V12.4484V12.4441V12.4397V12.4354V12.431V12.4266V12.4223V12.4179V12.4135V12.4092V12.4048V12.4004V12.396V12.3916V12.3872V12.3828V12.3784V12.374V12.3696V12.3652V12.3607V12.3563V12.3519V12.3475V12.343V12.3386V12.3342V12.3297V12.3253V12.3208V12.3164V12.3119V12.3075V12.303V12.2986V12.2941V12.2896V12.2852V12.2807V12.2762V12.2718V12.2673V12.2628V12.2583V12.2539V12.2494V12.2449V12.2404V12.2359V12.2314V12.227V12.2225V12.218V12.2135V12.209V12.2045V12.2V12.1955V12.191V12.1865V12.182V12.1775V12.173V12.1685V12.164V12.1595V12.155V12.1505V12.146V12.1415V12.137V12.1325V12.128V12.1235V12.119V12.1145V12.11V12.1055V12.1009V12.0964V12.0919V12.0874V12.0829V12.0784V12.0739V12.0694V12.0649V12.0604V12.056V12.0515V12.047V12.0425V12.038V12.0335V12.029V12.0245V12.02V12.0155V12.0111V12.0066V12.0021V11.9976V11.9932V11.9887V11.9842V11.9797V11.9753V11.9708V11.9663V11.9619V11.9574V11.953V11.9485V11.9441V11.9396V11.9352V11.9307V11.9263V11.9219V11.9174V11.913V11.9086V11.9041V11.8997V11.8953V11.8909V11.8865V11.8821V11.8777V11.8733V11.8689V11.8645V11.8601V11.8557V11.8513V11.847V11.8426V11.8382V11.8338V11.8295V11.8251V11.8208V11.8164V11.8121V11.8077V11.8034V11.7991V11.7948V11.7904V11.7861V11.7818V11.7775V11.7732V11.7689V11.7646V11.7603V11.7561V11.7518V11.7475V11.7433V11.739V11.7347V11.7305V11.7263V11.722V11.7178V11.7136V11.7094V11.7052V11.7009V11.6967V11.6926V11.6884V11.6842V11.68V11.6759V11.6717V11.6675V11.6634V11.6593V11.6551V11.651V11.6469V11.6428V11.6387V11.6346V11.6305V11.6264V11.6223V11.6183V11.6142V11.6101V11.6061V11.6021V11.598V11.594V11.59V11.586V11.582V11.578V11.574V11.57V11.5661V11.5621V11.5582V11.5542V11.5503V11.5464V11.5424V11.5385V11.5346V11.5308V11.5269V11.523V11.5191V11.5153V11.5114V11.5076V11.5038V11.5V11.4962V11.4924V11.4886V11.4848V11.481V11.4773V11.4735V11.4698V11.4661V11.4623V11.4586V11.4549V11.4512V11.4476V11.4439V11.4402V11.4366V11.4329V11.4293V11.4257V11.4221V11.4185V11.4149V11.4113V11.4078V11.4042V11.4007V11.3971V11.3936V11.3901V11.3866V11.3831V11.3797V11.3762V11.3728V11.3693V11.3659V11.3625V11.3591V11.3557V11.3523V11.3489V11.3456V11.3422V11.3389V11.3356V11.3323V11.329V11.3257V11.3224V11.3192V11.3159V11.3127V11.3095V11.3063V11.3031V11.2999V11.2967V11.2936V11.2904V11.2873V11.2842V11.2811V11.278V11.2749V11.2719V11.2688V11.2658V11.2628V11.2598V11.2568V11.2538V11.2508V11.2479V11.2449V11.242V11.2391V11.2362V11.2333V11.2305V11.2276V11.2248V11.2219V11.2191V11.2163V11.2136V11.2108V11.2081V11.2053V11.2026V11.1999V11.1972V11.1945V11.1919V11.1892V11.1866V11.184V11.1814V11.1788V11.1763V11.1737V11.1712V11.1687V11.1662V11.1637V11.1612V11.1588V11.1563V11.1539V11.1515V11.1491V11.1467V11.1444V11.142V11.1397V11.1374V11.1351V11.1329V11.1306V11.1284V11.1261V11.1239V11.1217V11.1196V11.1174V11.1153V11.1132V11.1111V11.109V11.1069V11.1049V11.1028V11.1008V11.0988V11.0969V11.0949V11.093V11.091V11.0891V11.0873V11.0854V11.0835V11.0817V11.0799V11.0781V11.0763V11.0746V11.0728V11.0711V11.0694V11.0677V11.0661V11.0644V11.0628V11.0612V11.0596V11.058V11.0565V11.055V11.0535V11.052V11.0505V11.049V11.0476V11.0462V11.0448V11.0434V11.0421V11.0408V11.0394V11.0382V11.0369V11.0356V11.0344V11.0332V11.032V11.0308V11.0297V11.0286V11.0275V11.0264V11.0253V11.0243V11.0232V11.0222V11.0213V11.0203V11.0194V11.0185V11.0176V11.0167V11.0158V11.015V11.0142V11.0134V11.0126V11.0119V11.0112V11.0105V11.0098V11.0091V11.0085V11.0079V11.0073V11.0067V11.0062V11.0057V11.0052V11.0047V11.0042V11.0038V11.0034V11.003V11.0027V11.0023V11.002V11.0017V11.0014V11.0012V11.001V11.0008V11.0006V11.0004V11.0003V11.0002V11.0001V11V11C11 10.4477 11.4477 10 12 10Z"/> - """ - weight = 4 - - [[menu.main]] - identifier = "contact" - name = "Contact" - url = "/pages/contact/" - pre = """ - <svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"> - <path d="M17,21.63H5a3,3,0,0,1-3-3v-8a1,1,0,0,0-2,0v8a5,5,0,0,0,5,5H17a1,1,0,0,0,0-2Zm4-18H7a3,3,0,0,0-3,3v10a3,3,0,0,0,3,3H21a3,3,0,0,0,3-3v-10A3,3,0,0,0,21,3.63Zm-.41,2-5.88,5.88a1,1,0,0,1-1.42,0L7.41,5.63Zm1.41,11a1,1,0,0,1-1,1H7a1,1,0,0,1-1-1V7l5.88,5.88a3,3,0,0,0,4.24,0L22,7Z"/></svg> - """ - weight = 5 diff --git a/config/_default/markup.toml b/config/_default/markup.toml @@ -1,12 +0,0 @@ -defaultMarkdownHandler = "goldmark" - -[goldmark.renderer] -unsafe = true - -[highlight] -noClasses = false - -[tableOfContents] -endLevel = 6 -ordered = false -startLevel = 2 diff --git a/config/_default/params.toml b/config/_default/params.toml @@ -1,65 +0,0 @@ -title = "Michael Neuper" -description = "Michael's Personal Website" -footnote = """ -Made with <a href="https://gohugo.io" target="_blank"> -<img src="/images/icons/hugo.svg" alt="Hugo" width="45px" height="12px"class="hugo-svg"> -</a> and <a href="https://www.gnu.org/software/emacs/" target="_blank"> -<img src="/images/icons/emacs-alt.svg" width="20px" height="20px" alt="Emacs" class="emacs-svg"></a> -""" -keywords = ["michael", "neuper", "linux", "blog", "productivity", "emacs", "doom emacs"] -customCSS = ["css/styles.css"] -dateFormat = "2 January 2006" -emphasisWithDots = true -toc = true -showWordCount = true -showReadingTime = true -rootFontSize = "105%" -math = false -enableDuckDuckGoSearchBox = true -numberedSubtitles = true - -[commentEngine] -code = """ -<script src="https://giscus.app/client.js" - data-repo="michaelneuper/website" - data-repo-id="R_kgDOIjPNaQ" - data-category="General" - data-category-id="DIC_kwDOIjPNac4CaklA" - data-mapping="pathname" - data-strict="0" - data-reactions-enabled="1" - data-emit-metadata="0" - data-input-position="top" - data-theme="gruvbox" - data-lang="en" - data-loading="lazy" - crossorigin="anonymous" - async> -</script> -""" - -[buymeacoffee] -code = """ -<script async data-name="BMC-Widget" - data-cfasync="true" - src="https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js" - data-id="michaelneuper" - data-description="Like what I do? Buy me a coffee!" - data-message="" - data-color="#d79921" - data-position="Right" - data-x_margin="18" - data-y_margin="18" - crossorigin="anonymous"> -</script> -""" - -[sharingbuttons] -facebook = false -twitter = false -email = false -linkedin = false -reddit = false -whatsapp = false -hackernews = false -telegram = false diff --git a/config/production/hugo.toml b/config/production/hugo.toml @@ -1,3 +0,0 @@ -[services] - [services.googleAnalytics] - googleAnalytics = "G-BLX24KP7CS" diff --git a/content/_index.md b/content/_index.md @@ -1,24 +0,0 @@ ---- -title: "Home" ---- - -## Hi, I'm Michael - -I spend far too much time tweaking [my emacs config](https://github.com/michaelneuper/doom), -tinkering with Linux, writing software, and occasionally disappearing down obscure technical rabbit holes. - -I’m also into linguistics, low-level software, and just about anything open-source. - -<br> - -This site is where I write about whatever happens to have my attention at the time: -projects I’m working on, tools I’m obsessing over, things I’ve learned, and the occasional deep dive into some niche technical topic. - -<!-- --- --> - -<!-- ## Introduction --> - -<!-- - [Programs I use and recommend](/pages/software/) --> -<!-- - [Key bindings I use](/pages/keybindings/) --> -<!-- - [Personal library](/pages/library) --> -<!-- - [Make a donation](/pages/donate/) --> diff --git a/content/pages/contact.md b/content/pages/contact.md @@ -1,42 +0,0 @@ ---- -title: "Contact Me" ---- - -## Comment - -If you wish to comment or ask a question regarding a specific post, you can do so in the comment section of that post. -Please note that a GitHub account is required for this purpose to help prevent spam. - -## Form - -If you would like to make a general comment or give any suggestions, you can submit a form below. -<p> - <form name="contact" class="suggestion" netlify> - <p> - <label>Name <input type="text" name="name" /></label> - </p> - <p> - <label>Email <input type="email" name="email" /></label> - </p> - <p> - <label>Comment <input type="text" name="comment" /></label> - </p> - <p> - <button type="submit">Send</button> - </p> - </form> -</p> - -## Email - -If you wish to contact me for any other reason, you can do so by email. Details are given below: - -- **Email**: <a href="mailto: michael@michaelneuper.com">michael@michaelneuper.com</a> -- **GPG key** for encrypting mail if you know how, download [here](https://michaelneuper.com/michaelneuper.gpg) or run: - ``` - curl -sL https://michaelneuper.com/michaelneuper.gpg | gpg --import - ``` -- **Fingerprint**: - ``` - 4E7B F800 0D86 182D F484 5C37 508B CF84 373C 8930 - ``` diff --git a/content/pages/donate.md b/content/pages/donate.md @@ -1,49 +0,0 @@ ---- -title: "Donate" ---- - -If you like what I do or any of my content has added value to you, you are welcome to make a donation through -[GitHub Sponsors](https://github.com/sponsors/michaelneuper), [buymeacoffee](https://www.buymeacoffee.com/michaelneuper), -or [if you must](https://digiconomist.net/bitcoin-energy-consumption), crypto. -Details are given below: -- <img style="max-height:1.4em;max-width:1.4em;" align="left" src="/images/crypto/xmr-logo.svg"> Monero - ``` yaml - 46wvTaMgm1sX12KghEwkuz7A3XvGdGDrEieiv1REDbU2Uu9rnFwmRBa63b42xd1PZ2PBUFwpm44EGgWaQb6gqHCPQuMz52h - ``` - -<!-- ![Monero address](https://www.bitcoinqrcodemaker.com/api/?style=monero&address=46wvTaMgm1sX12KghEwkuz7A3XvGdGDrEieiv1REDbU2Uu9rnFwmRBa63b42xd1PZ2PBUFwpm44EGgWaQb6gqHCPQuMz52h "Monero address") --> - -<!-- ![Monero Address](/images/crypto/monero.png) --> - -- <img style="max-height:1.4em;max-width:1.4em" align="left" src="/images/crypto/btc-logo.svg"> Bitcoin - ``` yaml - bc1qmj2nxgwtej69y7d4umqst5fv7s7v4604ml5xzr - ``` - -<!-- ![Bitcoin address](https://www.bitcoinqrcodemaker.com/api/?style=bitcoin&amp;address=bc1qmj2nxgwtej69y7d4umqst5fv7s7v4604ml5xzr "Bitcoin address") --> - -<!-- ![Bitcoin Address](/images/crypto/bitcoin.png) --> - -<!-- <table> --> -<!-- <tr> --> -<!-- <th> <h2>Bitcoin</h2> </th> --> -<!-- <th> <h2>Monero</h2> </th> --> -<!-- </tr> --> -<!-- <tr> --> -<!-- <td> --> - -<!-- ![Monero Address](/images/monero.png) --> -<!-- <code style="font-size:xx-small;overflow-wrap:break-word;">bc1qkyvknjap3cjtgfqd5qwc0q2ygry7nep7d4t57y</code> --> - -<!-- </td> --> -<!-- <td> --> - -<!-- ![Bitcoin Address](/images/bitcoin.png) --> - -<!-- ``` yaml --> -<!-- bc1qmj2nxgwtej69y7d4umqst5fv7s7v4604ml5xzr --> -<!-- ``` --> - -<!-- </td> --> -<!-- </tr> --> -<!-- </table> --> diff --git a/content/pages/keybindings.md b/content/pages/keybindings.md @@ -1,131 +0,0 @@ ---- -title: "Key Bindings" ---- - -This is an archive of the various key bindings/shortcuts that I use across different software/hardware, written using Emacs Key Notation.[^1] - -[^1]: [Emacs Key Notation](https://www.emacswiki.org/emacs/EmacsKeyNotation) - -## Keyboard - -### Window Manager - -#### Basic Key Bindings -| **Key Binding** | **Action** | -|-------------------------------|-----------------------| -| <kbd>s-RET</kbd> | spawn terminal | -| <kbd>s-q</kbd> | close window | -| <kbd>s-SPC</kbd> | show run launcher | -| <kbd>s-m</kbd> | toggle monocle layout | -| <kbd>s-{h, j, k, l}</kbd> | cycle through windows | -| <kbd>s-S-{h, j, k, l}</kbd> | move window | -| <kbd>C-M-{h, j, k, l}</kbd> | increase window size | -| <kbd>C-S-M-{h, j, k, l}</kbd> | decrease window size | - -#### Window States -| **Key Binding** | **State** | -|-------------------|-------------------------| -| <kbd>s-t</kbd> | tiled | -| <kbd>s-t</kbd> | pseudo tiled | -| <kbd>s-S-f</kbd> | floating | -| <kbd>s-f</kbd> | fullscreen | - -#### Window Flags -| **Key Binding** | **Flag** | -|------------------|----------| -| <kbd>s-C-m</kbd> | marked | -| <kbd>s-C-x</kbd> | locked | -| <kbd>s-C-y</kbd> | sticky | -| <kbd>s-C-z</kbd> | private | - -#### Basic Utilities -| **Key Binding** | **Action** | -|--------------------|--------------------------------------------| -| <kbd>s-x</kbd> | lock the screen | -| <kbd>s-S-x</kbd> | show powermenu | -| <kbd>PRNTSC</kbd> | screenshot entire screen | -| <kbd>s-PRTSC</kbd> | select portion of the screen to screenshot | - -#### Basic Programs -| **Key Binding** | **Program** | -|------------------|------------------------| -| <kbd>s-w</kbd> | web browser | -| <kbd>s-e</kbd> | terminal file manager | -| <kbd>s-S-e</kbd> | graphical file manager | -| <kbd>s-d</kbd> | doom emacs | -| <kbd>s-c</kbd> | calculator | -| <kbd>s-v</kbd> | vscode | - -### Key Remaps - -I use a program called [keyd](https://github.com/rvaiya/keyd) to remap some of the keys on my keyboard. -Here is my configuration: - -``` shell -[ids] -* - -[main] -# Make shift key oneshot -shift = oneshot(shift) -# Remap capslock to esc when clicked and the nav profile when holded -capslock = overload(nav, esc) -# Remap esc to capslock -esc = capslock -# Remap right shift to control -rightshift = rightcontrol - -[nav:C] -# Remap left control + vim keys to navigation keys -h = left -j = down -k = up -l = right -``` - -## Mouse - -I use the Redragon Perdition 2 MMO mouse. -It has 12 buttons on the side and allows for different profiles. -I have each profile set to a different game/progam and a colour corresponding to that game/program. - -This is what the mouse looks like: - -![Redragon Mouse](/images/redragon_mouse.webp) - -This is my configuration: - -| | **Profiles** | | | -|------------|-------------------------|------------------------------|-----------------------------| -| **Button** | **Profile 1 (Default)** | **Profile 2 (Runescape)** | **Profile 3 (Doom)** | -| **1** | <kbd>M-left</kbd> | <kbd>SPC</kbd> | <kbd>q</kbd> (*weapon*) | -| **2** | <kbd>C</kbd> | <kbd>S</kbd> | <kbd>f</kbd> (*glory kill*) | -| **3** | <kbd>ESC</kbd> | <kbd>ESC</kbd> (*inventory*) | <kbd>TAB</kbd> | -| **4** | <kbd>C-c</kbd> | <kbd>F1</kbd> (*combat*) | <kbd>r</kbd> (*mod*) | -| **5** | <kbd>C-v</kbd> | <kbd>F5</kbd> (*prayer*) | <kbd>g</kbd> (*chainsaw*) | -| **6** | <kbd>C-z</kbd> | <kbd>F6</kbd> (*spells*) | <kbd>t</kbd> (*BFG*) | -| **7** | <kbd>s-e</kbd> | <kbd>F2</kbd> (*skills*) | <kbd>f</kbd> (*pickup*) | -| **8** | <kbd>s-b</kbd> | <kbd>F3</kbd> (*quests*) | <kbd>c</kbd> (*crouch*) | -| **9** | <kbd>M-F4</kbd> | <kbd>F4</kbd> (*equip*) | <kbd>ESC</kbd> | -| **10** | Decrease DPI | | | -| **11** | Increase DPI | | | -| **12** | Change Profile | | | - -## Koreader - -I use a program called [koreader](https://koreader.rocks/) on my jailbroken Kindle Paperwhite (10th Gen). -This has a lot more features than the default reader program on the kindle including: epub support, sending books over the network, and way more. - -These are some of my shortcuts: - -| | **Top Right (_Contents_)** | **Top Left (_Screen_)** | **Bottom Left (_Page_)** | -|----------------|----------------------------|-------------------------|--------------------------| -| **Tap** | Table of Contents | Toggle Frontlight | Go to Previous Location | -| **Double Tap** | Book Map | Toggle Dark Mode | Bookmark Page | -| **Hold** | Page Browser | Refresh Screen | Toggle RTL Page Turning | - -## Wacom Tablet - -![Wacom Tablet](/images/wacom_tablet.webp) - -In progress diff --git a/content/pages/library.md b/content/pages/library.md @@ -1,116 +0,0 @@ ---- -title: "My Personal Library" ---- - -This is a list of the books in my personal library. -I haven't read every book here, nor do I own all the books I've read or like. -I also don't necessarily like all the books I own. - -## Philosophy - -<div class="book-container"> - <img align="right" src="/images/books/critique-of-reason.webp" width="100" height="150"> -</div> - -- Aristotle - _The Art of Rhetoric_ -- Aurelius, Marcus - _Meditations_ -- Benatar, David - _Better Never to Have Been: The Harm of Coming into Existence_ -- Benatar, David - _The Human Predicament: Life Without Illusions_ -- Epicurus - _The Art of Happiness_ -- Hitchens, Christopher - _Letters to a Young Contrarian_ -- Hitchens, Christopher - _Mortality_ - <div class="book-container"> - <img align="right" src="/images/books/republic.webp" width="100" height="150"> - </div> -- Hume, David - _A Treatise of Human Nature_ -- Kant, Immanuel - _Critique of Pure Reason_ -- Mill, John Stuart - _Utilitarianism_ -- Mill, John Stuart - _On Liberty_ -- Nietzsche, Friedrich - _Beyond Good and Evil_ -- Plato - _The Republic_ -- Sidgwick, Henry - _The Methods of Ethics_ -- Singer, Peter - _Animal Liberation_ -- Schopenhauer, Arthur - _Essays and Aphorisms_ -- Tzu, Sun- _The Art of War_ - -## Language - -<div class="book-container"> - <img align="right" src="/images/books/lingua-latina.webp" width="100" height="150"> -</div> - -- Caesar, Julius - _De Bello Civilli (**The Civil War**)_ -- Caesar, Julius - _De Bello Gallico (**The Gallic War**)_ -- Lawall, Gilbert - _Ecce Romani_ -- Oosterhoff, Jenneke A. - _Basic Dutch_ -- Ørberg, Hans - _Lingua Latina per se Illustrata_ -- Wheelock, Frederic M. - _Wheelock's Latin_ - -## General Science - -<div class="book-container"> - <img align="right" src="/images/books/short-history.webp" width="100" height="150"> -</div> - -- Bryson, Bill - _A Short History of Nearly Everything_ -- Darwin, Charles - _The Origin of Species_ -- Hawking, Stephen - _A Brief History of Time_ -- Krauss, Lawrence M. - _A Universe from Nothing: Why There Is Something Rather than Nothing_ -- Tyson, Neil deGrasse - _Astrophysics for People in a Hurry_ - -## Computer Science - -<div class="book-container"> - <img align="right" src="/images/books/how-linux-works.webp" width="100" height="150"> -</div> - -- Ericson, Jon - _Hacking: The Art of Exploitation_ -- Stallman, Richard M. - _Free Software, Free Society_ -- Ward, Brian - _How Linux Works_ -- Zuboff, Shoshana- _The Age of Surveillance Capitalism_ - -## Fiction - -<div class="book-container"> - <img align="right" src="/images/books/1984.webp" width="100" height="150"> -</div> - -- Danielewski, Mark Z. - _House of Leaves_ -- Dick, Philip K. - _Do Androids Dream of Electric Sheep?_ -- Jackson, Shirley - _The Haunting of Hill House_ -- Langan, John - _The Fisherman_ -- Nabokov, Vladimir - _Lolita_ -- Orwell, George - _1984_ - -## Psychology - -- Greene, Robert - _The 48 Laws of Power_ -- Kahneman, Daniel - _Thinking, Fast and Slow_ - -## Other - -- Chernev, Irving - _Logical Chess_ -- LaBerge, Stephen - _Exploring the World of Lucid Dreaming_ -- Ollam, Deviant- _Practical Lock Picking_ -- Seirawan, Yasser - _Winning Chess Tactics_ - -## Suggestions - -If you would like to suggest a book, you can submit the form below. - -<p> - <form name="book" class="suggestion" netlify> - <p> - <label>Name <input type="text" name="name" /></label> - </p> - <p> - <label>Title <input type="text" name="title" /></label> - </p> - <p> - <label>Author <input type="text" name="author" /></label> - </p> - <p> - <button type="submit">Send</button> - </p> - </form> -</p> -\ No newline at end of file diff --git a/content/pages/software.md b/content/pages/software.md @@ -1,77 +0,0 @@ ---- -title: "Programs I Use" ---- - -<img align="right" src="/images/logo.webp"> - -## Basic - -**Operating system:** -I use [arch](https://archlinux.org/), btw. - -**Terminal:** -[Alactritty](https://alacritty.org/) on desktop and [iTerm2](https://iterm2.com/) on mac. -Nowadays I mostly use vterm or eshell in emacs. - -**Shell:** -[fish](https://fishshell.com/) on Linux and zsh on macOS and eshell emacs. - -**Window manager:** -[bspwm](https://github.com/baskerville/bspwm) on Linux and [yabai](https://github.com/koekeishiya/yabai) on macOS. - -**Text editor/IDE:** -[GNU Emacs](https://www.gnu.org/software/emacs/) with the [Doom Emacs](https://github.com/hlissner/doom-emacs) configuration framework. - -## Utilities - -**File manager:** -I do 99% of my file management with dired inside emacs. -For the other 1% I'll use the default file manager. - -**Web browser:** -[Firefox](https://www.mozilla.org/en-US/firefox/new/), obviously. - -**Mail client:** -I started to use [mu4e](https://www.emacswiki.org/emacs/mu4e) in emacs more but otherwise I use [mailspring](https://getmailspring.com/). - -**Video player:** -Used to use vlc, now I use mpv like all the cool kids. - -**Torrent client:** -[qBittorrent](https://www.qbittorrent.org/) on Linux and [Transmission](https://transmissionbt.com/) on macOS. - -## Production - -**Digital Art:** -Been getting into digital art lately and have been loving [krita](https://krita.org/en/). - -**Writing documents:** -I write almost everything [Org Mode](https://orgmode.org/) and I'll export to LaTeX occasionally. -Professional documents I write directly in [LaTeX](https://www.latex-project.org/). - -**Office suite:** -[LibreOffice](https://www.libreoffice.org/). -Don't really use an office suite since I write documents and slideshows in org mode and LaTeX. - -**PDF viewer:** -I used to use [zathura](https://pwmt.org/projects/zathura/) but now I use pdf-tools inside Emacs. - -**Image modification:** -[GIMP](https://www.gimp.org/) - -## Suggestions - -If you would like to suggest a program/software for me to try, you can submit the form below. -<p> - <form name="software" class="suggestion" netlify> - <p> - <label>Name <input type="text" name="name" /></label> - </p> - <p> - <label>Program <input type="text" name="program" /></label> - </p> - <p> - <button type="submit">Send</button> - </p> - </form> -</p> diff --git a/content/posts/best-firefox-extensions.md b/content/posts/best-firefox-extensions.md @@ -1,174 +0,0 @@ ---- -title: "Best Firefox Extensions" -date: 2023-04-08T08:18:16+02:00 -categories: ['Listicles'] -tags: ['Productivity', 'Privacy'] -draft: true ---- - -Welcome to my comprehensive guide on the best Firefox extensions to supercharge your browsing experience! -As one of the most popular web browsers, Firefox offers a remarkable level of flexibility and customization through its vast extension ecosystem. -These extensions are like small add-ons that can enhance various aspects of your browsing, ranging from productivity and privacy to aesthetics and tailored experiences on platforms like YouTube and Reddit. - -## Productivity - -### [Tree Style Tab](https://addons.mozilla.org/en-US/firefox/addon/tree-style-tab/) -This extension provides the ability to work with tabs as "trees". - -New tabs opened from the current tab are automatically organized as "children" of the current tab. -Such "branches" are easily folded (collapsed) by clicking on the arrow shown in the "parent" tab, so you no longer need to suffer from too many visible tabs. -If you want, you can restructure the tree via drag and drop. - -![Tree style tab](https://addons.mozilla.org/user-media/previews/thumbs/275/275014.jpg?modified=1668096516) - -### [Simple Tab Groups](https://addons.mozilla.org/en-US/firefox/addon/simple-tab-groups/) -Simple Tab Groups works across browser instances/windows too. -If you select a group in another window, the selected window will jump to the foreground with the chosen group selected. You can even select the specific tab within that group in background browser windows. - -![GIF example](https://user-images.githubusercontent.com/7843031/33828871-806ccf6e-de76-11e7-9a0e-1ddfb97e878d.gif) - -### [Firefox Multi-Account Containers](https://addons.mozilla.org/en-US/firefox/addon/multi-account-containers/) -The Firefox Multi-Account Containers extension lets you carve out a separate box for each of your online lives – no more opening a different browser just to check your work email! - -![Multi-Account Containers](https://addons.mozilla.org/user-media/previews/thumbs/266/266159.jpg?modified=1643906676) - -### [DownThemAll!](https://addons.mozilla.org/en-US/firefox/addon/downthemall/) -DownThemAll will help you select, queue, sort and run your downloads faster. -It comes with advanced ways to select what links to download, and will remember your previous decisions so that you can queue more downloads with just One Click! - -Advanced users will also like using renaming masks, which let you automatically assign names (and even sub-folders within your downloads folder), fast-filtering or even custom, re-usable filters. - -![DownThemAll](https://addons.mozilla.org/user-media/previews/thumbs/224/224229.jpg?modified=1622132179) - -### [SingleFile](https://addons.mozilla.org/en-US/firefox/addon/single-file/) -SingleFile is an add-on for Firefox Desktop and Mobile that helps you to *save an entire webpage** including images, styling, frames, fonts etc. *as a single HTML file**. - -![SingleFile](https://addons.mozilla.org/user-media/previews/thumbs/235/235535.jpg?modified=1622133480) - -### [To Google Translate](https://addons.mozilla.org/en-US/firefox/addon/to-google-translate/) -This extension creates a context menu item in Firefox. -When you click on this menu item, the previously selected text is sent to Google Translate for translating or to Google TTS for listening pronunciation. -You can setup the default languages for translation on the options page. - -![To Google Translate](https://addons.mozilla.org/user-media/previews/thumbs/198/198330.jpg?modified=1622132267) - -## Privacy - -### [uBlock Origin](https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/) -An efficient wide-spectrum content blocker. -Easy on CPU and memory. - -![uBlock Origin](https://addons.mozilla.org/user-media/previews/thumbs/238/238546.jpg?modified=1622132421) - -### [User-Agent Switcher and Manager](https://addons.mozilla.org/en-US/firefox/addon/user-agent-string-switcher/) -Spoof websites trying to gather information about your web navigation—like your browser type and operating system—to deliver distinct content you may not want. - -![User-Agent Switcher](https://addons.mozilla.org/user-media/previews/thumbs/188/188200.jpg?modified=1622132777) - -### [Privacy Badger](https://addons.mozilla.org/en-US/firefox/addon/privacy-badger17/) -Privacy Badger automatically learns to block invisible trackers. -Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior. - -![Privacy Badger](https://addons.mozilla.org/user-media/previews/thumbs/171/171793.jpg?modified=1622132342) - -### [ClearURLs](https://addons.mozilla.org/en-US/firefox/addon/clearurls/) -This extension will automatically remove tracking elements from URLs to help protect your privacy when browsing through the Internet. - -![ClearURLs](https://addons.mozilla.org/user-media/previews/thumbs/231/231733.jpg?modified=1640781132) - -### [LocalCDN](https://addons.mozilla.org/en-US/firefox/addon/localcdn-fork-of-decentraleyes/) -LocalCDN is a web browser extension that emulates Content Delivery Networks to improve your online privacy. -It intercepts traffic, finds supported resources locally, and injects them into the environment. -All of this happens automatically, so no prior configuration is required. - -![LocalCDN](https://addons.mozilla.org/user-media/previews/full/271/271250.png?modified=1657374986) - -### [Facebook Container](https://addons.mozilla.org/en-US/firefox/addon/facebook-container/) -Facebook Container works by isolating your Facebook identity into a separate container that makes it harder for Facebook to track your visits to other websites with third-party cookies. - -![Facebook Container](https://addons.mozilla.org/user-media/previews/thumbs/235/235581.jpg?modified=1622133081) - -### [Google Container](https://addons.mozilla.org/en-US/firefox/addon/google-container/) -Google Container works by isolating your Google identity into a separate container that makes it harder for Google to track your visits to other websites with third-party cookies. - -It is a fork of the Facebook Container addon. - -## Quality of Life - -### [Auto Tab Discard](https://addons.mozilla.org/en-US/firefox/addon/auto-tab-discard/) -"Auto Tab Discard" is a lightweight browser extension that automatically reduces the amount of memory used by open but inactive tabs, helping to conserve battery life on portable devices by disabling JavaScript code and DOM events on discarded tabs. - -![Auto Tab Discard](https://addons.mozilla.org/user-media/previews/full/201/201762.png?modified=1622132901) - -### [I don't care about cookies](https://addons.mozilla.org/en-US/firefox/addon/istilldontcareaboutcookies/) -The EU regulations require that any website using tracking cookies must get user's permission before installing them. -These warnings appear on most websites until the visitor agrees with the website's terms and conditions. -Imagine how irritating that becomes when you surf anonymously or if you delete cookies automatically every time you close the browser. - -This add-on will remove these cookie warnings from almost all websites! You can report any website which still warns you about cookies: just click 'Report a cookie warning' from the extension menu (the brown cookie image next to your address bar). - -In most cases, the add-on just blocks or hides cookie related pop-ups. -When it's needed for the website to work properly, it will automatically accept the cookie policy for you (sometimes it will accept all and sometimes only necessary cookie categories, depending on what's easier to do). -It doesn't delete cookies. - -## Aesthetics - -### [Dark Reader](https://addons.mozilla.org/en-US/firefox/addon/darkreader/) -This eye-care extension enables night mode creating dark themes for websites on the fly. -Dark Reader inverts bright colors making them high contrast and easy to read at night. - -You can adjust brightness, contrast, sepia filter, dark mode, font settings and ignore-list. - -![Dark Reader](https://addons.mozilla.org/user-media/previews/thumbs/201/201069.jpg?modified=1638883247) - -## Social Platforms - -### YouTube - -#### [Enhancer for Youtube™](https://addons.mozilla.org/en-US/firefox/addon/enhancer-for-youtube/) -Built to get the most out of YouTube, this extension comes packed with all sorts of features that allow you, among other things, to manage ads as you wish, control the playback speed and the volume level with the mouse wheel, automate repetitive tasks such as selecting the appropriate playback quality, configure dozens of keyboard shortcuts to control YouTube like a pro, and much more... -Give it a try! -But be aware that you will never want to use YouTube without it again ;) - -![YouTube Enhancer](https://addons.mozilla.org/user-media/previews/thumbs/257/257216.jpg?modified=1668589063) - -#### [PocketTube](https://addons.mozilla.org/en-US/firefox/addon/youtube-subscription-groups/) -Using this simple extension you can create collections that seamlessly fit into YouTube layout. This is easy way to manage Youtube subscription / channels. - -This extension enables you to: -- Create group collections list on YouTube. -- Group YouTube subscription / channels to collections / group. One YouTube subscription / channel can has few collections -- Add custom icon for collection. Choice prepare icons or upload own one -- Show last YouTube videos by collections / group. Play all video by collections using YouTube playlist -- Auto sync your collections on Android/iOS/Firefox using Google drive and Chrome profile -- Integration in Youtube main page -- Filter video by category on Youtube feed subscriptions page -- Hide watched YouTube video -- Order by last YouTube activity, a-z, subscription count and custom -- Catch up your Youtube subscriptions - -![PocketTube](https://addons.mozilla.org/user-media/previews/thumbs/270/270578.jpg?modified=1655574773) - -#### [Return YouTube Dislike](https://addons.mozilla.org/en-US/firefox/addon/return-youtube-dislikes/) -Returns ability to see dislike statistics on youtube. - -![Return YouTube Dislike](https://addons.mozilla.org/user-media/previews/thumbs/263/263668.jpg?modified=1637785158) - -#### [SponsorBlock](https://addons.mozilla.org/en-US/firefox/addon/sponsorblock/) -Easily skip YouTube video sponsors. -When you visit a YouTube video, the extension will check the database for reported sponsors and automatically skip known sponsors. -You can also report sponsors in videos. - -![SponsorBlock](https://addons.mozilla.org/user-media/previews/thumbs/227/227750.jpg?modified=1622134672) - -### Reddit - -#### [Reddit Enhancement Suite](https://addons.mozilla.org/en-US/firefox/addon/reddit-enhancement-suite/) -Reddit Enhancement Suite (RES) is a suite of tools to enhance your Reddit browsing experience. - -![RES](https://addons.mozilla.org/user-media/previews/thumbs/238/238629.jpg?modified=1622132176) - -#### [Unreddit](https://addons.mozilla.org/en-US/firefox/addon/unreddit/) -Read removed Reddit comments. - -![Unreddit](https://addons.mozilla.org/user-media/previews/thumbs/218/218512.jpg?modified=1622134062) diff --git a/content/posts/buffer-overflow.md b/content/posts/buffer-overflow.md @@ -1,83 +0,0 @@ ---- -title: "Buffer Overflows: Keep Your Code Safe" -date: 2022-12-14T18:59:28+02:00 -categories: ['Articles'] -tags: ['Security', 'Programming'] -draft: true ---- - -A buffer overflow attack is a type of cyber attack in which an attacker attempts to write more data to a buffer (a temporary data storage area) in a computer's memory than the buffer is designed to hold. -This can cause the buffer to overflow, or exceed its maximum capacity, which can corrupt other parts of the computer's memory and allow the attacker to gain unauthorized access to the system. - -In this post we will explore more about how a buffer overflow attack works and how to prevent it. - -## Programming a Vulnerable Program - -Buffer overflows are a common security vulnerability in computer programs, especially those written in the C programming language. -In C, buffers are often used to store strings of characters, such as user input or file contents. -When a program receives input from a user or reads data from a file, it writes that data to a buffer. -If the amount of data is larger than the size of the buffer, the excess data will overflow into other parts of the computer's memory, potentially overwriting or corrupting other data. - -Lets write a basic program in C that is vulnerable to a buffer overflow attack. Load up your favourite text editor and create a file called `vuln.c`, then copy and paste the following: -``` c -#include <stdio.h> -#include <string.h> - -void vulnerable_function(char* input) { - char buffer[8]; - strcpy(buffer, input); - printf("The input is: %s\n", buffer); -} - -int main(int argc, char* argv[]) { - vulnerable_function(argv[1]); - - return 0; -} - -``` - -This program contains a function called `vulnerable_function()` that takes a string of characters as input. -The function declares a buffer called 'buffer' with a size of 8 characters. -It then uses the `strcpy()` function to copy the input string into the buffer. -Finally, it prints the contents of the buffer using the `printf()` function. - -To compile this code, we need a C compiler. -GCC (GNU Compiler Collection) is a fantastic C compiler and what I will use in this post. -<!-- , it is the standard C compiler for Unix-like systems like Linux and macOS. --> - -To compile the code and generate an executable file called `vuln`, you can run the following command: - -``` shell -gcc -o vuln vuln.c -``` - -To use gdb to debug the vuln program, you can use the following steps: - -1. Start gdb by running the `gdb` command. - -2. Load the vuln program into gdb by running the `file vuln` command. - -3. Run the program by running the `run` command. - -4. When the program stops at the beginning of the `main()` function, you can set a breakpoint at the beginning of the `vulnerable_function()` function by running the `break vulnerable_function` command. - -5. Run the program again by running the `run` command. This time, the program will stop at the breakpoint in the `vulnerable_function()` function. - -6. Step through the code line by line by running the `next` command. You can use the print command to print the values of variables and the `x` command to examine the contents of memory. - -7. When the program reaches the `strcpy()` function, you can see that the buffer overflows if the input string is longer than 8 characters. - -## Preventing Buffer Overflow Attacks - -To prevent buffer overflow attacks, it is important to carefully design and implement your code to avoid such vulnerabilities. Here are some best practices to follow: - -1. Use safe functions for handling strings and other data. In C, the `strncpy()` and `strncat()` functions are safer alternatives to `strcpy()` and `strcat()` because they allow you to specify the maximum number of characters to copy or concatenate. - -2. Avoid using `gets()`, which is a particularly dangerous function because it does not check the size of the input and can therefore easily cause a buffer overflow. Instead, use `fgets()` or `getline()`, which allow you to specify the maximum size of the input. - -3. Always check the return value of functions that handle strings or other data. If a function returns a value indicating that an error occurred or that the input was too large, you can take appropriate action, such as truncating the input or displaying an error message. - -4. Use secure coding practices, such as avoiding the use of hard-coded passwords, sanitizing user input to prevent SQL injection attacks, and using encryption to protect sensitive data. - -By following these best practices, you can help protect your code from buffer overflow attacks and keep your computer systems secure. diff --git a/content/posts/efficient-latex-editing-with-emacs/abbreviations.webm b/content/posts/efficient-latex-editing-with-emacs/abbreviations.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/accents.webm b/content/posts/efficient-latex-editing-with-emacs/accents.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/evil-tex.webm b/content/posts/efficient-latex-editing-with-emacs/evil-tex.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/gnu-calc.webm b/content/posts/efficient-latex-editing-with-emacs/gnu-calc.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/index.md b/content/posts/efficient-latex-editing-with-emacs/index.md @@ -1,261 +0,0 @@ ---- -title: "Efficient LaTeX Editing With Emacs" -date: 2023-11-15T13:26:32+02:00 -categories: ["Guides"] -tags: ["Emacs", "LaTeX"] -toc: true -math: false -draft: false ---- - -The aim of this post is to show my customised LaTeX setup with Emacs and the packages I used to achieve it. -The configurations I'll be showing will be tailored to [Doom Emacs](https://github.com/doomemacs/doomemacs), as that's what I'm using. -However, all of this is possible in vanilla Emacs. -This guide assumes basic knowledge of both Emacs and LaTeX. -<!--more--> - -## AUCTeX - -[AUCTeX](https://www.gnu.org/software/auctex/) can be enabled by enabling `:lang latex` in your `doom` block. - -It has a lot of features, however, many of these features are replaced by other packages mentioned later in this guide. -Here are some of the notable features that I use: - -### Live Preview - -You can enable the live preview by typing <kbd>C-c C-c</kbd> and then selecting the `View` option. -This will open the file in your preferred pdf-viewer and automatically update when you recompile your document (more on compiling later in the guide). - -Since I prefer to stay inside emacs, I set my pdf viewer to `pdf-tools` by adding the following to my `config.org`: - -```emacs-lisp -(setq +latex-viewers '(pdf-tools)) -``` - -Here's what it looks like: - -<video autoplay loop muted playsinline width="100%"> - <source src="preview.webm" type="video/webm"> - <source src="preview.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -### Pretty Symbols - -This is a minor mode that displays text like `\gamma` with their unicode equivalents (γ) in math mode. -The underlying text does not change, only the way they are displayed in the editor changes to make equations more readable. -It is enabled by default in Doom Emacs, otherwise you can run `M-x prettify-symbols-mode`. - -Here's what it looks like: - -![Symbols](symbols.png) - -You'll notice that the superscripts and subscripts are also displayed as such in the editor, this is also done by _AUCTeX_. -_AUCTeX_ can also automatically insert braces when you type `^` or `_`, this is done by setting the `TeX-electric-sub-and-superscript` variable, it is set to `t` by default in Doom Emacs. - -### Text Folding - -You can remove some of the visual noise in a LaTeX buffer by enabling `TeX-fold-mode`. -This is also enabled by default in Doom Emacs. - -This is easier to show than to explain: - -<video autoplay loop muted playsinline width="100%"> - <source src="tex-folding.webm" type="video/webm"> - <source src="tex-folding.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -## CDLaTeX - -[CDLaTeX](https://github.com/cdominik/cdlatex) is a minor mode supporting fast insertion of environment templates and math stuff in LaTeX.[^1] - -[^1]: <https://github.com/cdominik/cdlatex/blob/master/README> - -You can enable this by adding the `+cdlatex` flag to the latex section of your `doom` block, like: - -```emacs-lisp -(latex +cdlatex) -``` - -_CDLaTeX_ also has a ton of features, but here are the ones I use the most: - -### Abbreviations - -Abbreviation expansion is triggered with <kbd>TAB</kbd>, for example: - -<video autoplay loop muted playsinline width="100%"> - <source src="abbreviations.webm" type="video/webm"> - <source src="abbreviations.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -Use `M-x cdlatex-command-help` to see a full list of abbreviations. - -### Mathematical Symbols - -Backquote followed by any character inserts a LaTeX math macro into the buffer. -If necessary, a pair of `\(` is inserted to switch to math mode. -For example, typing `` `a`` inserts `\(\alpha\)`. - -You can wait a second after pressing `` ` `` and a list of all the available macros will pop up. -The macros can also be customised with the `cdlatex-math-symbol-alist` variable. - -<video autoplay loop muted playsinline width="100%"> - <source src="math-symbols.webm" type="video/webm"> - <source src="math-symbols.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -### Accents and Fonts - -Putting accents on mathematical characters and/or changing the font of a character uses key combinations with the quote character `'` as a prefix. -The accent or font change is applied to the character or LaTeX macro **before** point. - -<video autoplay loop muted playsinline width="100%"> - <source src="accents.webm" type="video/webm"> - <source src="accents.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -## LatexMk - -[Latexmk](https://ctan.org/pkg/latexmk) automates the process of compiling a LaTeX document. -Essentially, it is like a specialized relative of the general make utility, but one which determines dependencies automatically and has -some other very useful features.[^2] - -[^2]: https://mirror.ufs.ac.za/ctan/support/latexmk/latexmk.pdf - -You can enable it by adding the `+latexmk` flag to `latex` in your `doom` block. -So it should look something like this if you're using [cdlatex](#cdlatex) as well: - -```emacs-lisp -(latex +cdlatex +latexmk) -``` - -<!--TODO ass continuous build--> - -When you build your LaTeX project for the first time using _LatexMk_, press <kbd>C-c C-c</kbd> and select the `LatexMk` option. -After that, you can build it with `C-c C-a`. - -<video autoplay loop muted playsinline width="100%"> - <source src="latexmk.webm" type="video/webm"> - <source src="latexmk.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -## LSP - -[LSP](https://github.com/Microsoft/language-server-protocol/ "Language Server Protocol") is a communication protocol used between an integrated development environment (IDE) or code editor and a language server that provides language-specific analysis, autocompletion, diagnostics, and other language-related features for programming. - -You can enable [lsp-mode](https://github.com/emacs-lsp/lsp-mode/) for Doom Emacs by enabling the `:tools lsp` module in your `doom` block. - -You can view a list of useful _lsp-mode_ features **[here](https://emacs-lsp.github.io/lsp-mode/tutorials/how-to-turn-off/)**. - -To enable lsp-mode for LaTeX, add the `+lsp` flag to `latex` in your `doom` block. -Your `doom` block will look like this by now: - -```emacs-lisp -(latex +cdlatex +latexmk +lsp) -``` - -Additionally, you'll also need a language server for LaTeX installed. -The two most popular ones are [TexLab](https://github.com/latex-lsp/texlab) and [Digestif](https://github.com/astoff/digestif). -The choice between the two ultimately comes down to personal preference, and you'll have to look at their features and decide for yourself which one you prefer. -I prefer _TexLab_, but it you want to use _Digestif_ instead, you can add the following line to your `config.el`: - -```emacs-lisp -(setq lsp-tex-server 'digestif) -``` - -## Xenops - -[Xenops](https://github.com/dandavison/xenops) is a LaTeX editing environment for mathematical documents in Emacs. - -You can install it by adding `(package! xenops)` to your `packages.el`. -To enable it in a `LaTeX` buffer, run `M-x xenops-mode`. -If you would like to enable it automatically in `LaTeX` buffers, add the following line to your `config.el`: - -```emacs-lisp -(add-hook LaTeX-mode-hook #'xenops-mode) -``` - -Here are some the notable features of Xenops: - -### Render Maths, Tables and TikZ Diagrams - -_Xenops_ replaces the `preview-latex` functionality in _AUCTeX_, which does not seem to support rendering images as SVGs. - -<video autoplay loop muted playsinline width="100%"> - <source src="xenops-render.webm" type="video/webm"> - <source src="xenops-render.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -### Paste Images from the Clipboard - -Simply run `M-x xenops-image-handle-paste` to paste an image from the clipboard into your document. - -<video autoplay loop muted playsinline width="100%"> - <source src="xenops-paste.webm" type="video/webm"> - <source src="xenops-paste.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -## YASnippet - -[YASnippet](https://github.com/joaotavora/yasnippet) is a template system for Emacs. -It allows you to type an abbreviation and automatically expand it into function templates when pressing <kbd>TAB</kbd>. - -You can install _YASnippet_ by enabling `:editor snippets` in your `doom` block. - -Some useful snippets can be found [here](https://github.com/doomemacs/snippets). - -<video autoplay loop muted playsinline width="100%"> - <source src="snippets.webm" type="video/webm"> - <source src="snippets.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -Note that _[CDLaTeX](#cdlatex)_ also has snippet functionaly for LaTeX. -If the same snippet is defined in both _CDLaTeX_ and _YASnippet_, you'll probably want to use the _CDLaTeX_ snippet, so add the following line to your `config.el`: - -```emacs-lisp -(map! :map cdlatex-mode-map - :i "TAB" #'cdlatex-tab) -``` - -## GNU Calc - -[Calc](https://www.gnu.org/savannah-checkouts/gnu/emacs/manual/html_node/calc/index.html#SEC_Contents) is a calculator that's part of Emacs. -It can do symbolic differentiation, linear algebra, taylor series expansions, among many other things. - -You can start calc in embedded mode by running `M-x calc-embedded` and perform operations on LaTeX equations. -Here's an example of me finding the taylor series expansion of _e<sup>x</sup>_ to 6 terms: - -<video autoplay loop muted playsinline width="100%"> - <source src="gnu-calc.webm" type="video/webm"> - <source src="gnu-calc.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -## evil-tex - -[evil-tex](https://github.com/iyefrat/evil-tex) provides a number of useful features for [evil](https://github.com/emacs-evil/evil) users. -This should also be installed by default in Doom Emacs. - -Here's an example of me using it: - -<video autoplay loop muted playsinline width="100%"> - <source src="evil-tex.webm" type="video/webm"> - <source src="evil-tex.mp4" type="video/mp4"> - Your browser does not support the video tag or the file format of this video. -</video> - -## Ackowledgement - -Thanks to these articles for inspiring this post: - -- <https://castel.dev/post/lecture-notes-1/> -- <https://karthinks.com/software/latex-input-for-impatient-scholars/> -- <https://ejenner.com/post/latex-emacs/> diff --git a/content/posts/efficient-latex-editing-with-emacs/latexmk.webm b/content/posts/efficient-latex-editing-with-emacs/latexmk.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/math-symbols.webm b/content/posts/efficient-latex-editing-with-emacs/math-symbols.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/preview.webm b/content/posts/efficient-latex-editing-with-emacs/preview.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/snippets.webm b/content/posts/efficient-latex-editing-with-emacs/snippets.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/symbols.png b/content/posts/efficient-latex-editing-with-emacs/symbols.png Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/tex-folding.webm b/content/posts/efficient-latex-editing-with-emacs/tex-folding.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/xenops-paste.webm b/content/posts/efficient-latex-editing-with-emacs/xenops-paste.webm Binary files differ. diff --git a/content/posts/efficient-latex-editing-with-emacs/xenops-render.webm b/content/posts/efficient-latex-editing-with-emacs/xenops-render.webm Binary files differ. diff --git a/content/posts/enable-monitor-mode-on-tp-link.md b/content/posts/enable-monitor-mode-on-tp-link.md @@ -1,123 +0,0 @@ ---- -title: "Enable Monitor Mode on TP-Link TL-WN722N" -date: 2022-12-16T13:07:05+02:00 -categories: ['Tutorials'] -tags: ['Security', 'Linux'] -draft: true ---- - -## TP-Link TL-WN722N _v1 vs v2/v3_ - -The TP-Link TL-WN722N is a wireless network interface controller (NIC) that allows a computer to connect to a wireless network. -There are three versions of this NIC: v1, v2, and v3. While all three versions are similar in many ways, there are some notable differences between them. - -One of the main differences between the TP-Link TL-WN722N v1 and v2/v3 is the chipset they use. -- The v1 version uses a `Atheros AR9271` chipset -- The v2/v3 versions use a `Realtek RTL8188EUS` chipset - -The Atheros chip supports monitor mode and packet injection out of the box, but the Realtek chip requires changing the drivers. - -## Enabling Monitor Mode - -### v1 - -Run the following command: -``` shell -sudo airmon-ng start wlan0 -``` - -That's it, you should see that your card is in monitor mode when running the following: -``` shell -sudo iwconfig | grep "Mode" -``` - -### v2/v3 - -#### Upgrade your system - -On Debian-based systems (like Kali): -``` shell -sudo apt update && apt upgrade -``` - -On Arch-based systems (like Blackarch): -``` shell -sudo pacman -Syu -``` - -Then reboot: -``` shell -sudo reboot -``` - -#### Install headers - -Debian-based: -``` shell -sudo apt install linux-headers-$(uname -r) -``` - -Arch-based: -``` shell -sudo pacman -S install linux-headers-$(uname -r) -``` - -#### Change the kernel module - -Remove the previous driver module: -``` shell -sudo rmmod r8188eu.ko -``` - -Blacklist the old module: -``` shell -sudo echo "blacklist r8188eu" > "/etc/modprobe.d/realtek.conf" -``` - -Clone the new driver: -``` shell -git clone https://github.com/aircrack-ng/rtl8188eus -``` - -Install the new driver module: -``` shell -cd rtl8188eus -``` -``` shell -make -``` -``` shell -sudo make install -``` - -Enable the new module: -``` shell -sudo modprobe 8188eu -``` - -Reboot: -``` shell -sudo reboot -``` - -#### Enable monitor mode - -Kill all airmon-ng processes: -``` shell -sudo airmon-ng check kill -``` - -Set adapter to monitor mode: -``` shell -sudo iwconfig wlan0 mode monitor -``` - -Bring the interface up: -``` shell -sudo ifconfig wlan0 up -``` - -Test to see if packet injection works: -``` shell -sudo aireplay-ng --test wlan0 -``` diff --git a/content/posts/how-i-use-org-roam-to-takes-notes-for-cs/graph.png b/content/posts/how-i-use-org-roam-to-takes-notes-for-cs/graph.png Binary files differ. diff --git a/content/posts/how-i-use-org-roam-to-takes-notes-for-cs/index.md b/content/posts/how-i-use-org-roam-to-takes-notes-for-cs/index.md @@ -1,249 +0,0 @@ ---- -title: "How I Use Org-Roam to Take Notes for CS" -date: 2024-11-22T16:52:54+02:00 -categories: ["Articles"] -tags: ["Emacs"] -toc: true -math: false -draft: false ---- - -The aim of this post is to show how I use [Doom Emacs](https://github.com/doomemacs/doomemacs) -and [org-roam](https://www.orgroam.com/) to take notes for my Computer Science degree. -<!--more--> - -## Introduction - -This system has become an essential part of my workflow, and I hope sharing it might help others with -studies or gain new ideas for managing information. -There’s a comment section at the bottom of this post where you can share your questions or feedback. -You’ll need a GitHub account to sign in, but your comments could be valuable to others who come across this post. -If you’d rather not comment there, that’s fine too --- I appreciate your engagement regardless. - -<s> -Some people have expressed interest in actually seeing my notes, so I've decided to -make [all of my notes](https://notes.michaelneuper.com/) publicly available for free. -However, please note that there are no images or attachments included due to copyright considerations -involving university materials, textbooks, and other online resources. -There also seems to be an issue where LaTeX is not displaying correctly. -I have opened [an issue on GitHub](https://github.com/ikoamu/publish-org-roam-ui/issues/34) about this -and am also working on trying to fix it myself. - -These notes are far from perfect and they almost certainly contain errors, inconsistencies, -or things I simply missed. -They are all stored on [this GitHub repo](https://github.com/michaelneuper/notes), -so feel free to submit a pull request if you spot any. -Collaboration is always welcome! -</s> - -Unfortunately they had to be made private because of copyright concerns. - -## Why Org-Roam? - -### Integration with Emacs - -As someone deeply embedded in the emacs ecosystem, I rely on it for almost everything: -from writing code and managing tasks to organising my academic and personal life. -It’s my one-stop shop for productivity, and I find its flexibility unmatched. -Naturally, when it came to note-taking, I needed something that could integrate seamlessly into my -existing workflow without breaking the context-switching-free experience that emacs offers. - -### Org Mode - -Using org-roam means that I get all the benefits of org mode, more about this in [5](#code-and-latex-in-notes). - -### Plain Text - -One of my core requirements for a note-taking system is that my notes must be stored in plain text format. -Plain text is _timeless_, _portable_, and _future-proof_. -Unlike proprietary formats or specialised software, plain text notes can be read, edited, and processed -by almost any text editor or tool, so that my work remains accessible decades from now. - -## How I Structure my Notes - -At the heart of my system is a main index node, which serves as a centralised hub containing links to all my classes. -For example: -```org -* Year 1 -** Semester 1 -*** Class 1 -*** Class 2 -** Semester 2 -... -``` - -Each class has its own dedicated node, linked from the main index. -The structure within each class node depends on how the lecturer organises their material. -I tailor the hierarchy of my notes to match the specific course structure, so that I can easily -relate my notes to the lectures' notes/slides. -Here are two common examples of how I structure my class notes: - -### Week -> Lecture -> Topics - -Some professors organise their lecture notes/slides by week, with a separate pdf for each lecture. -So a typical class note might look like: -```org -* Week 1 -** Lecture 1 -*** Topic 1 -*** Topic 2 -** Lecture 2 -... -``` - -### Chapter -> Topics - -Some professors follow the structure of the textbook, with a pdf for every chapter. -So a class note might look like: -```org -* Chapter 1 -** Topic 1 -** Topic 2 -... -``` - -Topic nodes then link to other topic nodes, or other nodes which are not topic nodes (a node need not be connected to a class node). -Here is what a topic node might look like: - -![topic node image](topic-node.png) - -## When I Take Notes - -I’ve found that taking notes during the lecture itself offers little benefit, at least for me. -During lectures, you’re often just scrambling to keep up with the lecturer, copying down what they’re writing without -really processing or understanding the material. -Since lecture notes are usually available afterward, this feels like a pointless exercise. - -Instead, I prefer to **listen attentively during the lecture** and focus on understanding the concepts being taught. -By concentrating on the explanations and examples, I can grasp the material more effectively without the distraction of -trying to transcribe everything in real-time. - -At the end of the day, once I’m home and have some quiet time, I sit down to make my own notes. -By then, I’ve already formed a basic understanding of the topic from the lecture. -I start by writing down what I remember from class, which helps reinforce the key points. -If I realise I’ve forgotten something or need clarification, I consult the textbook, lecture notes, or other resources to fill in the gaps. - -This approach has several benefits: -1. **Reinforcement of Knowledge**: Revisiting the material shortly after hearing it helps solidify what I learned during the lecture. - It’s like giving my brain a second chance to process the information. -2. **Preparation for Homework**: Writing the notes serves as a quick refresher on the day’s work, - which is particularly helpful when tackling homework or assignments based on the lecture content. -3. **Deeper Understanding**: By writing notes in my own words and structuring them in a way that makes sense to me, - I engage more actively with the material. - This process helps me gain a better understanding of the concepts than if I had simply copied the lecturer’s words verbatim. - -Ultimately, this method allows me to focus on comprehension during the lecture and use my note-taking time to consolidate -and deepen my understanding of the material. -It’s a system that not only works well for my learning style but also ensures that my notes are meaningful and useful for future review. - -## Code and LaTeX in Notes - -When it comes to incorporating code and LaTeX into my notes, org-roam combined with the functionality of org mode provides -everything I need for a seamless and powerful workflow. - -### LaTeX - -For LaTeX rendering, I use the [Xenops](https://github.com/dandavison/xenops) package instead of org mode’s default LaTeX preview system. -Here’s why: -1. **Asynchronous Rendering**: Xenops renders LaTeX fragments asynchronously, meaning I can continue writing without being interrupted by rendering delays. This is especially useful when working with complex equations that take longer to render. -2. **Caching for Efficiency**: Once a LaTeX fragment is rendered, Xenops caches the result. This means fragments that have already been rendered don’t need to be processed again, saving time and avoiding unnecessary CPU usage. - -For those interested in setting up and configuring LaTeX for emacs, I’ve written a [separate blog post](https://michaelneuper.com/posts/efficient-latex-editing-with-emacs/) that goes into greater detail about working with LaTeX in emacs, -most of it applies to using LaTeX in org mode as well. - -### Code - -Org mode’s native functionality makes it ideal for including and executing code directly within my notes. -Here’s how I leverage it: -1. **Code Blocks**: I use org mode’s code block syntax to include code snippets directly in my notes. - This allows me to document algorithms, explain concepts with examples, and even run the code inline when needed. - - ```python - #+begin_src python - def binary_search(arr, target): - left, right = 0, len(arr) - 1 - while left <= right: - mid = (left + right) // 2 - if arr[mid] == target: - return mid - elif arr[mid] < target: - left = mid + 1 - else: - right = mid - 1 - return -1 - #+end_src - ``` - -2. **Tangle Feature**: With org mode’s tangling functionality, I can export code snippets into standalone files. - This is useful for assignments or projects where I need to test or submit my code outside of emacs. - -3. **Syntax Highlighting and Evaluation**: org mode supports syntax highlighting for various programming languages and allows for inline execution, making it easy to test small snippets of code directly within my notes. - -The ability to use both code and LaTeX within org mode gives me a significant advantage when documenting complex topics. -For example, I can create a note on an algorithm like Dynamic Programming, where: -- A code block demonstrates the implementation. -- LaTeX fragments explain the mathematical formulation and recurrence relations. -- All of this is interconnected with links to related notes, such as "Time Complexity". - -## How I View my Notes - -When it comes to reviewing and navigating my notes, I’ve experimented with both [org-roam-ui](https://github.com/org-roam/org-roam-ui) (ORUI) and emacs itself. -Over time, my workflow has shifted toward using emacs almost exclusively, but ORUI was an important part of my note-viewing process for a long time. - -ORUI generates a pretty graph based on the links between nodes; here is my graph after one year: - -![orui graph image](graph.png) - -ORUI also generates previews of your notes, and this is what I initially used to review my notes. -The main reason was because of how slow LaTeX previews in org mode are, but xenops has fixed that issue. - -But ORUI also has limitations that made me gravitate toward emacs for reviewing notes: -- **No Search Functionality**: Unlike emacs, ORUI doesn’t offer a way to search through notes. - Instead, you have to find notes by clicking on nodes on the graph, which becomes impractical as the graph grows. -- **Improper Table Rendering**: Tables in Org mode didn’t render well in ORUI, which made it harder to use tables effectively. -- **No Code Highlighting:** As a computer science student, code snippets are a big part of my notes, and - ORUI doesn’t support syntax highlighting for code blocks. - -## Setting up Doom Emacs for Org-Roam - -For xenops to be able to render the mathematical symbols I need, I have to add the following LaTeX packages: - -```elisp -(after! org - (add-to-list 'org-latex-packages-alist '("" "amsmath" t)) - (add-to-list 'org-latex-packages-alist '("" "amssymb" t)) - (add-to-list 'org-latex-packages-alist '("" "mathtools" t)) - (add-to-list 'org-latex-packages-alist '("" "mathrsfs" t))) -``` - -I let xenops automatically render LaTeX fragments when opening an org file and set the scale factor according to my display: - -```elisp -(add-hook 'org-mode-hook #'xenops-mode) -(setq xenops-math-image-scale-factor 1.7 - xenops-reveal-on-entry t) -``` - -I use the following keybindings for Org-roam: - -```elisp -(map! :map evil-org-mode-map - :leader - (:prefix ("r") - :desc "Insert node" - "i" #'org-roam-node-insert - :desc "Find node" - "f" #'org-roam-node-find - :desc "Capture to node" - "c" #'org-roam-capture - :desc "Toggle roam buffer" - "b" #'org-roam-buffer-toggle - :desc "Open random note" - "r" #'org-roam-node-random - :desc "Visit node" - "v" #'org-roam-node-visit - :desc "Open ORUI" - "u" #'org-roam-ui-open)) -``` - -If you're interested in seeing my entire config, it is available in [this GitHub repo](https://github.com/michaelneuper/doom). diff --git a/content/posts/how-i-use-org-roam-to-takes-notes-for-cs/topic-node.png b/content/posts/how-i-use-org-roam-to-takes-notes-for-cs/topic-node.png Binary files differ. diff --git a/content/posts/how-to-create-your-own-website.md b/content/posts/how-to-create-your-own-website.md @@ -1,122 +0,0 @@ ---- -title: "How to Create Your Own Static Website" -date: 2022-12-03T19:39:46+02:00 -categories: ['Tutorials'] -tags: [] -draft: true ---- - -Setting up your own static website can be a great way to showcase your personal brand, portfolio, or business online. -In this post, we'll walk through the process of setting up a static website using Hugo as the static site generator and Netlify as the hosting service. - -## Building The Site - -First, let's talk about what a static website is and why it's a good choice for many people. -A static website is a website that is built using only HTML, CSS, and JavaScript files. -These files are served to the user's web browser as-is, without the need for any server-side processing. -This makes static websites fast, secure, and easy to maintain. - -Hugo is a popular open-source static site generator that makes it easy to create and manage a static website. -It has a simple, easy-to-use interface and comes with a wide range of customizable templates and themes. - -To get started with Hugo, you'll need to download and install Hugo on your computer. - -1. Once you have Hugo installed, you can create a new website by running the following command in your terminal: - ``` shell - hugo new site SITE-NAME - ``` - This will create a new Hugo project in the current directory. - -2. Next, install git and initialize the directory as a git repository: - ``` shell - git init - ``` - Initializing the directory as a git repository is a useful way to keep track of changes and it will also be needed later when we upload our site to GitHub. - -3. Download a theme for you website from https://themes.gohugo.io/. A hugo theme is a template that defines the look and feel of your site. Add a theme to your site by running the following command in the root directory of your site: - ``` shell - git submodule add https://github.com/THEME_NAME/ themes/ - ``` - This will create a folder in the `/themes/` directory where your theme is stored. - -3. Open the `config.toml` file and edit according to your theme. - -4. Create content for your website by using the `hugo new` command. e.g. - ``` shell - hugo new posts/my-first-post.md - ``` - This will create a markdown file under the `/content/posts/` directory where you can edit your content. Hugo uses Markdown files for content, which makes it easy to write and format your content using a simple, readable syntax. - -5. Run the following command in the directory of your site: - ``` shell - hugo server - ``` - Hugo will build a local version of your site that you can view by going to `http://localhost:1313/` inside your browser. Hugo will also automatically show any changes you make to the site, no need to rerun the command or refresh the page. - -## Hosting Your Site - -Hosting a static website refers to the process of making a website accessible to the internet by storing its files on a web server. -A static website is one that contains static content, meaning that the content does not change unless manually updated by the website owner. -This is in contrast to a dynamic website, which generates content on the fly using server-side programming languages such as PHP or ASP.NET. - -To host a static website, you need to sign up for a web hosting service that provides the necessary storage space and bandwidth to host your website. -There are many web hosting providers available, each offering different plans and pricing options. S -ome of the most popular options include *shared hosting*, *VPS hosting*, and *dedicated hosting*. - -One solution for hosting a static website is to use a platform like Netlify. -Netlify is a cloud-based service that allows you to easily deploy and host static websites for free. -It provides a simple interface for uploading your website files, and automatically takes care of the necessary tasks such as setting up DNS records and configuring a CDN to ensure fast loading times for your website. - -In addition to hosting your static website for free, Netlify also offers a range of advanced features such as continuous deployment, split testing, and form handling. -This makes it a great option for teams and individuals looking to quickly and easily host and manage their static websites. - -To host a Hugo site on Netlify, you need to follow these steps: - -1. Create a new repository on GitHub with the name of your site - -2. On you local machine, navigate to the root directory of you Hugo site and run the following commands to create a new repository and push it to GitHub: - - ``` shell - ## Add all files in the Hugo site to the Git repository - $ git add . - - ## Commit the changes to the repository - $ git commit -m "Initial commit of Hugo site" - - ## Add the GitHub repository as a remote to your local Git repository - $ git remote add origin <GitHub repository URL> - - ## Push the Hugo site to the GitHub repository - $ git push -u origin master - ``` - -3. Once your Hugo site has been pushed to GitHub, you can connect your GitHub account to Netlify by signing in to Netlify and following the instructions on the Netlify website. - -4. Once your GitHub account is connected to Netlify, you can set up Netlify to deploy your Hugo site by clicking the "New site from Git" button and selecting your Hugo site's repository from the list of available repositories. - -5. In the next step, you need to configure the build settings for your Hugo site. This includes specifying the version of Hugo to use, the command to build your site, and the directory where the built site should be stored. - -6. After configuring the build settings, you can click the "Deploy site" button to deploy your Hugo site to Netlify. Netlify will automatically build your site using Hugo and make it available at a unique URL. For now, you can access your site by visiting the URL provided by Netlify, but in the next section we will setup a custom domain. - -That's it! Your Hugo site is now hosted on Netlify and available to the world. - -## Getting a Custom Domain (Not Free) - -Setting up a custom domain for your website involves purchasing a domain name and configuring it to point to your website's files on the web server. -A domain name is the unique address that users can type in their web browser to access your website, such as www.google.com. - -Purchasing a domain name typically costs money, as domain names are registered on a yearly basis and need to be renewed periodically to maintain ownership. -The exact cost of a domain name can vary depending on the domain registrar and the specific top-level domain (TLD) you choose (e.g. .com, .net, .org, etc.). - -There are many domain registrars available where you can purchase a domain name, such as GoDaddy, Namecheap, and Google Domains. -When choosing a domain registrar, it's important to consider factors such as pricing, customer support, and additional services offered (such as privacy protection and email hosting). - -Since we're already hosting a site on Netlify we can just purchase the domain from them. -One advantage of purchasing a domain name from Netlify is that it makes the process of setting up your custom domain easier. -Netlify provides a simple interface for purchasing and configuring your domain, and automatically sets up the necessary DNS records to point your domain to your website on Netlify's servers. A -dditionally, Netlify offers free SSL certificates for custom domains, which helps to secure your website and improve its ranking on search engines. - - -In conclusion, building your own website is a rewarding and empowering experience that allows you to share your ideas, passions, and creations with the world. -By using a static site generator like Hugo, you can quickly and easily create a professional-looking website without needing to write any complex code. -Overall, building and hosting your own website is a great way to share your creativity and ideas with the world, and can be a fun and rewarding experience. diff --git a/content/posts/modelling-population-growth-in-python/Figure_1.png b/content/posts/modelling-population-growth-in-python/Figure_1.png Binary files differ. diff --git a/content/posts/modelling-population-growth-in-python/Figure_1_old.png b/content/posts/modelling-population-growth-in-python/Figure_1_old.png Binary files differ. diff --git a/content/posts/modelling-population-growth-in-python/Figure_2.png b/content/posts/modelling-population-growth-in-python/Figure_2.png Binary files differ. diff --git a/content/posts/modelling-population-growth-in-python/Figure_2_old.png b/content/posts/modelling-population-growth-in-python/Figure_2_old.png Binary files differ. diff --git a/content/posts/modelling-population-growth-in-python/Figure_3.png b/content/posts/modelling-population-growth-in-python/Figure_3.png Binary files differ. diff --git a/content/posts/modelling-population-growth-in-python/Figure_3_old.png b/content/posts/modelling-population-growth-in-python/Figure_3_old.png Binary files differ. diff --git a/content/posts/modelling-population-growth-in-python/Figure_4.png b/content/posts/modelling-population-growth-in-python/Figure_4.png Binary files differ. diff --git a/content/posts/modelling-population-growth-in-python/Figure_4_old.png b/content/posts/modelling-population-growth-in-python/Figure_4_old.png Binary files differ. diff --git a/content/posts/modelling-population-growth-in-python/index.md b/content/posts/modelling-population-growth-in-python/index.md @@ -1,344 +0,0 @@ ---- -title: "Modelling Population Growth in Python" -date: 2023-11-12T13:25:23+02:00 -description: Generic description -categories: ["Tutorials"] -tags: ["Mathematics", "Programming"] -toc: true -math: true -draft: true ---- - -In this guide we will be modelling population growth using both the Logistic Model[^1] and the Lotka–Volterra (or Predator-Prey) Model[^2] in python and plotting it with `matplotlib`. -If you would just like the python code, you can download the code for the Logistic Model [here](logistic.py) and the code for the Lotka-Volterra Model [here](predator-prey.py). - -[^1]: Logistic function <https://en.wikipedia.org/wiki/Logistic_function> -[^2]: Lotka–Volterra equations <https://en.wikipedia.org/wiki/Lotka-Volterra_equations> -<!--more--> - -## Logistic Growth - -### The Logistic Equation - -The logistic equation is commonly expressed as a differential equation: - -$$ -\frac{\text{d}P}{\text{dt}} = rP\left(1 - \frac{P}{K}\right) -$$ - -However, for our purposes, we'll use the recurrence relation[^3] form: - -[^3]: Recurrence relation <https://en.wikipedia.org/wiki/Recurrence_relation> - -$$ -P_{n+1} = P_n + rP_n\left(1 - \frac{P_n}{K}\right) -$$ - -where: - -- $n$ is the cycle -- $P_n$ is the population after $n$ cycles -- $r$ is the intrinsic growth rate -- $K$ is the carrying capacity - -The recurrence relation is suitable for scenarios where population counts are measured at discrete intervals, aligning well with real-world data. -It is also easier to implement in Python. - -### Variables - -Let's set up the variables and import the necessary libraries in Python: - -```py -import matplotlib.pyplot as plt -import numpy as np - -p_0 = 5 # initial population -r = 0.1 # intrinsic growth rate -K = 500 # carrying capacity -n = 100 # number of cycles -``` - -Feel free to experiment with these variables to observe changes in the graphs. - -### Model the Population - -Now, let's create a Python function based on the logistic equation: - -```py -def p_n(): - populations = [p_0] - - for i in range(n): - p_n = populations[i] - p_n1 = p_n + r * p_n * (1 - p_n / K) - populations.append(p_n1) - - return populations -``` - -This function generates an array, `populations`, storing the population density after each cycle. - -### Plotting the Population vs Time Graph - -Utilising the `matplotlib` library, we can create a graph where $x$ represents each cycle (`n`) and $y$ represents the population density after $n$ cycles: - -```py -def plot_p_n(): - x = list(range(n + 1)) - y = p_n() - - plt.figure(1) - plt.plot(x, y, 'o') - plt.xlabel('n') - plt.ylabel('Pn') - plt.title('Pn+1 = Pn + r * Pn * (1 - Pn / K)') -``` - -This code produces a plot illustrating population growth over time. - -![Figure 1](Figure_1.png) - -Note that the graph is not continuous, since we are plotting the graph over discrete time intervals ($n$). - -### Plotting the Change in Population vs Population Graph - -Next, we calculate the change in population after each cycle using the logistic equation: - -$$ -rP_n\left(1 - \frac{P_n}{K}\right) -$$ - -```py -def delta_p_p(P): - return r * (1 - P / K) -``` - -We then create a function to plot $\Delta P / P$ against $P$, including a regression line: - -```py -def plot_delta_p_p(): - x = p_n() - y = [] - for i in range(1, n): - delta_p = (x[i + 1] - x[i - 1]) / 2 - y.append(delta_p / x[i]) - - del x[0] - del x[-1] - - x_reg = np.linspace(0, x[-1], 2) - y_reg = delta_p_p(x_reg) - - plt.figure(2) - plt.plot(x, y, 'o') - plt.plot(x_reg, y_reg) - plt.xlim(0, K) - plt.ylim(0, r) - plt.xlabel('Pn') - plt.ylabel('∆P/P') - plt.title('∆P/P = r * (1 - P / K)') -``` - -This code generates a plot depicting the relationship between the change in population and the population size. - -![Figure 2](Figure_2.png) - -### Showing the Plots - -Finally, we display our graphs by calling the functions: - -```py -plot_p_n() -plot_delta_p_p() -plt.show() -``` - -## Lotka–Volterra - -### The Lotka-Volterra Equations - -The Lotka-Volterra equations are also commonly expressed in their differential form: - -$$ -\frac{\text{d}x}{\text{d}t} = \alpha x - \beta xy -$$ - -$$ -\frac{\text{d}y}{\text{d}t} = \delta xy - \gamma y -$$ - -However, for the same reasons, I'll use their recurrence relation counterparts. -I'll also use $a$, $b$, $c$ and $f$ instead of $\alpha$, $\beta$, $\delta$ and $\gamma$. -Additionally, I'll use $R_n$ (for "rabbits") to represent the prey population, and $F_n$ (for "foxes") to represent the predator population. -This is more intuitive to use than $x$ and $y$ in my opinion. - -$$ -R_{n+1} = R_n + aR_n\left(1-\frac{R_n}{K}\right) - bR_nF_n -$$ - -$$ -F_{n+1} = F_n + fbR_nF_n - cF_n -$$ - -where: - -- $n$ is the cycle -- $R_n$ is the prey population after $n$ cycles -- $F_n$ is the predator population after $n$ cycles -- $a$ is the intrinsic growth rate of the prey -- $K$ is the carrying capacity of the prey -- $b$ is the rate at which the predators kill the prey -- $f$ is the effectiveness with which the predators can turn the prey into food -- $c$ is the natural per-capita death rate of the predators - -### Assumptions - -We'll assume that: -- The predators only die from natural causes - - i.e. the predators are not hunted by a bigger predator -- The prey only die from predators killing them - - i.e. the prey will be killed before dying of natural causes such as age - - -### Variables - -Let's implement these variables in Python, along with necessary libraries for graph plotting: - -```py -import matplotlib.pyplot as plt -import numpy as np - -cycles = 3000 # number of cycles - -# Prey -R_0 = 50 # initial population -a = 0.04 # intrinsic growth rate -K = 1200 # carrying capacity -b = 0.003 # per-capita attack rate of predators on prey - -# Predators -F_0 = 20 # initial population -c = 0.01 # natural death rate -f = 0.02 -``` - -Feel free to play around with these variables to see how the graphs change. - -Additionally, we'll initialise arrays for the prey populations and predators populations with the value of their initial populations. These are called `prey_population` and `predator_population`, respectively. - -We'll also create a variable called `marker_size`, which will be the size of the marker in our plots. This will make it easier to change the marker size of all our plots down the line. - -```py -prey_population = [R_0] -predator_population = [F_0] -marker_size = 2 -``` - -### Model the Prey Population - -Let's create a function to model the prey population according to the Lotka-Volterra equation: - -```py -def R(n): - R_n = prey_population[n - 1] - F_n = predator_population[n - 1] - - return R_n + a * R_n * (1 - R_n / K) - b * R_n * F_n -``` - -### Model the Predator Population - -Similarly, we model the predator population: - -```py -def F(n): - R_n = prey_population[n - 1] - F_n = predator_population[n - 1] - - return F_n + f * b * R_n * F_n - c * F_n -``` - -### Cycle Over the Populations - -A function to model both predator and prey populations over `n` cycles: - -```py -def model(): - for i in range(1, cycles): - prey_population.append(R(i)) - predator_population.append(F(i)) -``` - -### Getting the Equilibrium Populations - -To show how each of the populations tend toward equilibria on our graphs, we might want to define some variables for the equilibrium populations. - -```py -R_e = c / (b * f) -F_e = (a / b) * (1 - R_e / K) -``` - -where `R_e` is the equilibrium prey population and `F_e` is the equilibrium predator population - -We can derive these formulae by setting $R_{n+1}=R_n$ and $F_{n+1}=F_n$, which will yield the following: - -$$ -R_e = \frac{c}{bf} -$$ - -$$ -F_e = \frac{a}{b}\left(1 - \frac{R_e}{K}\right) -$$ - -### Plotting the Predator vs Prey Population Graph - -Using `matplotlib`, we plot the graph with their equilibria: - -```py -def plot_predator_prey(): - plt.figure(1) - plt.axvline(x=R_e, color='red', linestyle='--') - plt.axhline(y=F_e, color='red', linestyle='--') - plt.plot(prey_population, predator_population, markersize=marker_size) - plt.xlabel('Prey Population') - plt.ylabel('Predator Population') - plt.title('Predator vs Prey Population') -``` - -This produces a graph depicting the predator-prey interaction: - -![Figure 3](Figure_3.png) - -As can be seen on the plot, the graph spirals toward the intersection of the equilibria. - -### Plotting the Populations vs Time Graph - -Plot the populations against time, including horizontal lines for equilibrium: - -```py -def plot_population_time(): - plt.figure(2) - plt.axhline(y=F_e, color='red', linestyle='--') - plt.axhline(y=R_e, color='red', linestyle='--') - plt.plot(np.arange(cycles), prey_population, label='Prey Population', markersize=marker_size) - plt.plot(np.arange(cycles), predator_population, label='Predator Population', markersize=marker_size) - plt.ylabel('Population') - plt.xlabel('Time') - plt.title('Predator and Prey Populations over Time') - plt.legend() -``` - -The resulting graph illustrates the populations approaching equilibrium: - -![Figure 4](Figure_4.png) - -### Showing the Plots - -Call the functions to display the plots: - -```py -model() -plot_predator_prey() -plot_population_time() -plt.show() -``` diff --git a/content/posts/modelling-population-growth-in-python/logistic.py b/content/posts/modelling-population-growth-in-python/logistic.py @@ -1,57 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np - -p_0 = 5 # initial population -r = 0.1 # intrinsic growth rate -K = 500 # carrying capacity -n = 100 # number of cycles - -def p_n(): - populations = [p_0] - - for i in range(n): - p_n = populations[i] - # Pn+1 = Pn + r * Pn * (1 – Pn / K) - p_n1 = p_n + r * p_n * (1 - p_n / K) - populations.append(p_n1) - - return populations - -def plot_p_n(): - x = list(range(n + 1)) - y = p_n() - - plt.figure(1) - plt.plot(x, y, 'o') - plt.xlabel('n') - plt.ylabel('Pn') - plt.title('Pn+1 = Pn + r * Pn * (1 - Pn / K)') - -def delta_p_p(P): - return r * (1 - P / K) - -def plot_delta_p_p(): - x = p_n() - y = [] - for i in range(1, n): - delta_p = (x[i + 1] - x[i - 1]) / 2 - y.append(delta_p / x[i]) - - del x[0] - del x[-1] - - x_reg = np.linspace(0, x[-1], 2) - y_reg = delta_p_p(x_reg) - - plt.figure(2) - plt.plot(x, y, 'o') - plt.plot(x_reg, y_reg) - plt.xlim(0, K) - plt.ylim(0, r) - plt.xlabel('Pn') - plt.ylabel('∆P/P') - plt.title('ΔP/P = r * (1 - P / K)') - -plot_p_n() -plot_delta_p_p() -plt.show() -\ No newline at end of file diff --git a/content/posts/modelling-population-growth-in-python/predator-prey.py b/content/posts/modelling-population-growth-in-python/predator-prey.py @@ -1,66 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np - -cycles = 3000 # number of cycles - -# Prey -R_0 = 50 # initial population -a = 0.04 # intrinsic growth rate -K = 1200 # carrying capacity -b = 0.003 # per-capita attack rate of predators on prey - -# Predators -F_0 = 20 # initial population -c = 0.01 # natural death rate -f = 0.02 - -############################################################## - -R_e = c / (b * f) -F_e = (a / b) * (1 - R_e / K) - -prey_population = [R_0] -predator_population = [F_0] -marker_size = 2 - -def R(n): - R_n = prey_population[n - 1] - F_n = predator_population[n - 1] - - return R_n + a * R_n * (1 - R_n / K) - b * R_n * F_n - -def F(n): - R_n = prey_population[n - 1] - F_n = predator_population[n - 1] - - return F_n + f * b * R_n * F_n - c * F_n - -def model(): - for i in range(1, cycles): - prey_population.append(R(i)) - predator_population.append(F(i)) - -def plot_predator_prey(): - plt.figure(1) - plt.axvline(x=R_e, color='red', linestyle='--') - plt.axhline(y=F_e, color='red', linestyle='--') - plt.plot(prey_population, predator_population, markersize=marker_size) - plt.xlabel('Prey Population') - plt.ylabel('Predator Population') - plt.title('Predator vs Prey Population') - -def plot_population_time(): - plt.figure(2) - plt.axhline(y=F_e, color='red', linestyle='--') - plt.axhline(y=R_e, color='red', linestyle='--') - plt.plot(np.arange(cycles), prey_population, label='Prey Population', markersize=marker_size) - plt.plot(np.arange(cycles), predator_population, label='Predator Population', markersize=marker_size) - plt.ylabel('Population') - plt.xlabel('Time') - plt.title('Predator and Prey Populations over Time') - plt.legend() - -model() -plot_predator_prey() -plot_population_time() -plt.show() -\ No newline at end of file diff --git a/content/posts/read-more.md b/content/posts/read-more.md @@ -1,52 +0,0 @@ ---- -title: "Unlock the Joy of Reading: Simple Strategies to Read More" -date: 2023-03-13T20:36:16+02:00 -categories: ['Guides'] -tags: ['Reading', 'Productivity'] -draft: true ---- - -In today's fast-paced world, finding time to read can be challenging. -However, reading provides numerous benefits, such as boosting mental stimulation, reducing stress, and expanding our knowledge. -If you've been struggling to incorporate more reading into your life, don't worry – you're not alone. -In this blog post, we'll explore some easy and effective strategies to help you read more and enjoy the process. - -## Set Small, Achievable Goals - -When setting reading goals, it's crucial to avoid overwhelming yourself with unrealistic expectations. -Large goals, like reading for 30 minutes every day, can be challenging to maintain consistently. -Once we fail to meet such a goal, it can quickly spiral into a habit of not reading at all. -To counteract this, establish micro-goals that are almost impossible to miss, such as reading just one page a day. -This achievable target ensures you never fall into the habit of skipping your daily reading, and more often than not, you'll find yourself exceeding the goal and reading even more. By focusing on micro-goals, you build a sustainable reading habit that becomes second nature. - -## Focus on the Chapters That Intrigue You - -This tip is particularly relevant for non-fiction books, such as popular science titles, but can apply to other genres as well. -When diving into a book, you may find that only certain chapters capture your interest. -Instead of forcing yourself to read every single page, feel empowered to focus on the sections that truly engage you. -This approach maximizes your enjoyment and allows you to extract the most valuable information from the book. - -And yes, even if you haven't read every chapter, you can still claim that you've read the book. -After all, reading is a personal journey, and there's no rule stating that you must consume every word from cover to cover. -Embrace a tailored reading experience that caters to your interests and curiosity. - -## Embrace the Art of Moving On - -It's common to feel obliged to finish a book, especially if we've invested money in purchasing it. -This sense of obligation can sometimes lead us to stop reading altogether when we're struggling with an uninteresting book. -It's important to recognize this as the sunk cost fallacy – the misconception that we must continue an activity because of the resources we've already spent on it. - -To break free from this mindset, give yourself permission to move on from a book that isn't enjoyable. -Remember, reading is meant to be a pleasurable experience that enriches our lives, not a burdensome obligation. -By letting go of books that don't engage you, you create space for discovering new, captivating stories that reignite your passion for reading. -Don't let the sunk cost fallacy dictate your reading habits – embrace the freedom to explore new literary worlds without guilt. - -## Read Multiple Books at Once - -Our mood and energy levels can significantly influence our reading preferences. -Sometimes, we might be in the midst of a complex book, such as Kant's Critique of Pure Reason, which requires substantial thought and concentration. -However, after a long day at work or school, we might crave something lighter and more accessible. - -To ensure that your reading doesn't come to a halt due to mood fluctuations, keep a selection of books on hand that cater to different mental states and preferences. -This approach allows you to switch between books depending on your mood and energy levels, ensuring that you always have something enjoyable to read. -By maintaining a diverse reading list, you'll keep the momentum going and continue to reap the benefits of reading, no matter how you're feeling. diff --git a/content/posts/replace-jupyter-notebook-with-emacs-org-mode.md b/content/posts/replace-jupyter-notebook-with-emacs-org-mode.md @@ -1,293 +0,0 @@ ---- -title: "Replace Jupyter Notebook With Emacs Org Mode" -date: 2023-02-27T15:06:40+02:00 -categories: ['Guides'] -tags: ['Emacs', 'Programming'] -draft: false ---- - -## Introduction - -The popularity of Jupyter Notebook has surged in recent years as a powerful tool for interactive data analysis and visualization. -However, there is an alternative that has been around for a longer time and is proving to be a valuable resource for many programmers: Emacs Org Mode. -In this blog post, we will explore how you can replace Jupyter Notebook with Emacs Org Mode for a seamless and efficient literate programming experience. - -## What is Emacs Org Mode? - -Emacs Org Mode is an extension of the versatile Emacs text editor, offering a powerful platform for note-taking, project management, and literate programming. -Literate programming is an approach in which code and documentation are intertwined, allowing you to create executable documents that can be easily understood by others. -Org Mode excels at this by providing a simple and intuitive markup language that supports rich text formatting, embedded code, and exporting to various formats, such as HTML, PDF, and more. - -## Why Replace Jupyter Notebook with Emacs Org Mode? - -- Unified Environment: Emacs provides a unified environment for all your programming and text editing needs. With Org Mode, you can manage code, documentation, and project planning all within a single tool. This eliminates the need to switch between multiple applications, streamlining your workflow. - -- Extensibility: Emacs is known for its extensibility, and Org Mode is no exception. There are countless plugins and extensions available that can enhance your literate programming experience, such as `org-babel` for code execution, `org-ref` for bibliography management, and `org-present` for presentation support. - -- Version Control: Emacs integrates seamlessly with version control systems like Git, allowing you to track changes and collaborate with others easily. This is particularly useful for literate programming, as both code and documentation can be managed in the same repository. - -- Customization: Emacs and Org Mode can be tailored to suit your needs, from key bindings and appearance to functionality. This flexibility allows you to create a personalized environment that aligns with your preferences and workflow. - -## Getting Started with Emacs Org Mode for Literate Programming - -### Installing Emacs - -1. Choose your platform: - - Linux: Use your distribution's package manager to install Emacs (e.g., `sudo apt-get install emacs` for Ubuntu) - - macOS: Install Emacs using Homebrew (https://brew.sh/) with the command: `brew install --cask emacs` - - Windows: Download the installer from the official GNU Emacs website (https://www.gnu.org/software/emacs/) - -2. Launch Emacs and familiarize yourself with the interface. - -### Configuring Org Mode - -1. Ensure Org Mode is installed and up-to-date by checking your Emacs package list (`M-x list-packages`) or manually updating it. - -2. Add Org Mode configuration settings to your Emacs init file (usually `.emacs` or `init.el`). For example: - ```elisp - (require 'org) - (setq org-src-fontify-natively t) - (setq org-confirm-babel-evaluate nil) - ``` - -### Installing essential packages for data science - -Install the following packages using the built-in Emacs package manager (`M-x list-packages`): -- `org-babel`: For code block execution and literate programming -- `ess`: For R programming language support -- `elpy`: For Python programming language support - -Configure the installed packages by adding appropriate settings to your Emacs init file. - -### Setting up a Python environment in Emacs - -1. Ensure Python is installed on your system and available in your PATH. - -2. Install the ipython packages using pip: - ```shell - pip install ipython - ``` - -3. Configure Emacs to use IPython as the default Python interpreter by adding the following to your Emacs init file: - ```elisp - (setq python-shell-interpreter "ipython" - python-shell-interpreter-args "-i --simple-prompt") - ``` - -### Creating and organizing Org files for literate programming - -1. Create a new Org file with the extension `.org` (e.g., `my_project.org`). - -2. Learn the basics of Org Mode markup, such as headings, lists, and links. - -2. Write and execute code blocks within your Org file: - - Inline code execution: Use `src_<language>{<code>}` to insert inline code (e.g., `src_python{2 + 3}`). - - Code block execution: Use the following syntax to create a code block: - - ```org - #+BEGIN_SRC <language> - <code> - #+END_SRC - ``` -For example: - -```org -#+BEGIN_SRC python -print("Hello, Emacs Org Mode!") -#+END_SRC -``` - -- Execute code blocks using `C-c C-c` and display the results directly in your Org file. -- Export your Org file to various formats (e.g., HTML, PDF) for sharing and publishing. - -## Advanced Features of Emacs Org Mode for Data Science - -### Working with multiple languages in a single Org file - -Org Mode's support for various programming languages allows you to work with multiple languages in a single document. - -Configure additional languages in your Emacs init file by adding the appropriate org-babel settings, such as: - -```elisp -(org-babel-do-load-languages - 'org-babel-load-languages - '((python . t) - (R . t) - (shell . t) - ;; Add other languages here - )) -``` - -### Integrating with external tools and libraries - -Use Org Mode's `#+CALL` syntax to integrate external tools or libraries into your Org document. - -Example: Integrating Pandoc for document conversion: - -```org -#+NAME: pandoc -#+BEGIN_SRC sh :results output :var input="input.md" output="output.pdf" -pandoc $input -o $output -#+END_SRC - -#+CALL: pandoc(input="my_markdown_file.md", output="my_converted_file.pdf") -``` - -### Debugging and profiling code within Org Mode - -Leverage the debugging and profiling capabilities of your programming language within Org Mode. - -Example: Debugging Python code with pdb: - -```org -#+BEGIN_SRC python :results output -import pdb - -def my_function(a, b): - pdb.set_trace() - return a + b - -my_function(3, 5) -#+END_SRC -``` - -### Customizing code block execution and display options - -Customize code block execution with header arguments. - -Example: Exporting code block results as a separate file: - -```org -#+BEGIN_SRC python :results file :file output.png -import matplotlib.pyplot as plt - -x = [1, 2, 3, 4] -y = [2, 4, 6, 8] - -plt.plot(x, y) -plt.savefig('output.png') -#+END_SRC -``` - -### Utilizing Org Mode for project management and collaboration - -- Take advantage of Org Mode's task management and agenda features to manage data science projects. -- Create TODO items, set deadlines, and track progress using Org Mode. -- Collaborate with teammates by sharing Org files and using Git for version control. -- Example: Project management in Org Mode: - - ```org - * TODO Prepare dataset - DEADLINE: <2023-04-01> - * TODO Train machine learning model - DEADLINE: <2023-04-15> - * DONE Write report - CLOSED: [2023-03-25] - ``` - -## Tips and Tricks for Optimizing Your Emacs Org Mode Workflow - -### Keyboard shortcuts for Org Mode - -Learn and utilize Org Mode's keyboard shortcuts to improve your productivity: -- `C-c C-t`: Toggle TODO states -- `C-c C-s`: Schedule a task -- `C-c C-d`: Set a deadline -- `C-c C-o`: Open a link -- `TAB`: Fold/unfold headings -- `S-TAB`: Fold/unfold all headings - -Customize your own keyboard shortcuts in your Emacs init file, if needed. - -### Customizing your Emacs theme - -Choose from various built-in and community-provided Emacs themes to personalize your workspace. - -Install a new theme using the Emacs package manager (`M-x list-packages`), and activate it by adding the following to your Emacs init file: - -```elisp -(load-theme 'theme-name t) -``` -Adjust the appearance of Org Mode elements (e.g., headings, links, and code blocks) by customizing their faces. - -### Integrating with other Emacs packages for productivity - -Enhance your Org Mode experience by integrating it with other Emacs packages: -- `org-ref`: Manage citations and references within Org documents -- `org-brain`: Create a personal wiki or knowledge base using Org Mode -- `magit`: Integrate Git version control with your Org workflow -- `org-present`: Create presentations using Org Mode - -Install and configure these packages according to their respective documentation. - -### Using Org Mode for note-taking and knowledge management - -Use Org Mode as a powerful note-taking tool to complement your data science projects. - -Organize and search your notes using Org Mode's hierarchical structure and built-in search capabilities. - -Example: Organizing notes in Org Mode: - -```org -* Data Science Concepts -** Supervised Learning -*** Regression -- Linear Regression -- Polynomial Regression -*** Classification -- Logistic Regression -- Decision Trees -** Unsupervised Learning -*** Clustering -- K-means Clustering -- Hierarchical Clustering -``` -## Transitioning from Jupyter Notebook to Emacs Org Mode - -### Importing existing Jupyter Notebooks into Org Mode - -Use jupytext to convert Jupyter Notebooks to Org Mode files: -- Install jupytext with the command: `pip install jupytext` -- Convert your Jupyter Notebook (`.ipynb`) to an Org Mode file (`.org`) using the following command: - ```shell - jupytext --to org my_notebook.ipynb - ``` --Review the converted Org Mode file to ensure proper formatting and correct any issues. - -### Exporting Org files to Jupyter Notebook format - -- Use jupytext to convert Org Mode files back to Jupyter Notebooks, if needed: -- Convert your Org Mode file (`.org`) to a Jupyter Notebook (`.ipynb`) using the following command: - ```shell - jupytext --to ipynb my_org_file.org - ``` -- Open the converted Jupyter Notebook with your preferred Jupyter environment (e.g., JupyterLab, Jupyter Notebook) and verify its contents. - -### Overcoming common challenges during the transition - -- Familiarize yourself with Emacs key bindings and commands, which may differ significantly from traditional text editors. -- Take the time to explore and customize your Emacs settings to create a comfortable and productive workspace. -- Seek help from the Emacs and Org Mode communities through online forums, mailing lists, and chat rooms. Many users are happy to share their experiences and offer support. - -## Conclusion - -### Recap of the benefits of using Emacs Org Mode for data science - -- Emacs Org Mode offers a powerful, flexible, and customizable environment for data science tasks, addressing many limitations of Jupyter Notebook. -- Org Mode's support for literate programming enables seamless integration of code, results, and documentation, promoting reproducible research and collaboration. -- The extensible nature of Emacs allows users to tailor their workflow to their specific needs, integrating various programming languages, tools, and productivity-enhancing packages. - -### Emphasizing the flexibility and customizability of Emacs Org Mode - -- One of the most significant advantages of Emacs Org Mode is its customizability, allowing users to create a personalized workspace that suits their needs and preferences. -- Users can choose from a wide variety of packages, themes, and settings to create an environment that enhances their productivity and enjoyment of the data science process. - -### Encouragement for readers to give Emacs Org Mode a try - -- If you're intrigued by the benefits of Emacs Org Mode for data science, consider giving it a try and experiencing its capabilities firsthand. -- Transitioning from Jupyter Notebook to Emacs Org Mode may require some initial effort, but the long-term gains in productivity and flexibility can be well worth the investment. - -### Invitation to join the Emacs Org Mode community and share experiences - -- As you embark on your journey with Emacs Org Mode, don't hesitate to reach out to the vibrant community of users and developers for help, support, and inspiration. -- Share your experiences, tips, and tricks with others, contributing to the collective knowledge and strengthening the community of Emacs Org Mode enthusiasts in the data science world. diff --git a/content/posts/stop-using-proprietary-software.md b/content/posts/stop-using-proprietary-software.md @@ -1,50 +0,0 @@ ---- -title: "Free Yourself from the Shackles of Proprietary Software: A Rant" -date: 2023-03-27T21:19:13+02:00 -categories: ['Editorials'] -tags: ['Open-source', 'Software'] -draft: true ---- - -## Introduction - -Have you ever found yourself frustrated by the limitations, restrictions, and lack of control you have when using proprietary software? -Welcome to the club. -So, let's dive into the many reasons why proprietary software is terrible and why we, as users and developers, should put our collective foot down and demand change. - -## The Greed of Corporations - -Proprietary software is the epitome of corporate greed, the embodiment of a money-hungry system that thrives on the limitations and frustrations it imposes upon users. -It's time to unshackle ourselves from the chains of expensive licensing fees, forced upgrades, and the never-ending cycle of subscription-based models that drain our wallets and limit our freedom to innovate. - -## Lack of Customization and Flexibility - -How many times have you used a piece of software and thought, "If only I could change this one feature or tweak this setting, it would be perfect?" Well, with proprietary software, that's just a pipe dream. -The rigidity of proprietary software stifles creativity and innovation, leaving you stuck with whatever features the software company deems necessary or, more likely, profitable. -Open-source software, on the other hand, empowers users and developers to modify, improve, and adapt the software to meet their unique needs. - -## The Inevitable Obsolescence - -Ever had a software program you loved, only to have it rendered useless when the company decided to discontinue support or force an unwanted upgrade? -It's frustrating, to say the least. -With proprietary software, you're completely at the mercy of the company's whims and decisions. -Open-source software, however, offers longevity and security, as it can be maintained and updated by a dedicated community of developers, even if the original creator moves on. - -## A Breeding Ground for Security Risks - -When it comes to proprietary software, you're essentially putting blind trust in the company to keep your data safe and protect you from security threats. -But we've all heard the horror stories of data breaches and hackers exploiting vulnerabilities in widely-used software. -Open-source software provides a level of transparency and peer review that can help identify and fix security issues faster and more efficiently. - -## Stifling Collaboration and Knowledge Sharing - -Proprietary software creates a culture of secrecy and competition, where companies guard their trade secrets and intellectual property like a dragon hoarding gold. -This prevents the sharing of knowledge and ideas that could lead to better software and technology for everyone. -Open-source software, conversely, fosters collaboration, community, and knowledge sharing that benefits the entire industry and its users. - -## Conclusion - -The time has come to break free from the limitations and frustrations of proprietary software. -We must recognize the value and potential of open-source alternatives and demand transparency, flexibility, and collaboration from the software industry. -By embracing the open-source movement, we can help create a world where software is not only more accessible and customizable but also more secure and innovative. -So, next time you're considering a software purchase or download, remember: there's a whole world of open-source alternatives out there, just waiting for you to explore. diff --git a/content/posts/turning-a-window-manager-into-a-desktop-environment.md b/content/posts/turning-a-window-manager-into-a-desktop-environment.md @@ -1,228 +0,0 @@ ---- -title: "A Guide to Building Your Own Desktop Environment" -date: 2022-12-11T21:31:27+02:00 -categories: ['Guides'] -tags: ['Linux'] -draft: false ---- - -<!-- TODO add notification daemon--> - -## Introduction - -If you're a Linux user, you're probably familiar with the concept of window managers and desktop environments. -These programs are responsible for managing the appearance and functionality of your desktop, providing the tools and features that you need to interact with your operating system. - -But what's the difference between a window manager and a desktop environment? -And why might someone want to turn a window manager into a desktop environment? - -In this blog post, we'll explore these questions and more. -I'll provide a step-by-step guide on how to turn a window manager into a desktop environment, along with tips and tricks for customizing your window manager and making it more user-friendly. -We'll also discuss the benefits and drawbacks of using a window manager as a desktop environment, and compare popular window managers and desktop environments. - -So let's dive in and learn more about the fascinating world of window managers and desktop environments! - -## Turning a window manager into a desktop environment - -If you want to turn a window manager into a desktop environment, the first thing you need to do is install the necessary components. -This typically includes the window manager itself, a display manager, and additional utilities and applications. - -Let's explore some of these components: - -### Window Manager - -A window manager is a program that manages the placement and appearance of windows on a computer's desktop. -It is responsible for providing the "frame" around each window, allowing the user to move, resize, and minimize windows. -A window manager also provides the ability to switch between windows and to tile them on the desktop in various ways. - -There are many different window managers available for Linux and other operating systems. -Some of the most popular ones include the following: - -1. **i3**: i3 is a tiling window manager that is designed to be fast and efficient. It is easy to configure and customize, and it provides a number of advanced features for power users. - -2. **Openbox**: Openbox is a lightweight and flexible window manager that is easy to customize. It provides a minimalistic interface and a wide range of options for advanced users. - -3. **bspwm**: bspwm is a tiling window manager that is based on binary space partitioning. It is lightweight and efficient, and it provides a number of advanced features, such as automatic tiling and support for multiple monitors. - -3. **dwm**: dwm is a dynamic window manager that is written in the C programming language. It is fast and lightweight, and it provides a number of advanced features, such as support for multiple monitors and a customizable status bar. - -4. **xmonad**: xmonad is a tiling window manager that is written in the Haskell programming language. It is highly configurable and customizable, and it provides a number of advanced features, such as support for multiple workspaces and automatic tiling. - -Each window manager has its own unique features and capabilities, and the right one for you will depend on your personal preferences and needs. -Some of the pros and cons of using different window managers are as follows: - -- **i3**: i3 is a powerful and customizable window manager that is well-suited for users who want a highly efficient and flexible desktop environment. It has a steep learning curve, but once you master it, you can achieve a high level of productivity. Some of the pros of using i3 are its tiling capabilities, its support for multiple workspaces, and its ability to run on low-end hardware. Some of the cons are its lack of a built-in panel or application launcher, and its reliance on keyboard shortcuts. - -- **Openbox**: Openbox is a lightweight and flexible window manager that is easy to customize. It provides a minimalistic interface and a wide range of options for advanced users. Some of the pros of using Openbox are its low resource usage, its support for desktop icons, and its ability to integrate with other desktop environments. Some of the cons are its lack of tiling capabilities, its reliance on external utilities for certain features, and its lack of a built-in system tray. - -- **bspwm**: bspwm is a tiling window manager that is based on binary space partitioning. It is lightweight and efficient, and it provides a number of advanced features, such as automatic tiling and support for multiple monitors. Some of the pros of using bspwm are its low resource usage, its advanced tiling capabilities, and its support for multiple monitors. Some of the cons are its lack of a built-in panel or application launcher, and its reliance on external utilities for certain features. - -- **dwm**: dwm is a dynamic window manager that is written in the C programming language. It is fast and lightweight, and it provides a number of advanced features, such as support for multiple monitors and a customizable status bar. Some of the pros of using dwm are its low resource usage, its fast performance, and its customizable status bar. Some of the cons are its lack of a built-in panel or application launcher, and its reliance on keyboard shortcuts. - -- **xmonad**: xmonad is a tiling window manager that is written in the Haskell programming language. It is highly configurable and customizable, and it provides a number of advanced features, such as support for multiple workspaces and automatic tiling. Some of the pros of using xmonad are its advanced tiling capabilities, its support for multiple workspaces, and its high level of configurability. Some of the cons are its steep learning curve, its lack of a built-in panel or application launcher, and its reliance on external utilities for certain features. - -### Display Manager - -A display manager is a program that manages the login and display of the desktop environment on a computer. -It is responsible for providing the login screen, allowing the user to enter their username and password, and then starting the desktop environment and managing its display. - -Some common examples of display managers include LightDM, GDM, and SDDM. -LightDM is a cross-platform display manager that is lightweight and customizable. -GDM is the default display manager on the GNOME desktop environment, and it provides a user-friendly login screen and a range of options for advanced users. -SDDM is the default display manager on the KDE desktop environment, and it provides a modern and attractive login screen. - -When you install a desktop environment on your computer, it typically includes a default display manager. -However, you can also choose to install and use a different display manager if you prefer. -For example, if you are using the Xfce desktop environment, you could choose to use LightDM instead of the default XDM display manager. - -### Compositor - -A compositor is a program that is responsible for combining the outputs of multiple applications and displaying them on the screen. -It is typically used to provide advanced graphical effects, such as transparency, animations, and 3D transformations. - -On Linux, a compositor is typically used in conjunction with a window manager to provide a desktop environment. -The window manager is responsible for managing the placement and appearance of windows on the desktop, while the compositor provides the graphical effects. -Some window managers, such as xmonad and i3, include a built-in compositor, while others, such as Openbox, dwm and bspwm, require the use of an external compositor. - -There are many compositors available for Linux, and the right one for you will depend on your personal preferences and needs. -Some popular compositors include compton, picom, and xcompmgr. Compton is a feature-rich compositor that provides a wide range of options and effects, picom is a lightweight and efficient compositor, and xcompmgr is a simple compositor that provides basic graphical effects. - -To choose a compositor, you can consider the following factors: - -1. **Features**: Different compositors provide different sets of features and capabilities. Consider which features are most important to you, and choose a compositor that provides them. - -2. **Performance**: Compositors can have a significant impact on the performance of your desktop environment. If you are using a low-end computer or you have a lot of applications running, you may want to choose a lightweight compositor that uses fewer resources. - -3. **Compatibility**: Some compositors are compatible with only certain window managers or desktop environments. If you are using a specific window manager or desktop environment, make sure the compositor you choose is compatible with it. - -### Additional Utilities - -#### Wallpaper Setter - -You can use a program such as nitrogen or feh to set your wallpaper. -Nitrogen and feh are two popular programs that allow you to browse and select an image to use as your wallpaper, and then set it as the background for your desktop. - -To use nitrogen or feh to set your wallpaper, follow these steps: - -1. Install nitrogen or feh on your system. You can use your package manager to install the program, or you can download and compile the source code from the program's website. - -2. Run nitrogen or feh. This will open a window that allows you to browse and select an image to use as your wallpaper. - -3. Browse to the location of the image you want to use as your wallpaper, and select it. - -4. Once you have selected the image, click on the "Set as wallpaper" button (in nitrogen) or the "Apply" button (in feh) to set the image as your wallpaper. - -5. The selected image will now be displayed as your wallpaper. - -6. Add a line to your startup script to set the wallpaper. -If you're using nitrogen add: - ```shell - nitrogen --restore - ``` - If you're using feh add: - ```shell - feh --bg-scale /path/to/image.jpg - ``` - -#### Bar - -A bar on Linux is a program that displays information on the desktop, such as the current time and date, the system load, and the status of various system services. -A bar is typically used in conjunction with a window manager or desktop environment, and it provides a convenient way to access important information without needing to open a separate application. - -There are many bars available for Linux, and the right one for you will depend on your personal preferences and the desktop environment you are using. -Some popular bars include polybar, lemonbar, i3bar, xmobar, and dwmblocks. -These bars are designed to be used with specific desktop environments or window managers, and they provide a range of features and customization options. - -For example, polybar and lemonbar are general-purpose bars that can be used with any desktop environment or window manager. -They provide a wide range of features, such as support for multiple monitors and custom colors and fonts, and they are highly customizable. -i3bar is the default bar for the i3 window manager, and it provides a minimalistic interface and support for displaying information from i3 modules. -xmobar is the default bar for the xmonad window manager, and it provides a customizable interface and support for displaying information from xmonad plugins. -dwmblocks is the default bar for the dwm window manager, and it provides a minimalist interface and support for displaying information from dwm status commands. - -To choose a bar, you can consider the following factors: - -1. **Compatibility**: Some bars are designed to be used with specific desktop environments or window managers. If you are using a specific desktop environment or window manager, make sure the bar you choose is compatible with it. - -2. **Features**: Different bars provide different sets of features and capabilities. Consider which features are most important to you, and choose a bar that provides them. - -3. **Customization**: Some bars are highly customizable, allowing you to change the appearance and behaviour of the bar to suit your preferences. If you want a bar that you can tailor to your specific needs, choose a bar that provides a high degree of customization. Polybar is a popular choice. - -#### Application Launcher - -An application launcher is a program that allows you to quickly search for and launch applications on your Linux system. -An application launcher typically provides a search bar or a menu that allows you to enter the name of the application you want to launch, and it displays a list of matching applications that you can select from. - -Some popular application launchers include rofi, dmenu, and albert. - -1. **Rofi** is a flexible and customizable application launcher that allows you to search for and launch applications, as well as perform a range of other actions, such as opening a terminal or running a command. - -3. **Dmenu** is a simple and lightweight application launcher that provides a minimalistic interface and support for fuzzy search. - -4. **Albert** is a fast and efficient application launcher that uses a customizable keyboard shortcut to launch applications and perform other actions. - -#### System Tray - -A system tray (also known as a notification area) is a part of the graphical user interface (GUI) on Linux (and other operating systems) that displays icons for system and application notifications. -The system tray is typically located at the bottom or side of the screen, and it provides a convenient way for applications to display important information and notifications without disrupting the user's work. - -For example, the system tray might display an icon for a network manager application, which shows the current network status and allows the user to manage their network connections. -It might also display an icon for a battery manager application, which shows the current battery level and allows the user to manage their power settings. - -#### Polkit - -Polkit (formerly known as PolicyKit) is a framework for defining and managing administrative policies on Linux. -It provides a mechanism for controlling access to system-wide privileges, and it allows users to perform privileged tasks without needing to log in as the root user. - -Polkit consists of a number of components, including a daemon (polkitd), a command-line tool (polkit), and a library (libpolkit). -The polkit daemon runs in the background and listens for requests from applications that need to perform privileged tasks. -The polkit command-line tool allows administrators to manage and configure polkit policies. -The libpolkit library provides a convenient interface for developers to integrate polkit into their applications. - -See [the arch wiki](https://wiki.archlinux.org/title/Polkit) for more information. - -## Customizing your window manager - -Most window managers on Linux allow for customization to some extent. -Customizing your window manager can allow you to tailor the appearance and behaviour of your desktop environment to suit your preferences and needs. - -To customize your window manager, you will need to edit the window manager's configuration files. -These files are typically written in a scripting language, such as Lua or Shell, and they control the various aspects of the window manager's behaviour and appearance. - -Here are some examples of the types of things you can customize in your window manager: - -- **Appearance**: You can customize the appearance of your window manager by changing the colors, fonts, and other visual elements. For example, you might change the color of the window borders, the font used for window titles, or the size of gaps between windows. - -- **Keybindings**: You can customize the keybindings of your window manager to define which keys perform which actions. For example, you might bind the "Alt + Tab" keys to switch between windows, or the "Super + L" keys to lock the screen. - -- **Behaviour**: You can customize the behaviour of your window manager to control how windows are managed and displayed. For example, you might change the default layout of windows on the screen, or the way windows are focused when they are opened. - -- **Autostart**: You can customize the autostart of your window manager to define which applications are automatically launched when you log in. For example, you might specify that your web browser, email client, and music player are automatically started when you log in. - -To customize your window manager, you will need to edit the appropriate configuration files and specify the desired changes. -The exact steps for doing this will depend on the specific window manager you are using. -You can find instructions for customizing your window manager in the documentation or online forums for your window manager. - -## Benefits and drawbacks - -There are both benefits and drawbacks to using a window manager instead of a full desktop environment on Linux. - -As said before, a window manager is a program that provides the basic functions for managing windows on the desktop, such as opening, closing, minimizing, and maximizing windows. -A full desktop environment, on the other hand, is a complete graphical user interface (GUI) that includes not only a window manager, but also a range of other applications and utilities, such as a taskbar, a system tray, a file manager, and a desktop background. - -Here are some of the benefits of using a window manager instead of a full desktop environment on Linux: - -- **Lightweight**: Window managers are typically much lighter and more efficient than full desktop environments. This means they use fewer system resources, such as memory and CPU, and they can run on lower-powered hardware. - -- **Customizable**: Window managers are typically highly customizable, allowing users to tailor the appearance and behavior of their desktop environment to their preferences. This is because window managers typically have simple, modular architectures, with configuration files that are easy to edit and modify. - -- **Flexible**: Window managers are typically more flexible than full desktop environments, allowing users to mix and match different applications and utilities from different desktop environments. For example, a user might use the window manager from one desktop environment, but the file manager from another. -Here are some of the drawbacks of using a window manager instead of a full desktop environment on Linux: - -- **Less user-friendly**: Window managers are typically less user-friendly than full desktop environments, because they do not include many of the applications and utilities that users expect in a GUI. This can make it more difficult for new users to get started with a window manager, and it can limit the functionality of the desktop environment. - -- **Less integrated**: Window managers are typically less integrated than full desktop environments, because they do not include many of the applications and utilities that are designed to work together. This can lead to a less cohesive and consistent user experience, and it can make it more difficult to perform certain tasks. - -- **More complex**: Window managers are typically more complex than full desktop environments, because they require the user to manually configure and manage many of the components of the desktop environment. This can be a challenge for inexperienced users, and it can require more time and effort to set up and maintain a window manager. - -Overall, whether to use a window manager or a full desktop environment on Linux depends on your personal preferences and needs. -Some users may prefer the lightweight, customizable, and flexible nature of window managers, while others may prefer the user-friendly, integrated, and simple nature of full desktop environments. diff --git a/content/posts/what-linux-packaging-format-to-use.md b/content/posts/what-linux-packaging-format-to-use.md @@ -1,122 +0,0 @@ ---- -title: "Which Linux Packaging Format Should You Use?" -date: 2023-01-09T13:36:52+02:00 -categories: ['Articles'] -tags: ['Linux'] -draft: true ---- - -## Introduction - -Linux, a widely popular open-source operating system, is known for its versatility and adaptability. -The software distribution in Linux is primarily done through packages, which are used to install, update, and remove applications. -There are several package formats available, and choosing the right one can be confusing for newcomers or even experienced users. -In this blog post, we will discuss the key differences between popular package formats such as Flatpak, Snap, Deb, RPM, AppImage, and AUR, and provide insights to help you choose the best format for your needs. - -## Flatpak - -Flatpak is a relatively new package format. -It aims to create a universal packaging system for all Linux distributions, providing a sandboxed environment for applications. -This isolation ensures that apps have limited access to system resources, enhancing security and stability. - -### Pros: - -- Distribution-agnostic packaging system -- Improved security through sandboxing -- Easy to update and manage applications - -### Cons: - -- Increased disk space usage due to bundling of dependencies -- Slower application startup times - -## Snap - -Snap is a package format developed by Canonical, the company behind Ubuntu. -Similar to Flatpak, it focuses on providing a universal packaging system that works across multiple distributions. -Snaps are self-contained and sandboxed, which improves security and stability. - -### Pros: - -- Works across various Linux distributions -- Enhanced security with sandboxing -- Automatic updates - -### Cons: - -- Limited support for themes and desktop integration -- Increased disk space usage due to bundled dependencies - -## Deb - -Deb is the native package format for Debian-based distributions, such as Ubuntu and Linux Mint. -It uses the Advanced Package Tool (APT) for package management, making it easy to install, update, and remove applications. -Deb packages have been the standard for Debian-based systems for many years. - -### Pros: - -- Well-established and widely supported -- Efficient dependency handling -- Large repository of available packages - -### Cons: - -- Limited to Debian-based distributions -- No sandboxing or containerization - -## RPM - -RPM (RPM Package Manager) is a package format used by Red Hat-based distributions, such as Fedora and CentOS. -RPM packages are managed by various package management tools like DNF and YUM. - -### Pros: - -- Extensive support for Red Hat-based distributions -- Good dependency management -- Large repository of available packages - -### Cons: - -- Limited to Red Hat-based distributions -- No sandboxing or containerization - -## AppImage - -AppImage is a portable package format that allows users to run applications without installing them. -It is distribution-agnostic and works across various Linux distributions. -AppImages are self-contained, bundling all required dependencies, which can lead to increased disk space usage. - -### Pros: - -- Distribution-agnostic -- Portable and easy to use -- No installation required - -### Cons: - -- Increased disk space usage -- No centralized update mechanism - -## AUR (Arch User Repository) - -AUR is a community-driven repository for Arch Linux and its derivatives, such as Manjaro. -It contains a vast collection of packages that are not available in the official repositories. -Users can build and install packages directly from the AUR using helper tools like yay or paru. - -### Pros: - -- Large collection of packages -- Community-driven and maintained -- Easy to use with helper tools - -### Cons: - -- Limited to Arch-based distributions -- Packages may have varying quality and stability - -## Conclusion - -Selecting the right package format depends on various factors, such as your distribution, security requirements, and personal preferences. -If you prioritize universal compatibility and sandboxing, Flatpak and Snap are great options. -For Debian or Red Hat-based distributions, Deb and RPM are well-established choices. -If you need portability and ease of use, AppImage is the way to go. Lastly, for Arch Linux users, AUR provides a vast array of community-maintained packages. diff --git a/go.mod b/go.mod @@ -1,5 +0,0 @@ -module github.com/michaelneuper/website - -go 1.20 - -require github.com/michaelneuper/hugo-texify3 v0.0.0-20260516135108-939a8f965b44 // indirect diff --git a/go.sum b/go.sum @@ -1,26 +0,0 @@ -github.com/michaelneuper/hugo-texify3 v0.0.0-20231108072202-3058960968ef h1:UQ7GNq4JDisAwym16nArIT7LE0SIGKQs0lqj900pGk4= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231108072202-3058960968ef/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231108193134-931ec8cf13e5 h1:o1U24PkkulIkrg5IG6ssXwdwZuPISEf7+21b2kVSS5M= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231108193134-931ec8cf13e5/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231109085612-50d2e32742c6 h1:dbCHTtYayxW5WhJT+roTyPs7uw3UtI4UWPUmYM+mgVc= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231109085612-50d2e32742c6/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231109133233-7aea7a5680b1 h1:u27EKaJaNRkalGMAU0mIJ+41kF9tUUS3qsYa0sxJZIQ= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231109133233-7aea7a5680b1/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231110103632-82079534d505 h1:cvCt/15GCvGtMhG81dX7L62AqhOsH4+Raprsy/mte8U= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231110103632-82079534d505/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231111084143-0e6aa69fec1a h1:3BRBqaeaKoPAwvJ7DwmMdWnCLoSsKjK1Ns9XORKhsAU= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231111084143-0e6aa69fec1a/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231111210813-726bb6ce6eed h1:rLQ1HPAjLYBlGOoHU6J033UuasT1HtCVraOFGATg7hg= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231111210813-726bb6ce6eed/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231111211613-1b2ea6c0315b h1:gxaW2ZfBlC2vWJs3kc9hLGNkYnxzVTkMC0TtacPIcCI= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231111211613-1b2ea6c0315b/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231116180805-f3085dd19adf h1:G4lbqz+MisgEL7jEeSCgLwrZ8TdlEw2IJkgLaqH38+o= -github.com/michaelneuper/hugo-texify3 v0.0.0-20231116180805-f3085dd19adf/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20241119231410-e0256e3543a1 h1:aa9nBDgCDiKourepM2G6l6t2earzF6a0diFCvDopKFg= -github.com/michaelneuper/hugo-texify3 v0.0.0-20241119231410-e0256e3543a1/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20250107174151-2a4b2f728715 h1:ZzfE6qTcYYZZ/D/GcFEfBb5dtrRF4ntKlK+3S2w4xqM= -github.com/michaelneuper/hugo-texify3 v0.0.0-20250107174151-2a4b2f728715/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20260501161904-7050fe184f70 h1:wXwqnLcrFNQxBC2EXRvEyZNExAzsspdWrZF8PDmwqzs= -github.com/michaelneuper/hugo-texify3 v0.0.0-20260501161904-7050fe184f70/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= -github.com/michaelneuper/hugo-texify3 v0.0.0-20260516135108-939a8f965b44 h1:DSPqSuVnJu+l2l3UlVxt4836rKy+c7PN3AFfFv1htqg= -github.com/michaelneuper/hugo-texify3 v0.0.0-20260516135108-939a8f965b44/go.mod h1:OLgVlYkX7N8YT/Qx//nu6Yemst3vx3jDUNTBTrIJIZE= diff --git a/layouts/404.html b/layouts/404.html @@ -1,8 +0,0 @@ -{{ define "main" }} - <main id="main"> - <div> - <h1 id="title">404</h1> - <h3>You once were found, but now you're lost :(</h2> - </div> - </main> -{{ end }} diff --git a/netlify.toml b/netlify.toml @@ -1,65 +1,18 @@ [build] -publish = "public" -command = """\ - curl -LJO https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz && \ - tar -xf dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz && \ - rm dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz && \ - export PATH=/opt/build/repo/dart-sass:$PATH && \ - hugo --gc --minify \ - """ - [build.environment] - HUGO_VERSION = "0.138.0" - DART_SASS_VERSION = "1.63.6" - NODE_VERSION = "18" - TZ = "America/Los_Angeles" +command = "npm run build" +publish = "dist" -[[redirects]] -from = "/*" -to = "/404.html" -status = "404" + [build.environment] + # Astro 7 needs Node 22.12 or newer. + NODE_VERSION = "22" [[headers]] for = "/*" [headers.values] - Cache-Control = "max-age=3600" X-Content-Type-Options = "nosniff" +# Astro puts a content hash in these file names, so browsers can keep them for good. [[headers]] -for = "/*.css" - [headers.values] - Cache-Control = "max-age=31536000" - -[[headers]] -for = "/*.js" - [headers.values] - Cache-Control = "max-age=31536000" - -[[headers]] -for = "/*.jpg" - [headers.values] - Cache-Control = "max-age=604800" - -[[headers]] -for = "/*.jpeg" - [headers.values] - Cache-Control = "max-age=604800" - -[[headers]] -for = "/*.png" - [headers.values] - Cache-Control = "max-age=604800" - -[[headers]] -for = "/*.gif" - [headers.values] - Cache-Control = "max-age=604800" - -[[headers]] -for = "/*.svg" - [headers.values] - Cache-Control = "max-age=604800" - -[[headers]] -for = "/*.woff" +for = "/_astro/*" [headers.values] - Cache-Control = "public, max-age=31536000" + Cache-Control = "public, max-age=31536000, immutable" diff --git a/package-lock.json b/package-lock.json @@ -1,542 +1,2735 @@ { - "name": "website", + "name": "personal-site", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "personal-site", + "version": "0.0.1", "dependencies": { - "autoprefixer": "^10.4.16", - "postcss": "^8.4.49", - "postcss-cli": "^10.1.0", - "postcss-import": "^15.1.0" + "astro": "^7.3.8" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@astrojs/compiler-binding": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding/-/compiler-binding-0.5.1.tgz", + "integrity": "sha512-oczyolLUl9mNrtuBuNjuvn5thpHrFLXAHAWGTRg0JDHQ8cGVsVeFekOu2uSoQGgainJIi+A3/9m0DyYwz3Nlnw==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@astrojs/compiler-binding-android-arm64": "0.5.1", + "@astrojs/compiler-binding-darwin-arm64": "0.5.1", + "@astrojs/compiler-binding-darwin-x64": "0.5.1", + "@astrojs/compiler-binding-linux-arm64-gnu": "0.5.1", + "@astrojs/compiler-binding-linux-arm64-musl": "0.5.1", + "@astrojs/compiler-binding-linux-x64-gnu": "0.5.1", + "@astrojs/compiler-binding-linux-x64-musl": "0.5.1", + "@astrojs/compiler-binding-wasm32-wasi": "0.5.1", + "@astrojs/compiler-binding-win32-arm64-msvc": "0.5.1", + "@astrojs/compiler-binding-win32-x64-msvc": "0.5.1" + } + }, + "node_modules/@astrojs/compiler-binding-android-arm64": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-android-arm64/-/compiler-binding-android-arm64-0.5.1.tgz", + "integrity": "sha512-nMb2nMIJtcWLNH+fV75Enmi+jp4tIOYOfsv4XtpgdOWkqc9P4uSSdK5u1xb340AzrXo5V18SxLl/nc3vcqtamQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-darwin-arm64": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-arm64/-/compiler-binding-darwin-arm64-0.5.1.tgz", + "integrity": "sha512-5k4+nZ/WRt+dcVow4z7rBuI7iv9A58h/uQ91YJe1PrTivbcCkq3u2Ynx/AZJwII4CsZawBCeGpojkFjutZBhBQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-darwin-x64": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-darwin-x64/-/compiler-binding-darwin-x64-0.5.1.tgz", + "integrity": "sha512-0Buw+YST9Ff2EqQyhRMQujuFq/dijLw3zXWhsvI0dJ2pGrT38iVoxTEca2eBX/PfhlwkVWSRJEKO5gMqKHyeHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-arm64-gnu": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-gnu/-/compiler-binding-linux-arm64-gnu-0.5.1.tgz", + "integrity": "sha512-x5LRpyCoMKuu3INr18cn42YhwSOaRpp9b5Ny3eJJ/sWVeejC16Zeshu1JlvlSmEZACLeWxU5JM0RX6T6nI+YyA==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-arm64-musl": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-arm64-musl/-/compiler-binding-linux-arm64-musl-0.5.1.tgz", + "integrity": "sha512-mL7tQEuDk3rGfaKmrO63nw6WBy1TPVioQGmVyjcAr+C+a/k3SVMYBytNSMqH9mZPT/Swj30JaZ2N842Z1NnOEQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-x64-gnu": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-gnu/-/compiler-binding-linux-x64-gnu-0.5.1.tgz", + "integrity": "sha512-uLGc9jtxwiDe4cQyhNPQim4ECiB/YzbWlXssfLAv8r374kArfTwBHjwR2+j+XVyF71yCx5mF9YNRclRqdNBgeg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-linux-x64-musl": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-linux-x64-musl/-/compiler-binding-linux-x64-musl-0.5.1.tgz", + "integrity": "sha512-G0cywinaQUc8v1MrytvYKUX7svTDMmYtOCZfxjwKPbJi59zIqM+Ll0rWgO0GQWLZH3XoPYo19ZwlP3Xt9ep9YA==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-wasm32-wasi": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-wasm32-wasi/-/compiler-binding-wasm32-wasi-0.5.1.tgz", + "integrity": "sha512-yMhLL8asmLydoAdnEZxAw6eLfNDs3YJl6jqn0pjPt6zrb2U5qIDLnii4/twThpIFODKkQ6YDpBRTOz/vSfZCxw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.3", + "@emnapi/runtime": "1.11.3", + "@napi-rs/wasm-runtime": "^1.2.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-win32-arm64-msvc": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-arm64-msvc/-/compiler-binding-win32-arm64-msvc-0.5.1.tgz", + "integrity": "sha512-aClIG6poFt3Wf/bZykrEAX2nAnKvBHW6RXiKUa69QjBtWH0/FOlOAjnFcxRNlhej2AMWNYFx0o+LGjwMcH8P7Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-binding-win32-x64-msvc": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-binding-win32-x64-msvc/-/compiler-binding-win32-x64-msvc-0.5.1.tgz", + "integrity": "sha512-/E6uBCagY70YpWqssBC+/FuniNSloeQPRgj7l3LDWiqjxIyTLnIgX1sTt18FU7jrigetpSnC9cHAM6b6IxSgPw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@astrojs/compiler-rs": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@astrojs/compiler-rs/-/compiler-rs-0.5.1.tgz", + "integrity": "sha512-1k1acnX7DepIiea9U9/Y+d1hdAFfylu1ZQQkkYgRSwBOBAsXInolyZuh/2tax+83vu/A+hOYP6P3+265RvMTvw==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-binding": "0.5.1" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@astrojs/internal-helpers": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.12.0.tgz", + "integrity": "sha512-pKPuwCDtO0L7zgmt1JGd9X4Aes1+0SX3IEBSqBNPHsScYdPMlfmed3Y7DTbXyF7E+8ylnb563o/0OzGQPOFehw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "picomatch": "^4.0.4", + "retext-smartypants": "^6.2.0", + "shiki": "^4.0.2", + "smol-toml": "^1.8.0", + "unified": "^11.0.5", + "yaml": "^2.9.1" + } + }, + "node_modules/@astrojs/markdown-satteri": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.4.3.tgz", + "integrity": "sha512-PFbEHPnwUlLvpXd7RXrrKM+j12akF4bG+DSuNuoN+3eiwjOwp4HaPi+QQdbkBV7QEYXmzyKca50OJsmGxhNIUA==", + "license": "MIT", + "dependencies": { + "@astrojs/internal-helpers": "0.12.0", + "@astrojs/prism": "4.0.2", + "github-slugger": "^2.0.0", + "satteri": "^0.10.3" + } + }, + "node_modules/@astrojs/prism": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.2.tgz", + "integrity": "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==", + "license": "MIT", + "dependencies": { + "prismjs": "^1.30.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@astrojs/telemetry": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.3.tgz", + "integrity": "sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==", + "license": "MIT", + "dependencies": { + "ci-info": "^4.4.0", + "dset": "^3.1.4", + "is-docker": "^4.0.0", + "package-manager-detector": "^1.6.0" + }, + "engines": { + "node": "18.20.8 || ^20.3.0 || >=22.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bruits/satteri-darwin-arm64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-arm64/-/satteri-darwin-arm64-0.10.5.tgz", + "integrity": "sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@bruits/satteri-darwin-x64": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-darwin-x64/-/satteri-darwin-x64-0.10.5.tgz", + "integrity": "sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@bruits/satteri-linux-arm64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-gnu/-/satteri-linux-arm64-gnu-0.10.5.tgz", + "integrity": "sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-linux-arm64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-arm64-musl/-/satteri-linux-arm64-musl-0.10.5.tgz", + "integrity": "sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-linux-x64-gnu": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-gnu/-/satteri-linux-x64-gnu-0.10.5.tgz", + "integrity": "sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-linux-x64-musl": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-linux-x64-musl/-/satteri-linux-x64-musl-0.10.5.tgz", + "integrity": "sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@bruits/satteri-wasm32-wasi": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-wasm32-wasi/-/satteri-wasm32-wasi-0.10.5.tgz", + "integrity": "sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@bruits/satteri-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@bruits/satteri-win32-arm64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-arm64-msvc/-/satteri-win32-arm64-msvc-0.10.5.tgz", + "integrity": "sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@bruits/satteri-win32-x64-msvc": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@bruits/satteri-win32-x64-msvc/-/satteri-win32-x64-msvc-0.10.5.tgz", + "integrity": "sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@capsizecss/unpack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-4.0.1.tgz", + "integrity": "sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==", + "license": "MIT", + "dependencies": { + "fontkitten": "^1.0.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@clack/core": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.5.1.tgz", + "integrity": "sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==", + "license": "MIT", + "dependencies": { + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@clack/prompts": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.8.1.tgz", + "integrity": "sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==", + "license": "MIT", + "dependencies": { + "@clack/core": "1.5.1", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz", + "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz", + "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz", + "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz", + "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz", + "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz", + "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz", + "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz", + "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz", + "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz", + "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz", + "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz", + "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz", + "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz", + "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz", + "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz", + "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz", + "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz", + "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz", + "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz", + "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz", + "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz", + "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz", + "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz", + "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz", + "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz", + "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.5.tgz", + "integrity": "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + } + }, + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT" + }, + "node_modules/@oxc-project/types": { + "version": "0.153.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.153.0.tgz", + "integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.13.tgz", + "integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.13.tgz", + "integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.13.tgz", + "integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.13.tgz", + "integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.13.tgz", + "integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.13.tgz", + "integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.13.tgz", + "integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.13.tgz", + "integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.13.tgz", + "integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.13.tgz", + "integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.13.tgz", + "integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.13.tgz", + "integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.13.tgz", + "integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.13.tgz", + "integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.13.tgz", + "integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "license": "MIT" + }, + "node_modules/@shikijs/core": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.5.0.tgz", + "integrity": "sha512-6CIgwq+bt2JZ3OSjb/nBkkwEf/CfpHcbam+Mg5Pllco7HAGRQ2/EFhZrrJtbyNTgKwknfVS+llsXGygiDGwJWw==", + "license": "MIT", + "dependencies": { + "@shikijs/primitive": "4.5.0", + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.5.0.tgz", + "integrity": "sha512-Ed6UdEj84LyYkwnxM5CvSMWAD+id9ExTYri0/+x41U9zrgNifPSS9lZm0JqBP0VfYI8yr8tY5nbNq9+p9R0kFA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.5.0.tgz", + "integrity": "sha512-dKVmbJecVdB9recl8a/CU4jdpNXyjJQrIcesIkpS70s5HS02ohpnCSpMUbotPnEUzbAcLQ+S4hwZYbkBBiTcJw==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/langs": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.5.0.tgz", + "integrity": "sha512-wwBTqwduXSz0X4v9Qa2EWeFaYJEw1clCncWjoRNQRbVDu3SPRTRWucnouYapKj3b8Q+sk/41Vbc4B5c8nuYzLA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/primitive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.5.0.tgz", + "integrity": "sha512-UM7ShlA8oz0OWxLLO8BmO9Ip6fVqdkt8yF0EH7nOCqHfrx1eEAzF0ZUVK7L+I8NEgeu1PEWSRlxaiPPeCb4iDg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/themes": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.5.0.tgz", + "integrity": "sha512-zGb87H3UBbpuI4yoh5UguB1XbU+2BDU3kflM7UfZ+Cy2hWo9lBtqjSVK20gmLY6ukYl040hAypGXMgud9vul8Q==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.5.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/types": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.5.0.tgz", + "integrity": "sha512-drtPrtD8N0DENyD2cyt6Ajy+IWsiCLgMxODwLTpvH1UsN6a9jf90tNTPjqwHvA+0Lzu9e0txk8DjfqH1p9UJRw==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "license": "ISC" + }, + "node_modules/am-i-vibing": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/am-i-vibing/-/am-i-vibing-0.5.0.tgz", + "integrity": "sha512-KLcsDhqf1XRrJmJr+9I/C0EX2K+sGrAGZFgkmd84c8TJO9zJBu+/kFInjazu1KfJWFhWDKdRWkpBzEs7s35DVA==", + "license": "MIT", + "dependencies": { + "process-ancestry": "^0.1.0" + }, + "bin": { + "am-i-vibing": "dist/cli.mjs" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/astro": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/astro/-/astro-7.3.8.tgz", + "integrity": "sha512-LHzDHSaV+YzZiR3EFndDYTLLeNeuMtP1qX1FLcCNUUHOCqTTIWPczy2UV3zpA5VqvJe5cWZolqM9Z8JFqR2i9w==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler-rs": "^0.5.1", + "@astrojs/internal-helpers": "0.12.0", + "@astrojs/markdown-satteri": "0.4.3", + "@astrojs/telemetry": "3.3.3", + "@capsizecss/unpack": "^4.0.1", + "@clack/prompts": "^1.8.1", + "@oslojs/encoding": "^1.1.0", + "am-i-vibing": "^0.5.0", + "aria-query": "^5.3.2", + "axobject-query": "^4.1.0", + "ci-info": "^4.4.0", + "clsx": "^2.1.1", + "common-ancestor-path": "^2.0.0", + "cookie": "^2.0.1", + "devalue": "^5.9.4", + "diff": "^9.0.0", + "dset": "^3.1.4", + "es-module-lexer": "^3.0.2", + "find-proc": "0.2.0", + "flattie": "^1.1.1", + "fontace": "~0.4.1", + "get-tsconfig": "5.0.0-beta.6", + "github-slugger": "^2.0.0", + "html-escaper": "3.0.3", + "http-cache-semantics": "^4.2.0", + "jsonc-parser": "^3.3.1", + "magic-string": "^1.4.2", + "magicast": "^0.5.5", + "mrmime": "^2.0.1", + "neotraverse": "^1.0.1", + "obug": "^3.0.0", + "p-limit": "^7.3.3", + "p-queue": "^9.3.3", + "package-manager-detector": "^1.8.0", + "piccolore": "^0.1.3", + "picomatch": "^4.0.7", + "rolldown": "^1.2.11", + "shiki": "^4.4.3", + "smol-toml": "^1.9.0", + "svgo": "^4.1.0", + "tinyclip": "^1.0.3", + "tinyexec": "^1.3.1", + "tinyglobby": "^0.2.17", + "ultrahtml": "^1.7.0", + "unifont": "~0.7.5", + "unstorage": "^1.17.5", + "verkit": "^0.5.0", + "vite": "^8.3.1", + "vitefu": "^1.1.3", + "xxhash-wasm": "^1.1.0", + "yargs-parser": "^22.0.0", + "zod": "^4.6.5" + }, + "bin": { + "astro": "bin/astro.mjs" + }, + "engines": { + "node": ">=22.12.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/astrodotbuild" + }, + "optionalDependencies": { + "sharp": "^0.35.4" + }, + "peerDependencies": { + "@astrojs/markdown-remark": "^7.3.0" + }, + "peerDependenciesMeta": { + "@astrojs/markdown-remark": { + "optional": true + } + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/common-ancestor-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", + "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } + }, + "node_modules/cookie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==", + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cookie-es": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", + "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", + "license": "MIT" + }, + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/css-select": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.9.4", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.9.4.tgz", + "integrity": "sha512-sPAT4pztbu6586/hrhOnMKS17IJrvg12mXiSPSS3W5qDeN2RGgvZ0diZCm31dBbnevfVmujNO3IM2wrS4Y2Rhg==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "domelementtype": "^2.3.0" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "engines": { - "node": ">=8" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/es-module-lexer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-3.0.3.tgz", + "integrity": "sha512-yWGe1O/j+almnV4hOYrmZo8u58JdnmXEMneRQAYkWtqSiT86yoMIEKF4rpqEDj52tbYl3xceBD3DQIBwcsC9Pw==", + "license": "MIT" + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" + "fast-string-truncated-width": "^3.0.2" } }, - "node_modules/autoprefixer": { - "version": "10.4.16", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", - "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "license": "MIT", "dependencies": { - "browserslist": "^4.21.10", - "caniuse-lite": "^1.0.30001538", - "fraction.js": "^4.3.6", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, + "fast-string-width": "^3.0.2" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=12.0.0" }, "peerDependencies": { - "postcss": "^8.1.0" + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "node_modules/find-proc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/find-proc/-/find-proc-0.2.0.tgz", + "integrity": "sha512-a6h2nTrgB3g5Wrn4au9Ux4kMk7IJtyF6oA8uGn+mk3weLZssUtc1cp6meHIzzuW2o1srrBAxzkmXLbqjRkgB6w==", + "license": "MIT", "engines": { - "node": ">=8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, + "node_modules/flattie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", + "integrity": "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/fontace": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/fontace/-/fontace-0.4.1.tgz", + "integrity": "sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==", + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "fontkitten": "^1.0.2" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001559", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001559.tgz", - "integrity": "sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "node_modules/fontkitten": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fontkitten/-/fontkitten-1.0.3.tgz", + "integrity": "sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==", + "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "tiny-inflate": "^1.0.3" }, "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">=20" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/get-tsconfig": { + "version": "5.0.0-beta.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.6.tgz", + "integrity": "sha512-X6fBC0pmImC70gvX2zm56go9hx0MyoGVdG0tUCkg/D+Xnh5TJsOZ7iDbOdI3PvmtrDxnu1YdDufpK2QJX1Meqw==", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "resolve-pkg-maps": "^1.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=20.20.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" }, - "node_modules/dependency-graph": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", - "engines": { - "node": ">= 0.6.0" + "node_modules/h3": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", + "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.3", + "crossws": "^0.3.5", + "defu": "^6.1.6", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.4", + "radix3": "^1.1.2", + "ufo": "^1.6.3", + "uncrypto": "^0.1.3" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", "dependencies": { - "path-type": "^4.0.0" + "@types/hast": "^3.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/electron-to-chromium": { - "version": "1.4.575", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.575.tgz", - "integrity": "sha512-kY2BGyvgAHiX899oF6xLXSIf99bAvvdPhDoJwG77nxCSyWYuRH6e9a9a3gpXBvCs6lj4dQZJkfnW2hdKWHEISg==" + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "node_modules/http-cache-semantics": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz", + "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==", + "license": "BSD-2-Clause" }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" } }, - "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "node_modules/is-docker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-4.0.0.tgz", + "integrity": "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" }, "engines": { - "node": ">=8.6.0" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dependencies": { - "reusify": "^1.0.4" + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "license": "MPL-2.0", "dependencies": { - "to-regex-range": "^5.0.1" + "detect-libc": "^2.0.3" }, "engines": { - "node": ">=8" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "*" + "node": ">= 12.0.0" }, "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14.14" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", "optional": true, "os": [ - "darwin" + "freebsd" ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-stdin": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", - "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", - "ignore": "^5.2.4", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/globby/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dependencies": { - "function-bind": "^1.1.2" - }, + "node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 0.4" + "node": "20 || >=22" } }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "engines": { - "node": ">= 4" + "node_modules/magic-string": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.3.tgz", + "integrity": "sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/magicast": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.5.tgz", + "integrity": "sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==", + "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "source-map-js": "^1.2.1" } }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "engines": { - "node": ">=0.10.0" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "engines": { - "node": ">=10" - } + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } + "node_modules/micromark-util-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.3.tgz", + "integrity": "sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=10" } }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "funding": [ { "type": "github", @@ -551,40 +2744,163 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + "node_modules/neotraverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-1.0.1.tgz", + "integrity": "sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-mock-http": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.5.tgz", + "integrity": "sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==", + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/obug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/obug/-/obug-3.0.0.tgz", + "integrity": "sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12.20.0" + } + }, + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" + } + }, + "node_modules/ohash": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.12.tgz", + "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==", + "license": "MIT" + }, + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "node_modules/p-limit": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.3.tgz", + "integrity": "sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.2.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/p-queue": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.5.tgz", + "integrity": "sha512-Lki/zhXFVmDhesBUn/yHRLW9Bte7mE7xoFHzTR8sIomV7a2z+LxYAPkGvdfidNiu4fKSfjtawixxSHcZci5QcQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.4", + "p-timeout": "^7.0.0" + }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.2.tgz", + "integrity": "sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-manager-detector": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.9.0.tgz", + "integrity": "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==", + "license": "MIT" + }, + "node_modules/piccolore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/piccolore/-/piccolore-0.1.3.tgz", + "integrity": "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==", + "license": "ISC" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -592,28 +2908,21 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "funding": [ { "type": "opencollective", @@ -630,374 +2939,815 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-cli": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-10.1.0.tgz", - "integrity": "sha512-Zu7PLORkE9YwNdvOeOVKPmWghprOtjFQU3srMUGbdz3pHJiFh7yZ4geiZFMkjMfB0mtTFR3h8RemR62rPkbOPA==", - "dependencies": { - "chokidar": "^3.3.0", - "dependency-graph": "^0.11.0", - "fs-extra": "^11.0.0", - "get-stdin": "^9.0.0", - "globby": "^13.0.0", - "picocolors": "^1.0.0", - "postcss-load-config": "^4.0.0", - "postcss-reporter": "^7.0.0", - "pretty-hrtime": "^1.0.3", - "read-cache": "^1.0.0", - "slash": "^5.0.0", - "yargs": "^17.0.0" + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-ancestry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/process-ancestry/-/process-ancestry-0.1.0.tgz", + "integrity": "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rolldown": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.13.tgz", + "integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.153.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { - "postcss": "index.js" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=14" + "node": "^20.19.0 || >=22.12.0" }, - "peerDependencies": { - "postcss": "^8.0.0" + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.13", + "@rolldown/binding-android-arm64": "1.2.13", + "@rolldown/binding-darwin-arm64": "1.2.13", + "@rolldown/binding-darwin-x64": "1.2.13", + "@rolldown/binding-freebsd-x64": "1.2.13", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.13", + "@rolldown/binding-linux-arm64-gnu": "1.2.13", + "@rolldown/binding-linux-arm64-musl": "1.2.13", + "@rolldown/binding-linux-ppc64-gnu": "1.2.13", + "@rolldown/binding-linux-s390x-gnu": "1.2.13", + "@rolldown/binding-linux-x64-gnu": "1.2.13", + "@rolldown/binding-linux-x64-musl": "1.2.13", + "@rolldown/binding-openharmony-arm64": "1.2.13", + "@rolldown/binding-win32-arm64-msvc": "1.2.13", + "@rolldown/binding-win32-x64-msvc": "1.2.13" + } + }, + "node_modules/satteri": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/satteri/-/satteri-0.10.5.tgz", + "integrity": "sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.5", + "@types/hast": "^3.0.5", + "@types/mdast": "^4.0.4", + "@types/unist": "^3.0.3" + }, + "optionalDependencies": { + "@bruits/satteri-darwin-arm64": "0.10.5", + "@bruits/satteri-darwin-x64": "0.10.5", + "@bruits/satteri-linux-arm64-gnu": "0.10.5", + "@bruits/satteri-linux-arm64-musl": "0.10.5", + "@bruits/satteri-linux-x64-gnu": "0.10.5", + "@bruits/satteri-linux-x64-musl": "0.10.5", + "@bruits/satteri-wasm32-wasi": "0.10.5", + "@bruits/satteri-win32-arm64-msvc": "0.10.5", + "@bruits/satteri-win32-x64-msvc": "0.10.5" + } + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz", + "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.5", + "@img/sharp-darwin-x64": "0.35.5", + "@img/sharp-freebsd-wasm32": "0.35.5", + "@img/sharp-libvips-darwin-arm64": "1.3.4", + "@img/sharp-libvips-darwin-x64": "1.3.4", + "@img/sharp-libvips-linux-arm": "1.3.4", + "@img/sharp-libvips-linux-arm64": "1.3.4", + "@img/sharp-libvips-linux-ppc64": "1.3.4", + "@img/sharp-libvips-linux-riscv64": "1.3.4", + "@img/sharp-libvips-linux-s390x": "1.3.4", + "@img/sharp-libvips-linux-x64": "1.3.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", + "@img/sharp-libvips-linuxmusl-x64": "1.3.4", + "@img/sharp-linux-arm": "0.35.5", + "@img/sharp-linux-arm64": "0.35.5", + "@img/sharp-linux-ppc64": "0.35.5", + "@img/sharp-linux-riscv64": "0.35.5", + "@img/sharp-linux-s390x": "0.35.5", + "@img/sharp-linux-x64": "0.35.5", + "@img/sharp-linuxmusl-arm64": "0.35.5", + "@img/sharp-linuxmusl-x64": "0.35.5", + "@img/sharp-webcontainers-wasm32": "0.35.5", + "@img/sharp-win32-arm64": "0.35.5", + "@img/sharp-win32-ia32": "0.35.5", + "@img/sharp-win32-x64": "0.35.5" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/shiki": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.5.0.tgz", + "integrity": "sha512-OcRW72ngQvc+MSVWBRIovC/BTW589iUE/Vxav7VeM4RcY9MUjqB+IR6ILG1k9nuW6LiG/nct9uma4/MBtnZbmQ==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.5.0", + "@shikijs/engine-javascript": "4.5.0", + "@shikijs/engine-oniguruma": "4.5.0", + "@shikijs/langs": "4.5.0", + "@shikijs/themes": "4.5.0", + "@shikijs/types": "4.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/smol-toml": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.1.tgz", + "integrity": "sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" } }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "license": "BSD-3-Clause", "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" + "node": ">=0.10.0" } }, - "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" - }, - "engines": { - "node": ">= 14" + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/postcss-reporter": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.5.tgz", - "integrity": "sha512-glWg7VZBilooZGOFPhN9msJ3FQs19Hie7l5a/eE6WglzYqVeH3ong3ShFcp9kDWJT1g2Y/wd59cocf9XxBtkWA==", + "node_modules/svgo": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.1.0.tgz", + "integrity": "sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==", + "license": "MIT", "dependencies": { - "picocolors": "^1.0.0", - "thenby": "^1.3.4" + "commander": "^11.1.0", + "css-select": "^6.0.0", + "css-tree": "^3.0.1", + "css-what": "^7.0.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "1.6.1" + }, + "bin": { + "svgo": "bin/svgo.js" }, "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "url": "https://opencollective.com/svgo" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" }, - "node_modules/pretty-hrtime": { + "node_modules/tinyclip": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-1.0.3.tgz", + "integrity": "sha512-nTv2raKFMzGG6JJp0lpNDsRPdfFE6UHlu2rVEjXo8vkx1ZS3LW2CVXqIaLu8xZlu+6tbFs9V58Qc/Jmk/Ii7wA==", + "license": "MIT", "engines": { - "node": ">= 0.8" + "node": "^16.14.0 || >= 17.3.0" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dependencies": { - "pify": "^2.3.0" + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "license": "MIT", + "engines": { + "node": ">=18" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" + "fdir": "^6.5.0", + "picomatch": "^4.0.4" }, "engines": { - "node": ">=8.10.0" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "license": "MIT" + }, + "node_modules/ultrahtml": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.7.0.tgz", + "integrity": "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==", + "license": "MIT" + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/undici": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", + "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=22.19.0" } }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node_modules/unifont": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.5.tgz", + "integrity": "sha512-ULe/Cs+ZIsq+dcFofNkhqielCrUJnb5mr+Yc4EBM2VlL+6OZR6+cjtI2mT1bJvRBrVncqHAbLURxmPLcCXzWMg==", + "license": "MIT", + "dependencies": { + "css-tree": "^3.1.0", + "ohash": "^2.0.11", + "undici": "^8.0.0" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", "dependencies": { - "queue-microtask": "^1.2.2" + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "engines": { - "node": ">=14.16" + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/unstorage": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", + "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^5.0.0", + "destr": "^2.0.5", + "h3": "^1.15.10", + "lru-cache": "^11.2.7", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.3" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6 || ^7 || ^8", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1 || ^2 || ^3", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/verkit": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.5.0.tgz", + "integrity": "sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==", + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=18.12.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/thenby": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", - "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" }, - "engines": { - "node": ">=8.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "engines": { - "node": ">= 10.0.0" + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/vite": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.4.tgz", + "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==", + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.29", + "rolldown": "~1.2.12", + "tinyglobby": "^0.2.17" }, "bin": { - "update-browserslist-db": "cli.js" + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "browserslist": ">= 4.21.0" + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "node_modules/vitefu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/xxhash-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" }, "engines": { - "node": ">=10" + "node": ">= 14.6" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/eemeli" } }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", "engines": { - "node": ">=10" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", "engines": { - "node": ">= 14" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" + "node_modules/zod": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.6.tgz", + "integrity": "sha512-4UmzQUF5fxvfcYHlbjBmejU+w+hbDnWFx4aS8kBx7nPBHcO2SqPbpAG8snbdg+Xse4pRefR98hgjFgIMCI/UhA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } } } diff --git a/package.json b/package.json @@ -1,11 +1,15 @@ { - "dependencies": { - "autoprefixer": "^10.4.16", - "postcss": "^8.4.49", - "postcss-cli": "^10.1.0", - "postcss-import": "^15.1.0" + "name": "personal-site", + "type": "module", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" }, - "engines": { - "node": "18.x" + "dependencies": { + "astro": "^7.3.8" } } diff --git a/postcss.config.js b/postcss.config.js @@ -1,3 +0,0 @@ -module.exports = { - plugins: [require("postcss-import")], -}; diff --git a/public/favicon.svg b/public/favicon.svg @@ -0,0 +1,12 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> + <style> + rect { fill: #000; } + path { stroke: #f3f1ea; } + @media (prefers-color-scheme: light) { + rect { fill: #fff; } + path { stroke: #111; } + } + </style> + <rect width="32" height="32" rx="6"/> + <path d="M2 22H4V10H10V22H12V10H18V22H21V10H27V22H30" fill="none" stroke-width="2.5" stroke-linejoin="miter" stroke-linecap="square"/> +</svg> diff --git a/public/fonts/cm-italic.woff2 b/public/fonts/cm-italic.woff2 Binary files differ. diff --git a/public/fonts/cm-regular.woff2 b/public/fonts/cm-regular.woff2 Binary files differ. diff --git a/public/fonts/jetbrains-mono-regular.woff2 b/public/fonts/jetbrains-mono-regular.woff2 Binary files differ. diff --git a/public/fonts/jetbrains-mono-semibold.woff2 b/public/fonts/jetbrains-mono-semibold.woff2 Binary files differ. diff --git a/static/michaelneuper.gpg b/public/michaelneuper.gpg Binary files differ. diff --git a/public/notes-to-self.txt b/public/notes-to-self.txt @@ -0,0 +1,6 @@ +Note to self: robots.txt asks well-behaved crawlers to stay away from a path. +It does nothing to stop anyone else from reading it. + +flag{robots_txt_is_not_access_control} + +Submit it with M-x submit-flag. diff --git a/public/robots.txt b/public/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: / +Disallow: /notes-to-self.txt diff --git a/src/pages/index.astro b/src/pages/index.astro @@ -0,0 +1,352 @@ +--- +import "../styles/style.css"; +--- +<!doctype html> +<html lang="en" data-theme="doom-gruvbox"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> +<title>Michael Neuper</title> +<meta name="description" content="Computer science student at Stellenbosch University. Low-level software, electronics, a little security, and a lot of Emacs."> +<link rel="icon" href="/favicon.svg" type="image/svg+xml"> +<link rel="preload" href="/fonts/jetbrains-mono-regular.woff2" as="font" type="font/woff2" crossorigin> +<link rel="preload" href="/fonts/cm-regular.woff2" as="font" type="font/woff2" crossorigin> +{/* is:inline: Astro ships this script as written instead of bundling it, so it still runs before first paint. */} +<script is:inline> + // Pick the theme before first paint so there is no flash. Keep this list in sync with src/scripts/themes.js. + try { + var t = localStorage.getItem("theme"); + var known = /^(doom-gruvbox|doom-gruvbox-light|doom-one|atom-one-dark|modus-vivendi|modus-operandi|doom-dracula|doom-nord|catppuccin|doom-tokyo-night|doom-solarized-light)$/; + if (!known.test(t || "")) t = matchMedia("(prefers-color-scheme: light)").matches ? "doom-gruvbox-light" : ""; + if (t) document.documentElement.dataset.theme = t; + } catch (e) {} + // Hide the name until src/scripts/decode.js has split it into letters, so it never flashes whole first. + // CSS shows it anyway after a moment in case the script never runs. + try { + if (!matchMedia("(prefers-reduced-motion: reduce)").matches && (!location.hash || location.hash === "#top")) { + document.documentElement.classList.add("boot"); + } + } catch (e) {} +</script> +<script src="../scripts/main.js"></script> +</head> +<!-- Reading the source? Good instinct. flag{view_source_is_recon} --> +<body> +<a class="skip" href="#about">Skip to content</a> + +<header class="top"> + <a class="brand" href="#top" aria-label="Michael Neuper, back to top"> + <svg class="logo" viewBox="0 0 32 16" aria-hidden="true"><path d="M1 14H3V2H9V14H11V2H17V14H20V2H26V14H31"/></svg> + <span>michael neuper</span> + </a> + <nav class="nav" id="nav" aria-label="Sections"> + <a href="#top">pinout</a> + <a href="#about">about</a> + <a href="#projects">projects</a> + <a href="#posts">posts</a> + <a href="#contact">contact</a> + </nav> + <button class="theme-key" type="button" title="SPC h t">load-theme</button> + <button class="menu-key" type="button" aria-expanded="false" aria-controls="nav">menu</button> +</header> + +<main> + + <!-- ─────────────────────────── landing ─────────────────────────── --> + <section class="hero" id="top" data-file="mn-2026.kicad_sym" data-mode="Lisp Data" aria-labelledby="hero-name"> + <div class="hero-id"> + <h1 class="hero-name" id="hero-name">Michael Neuper</h1> + <p class="hero-lede">Computer science student at Stellenbosch University. I like low-level software, electronics and the maths underneath both, and I do almost all of it in Emacs.</p> + <ul class="legend" aria-label="Colour key used across the site"> + <li data-cat="hw">hardware</li> + <li data-cat="sw">software</li> + <li data-cat="math">maths</li> + <li data-cat="sec">security</li> + </ul> + </div> + + <div class="hero-chip"> + <figure class="pinout"> + <div class="chip-wrap"><!-- built from the list below --></div> + <div class="pin-readout" aria-live="polite"><p class="dim">Point at a pin to read its function.</p></div> + <figcaption>Figure 1. MN-2026, DIP-16 package, top view.</figcaption> + <!-- Edit the pins here. data-cat: hw, sw, math or sec. "M-x some-command" in a description becomes a button. --> + <ol class="pin-list"> + <li data-name="VCC" data-type="power">Supply input: coffee. Top it up with M-x coffee-refill.</li> + <li data-name="C" data-type="I/O" data-cat="sw">Most of what I write, from a compiler to terminal toys like a spinning cube and the Game of Life.</li> + <li data-name="ASM" data-type="I/O" data-cat="sw">Assembly, starting with the 8-bit computer’s eleven instructions.</li> + <li data-name="JVM" data-type="output" data-cat="sw">The target of my compiler, so I read javap output for fun.</li> + <li data-name="LINUX" data-type="I/O" data-cat="sw">Daily driver. Dotfiles on GitHub, and posts on packaging formats and turning a window manager into a desktop.</li> + <li data-name="TTL" data-type="I/O" data-cat="hw">74-series logic. The 8-bit computer is dozens of these chips on breadboards.</li> + <li data-name="SEC" data-type="input" data-cat="sec">Security: a consulting internship, a web application assessment, and the habit of asking how things break.</li> + <li data-name="GND" data-type="power">Return path. Sleep, when the config is finished (it is never finished).</li> + <li data-name="RST" data-type="input">Active low. Asserted by a walk without a laptop.</li> + <li data-name="TA" data-type="output" data-cat="hw">Teaching assistant for introductory computer science and computer architecture.</li> + <li data-name="TEX" data-type="output" data-cat="math">Notes, templates and maths typeset in LaTeX, usually from Emacs.</li> + <li data-name="ORG" data-type="I/O" data-cat="sw">Org mode and org-roam for notes, literate configs, and replacing Jupyter.</li> + <li data-name="EMACS" data-type="I/O" data-cat="sw">Doom Emacs, with a literate config of over a thousand lines. Location: ~/.config/emacs/.</li> + <li data-name="MATH" data-type="input" data-cat="math">Project Euler, discrete maths, and modelling things in Python.</li> + <li data-name="CAN" data-type="I/O">CAN bus, the network inside every car. Cars are my one interest that isn’t a computer, mostly.</li> + <li data-name="NC" data-type="no connect">Reserved for the next obsession.</li> + </ol> + </figure> + </div> + </section> + + <!-- ───────────────────────────── datasheet ───────────────────────────── --> + <section class="sec" id="about" data-file="whoami.pdf" data-mode="PDFView"> + <p class="winbar"><span class="file">whoami.pdf</span><span class="rule" aria-hidden="true"></span><span class="meta">revised June 2026</span></p> + + <header class="ds-head"> + <p class="ds-part">MN-2026</p> + <h2 class="ds-title">About</h2> + </header> + + <p class="prose ds-desc">I study computer science at Stellenbosch University and have been a teaching assistant for introductory computer science and computer architecture. I like understanding things all the way down, from a line of C to the gates that run it, and I’m happiest when that ends in something I built: a scheduler, a compiler, or a computer on breadboards. Away from that I’m a linguistics nerd and a free-software advocate.</p> + + <!-- Experience, as the one-line git log that would print it: "<date> - (refs) <subject> <author>". + data-lanes colours each graph character by branch: m main, u undergrad, t teaching-assistant, + b bbd-software, i mwr-internship (the colours are set in src/styles/style.css). data-cont is the graph that continues below a commit, and a + .gl-desc becomes its expandable description. data-branch colours the date; data-tip makes the + * bold for a branch that's still going; data-today swaps in the current month when the page loads. + Without JavaScript this shows as plain text. --> + <h3 class="ds-h gitlog-cmd"><span class="prompt" aria-hidden="true">$ </span>git log --graph --all --color \ + --date=format:'%Y-%m' \ + --format='%ad -%C(auto)%d%C(reset) %s %C(blue)&lt;%an&gt;%C(reset)'</h3> + <div class="gitlog" aria-label="Experience, newest first"> +<div class="gl-line" data-lanes=" b u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="m" data-tip data-today>* | | | 2026-10 - (HEAD -&gt; main)</div> +<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="b" data-tip>| * | | 2026-06 - (bbd-software) Vac Week 2026 &lt;BBD Software&gt;<div class="gl-desc">Built an online foosball game: players steer the rods by +tilting their phones, using the gyroscope. Designed and +presented as a full-stack web app with a small team.</div></div> +<div class="gl-line" data-lanes="m b u " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="t" data-tip>| | | * 2026-06 - (teaching-assistant) Teach computer architecture as a TA &lt;Stellenbosch University&gt;</div> +<div class="gl-line" data-lanes="m b u t">| | | |</div> +<div class="gl-line" data-lanes="m b u " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="t">| | | * 2026-02 - Teach introductory computer science as a TA &lt;Stellenbosch University&gt;</div> +<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="b">| * | | 2025-06 - Vac Week 2025 &lt;BBD Software&gt;<div class="gl-desc">Built an online laser tag game: computer vision finds players +in the camera feed and tags them. Designed and presented as a +full-stack web app with a small team.</div></div> +<div class="gl-line" data-lanes="m b u t">| | | |</div> +<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m b u t " data-branch="b">| * | | 2025-01 - Join BBD Software as a bursar &lt;BBD Software&gt;<div class="gl-desc">Part of the Bursary &amp; Beyond Programme, which includes the +yearly Vac Weeks.</div></div> +<div class="gl-line" data-lanes="mb u t">|/ | |</div> +<div class="gl-line" data-lanes="m u t">| | |</div> +<div class="gl-line" data-lanes="mi u t">|\ | |</div> +<div class="gl-line" data-lanes="m u t " data-cont="| | | | " data-cont-lanes="m i u t " data-branch="i">| * | | 2024-12 - (mwr-internship) Complete a cybersecurity consultant internship &lt;MWR CyberSec&gt;<div class="gl-desc">- Completed cybersecurity training with labs on TryHackMe. +- Assessed a web application end to end, documenting each + vulnerability with its risk and how to fix it. +- Wrote a professional report and presented it, client-style, + to a panel of industry professionals.</div></div> +<div class="gl-line" data-lanes="mi u t">|/ | |</div> +<div class="gl-line" data-lanes="m ut">| |/</div> +<div class="gl-line" data-lanes="m " data-cont="| | " data-cont-lanes="m u " data-branch="u" data-tip>| * 2024-01 - (undergrad) Start an undergraduate degree in computer science &lt;Stellenbosch University&gt;</div> +<div class="gl-line" data-lanes="m u">| /</div> +<div class="gl-line" data-lanes="mu">|/</div> +<div class="gl-line" data-lanes=" " data-cont=" " data-cont-lanes=" " data-branch="m">* 2005-06 - Initial commit &lt;Michael Neuper&gt;</div> + </div> + <p class="gitlog-hint dim">Click an underlined commit message to read the rest of it.</p> + + </section> + + <!-- ──────────────────────────── memory map ──────────────────────────── --> + <section class="sec" id="projects" data-file="memory.map" data-mode="Fundamental"> + <p class="winbar"><span class="file">memory.map</span><span class="rule" aria-hidden="true"></span><span class="meta" data-mm="meta"></span></p> + <h2 class="h2">Projects</h2> + <p class="lede">Laid out like a linker map: each project is a region in memory holding its one-line summary, and the hexdump shows exactly those bytes. Select one to read about it and try it out.</p> + + <div class="mm"> + <div class="mm-bar" aria-hidden="true"></div> + <div class="mm-cols"> + <div class="mm-table"> + <p class="mm-head" aria-hidden="true"><span>origin</span><span>length</span><span>name</span><span>source</span></p> + <!-- Edit projects here. data-cat: hw, sw, math or sec. data-src: shown in the source column. + data-demo: computer, scheduler, bytecode, othello or rbudp (optional); data-wide gives the + demo the full width under the list. --> + <ol class="mm-list"> + <li class="proj" data-cat="hw" data-src="built" data-demo="computer" data-wide> + <h3 class="proj-name">8-bit-computer</h3> + <p class="proj-sum">Ben Eater's 8-bit breadboard computer, built chip by chip.</p> + <div class="proj-body"> + <p>My most recent finished project: a programmable computer on breadboards, built from 74-series logic chips following Ben Eater’s video series. It has 16 bytes of RAM, an 8-bit bus, and microcode in EEPROMs that drives sixteen control lines.</p> + <p>The simulation below runs the same instruction set and microcode, so you can step through a program one control word at a time.</p> + <p class="proj-stack">74HC logic, EEPROMs, breadboards, a lot of jumper wire</p> + <p class="proj-links"><a href="https://eater.net/8bit">Ben Eater’s series</a></p> + </div> + </li> + <li class="proj" data-cat="sw" data-src="private" data-demo="scheduler"> + <h3 class="proj-name">os-scheduler</h3> + <p class="proj-sum">A multicore operating system scheduler, for a concurrency course.</p> + <div class="proj-body"> + <p>The part of an operating system that decides which process runs on which core, and for how long. I wrote it for a concurrency course, so the source stays private, but the idea fits in a small simulation: processes arrive, wait in a shared ready queue, and get dispatched to cores under first come, first served, round robin or preemptive priority scheduling.</p> + <p class="proj-links dim">Source private (concurrency coursework)</p> + </div> + </li> + <li class="proj" data-cat="sw" data-src="private" data-demo="othello"> + <h3 class="proj-name">othello-mcts</h3> + <p class="proj-sum">An Othello player in C that runs Monte Carlo tree search across MPI processes.</p> + <div class="proj-body"> + <p>The player picks a move by running thousands of random games from the current position and keeping the move that was explored most, using UCT to balance trying new moves against improving promising ones. Each move gets one second.</p> + <p>The project was for a concurrency course, so the next step was to parallelise it with MPI, which I did in three ways: independent search trees combined at the end with <code>MPI_Allreduce</code>, trees that share their statistics every so often, and the same sharing done asynchronously with non-blocking sends. In ten-game matches on four processes, each version beat the one before it, except the asynchronous version, which won half its games against the synchronous one.</p> + <p>You can play a serial version, rewritten in JavaScript for this page, below. While it thinks, each legal move is shaded by how often the search tried it.</p> + <p class="proj-stack">C, MPI, Docker</p> + <p class="proj-links dim">Source private (concurrency coursework)</p> + </div> + </li> + <li class="proj" data-cat="sw" data-src="private" data-demo="bytecode"> + <h3 class="proj-name">jvm-compiler</h3> + <p class="proj-sum">A compiler in C for a custom language that targets the JVM.</p> + <div class="proj-body"> + <p>I wrote it in C for a computer architecture course. It reads a small custom programming language and produces bytecode the Java virtual machine can run. The source stays private, but the last stage is easy to show: the JVM is a stack machine, so an expression compiles to instructions that push and pop an operand stack. Type one below to see the bytecode and run it.</p> + <p class="proj-stack">C, JVM bytecode</p> + <p class="proj-links dim">Source private (computer architecture coursework)</p> + </div> + </li> + <li class="proj" data-cat="sw" data-src="private" data-demo="rbudp"> + <h3 class="proj-name">chat-voip-p2p</h3> + <p class="proj-sum">Four networking projects in Java: chat, fast UDP file transfer, voice calls and P2P sharing.</p> + <div class="proj-body"> + <p>A series of networking projects built with my group for a university course:</p> + <ul> + <li>A chat server that handles many clients at once, with a JavaFX client, load-tested with dozens of simultaneous users.</li> + <li>File transfer over Reliable Blast UDP, measured against TCP across packet sizes, loss rates and file sizes from 1 to 100&nbsp;MB.</li> + <li>The chat extended with voice calls and group calls streamed over UDP, plus voice notes.</li> + <li>Peer-to-peer file sharing: a server brokers searches, then peers send files to each other directly over TCP, encrypted with AES-GCM keys exchanged using RSA, with pause and resume. We tested it across four machines over Tailscale.</li> + </ul> + <p>Below is the RBUDP transfer in miniature: blast every packet over UDP, ask over TCP which ones arrived, and resend the gaps.</p> + <p class="proj-stack">Java, JavaFX, TCP and UDP sockets, Java Sound, RSA, AES-GCM</p> + <p class="proj-links dim">Source private (coursework, group project)</p> + </div> + </li> + </ol> + </div> + <article class="mm-detail" aria-live="polite"></article> + </div> + </div> + </section> + + <!-- ────────────────────────────── posts ────────────────────────────── --> + <section class="sec" id="posts" data-file="posts.org" data-mode="Org"> + <p class="winbar"><span class="file">posts.org</span><span class="rule" aria-hidden="true"></span><span class="meta" data-org="meta"></span></p> + <p class="org-p">From my blog at michaelneuper.com, shown the way I read them. <kbd>TAB</kbd> on a heading folds it, <kbd>S-TAB</kbd> cycles the whole buffer, and clicking a heading’s stars does the same.</p> + + <!-- Edit posts here. data-tags are space separated; each tag gets its own colour (see TAG_COLORS in src/scripts/org.js). --> + <ol class="posts"> + <li data-date="2024-11-22" data-tags="emacs org" data-cat="sw"><a href="https://michaelneuper.com/posts/how-i-use-org-roam-to-takes-notes-for-cs/">How I Use Org-Roam to Take Notes for CS</a></li> + <li data-date="2023-11-15" data-tags="emacs latex" data-cat="math"><a href="https://michaelneuper.com/posts/efficient-latex-editing-with-emacs/">Efficient LaTeX Editing With Emacs</a></li> + <li data-date="2023-11-12" data-tags="python maths" data-cat="math"><a href="https://michaelneuper.com/posts/modelling-population-growth-in-python/">Modelling Population Growth in Python</a></li> + <li data-date="2023-02-27" data-tags="emacs org" data-cat="sw"><a href="https://michaelneuper.com/posts/replace-jupyter-notebook-with-emacs-org-mode/">Replace Jupyter Notebook With Emacs Org Mode</a></li> + <li data-date="2023-01-09" data-tags="linux" data-cat="sw"><a href="https://michaelneuper.com/posts/what-linux-packaging-format-to-use/">Which Linux Packaging Format Should You Use?</a></li> + <li data-date="2022-12-16" data-tags="linux security" data-cat="sec"><a href="https://michaelneuper.com/posts/enable-monitor-mode-on-tp-link/">Enable Monitor Mode on TP-Link TL-WN722N</a></li> + <li data-date="2022-12-14" data-tags="security c" data-cat="sec"><a href="https://michaelneuper.com/posts/buffer-overflow/">Buffer Overflows: Keep Your Code Safe</a></li> + <li data-date="2022-12-11" data-tags="linux" data-cat="sw"><a href="https://michaelneuper.com/posts/turning-a-window-manager-into-a-desktop-environment/">A Guide to Building Your Own Desktop Environment</a></li> + <li data-date="2022-12-03" data-tags="web" data-cat="sw"><a href="https://michaelneuper.com/posts/how-to-create-your-own-website/">How to Create Your Own Static Website</a></li> + </ol> + </section> + + <!-- ───────────────────────────── contact ───────────────────────────── --> + <section class="sec" id="contact" data-file="*unsent mail*" data-mode="Message"> + <p class="winbar"><span class="file">*unsent mail*</span><span class="rule" aria-hidden="true"></span><span class="meta">draft</span></p> + <h2 class="h2">Say hello</h2> + <p class="lede">Email works best. For anything private, encrypt it with my GPG key below.</p> + + <div class="contact"> + <!-- The address is only ever put together in JavaScript, so scrapers reading this HTML don't see it. + The link and the copy button read data-user and data-host. --> + <a class="mail" href="#contact" data-user="michael" data-host="michaelneuper.com">michael<span class="at"> &lt;at&gt; </span>michaelneuper.com</a> + <button type="button" class="btn" data-email="copy">copy address</button> + </div> + + <div class="contact-grid"> + <div class="gpg"> + <h3 class="ds-h">Encrypt it</h3> + <p class="gpg-fp"><span class="dim">fingerprint</span><code>4E7B F800 0D86 182D F484 5C37 508B CF84 373C 8930</code></p> + <div class="gpg-cmd"> + <pre><code>curl -sL https://michaelneuper.com/michaelneuper.gpg | gpg --import</code></pre> + <button type="button" class="btn" data-copy=".gpg-cmd code">copy</button> + </div> + </div> + <div> + <h3 class="ds-h">Elsewhere</h3> + <ul class="elsewhere"> + <li><a href="https://github.com/michaelneuper">GitHub</a></li> + <li><a href="https://www.linkedin.com/in/michaelneuper/">LinkedIn</a></li> + <li><a href="https://michaelneuper.com">michaelneuper.com</a></li> + <li><a href="https://buymeacoffee.com/michaelneuper" target="_blank" rel="noopener">Buy me a coffee</a></li> + </ul> + </div> + </div> + + <div class="ctf"> + <h3 class="ds-h">Capture the flag</h3> + <p>Three flags are hidden on this site, the kind you would find in a beginner CTF. They look like <code>{"flag{…}"}</code>. Found one? Run <kbd>M-x</kbd> <code>submit-flag</code>, or use the button.</p> + <p class="ctf-row"><button type="button" class="btn" data-ctf="submit">submit a flag</button><span class="ctf-progress" aria-live="polite">0 of 3 found</span></p> + </div> + </section> + + <footer class="foot"> + <p>Made with HTML, CSS, JavaScript and Emacs, without a framework, a build step or cookies.</p> + <p class="dim">Press <kbd>SPC</kbd> for commands or <kbd>M-x</kbd> to run one by name.</p> + </footer> +</main> + +<!-- ───────────────────────── coffee, modeline and minibuffer ───────────────────────── --> +<div class="coffee" hidden role="dialog" aria-label="Coffee refill"> + <pre class="mug" aria-hidden="true"></pre> + <div class="coffee-info"> + <p class="winbar"><span class="file">*coffee*</span><span class="rule" aria-hidden="true"></span><span class="meta">q to close</span></p> + <p class="vcc"><span class="dim">VCC</span><span class="vbar" aria-hidden="true"></span><span class="volts">2.6 V</span></p> + <p class="coffee-msg" aria-live="polite">brewing…</p> + <p class="coffee-links"><a href="https://buymeacoffee.com/michaelneuper" target="_blank" rel="noopener">That one was simulated. Buy me an actual coffee</a></p> + </div> + <button type="button" class="coffee-close" aria-label="Close">×</button> +</div> +<div class="which-key" hidden aria-live="polite"></div> +<div class="frame-bottom"> + <div class="modeline"> + <span class="ml-evil" title="evil state">&lt;N&gt;</span> + <span class="ml-buf">sap-1.asm</span> + <span class="ml-pos" aria-hidden="true">1:0</span> + <span class="ml-pct" aria-hidden="true">Top</span> + <span class="ml-spacer"></span> + <span class="ml-misc" aria-live="polite"></span> + <span class="ml-flags" aria-hidden="true"></span> + <span class="ml-mode">Asm</span> + <span class="ml-enc" aria-hidden="true">LF UTF-8</span> + <span class="ml-vc" aria-hidden="true">master</span> + <span class="ml-time" aria-hidden="true"></span> + </div> + <div class="mini" hidden> + <form class="mini-prompt" autocomplete="off"> + <label><span class="mini-count"></span><span class="mini-ps"></span><input type="text" spellcheck="false" autocapitalize="off" role="combobox" aria-expanded="true" aria-controls="mini-list" aria-autocomplete="list"></label> + </form> + <ul class="mini-list" id="mini-list" role="listbox"></ul> + </div> + <div class="echo" role="status"></div> +</div> + +<dialog class="help" aria-labelledby="help-title"> + <p class="winbar"><span class="file" id="help-title">*Help*</span><span class="rule" aria-hidden="true"></span><span class="meta">q or esc to close</span></p> + <div class="help-cols"> + <div> + <h3>Keys</h3> + <dl> + <div><dt><kbd>SPC</kbd></dt><dd>leader key: shows every command</dd></div> + <div><dt><kbd>M-x</kbd></dt><dd>run a command by name (Alt+x or Option+x)</dd></div> + <div><dt><kbd>SPC h t</kbd></dt><dd>load a theme, with live preview</dd></div> + <div><dt><kbd>:</kbd></dt><dd>evil ex commands, like <code>:q</code></dd></div> + <div><dt><kbd>C-g</kbd></dt><dd>cancel (so does <kbd>esc</kbd>)</dd></div> + </dl> + </div> + <div> + <h3>On this page</h3> + <dl> + <div><dt><kbd>c</kbd> <kbd>n</kbd> <kbd>r</kbd></dt><dd>computer: run or pause, step, reset</dd></div> + <div><dt><kbd>TAB</kbd></dt><dd>fold the Org heading under focus</dd></div> + <div><dt><kbd>S-TAB</kbd></dt><dd>cycle the whole Org buffer</dd></div> + <div><dt><code>coffee-refill</code></dt><dd>top up VCC and overclock the computer</dd></div> + <div><dt><code>submit-flag</code></dt><dd>check a CTF flag</dd></div> + </dl> + </div> + </div> + <form method="dialog"><button class="btn" type="submit">close</button></form> +</dialog> +</body> +</html> diff --git a/src/scripts/coffee.js b/src/scripts/coffee.js @@ -0,0 +1,148 @@ +// M-x coffee-refill: my GitHub bio, made to do something. A mug fills while +// VCC (the chip's coffee supply pin) climbs back to 5 V, then the 8-bit +// computer in Projects runs at four times its clock for 30 seconds. + +import { $, emit, reducedMotion, isTyping } from "./util.js"; +import { defcommand, message } from "./shell.js"; +import { showComputer } from "./computer.js"; + +const ROWS = 5; +const WIDTH = 10; +const V_LOW = 2.6; +const V_FULL = 5.0; +const BOOST = { factor: 4, seconds: 30 }; +const STEAM = [ + [" ( ) ( ", " ) ( ) "], + [" ) ( ) ", " ( ) ( "], +]; + +const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); + +function mug(level, frame) { + const filled = Math.round(level * ROWS); + const row = (i) => { + const fromBottom = ROWS - 1 - i; + if (fromBottom >= filled) return " ".repeat(WIDTH); + const top = fromBottom === filled - 1; + return `<span class="${top ? "crema" : "brew"}">${(top ? "~" : "▒").repeat(WIDTH)}</span>`; + }; + const steam = filled ? STEAM[frame % 2] : ["", ""]; + const handle = ["|--.", "| |", "| |", "|--'", "| "]; + return [ + `<span class="steam">${esc(steam[0])}</span>`, + `<span class="steam">${esc(steam[1])}</span>`, + " .----------.", + ...Array.from({ length: ROWS }, (_, i) => ` |${row(i)}${handle[i]}`), + " '----------'", + ].join("\n"); +} + +function cupsToday(increment = false) { + const key = `coffee:${new Date().toISOString().slice(0, 10)}`; + let n = 0; + try { + n = Number(localStorage.getItem(key)) || 0; + if (increment) localStorage.setItem(key, String(++n)); + } catch { + if (increment) n = 1; + } + return n; +} + +export function initCoffee() { + const panel = $(".coffee"); + if (!panel) return; + const pre = $(".mug", panel); + const bar = $(".vbar", panel); + const volts = $(".volts", panel); + const msg = $(".coffee-msg", panel); + const links = $(".coffee-links", panel); + const closeBtn = $(".coffee-close", panel); + + const watch = document.createElement("button"); + watch.type = "button"; + watch.className = "linkish"; + watch.textContent = "watch the computer"; + watch.hidden = true; + watch.addEventListener("click", () => showComputer()); + links.append(" ", watch); + + let raf = 0; + let steamTimer = 0; + let returnFocus = null; + + const meter = (v, over = false) => { + const cells = 12; + const n = Math.max(0, Math.min(cells, Math.round(((v - V_LOW) / (V_FULL - V_LOW)) * cells))); + bar.textContent = `▕${"█".repeat(n)}${"░".repeat(cells - n)}▏`; + volts.textContent = `${v.toFixed(1)} V`; + panel.classList.toggle("is-over", over); + }; + + function close() { + if (panel.hidden) return; + cancelAnimationFrame(raf); + clearInterval(steamTimer); + panel.hidden = true; + if (returnFocus && document.contains(returnFocus)) returnFocus.focus({ preventScroll: true }); + } + + function refill() { + cancelAnimationFrame(raf); + clearInterval(steamTimer); + returnFocus = document.activeElement; + panel.hidden = false; + watch.hidden = true; + msg.textContent = "brewing…"; + closeBtn.focus({ preventScroll: true }); + + const finish = () => { + const n = cupsToday(true); + let frame = 0; + steamTimer = setInterval(() => { pre.innerHTML = mug(1, ++frame); }, 450); + pre.innerHTML = mug(1, 0); + if (n > 5) { + meter(5.6, true); + msg.textContent = `Cup ${n} today. Absolute maximum rating exceeded: stresses beyond it may cause permanent damage, so no overclock this time. Have some water.`; + message("VCC above absolute maximum rating", "error"); + return; + } + meter(V_FULL); + const note = n === 1 ? "VCC is back to 5.0 V." + : n <= 3 ? `Cup ${n} today, within the typical range.` + : n === 4 ? "Cup 4 today, above typical." + : "Cup 5 today: that’s the absolute maximum rating."; + msg.textContent = `${note} The 8-bit computer in Projects now runs at ${BOOST.factor}× clock for ${BOOST.seconds} seconds.`; + watch.hidden = false; + emit("caffeine", BOOST); + message(`Refilled. VCC 5.0 V, ${BOOST.factor}× clock for ${BOOST.seconds}s`, "ok"); + }; + + if (reducedMotion.matches) return finish(); + const t0 = performance.now(); + const step = (now) => { + const t = Math.min(1, (now - t0) / 2400); + const e = 1 - Math.pow(1 - t, 2); + pre.innerHTML = mug(e, Math.floor(now / 450)); + meter(V_LOW + (V_FULL - V_LOW) * e); + if (t < 1) raf = requestAnimationFrame(step); + else finish(); + }; + meter(V_LOW); + raf = requestAnimationFrame(step); + } + + closeBtn.addEventListener("click", close); + addEventListener("keydown", (e) => { + if (panel.hidden || e.metaKey || e.altKey || isTyping(e)) return; + if (e.key === "q" || e.key === "Escape" || (e.ctrlKey && e.key === "g")) { + e.preventDefault(); + e.stopPropagation(); + close(); + } + }, true); + + defcommand("coffee-refill", refill, { doc: "Top up VCC and overclock the computer for a while", key: "SPC r" }); + pre.innerHTML = mug(0, 0); + meter(V_LOW); +} diff --git a/src/scripts/computer.js b/src/scripts/computer.js @@ -0,0 +1,608 @@ +// Ben Eater's 8-bit breadboard computer, simulated one clock cycle at a time. +// +// Same architecture as the build: a 4-bit address space with 16 bytes of RAM, +// an 8-bit bus, A and B registers, an adder/subtractor, an output register on +// a 7-segment display, carry and zero flags, and microcode that drives sixteen +// control lines over five steps per instruction. + +import { $, $$, hex, reducedMotion, onFrame, isTyping, on, emit } from "./util.js"; +import { defcommand, message, completingRead, setSegment } from "./shell.js"; + +// Control lines, in the order the control-word LEDs show them. +const LINES = ["HLT", "MI", "RI", "RO", "IO", "II", "AI", "AO", "EO", "SU", "BI", "OI", "CE", "CO", "J", "FI"]; +const L = Object.fromEntries(LINES.map((n, i) => [n, 1 << (15 - i)])); +// How the lines are printed on the board: the sum-out line is ΣO, as on the build. +const LABEL = { EO: "ΣO" }; + +const OPS = { 0: "NOP", 1: "LDA", 2: "ADD", 3: "SUB", 4: "STA", 5: "LDI", 6: "JMP", 7: "JC", 8: "JZ", 14: "OUT", 15: "HLT" }; +const CODE = Object.fromEntries(Object.entries(OPS).map(([k, v]) => [v, +k])); +const TAKES_ARG = new Set(["LDA", "ADD", "SUB", "STA", "LDI", "JMP", "JC", "JZ"]); + +// Microcode. Every instruction starts with the same two fetch steps. +const FETCH = [L.CO | L.MI, L.RO | L.II | L.CE]; +const MICRO = { + LDA: [L.IO | L.MI, L.RO | L.AI, 0], + ADD: [L.IO | L.MI, L.RO | L.BI, L.EO | L.AI | L.FI], + SUB: [L.IO | L.MI, L.RO | L.BI, L.EO | L.AI | L.SU | L.FI], + STA: [L.IO | L.MI, L.AO | L.RI, 0], + LDI: [L.IO | L.AI, 0, 0], + JMP: [L.IO | L.J, 0, 0], + JC: [L.IO | L.J, 0, 0], + JZ: [L.IO | L.J, 0, 0], + OUT: [L.AO | L.OI, 0, 0], + HLT: [L.HLT, 0, 0], +}; + +function controlWord(s) { + if (s.step < 2) return FETCH[s.step]; + const op = OPS[s.ir >> 4]; + if (!MICRO[op]) return 0; + if ((op === "JC" && !s.cf) || (op === "JZ" && !s.zf)) return 0; + return MICRO[op][s.step - 2]; +} + +function alu(s, cw) { + const raw = cw & L.SU ? s.a + ((~s.b & 0xff) + 1) : s.a + s.b; + return { sum: raw & 0xff, carry: raw > 0xff ? 1 : 0, zero: (raw & 0xff) === 0 ? 1 : 0 }; +} + +function busValue(s, cw, sum) { + if (cw & L.CO) return s.pc; + if (cw & L.RO) return s.ram[s.mar]; + if (cw & L.IO) return s.ir & 0x0f; + if (cw & L.AO) return s.a; + if (cw & L.EO) return sum; + return 0; // pull-down resistors +} + +// One rising clock edge: everything with an "in" line latches the bus. +function tick(s) { + if (s.halted) return; + const cw = controlWord(s); + const r = alu(s, cw); + const v = busValue(s, cw, r.sum); + if (cw & L.MI) s.mar = v & 0x0f; + if (cw & L.RI) s.ram[s.mar] = v; + if (cw & L.II) s.ir = v; + if (cw & L.AI) s.a = v; + if (cw & L.BI) s.b = v; + if (cw & L.OI) s.out = v; + if (cw & L.FI) { s.cf = r.carry; s.zf = r.zero; } + if (cw & L.J) s.pc = v & 0x0f; + if (cw & L.CE) s.pc = (s.pc + 1) & 0x0f; + s.step = (s.step + 1) % 5; + s.cycles++; + // HLT gates the clock as soon as its control word appears. + if (controlWord(s) & L.HLT) s.halted = true; +} + +function resetState(s) { + Object.assign(s, { a: 0, b: 0, ir: 0, mar: 0, pc: 0, out: 0, step: 0, cf: 0, zf: 0, halted: false, cycles: 0 }); +} + +const disasm = (byte) => { + const op = OPS[byte >> 4] ?? "???"; + return TAKES_ARG.has(op) ? `${op} ${byte & 15}` : op; +}; + +// ── programs ────────────────────────────────────────────────────────── + +const PROGRAMS = { + fibonacci: { + title: "fibonacci", + code: [["LDI", 1], ["STA", 15], ["LDI", 0], ["OUT"], ["ADD", 15], ["JC", 0], ["STA", 14], ["LDA", 15], + ["STA", 13], ["LDA", 14], ["STA", 15], ["LDA", 13], ["JMP", 3]], + data: { 13: ["z", 0], 14: ["t", 0], 15: ["y", 0] }, + }, + multiply: { + title: "multiply 7 × 6", + code: [["LDA", 14], ["SUB", 12], ["JC", 6], ["LDA", 13], ["OUT"], ["HLT"], ["STA", 14], ["LDA", 13], + ["ADD", 15], ["STA", 13], ["JMP", 0]], + data: { 12: ["one", 1], 13: ["prod", 0], 14: ["y", 6], 15: ["x", 7] }, + }, + count: { + title: "count up and down", + code: [["OUT"], ["ADD", 15], ["JC", 4], ["JMP", 0], ["SUB", 15], ["OUT"], ["JZ", 0], ["JMP", 4]], + data: { 15: ["step", 5] }, + }, + add: { + title: "add 28 + 14", + code: [["LDA", 14], ["ADD", 15], ["OUT"], ["HLT"]], + data: { 14: ["a", 28], 15: ["b", 14] }, + }, +}; + +function assemble(p) { + const ram = new Uint8Array(16); + p.code.forEach(([op, arg = 0], i) => { ram[i] = (CODE[op] << 4) | (arg & 15); }); + for (const [addr, [, v]] of Object.entries(p.data)) ram[addr] = v; + return ram; +} + +// ── 7-segment digits ────────────────────────────────────────────────── + +const H = (y, x1, x2) => `M${x1} ${y}l1.6 -1.6H${x2 - 1.6}l1.6 1.6l-1.6 1.6H${x1 + 1.6}z`; +const V = (x, y1, y2) => `M${x} ${y1}l1.6 1.6V${y2 - 1.6}l-1.6 1.6l-1.6 -1.6V${y1 + 1.6}z`; +const SEGS = { a: H(2, 3, 19), b: V(20, 3, 18.4), c: V(20, 19.6, 35), d: H(36, 3, 19), e: V(2, 19.6, 35), f: V(2, 3, 18.4), g: H(19, 3, 19) }; +const GLYPH = { 0: "abcdef", 1: "bc", 2: "abdeg", 3: "abcdg", 4: "bcfg", 5: "acdfg", 6: "acdefg", 7: "abc", 8: "abcdefg", 9: "abcdfg", "-": "g", " ": "" }; + +// ── UI ──────────────────────────────────────────────────────────────── + +const fmtHz = (f) => (f < 10 ? `${f.toFixed(1)} Hz` : `${Math.round(f)} Hz`); + +// State that outlives any one mounted board: the coffee overclock, and which +// board is on the page (the 8-bit project's demo mounts and unmounts it). +let boost = 1; +let boostTimer = 0; +let current = null; + +const TEMPLATE = ` + <div class="board" role="group" aria-label="Simulated 8-bit breadboard computer"></div> + <div class="sim-bar"> + <button type="button" class="btn" data-sim="run" aria-pressed="false">run</button> + <button type="button" class="btn" data-sim="step">step</button> + <button type="button" class="btn" data-sim="reset">reset</button> + <label class="sim-field"><span>program</span> + <select data-sim="program"> + <option value="fibonacci">fibonacci</option> + <option value="multiply">multiply 7 × 6</option> + <option value="count">count up and down</option> + <option value="add">add 28 + 14</option> + </select> + </label> + <label class="sim-field"><span>clock</span> + <input type="range" min="0" max="100" value="43" data-sim="hz" aria-label="Clock speed"> + <output>10 Hz</output> + </label> + </div> + <p class="sim-note">Simulated one clock cycle at a time. <kbd>c</kbd> runs or pauses, <kbd>n</kbd> steps one cycle, <kbd>r</kbd> resets. Click a bit in RAM to change the program, or the display to switch to signed.</p>`; + +export function mount(host) { + host.innerHTML = TEMPLATE; + const board = $(".board", host); + const runBtn = $('[data-sim="run"]', host); + const progSel = $('[data-sim="program"]', host); + const hzIn = $('[data-sim="hz"]', host); + const hzOut = $("output", host); + + const s = { ram: new Uint8Array(16) }; + resetState(s); + let program = PROGRAMS.fibonacci; + let running = false; + let hz = 10; + let acc = 0; + let phase = 0; + let signed = false; + let dirty = true; + let lastBoost = boost; + const effHz = () => Math.min(500, hz * boost); + + // ── build the board ──────────────────────────────────────────────── + const el = (tag, cls, text) => { + const e = document.createElement(tag); + if (cls) e.className = cls; + if (text != null) e.textContent = text; + return e; + }; + const mods = {}; + const mod = (key, name, sigs = []) => { + const m = el("section", `mod mod-${key}`); + const head = el("div", "mod-head"); + head.append(el("span", "mod-name", name)); + for (const sig of sigs) { + const t = el("span", "sig", LABEL[sig] ?? sig); + t.dataset.sig = sig; + head.append(t); + } + const body = el("div", "mod-body"); + m.append(head, body); + mods[key] = { m, body, sigs: $$(".sig", head), val: null, leds: [] }; + return mods[key]; + }; + const leds = (target, n, cls = "", gapAt = -1, tag = "span") => { + const w = el("div", "leds"); + for (let i = 0; i < n; i++) { + if (i === gapAt) w.append(el("span", "gap")); + const l = el(tag, `led ${cls}`); + w.append(l); + target.leds.push(l); + } + return w; + }; + const value = (target, text = "") => { + target.val = el("span", "mod-val", text); + return target.val; + }; + + const left = el("div", "col col-l"); + const right = el("div", "col col-r"); + + const clk = mod("clk", "clock", ["HLT"]); + clk.body.append(leds(clk, 1, "b"), value(clk)); + const mar = mod("mar", "memory address", ["MI"]); + mar.body.append(leds(mar, 4, "y"), value(mar)); + + const ram = mod("ram", "RAM", ["RI", "RO"]); + const rows = el("div", "ram-rows"); + const ramRows = []; + for (let a = 0; a < 16; a++) { + const row = el("div", "ram-row"); + const pcMark = el("span", "pc"); + const addr = el("span", "addr", hex(a, 1)); + const bits = el("span", "leds"); + const cells = []; + for (let b = 7; b >= 0; b--) { + const btn = el("button", "led"); + btn.type = "button"; + btn.tabIndex = a === 0 && b === 7 ? 0 : -1; + btn.dataset.addr = a; + btn.dataset.bit = b; + btn.setAttribute("aria-label", `address ${a}, bit ${b}`); + bits.append(btn); + cells.push(btn); + } + const dis = el("span", "dis"); + row.append(pcMark, addr, bits, dis); + rows.append(row); + ramRows.push({ row, pcMark, cells, dis }); + } + ram.body.replaceWith(rows); + + const ir = mod("ir", "instruction", ["II", "IO"]); + ir.body.append(leds(ir, 8, "", 4), value(ir)); + ir.leds.forEach((l, i) => l.classList.add(i < 4 ? "b" : "y")); + left.append(clk.m, mar.m, ram.m, ir.m); + + const pc = mod("pc", "program counter", ["CO", "J", "CE"]); + pc.body.append(leds(pc, 4, "g"), value(pc)); + const a = mod("a", "A register", ["AI", "AO"]); + a.body.append(leds(a, 8), value(a)); + const sum = mod("sum", "ALU Σ", ["EO", "SU"]); + sum.body.append(leds(sum, 8), value(sum)); + const b = mod("b", "B register", ["BI"]); + b.body.append(leds(b, 8), value(b)); + const out = mod("out", "output", ["OI"]); + const seg = el("div", "seg7"); + const digits = []; + for (let d = 0; d < 4; d++) { + const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svg.setAttribute("viewBox", "0 0 22 38"); + svg.setAttribute("aria-hidden", "true"); + const g = document.createElementNS("http://www.w3.org/2000/svg", "g"); + g.setAttribute("transform", "skewX(-6) translate(2 0)"); + const segs = {}; + for (const [k, dpath] of Object.entries(SEGS)) { + const p = document.createElementNS("http://www.w3.org/2000/svg", "path"); + p.setAttribute("d", dpath); + g.append(p); + segs[k] = p; + } + svg.append(g); + seg.append(svg); + digits.push(segs); + } + const outLabel = el("span", "sr-only"); + out.body.append(seg, value(out), outLabel); + out.body.title = "Click to switch between unsigned and signed"; + const flags = mod("flags", "flags", ["FI"]); + const fl = el("div", "leds"); + const cfLed = el("span", "led g"); + const zfLed = el("span", "led g"); + fl.append(cfLed, el("span", "dim", "C"), el("span", "gap"), zfLed, el("span", "dim", "Z")); + fl.style.alignItems = "center"; + flags.body.append(fl, value(flags)); + right.append(pc.m, a.m, sum.m, b.m, out.m, flags.m); + + const bus = el("div", "bus"); + const busHead = el("div", "mod-head"); + busHead.append(el("span", "mod-name", "bus")); + const busVal = el("span", "bus-val mod-val", "0"); + const lanesWrap = el("div", "lanes"); + const lanes = []; + for (let i = 0; i < 8; i++) { + const l = el("span", "lane"); + lanesWrap.append(l); + lanes.push(l); + } + bus.append(busHead, busVal, lanesWrap); + + const ctrl = mod("ctrl", "control word", []); + ctrl.m.classList.add("ctrl"); + const ctrlRow = el("div", "ctrl-row"); + const stepWrap = el("div", "cw"); + const stepLeds = []; + for (let i = 0; i < 5; i++) { + const bit = el("span", "cw-bit"); + const l = el("span", "led"); + bit.append(l, el("span", "", `T${i}`)); + stepWrap.append(bit); + stepLeds.push([bit, l]); + } + const cwWrap = el("div", "cw"); + const cwBits = LINES.map((n) => { + const bit = el("span", "cw-bit"); + const l = el("span", "led b"); + bit.append(l, el("span", "", LABEL[n] ?? n)); + cwWrap.append(bit); + return [bit, l]; + }); + ctrlRow.append(stepWrap, cwWrap); + const ustep = el("p", "ustep"); + ctrl.body.replaceWith(ctrlRow); + ctrl.m.append(ustep); + + board.replaceChildren(left, bus, right, ctrl.m); + + // ── render ───────────────────────────────────────────────────────── + const setBits = (list, v, n = list.length) => { + for (let i = 0; i < n; i++) list[i].classList.toggle("on", ((v >> (n - 1 - i)) & 1) === 1); + }; + const setText = (node, text) => { + if (node.textContent !== text) node.textContent = text; + }; + + let lastRam = ""; + function render() { + const cw = controlWord(s); + const r = alu(s, cw); + const v = busValue(s, cw, r.sum); + + // registers + setBits(mar.leds, s.mar); setText(mar.val, String(s.mar)); + setBits(pc.leds, s.pc); setText(pc.val, String(s.pc)); + setBits(a.leds, s.a); setText(a.val, String(s.a)); + setBits(b.leds, s.b); setText(b.val, String(s.b)); + setBits(sum.leds, r.sum); setText(sum.val, `${cw & L.SU ? "A−B" : "A+B"} ${r.sum}`); + setBits(ir.leds, s.ir); setText(ir.val, s.step < 2 && s.cycles === 0 ? "" : disasm(s.ir)); + cfLed.classList.toggle("on", !!s.cf); + zfLed.classList.toggle("on", !!s.zf); + setText(flags.val, ""); + setBits(lanes, v); setText(busVal, String(v)); + + // clock + clk.leds[0].classList.toggle("on", running && !s.halted && (effHz() > 24 || phase < 0.5)); + setText(clk.val, s.halted ? "halted" : running ? (boost > 1 ? `${fmtHz(effHz())} (${boost}×)` : fmtHz(hz)) : "paused"); + + // output display + const o = signed && s.out > 127 ? -(256 - s.out) : s.out; + const txt = (o < 0 ? "-" : " ") + String(Math.abs(o)).padStart(3, " "); + txt.split("").forEach((ch, i) => { + const on = GLYPH[ch] ?? ""; + for (const [k, p] of Object.entries(digits[i])) p.classList.toggle("on", on.includes(k)); + }); + setText(out.val, signed ? "signed" : ""); + setText(outLabel, `output ${o}`); + + // control word and step + cwBits.forEach(([bit, l], i) => { + const on = (cw >> (15 - i)) & 1; + bit.classList.toggle("on", !!on); + l.classList.toggle("on", !!on); + }); + stepLeds.forEach(([bit, l], i) => { + bit.classList.toggle("on", i === s.step); + l.classList.toggle("on", i === s.step); + }); + const d = describe(s, cw); + const html = `T${s.step}&ensp;<b>${d.label}</b>&ensp;${d.text}`; + if (ustep.innerHTML !== html) ustep.innerHTML = html; + + // which modules drive the bus, which latch it, and their control lines + const outs = { pc: L.CO, ram: L.RO, ir: L.IO, a: L.AO, sum: L.EO }; + const ins = { mar: L.MI, ram: L.RI, ir: L.II, a: L.AI, b: L.BI, out: L.OI, pc: L.J | L.CE, flags: L.FI, clk: L.HLT }; + for (const [key, m] of Object.entries(mods)) { + m.m.classList.toggle("is-out", !!(cw & (outs[key] ?? 0))); + m.m.classList.toggle("is-in", !!(cw & (ins[key] ?? 0)) && !(cw & (outs[key] ?? 0))); + for (const t of m.sigs) t.classList.toggle("on", !!(cw & L[t.dataset.sig])); + } + + // RAM matrix + const key = `${s.ram.join(",")}|${s.mar}|${s.pc}`; + if (key !== lastRam) { + lastRam = key; + ramRows.forEach((rr, addr) => { + setBits(rr.cells, s.ram[addr]); + rr.row.classList.toggle("is-mar", addr === s.mar); + setText(rr.pcMark, addr === s.pc ? "▸" : ""); + const data = program.data[addr]; + setText(rr.dis, data ? `${data[0]} = ${s.ram[addr]}` : disasm(s.ram[addr])); + }); + } + } + + function describe(st, cw) { + if (st.halted) return { label: "HLT", text: "clock stopped; reset to run again" }; + const label = st.step < 2 ? "fetch" : OPS[st.ir >> 4] ?? "???"; + if (!cw) { + if (label === "JC") return { label, text: "carry clear, so no jump" }; + if (label === "JZ") return { label, text: "zero clear, so no jump" }; + return { label, text: "nothing to do this step" }; + } + const src = [[L.CO, "PC"], [L.RO, "RAM"], [L.IO, "operand"], [L.AO, "A"], [L.EO, cw & L.SU ? "A − B" : "A + B"]].find(([bit]) => cw & bit); + const dst = [[L.MI, "MAR"], [L.RI, "RAM"], [L.II, "IR"], [L.AI, "A"], [L.BI, "B"], [L.OI, "output"], [L.J, "PC"]].filter(([bit]) => cw & bit).map(([, n]) => n); + const parts = []; + if (src && dst.length) parts.push(`${src[1]} → ${dst.join(", ")}`); + if (cw & L.CE) parts.push("PC + 1"); + if (cw & L.FI) parts.push("latch flags"); + return { label, text: parts.join(", ") }; + } + + + // ── simulation loop ──────────────────────────────────────────────── + function frame(t, dt) { + if (boost !== lastBoost) { + lastBoost = boost; + dirty = true; + } + if (running && !s.halted) { + acc += dt * effHz(); + phase = (phase + dt * effHz()) % 1; + let n = Math.floor(acc); + acc -= n; + n = Math.min(n, 400); + while (n-- > 0 && !s.halted) tick(s); + if (s.halted) halted(); + dirty = true; + } + if (dirty) { + render(); + dirty = false; + } + } + + function halted() { + running = false; + paintRun(); + message(`HLT: ${program.title} finished with ${s.out} on the display. Press r to reset.`, "", 6000); + } + + function paintRun() { + runBtn.setAttribute("aria-pressed", String(running)); + runBtn.textContent = running ? "pause" : "run"; + } + + // ── controls ─────────────────────────────────────────────────────── + function run(want = !running) { + if (want && s.halted) return message("Halted. Press r (or the reset button) to start again."); + running = want; + acc = 0; + paintRun(); + dirty = true; + } + function step() { + if (running) run(false); + if (s.halted) return message("Halted. Press r to reset."); + tick(s); + if (s.halted) halted(); + dirty = true; + } + function reset() { + resetState(s); + dirty = true; + } + function load(key) { + program = PROGRAMS[key] ?? PROGRAMS.fibonacci; + progSel.value = key; + s.ram = assemble(program); + resetState(s); + lastRam = ""; + dirty = true; + } + function setHz(v) { + hz = 0.5 * Math.pow(1000, v / 100); + hzOut.value = fmtHz(hz); + dirty = true; + } + + runBtn.addEventListener("click", () => run()); + $('[data-sim="step"]', host).addEventListener("click", step); + $('[data-sim="reset"]', host).addEventListener("click", reset); + progSel.addEventListener("change", () => { + load(progSel.value); + if (!reducedMotion.matches) run(true); + }); + hzIn.addEventListener("input", () => setHz(+hzIn.value)); + out.body.addEventListener("click", () => { + signed = !signed; + dirty = true; + message(signed ? "Output shows signed two’s complement" : "Output shows unsigned"); + }); + + // Edit RAM by clicking bits; arrow keys move around the matrix. + rows.addEventListener("click", (e) => { + const btn = e.target.closest(".led"); + if (!btn) return; + s.ram[+btn.dataset.addr] ^= 1 << +btn.dataset.bit; + focusCell(+btn.dataset.addr, +btn.dataset.bit); + dirty = true; + }); + rows.addEventListener("keydown", (e) => { + const btn = e.target.closest(".led"); + const d = { ArrowUp: [-1, 0], ArrowDown: [1, 0], ArrowLeft: [0, 1], ArrowRight: [0, -1] }[e.key]; + if (!btn || !d) return; + e.preventDefault(); + focusCell((+btn.dataset.addr + d[0] + 16) % 16, Math.min(7, Math.max(0, +btn.dataset.bit + d[1]))); + }); + function focusCell(addr, bit) { + for (const rr of ramRows) for (const c of rr.cells) c.tabIndex = -1; + const c = ramRows[addr].cells[7 - bit]; + c.tabIndex = 0; + c.focus({ preventScroll: true }); + } + + // c, n and r while the computer is on screen + let visible = false; + let off = null; + const io = new IntersectionObserver(([e]) => { + visible = e.intersectionRatio >= 0.25; + if (e.isIntersecting && !off) off = onFrame(frame); + else if (!e.isIntersecting && off) { off(); off = null; } + }, { threshold: [0, 0.25] }); + io.observe(board); + const onKey = (e) => { + if (!visible || e.defaultPrevented || e.repeat || isTyping(e) || e.metaKey || e.ctrlKey || e.altKey) return; + if (document.querySelector("dialog[open]")) return; + const act = { c: () => run(), n: step, r: reset }[e.key]; + if (!act) return; + e.preventDefault(); + act(); + }; + document.addEventListener("keydown", onKey); + + load("fibonacci"); + setHz(+hzIn.value); + run(!reducedMotion.matches || boost > 1); + const api = { run, step, reset, load, board, halted: () => s.halted, running: () => running }; + current = api; + return () => { + io.disconnect(); + off?.(); + document.removeEventListener("keydown", onKey); + if (current === api) current = null; + }; +} + +// The 8-bit project's demo, opened and scrolled to if it isn't on the page yet. +export async function showComputer() { + if (!current) { + emit("project", "8-bit-computer"); + for (let i = 0; i < 90 && !current; i++) await new Promise((r) => requestAnimationFrame(r)); + } + current?.board.scrollIntoView({ behavior: reducedMotion.matches ? "auto" : "smooth", block: "center" }); + return current; +} + +const withComputer = (fn) => async () => { + const c = current ?? (await showComputer()); + if (c) fn(c); +}; +defcommand("computer-run", withComputer((c) => c.run()), { doc: "Run or pause the 8-bit computer", key: "c" }); +defcommand("computer-step", withComputer((c) => c.step()), { doc: "Advance the clock by one cycle", key: "n" }); +defcommand("computer-reset", withComputer((c) => c.reset()), { doc: "Reset the computer (RAM is kept)", key: "r" }); +defcommand("computer-load-program", async () => { + const key = await completingRead("Load program: ", Object.entries(PROGRAMS).map(([k, p]) => ({ value: k, ann: p.title }))); + if (!key) return; + const c = await showComputer(); + c?.load(key); + c?.run(true); +}, { doc: "Load one of the example programs into RAM", key: "SPC c l" }); + +// M-x coffee-refill: four times the clock for a while. +on("caffeine", ({ factor, seconds }) => { + boost = factor; + if (current) { + if (current.halted()) current.reset(); + if (!current.running()) current.run(true); + } + let left = seconds; + clearInterval(boostTimer); + setSegment("misc", `${factor}× clock ${left}s`); + boostTimer = setInterval(() => { + left--; + if (left > 0) return setSegment("misc", `${factor}× clock ${left}s`); + clearInterval(boostTimer); + boost = 1; + setSegment("misc", ""); + message("The caffeine wore off. The clock is back to normal."); + }, 1000); +}); diff --git a/src/scripts/contact.js b/src/scripts/contact.js @@ -0,0 +1,28 @@ +// The page only shows "michael <at> michaelneuper.com"; the address is put +// together here so a scraper reading the HTML never sees it whole. + +import { $ } from "./util.js"; +import { message } from "./shell.js"; + +export function initContact() { + const sec = $("#contact"); + if (!sec) return; + const mail = $(".mail", sec); + const address = `${mail.dataset.user}@${mail.dataset.host}`; + const arm = () => { mail.href = `mailto:${address}`; }; + for (const ev of ["pointerenter", "focus", "touchstart"]) mail.addEventListener(ev, arm, { passive: true }); + mail.addEventListener("click", arm); + + const copy = $('[data-email="copy"]', sec); + copy?.addEventListener("click", async () => { + try { + await navigator.clipboard.writeText(address); + copy.textContent = "copied"; + message(`Copied ${address}`, "ok", 3000); + } catch { + message(address, "", 8000); + copy.textContent = "shown below"; + } + setTimeout(() => { copy.textContent = "copy address"; }, 2000); + }); +} diff --git a/src/scripts/ctf.js b/src/scripts/ctf.js @@ -0,0 +1,71 @@ +// Three beginner CTF flags hidden around the site. This file keeps only their +// SHA-256 hashes, so reading it shows how flags are checked without giving them away. + +import { $ } from "./util.js"; +import { defcommand, message, completingRead, setSegment, call } from "./shell.js"; + +const HASHES = [ + "7a80f308e7d3c86589ac38394f24154bf36149b8ad833f728c9e0ddeed29693e", + "b8af26fa58465fa7be727749c616d906054f12928d817dd34d94284943d6f02e", + "d43266a3ddf2cab859b257fad7ea2f2eceee3726e72f1651305a6d3f14bf064e", +]; + +const load = () => { + try { return new Set(JSON.parse(localStorage.getItem("flags") || "[]")); } catch { return new Set(); } +}; +const save = (set) => { + try { localStorage.setItem("flags", JSON.stringify([...set])); } catch { /* private mode */ } +}; + +async function sha256(text) { + const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text)); + return [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, "0")).join(""); +} + +export function initCtf() { + const progress = $(".ctf-progress"); + let found = load(); + + const paint = () => { + const n = [...found].filter((h) => HASHES.includes(h)).length; + if (progress) { + progress.textContent = n === 3 ? "3 of 3 found. Nicely done." : `${n} of 3 found`; + progress.classList.toggle("done", n === 3); + } + setSegment("flags", n ? `flags ${n}/3` : ""); + }; + paint(); + + async function submit() { + const guess = await completingRead("Flag: ", [], { requireMatch: false }); + if (!guess) return; + if (!crypto.subtle) return message("Checking flags needs a secure context (https or localhost).", "error"); + const h = await sha256(guess.trim()); + if (!HASHES.includes(h)) return message("Not a flag. Keep looking.", "error"); + if (found.has(h)) return message("You already found that one."); + found.add(h); + save(found); + paint(); + const n = [...found].filter((x) => HASHES.includes(x)).length; + message(n === 3 ? "Correct. That’s all three." : `Correct. ${n} of 3 found.`, "ok", 6000); + } + + defcommand("submit-flag", submit, { doc: "Check a CTF flag you found on this site", key: "SPC s f" }); + defcommand("copy-gpg-fingerprint", async () => { + const fp = $(".gpg-fp code")?.textContent ?? ""; + try { + await navigator.clipboard.writeText(fp); + message(`Copied ${fp}`, "ok"); + } catch { + message(fp); + } + }, { doc: "Copy my GPG key fingerprint", key: "SPC s g" }); + $('[data-ctf="submit"]')?.addEventListener("click", () => call("submit-flag")); + + // One flag lives in the console. + console.log( + "%cPoking around in the console? Good instinct.%c\nThere are three flags on this site. Here is one, base64-encoded:\nZmxhZ3tjb25zb2xlX2xvZ3NfbGVha30=\nSubmit flags with M-x submit-flag.", + "font: 600 13px monospace", + "font: 12px monospace", + ); +} diff --git a/src/scripts/datasheet.js b/src/scripts/datasheet.js @@ -0,0 +1,86 @@ +// Builds the DIP-16 pinout from the ordered list of pins in the HTML. +// Pins 1–8 run down the left side, 9–16 run back up the right. + +import { $, $$ } from "./util.js"; +import { call } from "./shell.js"; + +export function initDatasheet() { + const fig = $(".pinout"); + if (!fig) return; + const pins = $$(".pin-list li", fig).map((li, i) => ({ + num: i + 1, + name: li.dataset.name, + type: li.dataset.type, + ch: li.dataset.cat, + text: li.textContent.trim(), + })); + const half = pins.length / 2; + const readout = $(".pin-readout", fig); + + const chip = document.createElement("div"); + chip.className = "chip"; + const left = side("left"); + const right = side("right"); + const body = document.createElement("div"); + body.className = "chip-body"; + body.innerHTML = "<span>MN-2026</span>"; + chip.append(left, body, right); + + pins.forEach((p, i) => { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = "pin"; + if (p.ch) btn.dataset.cat = p.ch; + btn.setAttribute("aria-label", `Pin ${p.num}, ${p.name}`); + const parts = { name: p.name, num: p.num, leg: "" }; + const order = i < half ? ["name", "num", "leg"] : ["leg", "num", "name"]; + for (const k of order) { + const s = document.createElement("span"); + s.className = k; + s.textContent = parts[k]; + btn.append(s); + } + btn.addEventListener("pointerenter", () => show(p, btn)); + btn.addEventListener("focus", () => show(p, btn)); + btn.addEventListener("click", () => show(p, btn)); + if (i < half) left.append(btn); + else right.prepend(btn); + }); + + $(".chip-wrap", fig).append(chip); + fig.classList.add("is-built"); + + function show(p, btn) { + $$(".pin.is-active", chip).forEach((b) => b.classList.remove("is-active")); + btn.classList.add("is-active"); + if (p.ch) readout.dataset.cat = p.ch; + else delete readout.dataset.cat; + readout.innerHTML = ""; + const head = document.createElement("p"); + head.className = "pr-head"; + head.innerHTML = `<span class="dim">pin ${p.num}</span><span class="pr-name"></span><span class="dim"></span>`; + head.children[1].textContent = p.name; + head.children[2].textContent = p.type; + // "M-x some-command" in a pin description becomes a button that runs it. + const text = document.createElement("p"); + for (const part of p.text.split(/(M-x [\w-]+)/)) { + if (!part.startsWith("M-x ")) { + text.append(part); + continue; + } + const b = document.createElement("button"); + b.type = "button"; + b.className = "linkish"; + b.textContent = part; + b.addEventListener("click", () => call(part.slice(4))); + text.append(b); + } + readout.append(head, text); + } +} + +function side(cls) { + const d = document.createElement("div"); + d.className = `chip-side ${cls}`; + return d; +} diff --git a/src/scripts/decode.js b/src/scripts/decode.js @@ -0,0 +1,164 @@ +// The name arrives as bytes with a few bits flipped, so each letter starts out +// as some other character. The flipped bits are corrected one at a time, and +// every correction changes the letter to the character one bit closer, until +// it lands on the right one. The echo area shows the bytes while that happens. +// +// Afterwards, pointing at a letter flips a couple of its bits again, and +// M-x flip-bits replays the whole thing. + +import { $, onFrame, reducedMotion } from "./util.js"; +import { message, defcommand, goto } from "./shell.js"; + +const rand = (n) => Math.floor(Math.random() * n); +const bin = (n) => n.toString(2).padStart(8, "0"); + +// Characters a letter may pass through: printable, and in the serif font +// (it has no backtick). +const printable = (v) => v >= 0x20 && v < 0x7f && v !== 0x60; + +function shuffle(a) { + for (let i = a.length - 1; i > 0; i--) { + const j = rand(i + 1); + [a[i], a[j]] = [a[j], a[i]]; + } + return a; +} + +// Pick k bits to flip and the order to correct them in, so that every byte on +// the way back is printable. Letters keep bit 6 (they stay in 0x40-0x7f) and +// the space keeps bits 5 and 6 (it stays in 0x20-0x3f). +function corrupt(code, k) { + const pool = code === 0x20 ? [0, 1, 2, 3, 4] : [0, 1, 2, 3, 4, 5]; + for (let tries = 0; tries < 50; tries++) { + const order = shuffle([...pool]).slice(0, k); + let v = order.reduce((x, b) => x ^ (1 << b), code); + const path = [v]; + for (const b of order) path.push((v ^= 1 << b)); + if (path.every(printable)) return path; // path[0] corrupted ... path[k] === code + } + return [code]; +} + +function build(h1) { + const text = h1.textContent.trim(); + h1.setAttribute("aria-label", text); + h1.textContent = ""; + // Measure on one line, so the space between the words keeps its width. + h1.style.whiteSpace = "nowrap"; + let word = null; + const cells = [...text].map((ch) => { + // Each word's letters sit in a span that doesn't wrap: the browser would + // otherwise break the line between any two of them. + if (!word) { + word = document.createElement("span"); + word.className = "bc-word"; + h1.append(word); + } + const el = document.createElement("span"); + el.className = "bc"; + const glyph = document.createElement("span"); + glyph.className = "bc-ch"; + glyph.textContent = ch; + el.append(glyph); + word.append(el); + if (ch === " ") word = null; // the line may break after the space + return { el, glyph, code: ch.charCodeAt(0), path: [], busy: false }; + }); + // Fix each cell at its final letter's width, so the other characters a letter + // passes through never push the rest of the name around. + const fs = parseFloat(getComputedStyle(h1).fontSize); + const widths = cells.map((c) => c.el.getBoundingClientRect().width); + cells.forEach((c, i) => { c.el.style.width = `${(widths[i] / fs).toFixed(4)}em`; }); + h1.style.whiteSpace = ""; + h1.classList.add("is-cells"); + return cells; +} + +function show(c, v) { + c.glyph.textContent = String.fromCharCode(v); + c.el.classList.toggle("is-wrong", v !== c.code); +} + +// Step every cell along its path on its own schedule until all are correct. +// onStep runs after any change, for the echo area. +function run(cells, onStep) { + const t0 = performance.now(); + return new Promise((resolve) => { + const off = onFrame(() => { + const t = performance.now() - t0; + let changed = false; + let left = 0; + for (const c of cells) { + while (c.plan.length && c.plan[0].t <= t) { + show(c, c.plan.shift().v); + changed = true; + } + left += c.plan.length; + } + if (changed) onStep?.(); + if (!left) { + off(); + resolve(); + } + }); + }); +} + +export async function initDecode() { + const root = document.documentElement; + const h1 = $(".hero-name"); + const reveal = () => root.classList.remove("boot"); + if (!h1 || reducedMotion.matches) return reveal(); + + let cells; + try { + // The cells are measured in the serif, so wait for it (briefly). + await Promise.race([document.fonts.load(`400 64px "Computer Modern"`, "Michael Neuper"), new Promise((r) => setTimeout(r, 1500))]); + cells = build(h1); + } catch (err) { + console.error(err); + return reveal(); + } + // the byte each cell shows right now + const current = (c) => c.glyph.textContent.charCodeAt(0); + + async function decode() { + if (cells.some((c) => c.busy)) return; + let flipped = 0; + cells.forEach((c, j) => { + c.busy = true; + const path = corrupt(c.code, 3 + rand(3)); + flipped += path.length - 1; + show(c, path[0]); + let t = 150 + j * 55; + c.plan = path.slice(1).map((v) => ({ v, t: (t += 70 + Math.random() * 50) })); + }); + const echo = () => message(cells.map((c) => bin(current(c))).join(" "), "", 0); + reveal(); + echo(); + await run(cells, echo); + cells.forEach((c) => { c.busy = false; }); + message(`Corrected ${flipped} flipped bits in ${cells.length} bytes.`, "ok", 4000); + } + + // Point at a letter to flip a couple of its bits. + for (const c of cells) { + if (c.code === 0x20) continue; + c.el.addEventListener("pointerenter", () => { + if (c.busy || reducedMotion.matches) return; + c.busy = true; + const path = corrupt(c.code, 2); + show(c, path[0]); + c.plan = path.slice(1).map((v, n) => ({ v, t: 110 + n * 90 })); + run([c]).then(() => { c.busy = false; }); + }); + } + + defcommand("flip-bits", () => { + goto("top", true); + setTimeout(decode, 400); + }, { doc: "Flip random bits in my name and watch them get corrected" }); + + if (root.classList.contains("boot")) await decode(); + else reveal(); +} diff --git a/src/scripts/demos/bytecode.js b/src/scripts/demos/bytecode.js @@ -0,0 +1,208 @@ +// Integer expressions compiled to JVM bytecode, then run on an operand stack +// with Java's int semantics (wrap-around, truncating division, / by zero). + +import { reducedMotion } from "../util.js"; + +const LOCALS = { x: 6, y: 7, z: -2 }; // slots 0, 1, 2 of a static method +const SLOT = { x: 0, y: 1, z: 2 }; +const OPS = { "+": "iadd", "-": "isub", "*": "imul", "/": "idiv", "%": "irem" }; + +function tokenize(src) { + const out = []; + const re = /\s*(?:(\d+)|([A-Za-z_]\w*)|(.))/gy; + let m; + while (re.lastIndex < src.length && (m = re.exec(src))) { + const pos = m.index + m[0].length - (m[1] || m[2] || m[3] || "").length; + if (m[1]) out.push({ t: "num", v: m[1], pos }); + else if (m[2]) out.push({ t: "id", v: m[2], pos }); + else if (m[3] && m[3].trim()) out.push({ t: "op", v: m[3], pos }); + } + out.push({ t: "end", pos: src.length }); + return out; +} + +class CompileError extends Error { + constructor(msg, pos) { super(msg); this.pos = pos; } +} + +function parse(src) { + const toks = tokenize(src); + let i = 0; + const peek = () => toks[i]; + const next = () => toks[i++]; + const expect = (v) => { + const t = next(); + if (t.v !== v) throw new CompileError(`'${v}' expected`, t.pos); + }; + function expr() { + let l = term(); + while (peek().t === "op" && "+-".includes(peek().v)) l = { t: "bin", op: next().v, l, r: term() }; + return l; + } + function term() { + let l = unary(); + while (peek().t === "op" && "*/%".includes(peek().v)) l = { t: "bin", op: next().v, l, r: unary() }; + return l; + } + function unary() { + if (peek().t === "op" && peek().v === "-") { next(); return { t: "neg", e: unary() }; } + if (peek().t === "op" && peek().v === "+") { next(); return unary(); } + return primary(); + } + function primary() { + const t = next(); + if (t.t === "num") { + const v = Number(t.v); + if (v > 2147483647) throw new CompileError("integer number too large", t.pos); + return { t: "num", v }; + } + if (t.t === "id") { + if (!(t.v in SLOT)) throw new CompileError(`cannot find symbol: variable ${t.v}`, t.pos); + return { t: "var", name: t.v }; + } + if (t.v === "(") { const e = expr(); expect(")"); return e; } + throw new CompileError(t.t === "end" ? "illegal start of expression" : `unexpected '${t.v}'`, t.pos); + } + const tree = expr(); + if (peek().t !== "end") throw new CompileError(`unexpected '${peek().v}'`, peek().pos); + return tree; +} + +function codegen(tree) { + const code = []; + const pool = []; + const emit = (op, arg, size = 1) => code.push({ op, arg, size }); + (function gen(n) { + if (n.t === "num") { + const v = n.v; + if (v >= -1 && v <= 5) emit(v === -1 ? "iconst_m1" : `iconst_${v}`); + else if (v >= -128 && v <= 127) emit("bipush", v, 2); + else if (v >= -32768 && v <= 32767) emit("sipush", v, 3); + else { + let k = pool.indexOf(v); + if (k < 0) k = pool.push(v) - 1; + emit("ldc", v, 2); + code[code.length - 1].text = `ldc #${k + 2}`; + } + } else if (n.t === "var") emit(`iload_${SLOT[n.name]}`, n.name); + else if (n.t === "neg") { gen(n.e); emit("ineg"); } + else { gen(n.l); gen(n.r); emit(OPS[n.op]); } + })(tree); + emit("ireturn"); + let off = 0; + for (const c of code) { c.off = off; off += c.size; } + return code; +} + +function exec(ins, stack) { + const pop = () => stack.pop(); + if (ins.op.startsWith("iconst_")) stack.push(ins.op === "iconst_m1" ? -1 : +ins.op.slice(7)); + else if (ins.op === "bipush" || ins.op === "sipush" || ins.op === "ldc") stack.push(ins.arg); + else if (ins.op.startsWith("iload_")) stack.push(LOCALS[ins.arg]); + else if (ins.op === "ineg") stack.push(-pop() | 0); + else if (ins.op === "ireturn") return { done: true, value: stack[stack.length - 1] }; + else { + const b = pop(); + const a = pop(); + if ((ins.op === "idiv" || ins.op === "irem") && b === 0) throw new Error("java.lang.ArithmeticException: / by zero"); + stack.push( + ins.op === "iadd" ? (a + b) | 0 + : ins.op === "isub" ? (a - b) | 0 + : ins.op === "imul" ? Math.imul(a, b) + : ins.op === "idiv" ? Math.trunc(a / b) | 0 + : (a % b) | 0, + ); + } + return { done: false }; +} + +export function mount(host) { + host.innerHTML = ` + <div class="bc-input"> + <input type="text" value="(x + 3) * y - 10 / z" spellcheck="false" autocapitalize="off" aria-label="Expression to compile"> + <button type="button" class="btn" data-k="step">step</button> + <button type="button" class="btn" data-k="run">run</button> + </div> + <p class="dim" style="margin:0 0 12px">int x = 6, y = 7, z = -2 (local variable slots 0 to 2)</p> + <div class="bc-cols"> + <div><div class="dim">javap -c</div><ol class="bc-code"></ol></div> + <div><div class="dim">operand stack</div><div class="bc-stack"></div><p class="dim" data-k="result" style="margin:8px 0 0"></p></div> + </div>`; + const input = host.querySelector("input"); + const list = host.querySelector(".bc-code"); + const stackEl = host.querySelector(".bc-stack"); + const result = host.querySelector('[data-k="result"]'); + let code = []; + let pc = 0; + let stack = []; + let timer = 0; + let finished = false; + + function compile() { + clearInterval(timer); + pc = 0; + stack = []; + finished = false; + try { + code = codegen(parse(input.value)); + list.replaceChildren(...code.map((c) => { + const li = document.createElement("li"); + li.innerHTML = `<span class="off">${c.off}:</span><span><span class="op">${c.text ? "ldc" : c.op}</span>${c.text ? ` ${c.text.slice(4)}<span class="dim"> // int ${c.arg}</span>` : c.arg !== undefined && !c.op.startsWith("iload") ? ` ${c.arg}` : ""}</span>`; + return li; + })); + result.textContent = ""; + } catch (e) { + code = []; + const pre = document.createElement("li"); + pre.className = "bc-err"; + pre.textContent = `error: ${e.message}\n ${input.value}\n ${" ".repeat(e.pos ?? 0)}^`; + list.replaceChildren(pre); + result.textContent = ""; + } + paint(); + } + + function paint() { + [...list.children].forEach((li, i) => li.classList.toggle("is-pc", i === pc && !finished && code.length > 0)); + stackEl.replaceChildren(...stack.map((v) => { + const s = document.createElement("span"); + s.textContent = v; + return s; + })); + } + + function step() { + if (!code.length) return false; + if (finished) { pc = 0; stack = []; finished = false; result.textContent = ""; } + try { + const r = exec(code[pc], stack); + if (r.done) { + finished = true; + result.textContent = `returns ${r.value}`; + } else pc++; + } catch (e) { + finished = true; + result.textContent = e.message; + } + paint(); + return !finished; + } + + function run() { + clearInterval(timer); + if (finished) step(); + if (reducedMotion.matches) { + while (step()) { /* run to the end */ } + return; + } + timer = setInterval(() => { if (!step()) clearInterval(timer); }, 320); + } + + let debounce = 0; + input.addEventListener("input", () => { clearTimeout(debounce); debounce = setTimeout(compile, 180); }); + input.addEventListener("keydown", (e) => { if (e.key === "Enter") { e.preventDefault(); compile(); run(); } }); + host.querySelector('[data-k="step"]').addEventListener("click", () => { clearInterval(timer); step(); }); + host.querySelector('[data-k="run"]').addEventListener("click", run); + compile(); + return () => clearInterval(timer); +} diff --git a/src/scripts/demos/computer.js b/src/scripts/demos/computer.js @@ -0,0 +1 @@ +export { mount } from "../computer.js"; diff --git a/src/scripts/demos/othello.js b/src/scripts/demos/othello.js @@ -0,0 +1,242 @@ +// Othello against a serial Monte Carlo tree search player, rewritten from my C +// version: UCT selection (C = 1), random playouts, and the most-visited move +// at the end of the think time. While it thinks, each candidate move is shaded +// by its share of the search. + +const C = 1; +const DIRS = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]; +const BLACK = 1; // you +const WHITE = -1; // the search +const PASS = -1; +const name = (i) => "abcdefgh"[i % 8] + (Math.floor(i / 8) + 1); + +function flips(b, i, p) { + if (b[i]) return []; + const out = []; + const r0 = Math.floor(i / 8); + const c0 = i % 8; + for (const [dr, dc] of DIRS) { + const run = []; + let r = r0 + dr; + let c = c0 + dc; + while (r >= 0 && r < 8 && c >= 0 && c < 8 && b[r * 8 + c] === -p) { + run.push(r * 8 + c); + r += dr; + c += dc; + } + if (run.length && r >= 0 && r < 8 && c >= 0 && c < 8 && b[r * 8 + c] === p) out.push(...run); + } + return out; +} + +function moves(b, p) { + const out = []; + for (let i = 0; i < 64; i++) if (!b[i] && flips(b, i, p).length) out.push(i); + return out; +} + +function play(b, i, p) { + if (i === PASS) return; + for (const f of flips(b, i, p)) b[f] = p; + b[i] = p; +} + +function score(b) { + let n = 0; + for (const v of b) n += v; + return n; // > 0 black ahead +} + +// One random game to the end; returns the winner (BLACK, WHITE or 0). +function playout(board, toPlay) { + const b = board.slice(); + let p = toPlay; + let passes = 0; + while (passes < 2) { + const ms = moves(b, p); + if (ms.length) { + play(b, ms[(Math.random() * ms.length) | 0], p); + passes = 0; + } else passes++; + p = -p; + } + return Math.sign(score(b)); +} + +function node(parent, move, board, toPlay) { + let untried = moves(board, toPlay); + if (!untried.length && moves(board, -toPlay).length) untried = [PASS]; + return { parent, move, board, toPlay, untried, children: [], wins: 0, visits: 0 }; +} + +function iterate(root) { + let n = root; + // select + while (!n.untried.length && n.children.length) { + const logN = Math.log(n.visits); + let best = null; + let bestU = -Infinity; + for (const ch of n.children) { + const u = ch.wins / ch.visits + C * Math.sqrt(logN / ch.visits); + if (u > bestU) { bestU = u; best = ch; } + } + n = best; + } + // expand + if (n.untried.length) { + const k = (Math.random() * n.untried.length) | 0; + const m = n.untried.splice(k, 1)[0]; + const b = n.board.slice(); + play(b, m, n.toPlay); + const ch = node(n, m, b, -n.toPlay); + n.children.push(ch); + n = ch; + } + // simulate and back-propagate: wins count for whoever moved into the node + const winner = playout(n.board, n.toPlay); + for (let x = n; x; x = x.parent) { + x.visits++; + const mover = -x.toPlay; + if (winner === mover) x.wins += 1; + else if (winner === 0) x.wins += 0.5; + } +} + +export function mount(host) { + host.innerHTML = ` + <div class="demo-bar"> + <button type="button" class="btn" data-k="new">new game</button> + <label class="sim-field" style="margin:0"><span>think time</span> + <select data-k="time"> + <option value="250">0.25 s</option> + <option value="600" selected>0.6 s</option> + <option value="1000">1 s</option> + </select> + </label> + <span class="dim" data-k="score"></span> + </div> + <div class="oth" role="grid" aria-label="Othello board, you play black"></div> + <p class="cap" data-k="status" aria-live="polite"></p>`; + const grid = host.querySelector(".oth"); + const status = host.querySelector('[data-k="status"]'); + const scoreEl = host.querySelector('[data-k="score"]'); + const timeSel = host.querySelector('[data-k="time"]'); + + const cells = Array.from({ length: 64 }, (_, i) => { + const b = document.createElement("button"); + b.type = "button"; + b.className = "oth-cell"; + b.dataset.i = i; + b.innerHTML = '<span class="heat"></span><span class="disc"></span>'; + grid.append(b); + return b; + }); + + let board; + let turn; + let last = -1; + let thinking = false; + let alive = true; + let heat = null; + + function reset() { + board = new Int8Array(64); + board[27] = board[36] = WHITE; + board[28] = board[35] = BLACK; + turn = BLACK; + last = -1; + heat = null; + status.textContent = "Your move: you play black. Legal moves are dotted."; + paint(); + } + + function paint() { + const legal = turn === BLACK && !thinking ? new Set(moves(board, BLACK)) : new Set(); + let b = 0; + let w = 0; + cells.forEach((cell, i) => { + const v = board[i]; + if (v === BLACK) b++; + if (v === WHITE) w++; + cell.querySelector(".disc").className = `disc${v === BLACK ? " b" : v === WHITE ? " w" : ""}`; + cell.classList.toggle("legal", legal.has(i)); + cell.classList.toggle("last", i === last); + const h = heat?.get(i); + const hs = cell.querySelector(".heat"); + hs.textContent = h ? `${Math.round(h * 100)}` : ""; + hs.style.setProperty("--hp", h ? `${Math.round(15 + h * 75)}%` : "0%"); + cell.setAttribute("aria-label", `${name(i)}, ${v === BLACK ? "black" : v === WHITE ? "white" : legal.has(i) ? "legal move" : "empty"}`); + }); + scoreEl.textContent = `black ${b}, white ${w}`; + } + + function over() { + if (moves(board, BLACK).length || moves(board, WHITE).length) return false; + const s = score(board); + status.textContent = s > 0 ? "Game over: you win." : s < 0 ? "Game over: the search wins." : "Game over: a draw."; + turn = 0; + paint(); + return true; + } + + async function think() { + thinking = true; + paint(); + const root = node(null, null, board.slice(), WHITE); + const budget = +timeSel.value; + const t0 = performance.now(); + while (alive && performance.now() - t0 < budget) { + const slice = performance.now() + 14; + while (performance.now() < slice) iterate(root); + const total = root.visits || 1; + heat = new Map(root.children.filter((c) => c.move !== PASS).map((c) => [c.move, c.visits / total])); + status.textContent = `Searching: ${root.visits.toLocaleString("en")} random games so far.`; + paint(); + await new Promise((r) => setTimeout(r, 0)); + } + if (!alive) return; + let best = root.children[0]; + for (const c of root.children) if (c.visits > best.visits) best = c; + play(board, best.move, WHITE); + last = best.move; + heat?.delete(best.move); + thinking = false; + turn = BLACK; + const pct = Math.round((best.wins / best.visits) * 100); + status.textContent = `White played ${name(best.move)} after ${root.visits.toLocaleString("en")} random games, expecting to win ${pct}% of them.`; + paint(); + if (over()) return; + if (!moves(board, BLACK).length) { + status.textContent += " You have no legal move, so you pass."; + turn = WHITE; + setTimeout(() => alive && think(), 700); + } + heat = null; + setTimeout(() => alive && !thinking && paint(), 1200); + } + + grid.addEventListener("click", (e) => { + const cell = e.target.closest(".oth-cell"); + if (!cell || turn !== BLACK || thinking) return; + const i = +cell.dataset.i; + if (!flips(board, i, BLACK).length) return; + play(board, i, BLACK); + last = i; + heat = null; + paint(); + if (over()) return; + if (moves(board, WHITE).length) { + turn = WHITE; + think(); + } else { + status.textContent = "White has no legal move and passes. Your move again."; + paint(); + } + }); + host.querySelector('[data-k="new"]').addEventListener("click", () => { + if (!thinking) reset(); + }); + + reset(); + return () => { alive = false; }; +} diff --git a/src/scripts/demos/rbudp.js b/src/scripts/demos/rbudp.js @@ -0,0 +1,205 @@ +// Reliable Blast UDP in miniature, following our sender: blast every packet +// over UDP, send BLAST_COMPLETE over TCP, get back MISSING_PACKETS (or +// TRANSFER_DONE), and blast just the missing ones until nothing is missing. + +import { fitCanvas, themeColors, onFrame, reducedMotion } from "../util.js"; + +const PACKETS = 64; +const FLIGHT = 0.7; // seconds for a datagram to cross +const TCP_TRIP = 0.55; + +export function mount(host) { + host.innerHTML = ` + <div class="demo-bar"> + <button type="button" class="btn" data-k="send">send file</button> + <label class="sim-field" style="margin:0"><span>packet loss</span> + <input type="range" min="0" max="60" value="20" data-k="loss" aria-label="Packet loss rate"> + <output data-k="lossOut">20%</output> + </label> + <span class="dim" data-k="stats"></span> + </div> + <canvas class="rb-canvas" height="190" role="img" aria-label="Packets travelling from sender to receiver"></canvas> + <ol class="rb-log" aria-live="polite"></ol>`; + const cv = host.querySelector("canvas"); + const log = host.querySelector(".rb-log"); + const stats = host.querySelector('[data-k="stats"]'); + const lossIn = host.querySelector('[data-k="loss"]'); + const lossOut = host.querySelector('[data-k="lossOut"]'); + + let received = new Array(PACKETS).fill(false); + let toSend = []; + let round = 0; + let datagrams = 0; + let phase = "idle"; // idle | blast | tcp | done + let flights = []; + let tcp = null; + let clock = 0; + const loss = () => +lossIn.value / 100; + + const line = (r, proto, text) => { + const li = document.createElement("li"); + li.innerHTML = `<span class="dim">round ${r}</span><span class="rb-proto">${proto}</span><span></span>`; + li.lastChild.textContent = text; + log.append(li); + log.scrollTop = log.scrollHeight; + }; + + function start() { + received.fill(false); + toSend = Array.from({ length: PACKETS }, (_, i) => i); + round = 0; + datagrams = 0; + log.replaceChildren(); + blast(); + } + + function blast() { + round++; + datagrams += toSend.length; + line(round, "UDP", `blast ${toSend.length} packet${toSend.length === 1 ? "" : "s"}`); + const gap = Math.min(0.03, 0.9 / toSend.length); + flights = toSend.map((seq, k) => ({ seq, lost: Math.random() < loss(), t0: clock + k * gap })); + phase = "blast"; + if (reducedMotion.matches) { + for (const f of flights) if (!f.lost) received[f.seq] = true; + report(); + } + } + + function report() { + const missing = toSend.filter((s) => !received[s]); + line(round, "TCP", `BLAST_COMPLETE (${toSend.length} sequence numbers)`); + if (missing.length) { + const shown = missing.slice(0, 10).join(", ") + (missing.length > 10 ? ", …" : ""); + line(round, "TCP", `MISSING_PACKETS ${missing.length}: ${shown}`); + } else { + line(round, "TCP", "TRANSFER_DONE"); + } + toSend = missing; + if (reducedMotion.matches) { + if (missing.length && round < 50) return blast(); + return finish(); + } + tcp = { t0: clock, done: missing.length === 0 }; + phase = "tcp"; + } + + function finish() { + phase = "done"; + const extra = datagrams - PACKETS; + stats.textContent = `${round} round${round === 1 ? "" : "s"}, ${datagrams} datagrams (${extra} resent)`; + line(round, "done", `${PACKETS} packets delivered in ${round} round${round === 1 ? "" : "s"}`); + } + + function step(dt) { + clock += dt; + if (phase === "blast") { + let pending = false; + for (const f of flights) { + const t = (clock - f.t0) / FLIGHT; + if (t >= 1 && !f.lost) received[f.seq] = true; + if (t < (f.lost ? 1.4 : 1)) pending = true; + } + if (!pending) report(); + } else if (phase === "tcp" && clock - tcp.t0 > TCP_TRIP) { + if (tcp.done) finish(); + else blast(); + } + if (phase !== "done" && phase !== "idle") { + const got = received.filter(Boolean).length; + stats.textContent = `round ${round}, ${got} of ${PACKETS} received`; + } + } + + function draw() { + if (!cv.isConnected) return; + fitCanvas(cv); + const g = cv.getContext("2d"); + const W = cv.clientWidth; + const H = cv.clientHeight; + const c = themeColors(); + g.clearRect(0, 0, W, H); + g.font = "11px 'JetBrains Mono', monospace"; + g.textBaseline = "middle"; + + const tile = Math.max(7, Math.min(13, Math.floor((H - 70) / 8) - 3)); + const step8 = tile + 3; + const gridW = 8 * step8 - 3; + const top = 24; + const sx = 4; + const rx = W - gridW - 4; + const pos = (x0, seq) => [x0 + (seq % 8) * step8, top + Math.floor(seq / 8) * step8]; + + g.fillStyle = c.dim; + g.textAlign = "left"; + g.fillText("sender", sx, 10); + g.textAlign = "right"; + g.fillText("receiver", rx + gridW, 10); + g.textAlign = "center"; + g.fillText("UDP datagrams", W / 2, 10); + + const resend = new Set(phase === "blast" || phase === "tcp" ? toSend : []); + for (let s = 0; s < PACKETS; s++) { + const [x, y] = pos(sx, s); + g.fillStyle = resend.has(s) && round > 1 ? c.yellow : c.faint; + g.fillRect(x, y, tile, tile); + const [x2, y2] = pos(rx, s); + g.fillStyle = received[s] ? c.green : c.rule; + g.fillRect(x2, y2, tile, tile); + } + + if (phase === "blast") { + for (const f of flights) { + const t = (clock - f.t0) / FLIGHT; + if (t <= 0 || (!f.lost && t >= 1) || t >= 1.4) continue; + const [ax, ay] = pos(sx, f.seq); + const [bx, by] = pos(rx, f.seq); + if (f.lost && t > 0.55) { + // dropped somewhere in the network + const k = (t - 0.55) / 0.85; + const x = ax + (bx - ax) * 0.55; + const y = ay + (by - ay) * 0.55 + k * k * 60; + g.globalAlpha = Math.max(0, 1 - k); + g.fillStyle = c.red; + g.fillRect(x, y, tile, tile); + g.globalAlpha = 1; + } else { + g.fillStyle = c.fg; + g.fillRect(ax + (bx - ax) * t, ay + (by - ay) * t, tile, tile); + } + } + } + + // the TCP control channel along the bottom + const ty = top + 8 * step8 + 16; + g.strokeStyle = c.rule; + g.beginPath(); + g.moveTo(sx, ty + 0.5); + g.lineTo(rx + gridW, ty + 0.5); + g.stroke(); + g.fillStyle = c.dim; + g.textAlign = "center"; + g.fillText("TCP control channel", W / 2, ty + 14); + if (phase === "tcp") { + const k = Math.min(1, (clock - tcp.t0) / TCP_TRIP); + const x = rx + gridW - (rx + gridW - sx) * k; + g.fillStyle = c.cyan; + g.beginPath(); + g.arc(x, ty + 0.5, 4, 0, Math.PI * 2); + g.fill(); + g.textAlign = "center"; + g.fillText(tcp.done ? "TRANSFER_DONE" : `MISSING_PACKETS (${toSend.length})`, x, ty - 10); + } + } + + host.querySelector('[data-k="send"]').addEventListener("click", start); + lossIn.addEventListener("input", () => { lossOut.value = `${lossIn.value}%`; }); + + const off = onFrame((t, dt) => { + if (!host.isConnected) { off(); return; } + step(dt); + draw(); + }); + stats.textContent = "64 packets ready to send"; + return () => off(); +} diff --git a/src/scripts/demos/scheduler.js b/src/scripts/demos/scheduler.js @@ -0,0 +1,196 @@ +// A toy multicore scheduler: processes arrive, wait in one shared ready queue, +// and get dispatched to four cores under the chosen policy. Drawn as a Gantt chart. + +import { fitCanvas, themeColors, onFrame } from "../util.js"; + +const CORES = 4; +const SPAN = 48; +const QUANTUM = 3; + +export function mount(host) { + host.innerHTML = ` + <div class="demo-bar"> + <select aria-label="Scheduling policy"> + <option value="fcfs">first come, first served</option> + <option value="rr" selected>round robin, quantum ${QUANTUM}</option> + <option value="prio">preemptive priority</option> + </select> + <button type="button" class="btn" data-k="add">add process</button> + <button type="button" class="btn" data-k="pause" aria-pressed="false">pause</button> + <span class="dim" data-k="stats"></span> + </div> + <canvas height="150" aria-label="Gantt chart of processes running on four cores" role="img"></canvas> + <p class="cap">A small simulation written for this page: four cores share one ready queue. First come, first served runs each process to completion. Round robin preempts a process after ${QUANTUM} ticks. Preemptive priority always runs the highest-priority processes (p1 is highest), so a new arrival can take a core from a lower-priority one.</p>`; + const cv = host.querySelector("canvas"); + const sel = host.querySelector("select"); + const stats = host.querySelector('[data-k="stats"]'); + const pauseBtn = host.querySelector('[data-k="pause"]'); + + let t = 0; + let nextId = 1; + let queue = []; + let cores = Array.from({ length: CORES }, () => ({ p: null, slice: 0 })); + let hist = Array.from({ length: CORES }, () => []); + let done = 0; + let waitSum = 0; + let preempted = 0; + let paused = false; + const prioOf = new Map(); + + const spawn = () => { + const burst = 2 + Math.floor(Math.random() * 10); + const prio = 1 + Math.floor(Math.random() * 4); + prioOf.set(nextId, prio); + prioOf.delete(nextId - 200); + queue.push({ id: nextId++, burst, left: burst, prio, arrive: t, waited: 0 }); + }; + for (let i = 0; i < 7; i++) spawn(); + + function tick() { + const active = queue.length + cores.filter((c) => c.p).length; + if (active < 12 && Math.random() < 0.55) spawn(); + // preempt + if (sel.value === "rr") { + for (const c of cores) { + if (c.p && c.slice >= QUANTUM && queue.length) { + queue.push(c.p); + c.p = null; + preempted++; + } + } + } + // the first of the highest-priority waiting processes + const bestWaiting = () => { + let i = 0; + queue.forEach((p, j) => { if (p.prio < queue[i].prio) i = j; }); + return i; + }; + // dispatch + for (const c of cores) { + if (c.p || !queue.length) continue; + const i = sel.value === "prio" ? bestWaiting() : 0; + c.p = queue.splice(i, 1)[0]; + c.slice = 0; + } + if (sel.value === "prio") { + // once every core is busy, a waiting process that outranks the lowest-priority + // running one takes its core + while (queue.length && cores.every((c) => c.p)) { + const i = bestWaiting(); + const worst = cores.reduce((a, b) => (b.p.prio > a.p.prio ? b : a)); + if (queue[i].prio >= worst.p.prio) break; + queue.push(worst.p); + worst.p = queue.splice(i, 1)[0]; + worst.slice = 0; + preempted++; + } + } + // run one tick + cores.forEach((c, k) => { + hist[k].push(c.p ? c.p.id : 0); + if (hist[k].length > SPAN) hist[k].shift(); + if (!c.p) return; + c.p.left--; + c.slice++; + if (c.p.left === 0) { + done++; + waitSum += c.p.waited; + c.p = null; + } + }); + for (const p of queue) p.waited++; + t++; + const pre = sel.value === "fcfs" ? "" : `, ${preempted} preempted`; + stats.textContent = `t = ${t}, finished ${done}, mean wait ${done ? (waitSum / done).toFixed(1) : "0.0"} ticks${pre}`; + } + + function draw() { + if (!cv.isConnected) return; + fitCanvas(cv); + const g = cv.getContext("2d"); + const W = cv.clientWidth; + const H = cv.clientHeight; + const c = themeColors(); + const palette = [c.blue, c.green, c.yellow, c.magenta, c.cyan, c.orange, c.red]; + const color = (id) => palette[id % palette.length]; + g.clearRect(0, 0, W, H); + g.font = "11px 'JetBrains Mono', monospace"; + g.textBaseline = "middle"; + const lw = 46; + const cw = (W - lw) / SPAN; + const rh = 22; + for (let k = 0; k < CORES; k++) { + const y = 4 + k * (rh + 6); + g.fillStyle = c.dim; + g.fillText(`cpu${k}`, 0, y + rh / 2); + g.fillStyle = c.rule; + g.fillRect(lw, y, W - lw, rh); + const row = hist[k]; + const off = SPAN - row.length; + // draw each uninterrupted run as one block, labelled if it is wide enough + for (let i = 0; i < row.length;) { + const id = row[i]; + let j = i; + while (j < row.length && row[j] === id) j++; + if (id) { + const x = lw + (off + i) * cw; + const w = (j - i) * cw - 1; + g.fillStyle = color(id); + g.globalAlpha = 0.85; + g.fillRect(x, y, w, rh); + g.globalAlpha = 1; + const long = `P${id} p${prioOf.get(id)}`; + const label = sel.value === "prio" && g.measureText(long).width + 6 < w ? long : `P${id}`; + if (g.measureText(label).width + 6 < w) { + g.fillStyle = c.bg; + g.fillText(label, x + 3, y + rh / 2); + } + } + i = j; + } + } + // ready queue + const qy = 4 + CORES * (rh + 6) + 4; + g.fillStyle = c.dim; + g.fillText("ready", 0, qy + 9); + let x = lw; + // under priority scheduling, show the queue in the order it will be served + const prio = sel.value === "prio"; + const shown = prio ? [...queue].sort((a, b) => a.prio - b.prio) : queue; + for (const p of shown) { + const label = prio ? `P${p.id} p${p.prio}` : `P${p.id}·${p.left}`; + const w = g.measureText(label).width + 10; + if (x + w > W) break; + g.strokeStyle = color(p.id); + g.strokeRect(x + 0.5, qy + 0.5, w, 17); + g.fillStyle = c.fg; + g.fillText(label, x + 5, qy + 9); + x += w + 5; + } + } + + let acc = 0; + const off = onFrame((now, dt) => { + if (!host.isConnected) { off(); return; } + if (!paused) { + acc += dt; + while (acc > 0.25) { tick(); acc -= 0.25; } + } + draw(); + }); + + host.querySelector('[data-k="add"]').addEventListener("click", () => { spawn(); draw(); }); + pauseBtn.addEventListener("click", () => { + paused = !paused; + pauseBtn.setAttribute("aria-pressed", String(paused)); + pauseBtn.textContent = paused ? "resume" : "pause"; + }); + sel.addEventListener("change", () => { + hist = hist.map(() => []); + done = 0; + waitSum = 0; + preempted = 0; + }); + + return () => off(); +} diff --git a/src/scripts/gitlog.js b/src/scripts/gitlog.js @@ -0,0 +1,226 @@ +// Experience as one-line git log --graph output, the "git lg" way: +// <date> - (refs) <subject> <author> +// with the date standing in for the hash and the company as the author. +// +// The rows are plain text in src/pages/index.astro, so they read fine without JavaScript. +// This colours the graph by branch (data-lanes), colours the date, refs and +// author, and turns subjects that have a .gl-desc into buttons that expand it. +// Lanes: m main, u undergrad, t teaching-assistant, b bbd-software, i mwr-internship. +// +// When the log is wider than its box (on a phone), it wraps the way a narrow +// terminal would: at word boundaries, with each wrapped line starting with the +// commit's lane pipes and a short hanging indent. + +import { $, $$ } from "./util.js"; + +const LANE_CLASS = { m: "lm", u: "lu", t: "lt", b: "lb", i: "li" }; +const ROW = /^([|*/\\ ]*?)(\d{4}-\d{2}(?:-\d{2})?) - (?:\(([^)]*)\) ?)?(.*?)(?: ?<([^>]*)>)?$/; +const HANG = 2; + +function el(tag, cls, text) { + const e = document.createElement(tag); + if (cls) e.className = cls; + if (text != null) e.textContent = text; + return e; +} + +// The graph characters, coloured by lane and hidden from screen readers. +// `tip` makes the commit's * bold. +function graph(text, lanes = "", tip = false) { + const g = el("span", "gl-graph"); + g.setAttribute("aria-hidden", "true"); + [...text].forEach((ch, i) => { + const lane = LANE_CLASS[(lanes[i] || " ").trim()]; + if (ch === "*" && tip) g.append(el("span", "gl-tip", ch)); + else g.append(lane && ch.trim() ? el("span", lane, ch) : ch); + }); + return g; +} + +// The HEAD commit is dated with the month the page is viewed in. +function today() { + const d = new Date(); + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`; +} + +function parse(div) { + const descEl = $(".gl-desc", div); + const body = descEl ? descEl.textContent.replace(/^\n+|\s+$/g, "").split("\n") : null; + descEl?.remove(); + const text = div.textContent.replace(/\s+$/, ""); + const m = ROW.exec(text); + const row = { + graph: m ? m[1] : text, lanes: div.dataset.lanes, cont: div.dataset.cont ?? "", contLanes: div.dataset.contLanes, + tip: "tip" in div.dataset, branch: div.dataset.branch, + }; + if (!m) return row; + return { + ...row, + date: "today" in div.dataset ? today() : m[2], + refs: m[3] ? m[3].split(/,\s*/).map((r) => (r.startsWith("HEAD -> ") ? { head: true, name: r.slice(8) } : { name: r })) : [], + subject: m[4], + author: m[5], + body, + }; +} + +const refsText = (refs) => `(${refs.map((r) => (r.head ? "HEAD -> " : "") + r.name).join(", ")})`; + +// A commit line as words, so it can be wrapped. Each word knows how to draw itself. +function words(row) { + const w = [{ text: row.date, cls: `gl-date ${LANE_CLASS[row.branch] ?? ""}` }, { text: "-" }]; + if (row.refs.length) w.push({ text: refsText(row.refs), refs: row.refs }); + if (row.subject) for (const s of row.subject.split(" ")) w.push({ text: s, subj: true }); + if (row.author) w.push({ text: `<${row.author}>`, cls: "gl-author" }); // kept on one line + return w; +} + +// Greedy word wrap. Returns lines of words; a word longer than the width gets a line to itself. +function wrap(list, width, hang) { + const lines = [[]]; + let used = 0; + for (const w of list) { + const line = lines[lines.length - 1]; + const need = (line.length ? 1 : 0) + w.text.length; + if (line.length && used + need > width) { + lines.push([w]); + used = hang + w.text.length; + } else { + line.push(w); + used += need; + } + } + return lines; +} + +// Re-flow a description to a width, keeping "- " bullets with a hanging indent. +function reflow(body, width) { + const blocks = []; + for (const line of body) { + if (line.startsWith("- ") || !blocks.length || !line.startsWith(" ")) blocks.push(line.trim()); + else blocks[blocks.length - 1] += ` ${line.trim()}`; + } + // plain paragraphs that were hard-wrapped become one block again + const merged = []; + for (const b of blocks) { + if (merged.length && !b.startsWith("- ") && !merged[merged.length - 1].startsWith("- ")) merged[merged.length - 1] += ` ${b}`; + else merged.push(b); + } + const out = []; + for (const b of merged) { + const bullet = b.startsWith("- "); + const lines = wrap(b.split(" ").map((text) => ({ text })), width, bullet ? 2 : 0); + lines.forEach((l, i) => out.push((i && bullet ? " " : "") + l.map((w) => w.text).join(" "))); + } + return out; +} + +export function initGitlog() { + const host = $(".gitlog"); + if (!host) return; + const rows = $$(":scope > .gl-line", host).map(parse); + const open = new Set(); + let lastCols = 0; + + function measureCols() { + const probe = el("span", "", "0".repeat(20)); + probe.style.cssText = "position:absolute;visibility:hidden;white-space:pre"; + host.append(probe); + const ch = probe.getBoundingClientRect().width / 20 || 7; + probe.remove(); + const cs = getComputedStyle(host); + const inner = host.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight); + return Math.max(24, Math.floor(inner / ch)); + } + + function render(focusRow = -1) { + const cols = measureCols(); + lastCols = cols; + const lineLen = (r) => r.graph.length + words(r).reduce((n, w, i) => n + (i ? 1 : 0) + w.text.length, 0); + const wide = rows.every((r) => !r.date || lineLen(r) <= cols); + const pipesOnly = (r) => r && !r.date && /^[| ]+$/.test(r.graph); + const frag = document.createDocumentFragment(); + + rows.forEach((row, n) => { + if (!row.date) { + const line = el("div", "gl-line"); + line.append(graph(row.graph, row.lanes)); + frag.append(line); + return; + } + + const isOpen = open.has(n); + const lines = wrap(words(row), cols - row.graph.length, HANG); + let subjSeen = false; + lines.forEach((ws, li) => { + const line = el("div", "gl-line"); + line.append(li ? graph(row.cont, row.contLanes) : graph(row.graph, row.lanes, row.tip)); + if (li) line.append(" ".repeat(HANG)); + // consecutive subject words on a line become one button (or span) so the underline is unbroken + for (let k = 0; k < ws.length; k++) { + if (k) line.append(" "); + const w = ws[k]; + if (w.subj) { + let text = w.text; + while (ws[k + 1]?.subj) text += ` ${ws[++k].text}`; + if (row.body) { + const b = el("button", "gl-subj", text); + b.type = "button"; + b.dataset.row = n; + b.setAttribute("aria-expanded", String(isOpen)); + if (subjSeen) b.tabIndex = -1; // one tab stop per commit, even when its subject wraps + line.append(b); + } else { + line.append(el("span", "gl-text", text)); + } + subjSeen = true; + } else if (w.refs) { + const refs = el("span", "gl-refs"); + refs.append("("); + w.refs.forEach((r, i) => { + if (i) refs.append(", "); + if (r.head) refs.append(el("span", "gl-head", "HEAD -> ")); + refs.append(el("span", "gl-branch", r.name)); + }); + refs.append(")"); + line.append(refs); + } else { + line.append(w.cls ? el("span", w.cls, w.text) : w.text); + } + } + frag.append(line); + }); + + if (row.body && isOpen) { + const refsLen = row.refs.length ? refsText(row.refs).length + 1 : 0; + // under the subject when there's room; otherwise a little deeper than wrapped lines + const indent = wide ? row.date.length + 3 + refsLen : HANG + 2; + const text = wide ? row.body : reflow(row.body, cols - row.cont.length - indent); + const tail = pipesOnly(rows[n + 1]) ? [] : [""]; + for (const t of [...text, ...tail]) { + const b = el("div", "gl-line gl-body"); + b.append(graph(row.cont, row.contLanes), t ? " ".repeat(indent) + t : ""); + frag.append(b); + } + } + }); + + host.replaceChildren(frag); + host.classList.add("is-built"); + if (focusRow >= 0) host.querySelector(`.gl-subj[data-row="${focusRow}"]`)?.focus({ preventScroll: true }); + } + + host.addEventListener("click", (e) => { + const b = e.target.closest(".gl-subj"); + if (!b) return; + const n = +b.dataset.row; + if (open.has(n)) open.delete(n); + else open.add(n); + render(n); + }); + + render(); + new ResizeObserver(() => { + if (measureCols() !== lastCols) render(); + }).observe(host); +} diff --git a/src/scripts/main.js b/src/scripts/main.js @@ -0,0 +1,27 @@ +import { fontsReady } from "./util.js"; +import "./shell.js"; +import "./computer.js"; // registers the computer commands; the 8-bit project mounts it +import { initDecode } from "./decode.js"; +import { initDatasheet } from "./datasheet.js"; +import { initGitlog } from "./gitlog.js"; +import { initMemmap } from "./memmap.js"; +import { initOrg } from "./org.js"; +import { initContact } from "./contact.js"; +import { initCtf } from "./ctf.js"; +import { initCoffee } from "./coffee.js"; + +function safely(fn) { + try { fn(); } catch (err) { console.error(err); } +} + +initDecode().catch((err) => { console.error(err); document.documentElement.classList.remove("boot"); }); +safely(initDatasheet); +safely(initGitlog); +safely(initOrg); +safely(initContact); +safely(initCtf); +safely(initCoffee); + +// The hexdump measures character widths, so wait for the mono font. +await fontsReady(); +safely(initMemmap); diff --git a/src/scripts/memmap.js b/src/scripts/memmap.js @@ -0,0 +1,206 @@ +// Projects as a linker memory map. Each project's region holds its one-line +// summary as UTF-8, so a region is exactly as long as that text, origins are +// cumulative, and the hexdump shows the region's actual bytes. Projects with a +// data-demo attribute mount a small interactive demo under their write-up. + +import { $, $$, hex, reducedMotion, on } from "./util.js"; + +const GLYPHS = "░▒▓/\\<>+=*#%&@$0123456789ABCDEF"; + +export function initMemmap() { + const mm = $(".mm"); + if (!mm) return; + const bar = $(".mm-bar", mm); + const detail = $(".mm-detail", mm); + const narrow = matchMedia("(max-width: 920px)"); + const enc = new TextEncoder(); + + let origin = 0; + const projects = $$(".proj", mm).map((li) => { + const sum = $(".proj-sum", li).textContent.trim(); + const p = { + li, + cat: li.dataset.cat, + src: li.dataset.src || "", + demo: li.dataset.demo || "", + wide: "wide" in li.dataset, + name: $(".proj-name", li).textContent.trim(), + sum, + bytes: enc.encode(sum), + body: $(".proj-body", li), + origin, + }; + origin += p.bytes.length; + return p; + }); + const meta = $('[data-mm="meta"]'); + if (meta) meta.textContent = `${projects.length} regions, 0x${hex(origin, 4)} bytes`; + + projects.forEach((p, i) => { + const h = $(".proj-name", p.li); + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = "proj-row"; + btn.dataset.cat = p.cat; + btn.setAttribute("aria-pressed", "false"); + btn.innerHTML = `<span class="o">0x${hex(p.origin, 4)}</span><span class="l">0x${hex(p.bytes.length, 2)}</span><span class="n"></span><span class="y"></span>`; + const n = $(".n", btn); + n.textContent = p.name; + const s = document.createElement("span"); + s.className = "s"; + s.textContent = p.sum; + n.append(s); + $(".y", btn).textContent = p.src; + h.replaceChildren(btn); + btn.addEventListener("click", () => select(i, true)); + p.btn = btn; + + const seg = document.createElement("div"); + seg.className = "mm-seg"; + seg.dataset.cat = p.cat; + seg.style.flexGrow = p.bytes.length; + seg.textContent = p.name; + seg.title = `${p.name}: 0x${hex(p.origin, 4)}, ${p.bytes.length} bytes`; + seg.addEventListener("click", () => select(i, true)); + bar.append(seg); + p.seg = seg; + }); + mm.classList.add("is-built"); + + let current = -1; + let anim = 0; + let unmount = null; + let wideHost = null; + + async function select(i, user = false) { + const p = projects[i]; + if (user && i === current && narrow.matches) { + close(); + return; + } + current = i; + projects.forEach((q, j) => { + q.btn.setAttribute("aria-pressed", String(i === j)); + q.seg.classList.toggle("is-active", i === j); + }); + unmount?.(); + unmount = null; + wideHost?.remove(); + wideHost = null; + detail.dataset.cat = p.cat; + + const dump = document.createElement("pre"); + dump.className = "hex"; + dump.setAttribute("aria-hidden", "true"); + const title = document.createElement("h3"); + title.textContent = p.name; + const body = p.body.cloneNode(true); + detail.replaceChildren(dump, title, body); + place(); + hexdump(dump, p); + + if (p.demo) { + const host = document.createElement("div"); + host.className = p.wide ? "demo demo-wide" : "demo"; + if (p.wide) wideHost = host; + placeDemo(host, p); + try { + const mod = await import(`./demos/${p.demo}.js`); + if (current === i && host.isConnected) unmount = mod.mount(host) ?? null; + } catch (err) { + console.error(err); + host.remove(); + } + } + } + + function close() { + unmount?.(); + unmount = null; + wideHost?.remove(); + wideHost = null; + projects[current]?.btn.setAttribute("aria-pressed", "false"); + projects[current]?.seg.classList.remove("is-active"); + detail.replaceChildren(); + current = -1; + } + + // On narrow screens the write-up opens under its row instead of beside the list. + function place() { + const p = projects[current]; + if (!p) return; + if (narrow.matches) p.li.append(detail); + else $(".mm-cols", mm).append(detail); + if (wideHost) placeDemo(wideHost, p); + } + + // Most demos sit under the write-up; a wide one gets the full width under the list. + function placeDemo(host, p) { + if (p.wide && !narrow.matches) mm.append(host); + else detail.append(host); + } + + // Other parts of the page can open a project by name (the computer commands do). + on("project", (name) => { + const i = projects.findIndex((q) => q.name === name); + if (i >= 0 && i !== current) select(i); + }); + narrow.addEventListener("change", place); + + function hexdump(pre, p) { + // 16 bytes a line like hexdump -C when its 78 columns fit, otherwise 8 + const probe = document.createElement("span"); + probe.textContent = "0".repeat(10); + pre.append(probe); + const cols = Math.floor(pre.clientWidth / (probe.getBoundingClientRect().width / 10 || 7)); + probe.remove(); + const per = cols >= 78 ? 16 : 8; + const lines = []; + for (let off = 0; off < p.bytes.length; off += per) { + const chunk = [...p.bytes.slice(off, off + per)]; + const hx = chunk.map((b) => hex(b)).concat(Array(per - chunk.length).fill(" ")); + const ascii = chunk.map((b) => (b >= 32 && b < 127 ? String.fromCharCode(b) : ".")).join(""); + lines.push({ + addr: hex(p.origin + off, 8), + hex: per === 16 ? `${hx.slice(0, 8).join(" ")} ${hx.slice(8).join(" ")}` : hx.join(" "), + ascii: ascii.padEnd(per, " "), + }); + } + const render = (reveal) => { + pre.replaceChildren(); + lines.forEach((ln, li) => { + const k = reveal - li * 0.08; + const a = document.createElement("span"); + a.className = "addr"; + a.textContent = ln.addr; + const asc = document.createElement("span"); + asc.className = "a"; + asc.textContent = `|${scramble(ln.ascii, k)}|`; + pre.append(a, ` ${scramble(ln.hex, k)} `, asc, li < lines.length - 1 ? "\n" : ""); + }); + }; + cancelAnimationFrame(anim); + if (reducedMotion.matches) return render(9); + const t0 = performance.now(); + const frame = (now) => { + const k = (now - t0) / 480; + render(k); + if (k < 1 + lines.length * 0.08) anim = requestAnimationFrame(frame); + }; + anim = requestAnimationFrame(frame); + } + + select(0); +} + +// Characters left of the reveal point are final; to the right they flicker. +function scramble(str, k) { + if (k >= 1) return str; + const cut = Math.max(0, Math.floor(str.length * k)); + let out = str.slice(0, cut); + for (let i = cut; i < str.length; i++) { + const c = str[i]; + out += k < 0 ? " " : c === " " ? c : GLYPHS[(Math.random() * GLYPHS.length) | 0]; + } + return out; +} diff --git a/src/scripts/org.js b/src/scripts/org.js @@ -0,0 +1,168 @@ +// Renders the posts section as an Org buffer: keywords, a paragraph, years as +// "*" headings and posts as "**" headings with tags and a property drawer. +// TAB folds the heading at point; S-TAB cycles OVERVIEW, CONTENTS and SHOW ALL. + +import { $, $$ } from "./util.js"; +import { message } from "./shell.js"; + +const DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + +// One colour per tag, like org-tag-faces. Add an entry when you add a tag. +const TAG_COLORS = { + emacs: "var(--magenta)", + org: "var(--green)", + latex: "var(--cyan)", + python: "var(--yellow)", + maths: "var(--blue)", + linux: "var(--orange)", + security: "var(--red)", + c: "var(--violet)", + web: "var(--fg)", +}; + +export function initOrg() { + const sec = $("#posts"); + const src = sec && $(".posts", sec); + if (!src) return; + const intro = $(".org-p", sec); + + const posts = $$("li", src).map((li) => { + const a = $("a", li); + return { date: li.dataset.date, tags: (li.dataset.tags || "").split(/\s+/).filter(Boolean), title: a.textContent.trim(), href: a.href }; + }); + const years = [...new Set(posts.map((p) => p.date.slice(0, 4)))].sort().reverse(); + + const el = (tag, cls, text) => { + const e = document.createElement(tag); + if (cls) e.className = cls; + if (text != null) e.textContent = text; + return e; + }; + + const org = el("div", "org"); + const kw = (tag, key, value, cls) => { + const p = el(tag, "org-kw"); + const k = el("span", "org-key", `#+${key}: `); + if (tag === "h2") k.setAttribute("aria-hidden", "true"); + p.append(k, el("span", cls, value)); + return p; + }; + org.append(kw("h2", "title", "Posts", "org-title"), kw("p", "author", "Michael Neuper", "v"), kw("p", "startup", "content", "v")); + if (intro) org.append(intro); + + const tree = el("ul", "org-tree"); + tree.setAttribute("role", "tree"); + tree.setAttribute("aria-label", "Posts by year"); + const headings = []; + + function heading(li, level) { + const h = el("div", "org-h"); + h.tabIndex = headings.length === 0 ? 0 : -1; + const stars = el("button", "org-stars", "*".repeat(level)); + stars.type = "button"; + stars.tabIndex = -1; + stars.setAttribute("aria-label", "Fold or unfold"); + stars.addEventListener("click", () => { li._fold(!li._open()); h.focus({ preventScroll: true }); }); + h.append(stars); + li.prepend(h); + headings.push(h); + return h; + } + + for (const y of years) { + const items = posts.filter((p) => p.date.startsWith(y)); + const li = el("li", "org-h1"); + li.setAttribute("role", "treeitem"); + const h = heading(li, 1); + h.append(el("span", "org-text", y), el("span", "count", `[${items.length}]`)); + const ell = el("span", "org-ellipsis", "..."); + h.append(ell); + + const kids = el("ul", "org-tree"); + kids.setAttribute("role", "group"); + for (const p of items) { + const pl = el("li", "org-h2"); + pl.setAttribute("role", "treeitem"); + const ph = heading(pl, 2); + const a = el("a", "org-text", p.title); + a.href = p.href; + a.tabIndex = -1; + ph.append(a); + if (p.tags.length) { + const tags = el("span", "org-tags"); + tags.append(":"); + for (const t of p.tags) { + const tg = el("span", "t", t); + tg.style.setProperty("--tag", TAG_COLORS[t] ?? "var(--dim)"); + tags.append(tg, ":"); + } + ph.append(tags); + } + const pell = el("span", "org-ellipsis", "..."); + ph.append(pell); + + const d = new Date(`${p.date}T12:00:00Z`); + const drawer = el("div", "org-drawer"); + drawer.innerHTML = `<span class="k">:PROPERTIES:</span>\n<span class="k">:DATE:</span> <span class="ts">&lt;${p.date} ${DAYS[d.getUTCDay()]}&gt;</span>\n<span class="k">:URL:</span> <a href="${p.href}" tabindex="-1">${p.href.replace(/^https?:\/\//, "")}</a>\n<span class="k">:END:</span>`; + pl.append(drawer); + pl._fold = (open) => { + drawer.hidden = !open; + pell.hidden = open; + pl.setAttribute("aria-expanded", String(open)); + }; + pl._open = () => !drawer.hidden; + pl._fold(false); + kids.append(pl); + } + li.append(kids); + li._fold = (open) => { + kids.hidden = !open; + ell.hidden = open; + li.setAttribute("aria-expanded", String(open)); + }; + li._open = () => !kids.hidden; + li._fold(true); + tree.append(li); + } + org.append(tree); + src.replaceWith(org); + + const meta = $('[data-org="meta"]', sec); + if (meta) meta.textContent = `${posts.length} posts`; + + // Global visibility cycling, like S-TAB in Org. + const STATES = ["OVERVIEW", "CONTENTS", "SHOW ALL"]; + let global = 1; + function globalCycle() { + global = (global + 1) % 3; + for (const y of $$(".org-h1", tree)) { + y._fold(global > 0); + for (const p of $$(".org-h2", y)) p._fold(global === 2); + } + message(STATES[global]); + } + + const visible = () => headings.filter((h) => h.offsetParent !== null); + tree.addEventListener("keydown", (e) => { + const h = e.target.closest(".org-h"); + if (!h) return; + const li = h.parentElement; + const vis = visible(); + const i = vis.indexOf(h); + const move = (j) => { + const t = vis[Math.max(0, Math.min(vis.length - 1, j))]; + for (const x of headings) x.tabIndex = -1; + t.tabIndex = 0; + t.focus(); + }; + if (e.key === "Tab" && e.shiftKey) { e.preventDefault(); globalCycle(); } + else if (e.key === "Tab") { e.preventDefault(); li._fold(!li._open()); } + else if (e.key === "ArrowDown" || e.key === "j") { e.preventDefault(); move(i + 1); } + else if (e.key === "ArrowUp" || e.key === "k") { e.preventDefault(); move(i - 1); } + else if (e.key === "Enter") { + const a = h.querySelector("a"); + if (a) a.click(); + else li._fold(!li._open()); + } + }); +} diff --git a/src/scripts/shell.js b/src/scripts/shell.js @@ -0,0 +1,511 @@ +// The Emacs around the page: doom-modeline, the echo area, a minibuffer with +// vertico-style completion (M-x, evil's :), which-key on the SPC leader, and +// load-theme with live preview. Other modules add commands with defcommand(). + +import { $, $$, emit, isTyping, finePointer, reducedMotion } from "./util.js"; +import { THEMES, DEFAULT_THEME } from "./themes.js"; + +const root = document.documentElement; +const modeline = $(".modeline"); +const ml = { + evil: $(".ml-evil"), buf: $(".ml-buf"), pos: $(".ml-pos"), pct: $(".ml-pct"), + flags: $(".ml-flags"), misc: $(".ml-misc"), mode: $(".ml-mode"), time: $(".ml-time"), +}; +const mini = $(".mini"); +const form = $(".mini-prompt"); +const input = $("input", form); +const psEl = $(".mini-ps"); +const countEl = $(".mini-count"); +const list = $(".mini-list"); +const echo = $(".echo"); +const wk = $(".which-key"); +const help = $(".help"); +const nav = $(".nav"); +const menuKey = $(".menu-key"); + +// ── echo area ───────────────────────────────────────────────────────── + +let echoTimer = 0; +const idleText = () => (finePointer.matches ? "Press SPC for commands, or M-x to run one by name." : ""); +export function message(text, kind = "", ms = 5000) { + echo.textContent = text; + echo.className = kind ? `echo is-${kind}` : "echo"; + clearTimeout(echoTimer); + if (ms) echoTimer = setTimeout(() => message(idleText(), "", 0), ms); +} +message(idleText(), "", 0); + +// ── modeline ────────────────────────────────────────────────────────── + +export function setSegment(name, text) { + if (ml[name]) ml[name].textContent = text; +} + +function evilState() { + const a = document.activeElement; + let s = "N"; + if (!mini.hidden || (a && isTyping({ target: a }))) s = "I"; + else if (String(getSelection()).length) s = "V"; + modeline.dataset.evil = s; + ml.evil.textContent = `<${s}>`; +} +document.addEventListener("focusin", evilState); +document.addEventListener("focusout", () => setTimeout(evilState)); +document.addEventListener("selectionchange", evilState); + +function onScroll() { + const max = root.scrollHeight - innerHeight; + const y = scrollY; + ml.pct.textContent = y <= 2 ? "Top" : y >= max - 2 ? "Bot" : `${Math.round((y / max) * 100)}%`; + ml.pos.textContent = `${Math.floor(y / 21) + 1}:0`; + root.classList.toggle("is-scrolled", y > 24); +} +addEventListener("scroll", onScroll, { passive: true }); +onScroll(); + +function clock() { + const d = new Date(); + ml.time.textContent = `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`; +} +clock(); +setInterval(clock, 15000); + +// ── sections ────────────────────────────────────────────────────────── + +const sections = $$("main > section"); +const navLinks = $$(".nav a"); +const sectionIO = new IntersectionObserver((entries) => { + for (const e of entries) { + if (!e.isIntersecting) continue; + ml.buf.textContent = e.target.dataset.file; + ml.mode.textContent = e.target.dataset.mode; + for (const a of navLinks) a.setAttribute("aria-current", String(a.hash === `#${e.target.id}`)); + emit("section", e.target.id); + } +}, { rootMargin: "-40% 0px -55% 0px" }); +sections.forEach((s) => sectionIO.observe(s)); + +export function goto(id, quiet = false) { + const s = document.getElementById(id); + if (!s) return; + // Sections snap to their header line, so scroll to that rather than the padding above it. + ($(".winbar", s) ?? s).scrollIntoView({ behavior: reducedMotion.matches ? "auto" : "smooth", block: "start" }); + history.replaceState(null, "", id === "top" ? location.pathname : `#${id}`); + if (!quiet) message(`"${s.dataset.file}"`); +} + +document.addEventListener("click", (e) => { + const a = e.target.closest('a[href^="#"]'); + if (!a || e.defaultPrevented || e.metaKey || e.ctrlKey || e.shiftKey) return; + const id = a.hash.slice(1); + if (!sections.some((s) => s.id === id)) return; + e.preventDefault(); + goto(id, true); +}); + +// ── commands ────────────────────────────────────────────────────────── + +const commands = new Map(); +export function defcommand(name, run, { doc = "", key = "", hidden = false } = {}) { + commands.set(name, { name, run, doc, key, hidden }); +} +export function call(name, ...args) { + const c = commands.get(name); + if (!c) return message(`Symbol’s function definition is void: ${name}`, "error"); + return c.run(...args); +} + +// ── minibuffer: completing-read ─────────────────────────────────────── + +let pending = null; + +// Resolves to the chosen string, or null if cancelled. `candidates` is an array of +// { value, ann, key } (or strings), or a function of the input returning one. +export function completingRead(prompt, candidates, opts = {}) { + const { initial = "", requireMatch = true, select = null, onPreview = null } = opts; + if (pending) pending.finish(null); + const returnFocus = document.activeElement; + + return new Promise((resolve) => { + let items = []; + let sel = 0; + const norm = (c) => (typeof c === "string" ? { value: c } : c); + + const render = () => { + const q = input.value.trim().toLowerCase(); + const all = (typeof candidates === "function" ? candidates(input.value) : candidates).map(norm); + const terms = q.split(/\s+/).filter(Boolean); + items = typeof candidates === "function" ? all : all.filter((c) => terms.every((t) => c.value.toLowerCase().includes(t))); + // candidates that start with what you typed come first + if (terms.length && typeof candidates !== "function") { + const starts = (c) => c.value.toLowerCase().startsWith(terms[0]); + items = [...items.filter(starts), ...items.filter((c) => !starts(c))]; + } + sel = Math.min(sel, Math.max(0, items.length - 1)); + countEl.textContent = items.length ? `${sel + 1}/${items.length}` : "0/0"; + list.replaceChildren(...items.map((c, i) => { + const li = document.createElement("li"); + li.setAttribute("role", "option"); + li.setAttribute("aria-selected", String(i === sel)); + li.id = `mini-opt-${i}`; + const cand = document.createElement("span"); + cand.className = "cand"; + cand.append(...highlight(c.value, terms)); + li.append(cand); + if (c.ann) { + const a = document.createElement("span"); + a.className = "ann"; + a.textContent = c.ann; + li.append(a); + } + if (c.key) { + const k = document.createElement("span"); + k.className = "key"; + k.textContent = c.key; + li.append(k); + } + li.addEventListener("mousedown", (e) => e.preventDefault()); + li.addEventListener("click", () => { sel = i; accept(); }); + return li; + })); + input.setAttribute("aria-activedescendant", items.length ? `mini-opt-${sel}` : ""); + list.children[sel]?.scrollIntoView({ block: "nearest" }); + }; + + const move = (d) => { + if (!items.length) return; + sel = (sel + d + items.length) % items.length; + render(); + onPreview?.(items[sel].value); + }; + + const accept = () => { + const raw = input.value.trim(); + const hit = items[sel]?.value; + if (hit !== undefined && (requireMatch || typeof candidates !== "function" || raw === "")) finish(hit); + else if (!requireMatch) finish(raw || hit || null); + else if (hit !== undefined) finish(hit); + else message("[No match]", "error", 1500); + }; + + const onKey = (e) => { + const ctrl = e.ctrlKey && !e.metaKey; + if (e.key === "ArrowDown" || (ctrl && e.key === "n")) { e.preventDefault(); move(1); } + else if (e.key === "ArrowUp" || (ctrl && e.key === "p")) { e.preventDefault(); move(-1); } + else if (e.key === "Enter") { e.preventDefault(); accept(); } + else if (e.key === "Escape" || (ctrl && e.key === "g")) { e.preventDefault(); finish(null); } + else if (e.key === "Tab") { + e.preventDefault(); + if (items[sel]) { + input.value = items[sel].value; + render(); + } + } + }; + const onInput = () => { + sel = 0; + render(); + if (items.length) onPreview?.(items[0].value); + }; + const onBlur = () => setTimeout(() => { if (pending?.finish === finish && document.activeElement !== input) finish(null); }, 0); + const onSubmit = (e) => e.preventDefault(); + + function finish(value) { + if (pending?.finish !== finish) return; + pending = null; + input.removeEventListener("keydown", onKey); + input.removeEventListener("input", onInput); + input.removeEventListener("blur", onBlur); + form.removeEventListener("submit", onSubmit); + mini.hidden = true; + list.replaceChildren(); + if (returnFocus && returnFocus !== input && document.contains(returnFocus)) returnFocus.focus({ preventScroll: true }); + else input.blur(); + evilState(); + resolve(value); + } + + pending = { finish }; + psEl.textContent = prompt; + input.value = initial; + mini.hidden = false; + input.addEventListener("keydown", onKey); + input.addEventListener("input", onInput); + input.addEventListener("blur", onBlur); + form.addEventListener("submit", onSubmit); + if (select) { + const all = (typeof candidates === "function" ? candidates("") : candidates).map(norm); + sel = Math.max(0, all.findIndex((c) => c.value === select)); + } + render(); + input.focus({ preventScroll: true }); + evilState(); + }); +} + +function highlight(text, terms) { + if (!terms.length) return [text]; + const lower = text.toLowerCase(); + const marks = new Array(text.length).fill(false); + for (const t of terms) { + const i = lower.indexOf(t); + if (i >= 0) for (let k = i; k < i + t.length; k++) marks[k] = true; + } + const out = []; + let buf = ""; + let on = false; + for (let i = 0; i <= text.length; i++) { + const m = i < text.length && marks[i]; + if (i === text.length || m !== on) { + if (buf) { + if (on) { + const mk = document.createElement("mark"); + mk.textContent = buf; + out.push(mk); + } else out.push(buf); + } + buf = ""; + on = m; + } + if (i < text.length) buf += text[i]; + } + return out; +} + +// ── M-x and evil ex ─────────────────────────────────────────────────── + +async function mx() { + const cands = [...commands.values()].filter((c) => !c.hidden).sort((a, b) => a.name.localeCompare(b.name)) + .map((c) => ({ value: c.name, ann: c.doc, key: c.key })); + const name = await completingRead("M-x ", cands); + if (name) call(name); +} +defcommand("execute-extended-command", mx, { hidden: true }); + +const EX = ["colorscheme", "edit", "help", "quit", "write", "wq"]; +async function ex() { + const line = await completingRead(":", (q) => { + const [cmd, arg = ""] = q.trim().split(/\s+/); + if (/^colo/.test(cmd || "") && q.includes(" ")) return THEMES.filter((t) => t.id.startsWith(arg)).map((t) => ({ value: `colorscheme ${t.id}`, ann: t.desc })); + if (/^e(dit)?$/.test(cmd || "") && q.includes(" ")) return sections.filter((s) => s.id.startsWith(arg)).map((s) => ({ value: `edit ${s.id}`, ann: s.dataset.file })); + return EX.filter((c) => c.startsWith(cmd || "")).map((c) => ({ value: c })); + }, { requireMatch: false }); + if (line) runEx(line); +} + +function runEx(line) { + const [cmd, arg] = line.trim().split(/\s+/); + if (/^q(uit|a)?!?$/.test(cmd)) call("save-buffers-kill-terminal"); + else if (/^(w|write)$/.test(cmd)) message(`"${ml.buf.textContent}" written`); + else if (/^(wq|x)!?$/.test(cmd)) message(`"${ml.buf.textContent}" written. Still here, though.`); + else if (/^colo(r(scheme)?)?$/.test(cmd)) arg ? setTheme(arg) : call("load-theme"); + else if (/^e(dit)?$/.test(cmd)) goto(findSection(arg)?.id ?? "top"); + else if (/^h(elp)?$/.test(cmd)) call("help"); + else message(`E492: Not an editor command: ${line}`, "error"); +} + +function findSection(word = "") { + const w = word.toLowerCase(); + return sections.find((s) => s.id === w || s.dataset.file === w) || sections.find((s) => s.id.startsWith(w) || s.dataset.file.startsWith(w)); +} + +// ── themes ──────────────────────────────────────────────────────────── + +const currentTheme = () => root.dataset.theme || DEFAULT_THEME; +function applyTheme(id) { + if (root.dataset.theme === id) return; + root.dataset.theme = id; + emit("theme", id); +} +export function setTheme(id) { + if (!THEMES.some((t) => t.id === id)) return message(`Unable to find theme file for ‘${id}’`, "error"); + applyTheme(id); + try { localStorage.setItem("theme", id); } catch { /* private mode */ } + message(`Loaded theme ${id}`); +} + +async function loadTheme() { + const saved = currentTheme(); + const id = await completingRead("Load custom theme: ", THEMES.map((t) => ({ value: t.id, ann: t.desc })), { + select: saved, + onPreview: applyTheme, + }); + if (id) setTheme(id); + else applyTheme(saved); +} +defcommand("load-theme", loadTheme, { doc: "Load a theme, previewing each one", key: "SPC h t" }); +$(".theme-key").addEventListener("click", loadTheme); + +// ── a few more commands ─────────────────────────────────────────────── + +defcommand("find-file", async () => { + const id = await completingRead("Find file: ", sections.map((s) => ({ value: s.dataset.file, ann: s.querySelector("h1, h2")?.textContent ?? "" }))); + const s = id && sections.find((x) => x.dataset.file === id); + if (s) goto(s.id); +}, { doc: "Jump to a section by its file name", key: "SPC ." }); + +for (const s of sections) { + defcommand(`goto-${s.id}`, () => goto(s.id), { hidden: true }); +} + +defcommand("help", () => { if (!help.open) help.showModal(); }, { doc: "Show keys and commands", key: "SPC h h" }); +defcommand("save-buffers-kill-terminal", () => message("This is a website: close it with C-w. Glad you stayed, though."), { doc: "Quit Emacs", key: "SPC q q" }); +defcommand("restart-emacs", () => location.reload(), { doc: "Restart Emacs (reloads the page)", key: "SPC q r" }); +defcommand("buy-me-a-coffee", () => { + window.open("https://buymeacoffee.com/michaelneuper", "_blank", "noopener"); + message("Opened buymeacoffee.com/michaelneuper"); +}, { doc: "Open my Buy Me a Coffee page", key: "SPC b" }); +defcommand("keyboard-quit", () => message("Quit"), { hidden: true }); +help.addEventListener("keydown", (e) => { if (e.key === "q") help.close(); }); + +// ── which-key on the SPC leader ─────────────────────────────────────── + +const KEYMAP = [ + { key: "SPC", desc: "find file", cmd: "find-file" }, + { key: ":", desc: "M-x", cmd: "execute-extended-command" }, + { key: "c", desc: "+computer", map: [ + { key: "c", desc: "run or pause", cmd: "computer-run" }, + { key: "n", desc: "step one cycle", cmd: "computer-step" }, + { key: "r", desc: "reset", cmd: "computer-reset" }, + { key: "l", desc: "load program", cmd: "computer-load-program" }, + ] }, + { key: "a", desc: "about", cmd: "goto-about" }, + { key: "p", desc: "projects", cmd: "goto-projects" }, + { key: "n", desc: "posts", cmd: "goto-posts" }, + { key: "m", desc: "mail me", cmd: "goto-contact" }, + { key: "r", desc: "refill coffee", cmd: "coffee-refill" }, + { key: "b", desc: "buy me a coffee", cmd: "buy-me-a-coffee" }, + { key: "h", desc: "+help", map: [ + { key: "t", desc: "load-theme", cmd: "load-theme" }, + { key: "h", desc: "keys and commands", cmd: "help" }, + ] }, + { key: "s", desc: "+security", map: [ + { key: "f", desc: "submit-flag", cmd: "submit-flag" }, + { key: "g", desc: "copy GPG fingerprint", cmd: "copy-gpg-fingerprint" }, + ] }, + { key: "q", desc: "+quit", map: [ + { key: "q", desc: "quit", cmd: "save-buffers-kill-terminal" }, + { key: "r", desc: "restart", cmd: "restart-emacs" }, + ] }, +]; + +let leader = null; // { map, prefix } +let wkTimer = 0; + +function startLeader() { + leader = { map: KEYMAP, prefix: "SPC" }; + message("SPC-", "", 0); + clearTimeout(wkTimer); + wkTimer = setTimeout(showWhichKey, 300); +} + +function showWhichKey() { + if (!leader) return; + const title = document.createElement("p"); + title.className = "wk-title"; + title.textContent = `${leader.prefix}-`; + wk.replaceChildren(title, ...leader.map.map((b) => { + const item = document.createElement("button"); + item.type = "button"; + item.className = "wk-item"; + item.style.cssText = "border:0;background:none;padding:0;text-align:left;font:inherit;color:inherit"; + item.innerHTML = `<span class="wk-key"></span><span class="wk-arrow">→</span><span class="wk-desc${b.map ? " group" : ""}"></span>`; + item.children[0].textContent = b.key; + item.children[2].textContent = b.desc; + item.addEventListener("mousedown", (e) => e.preventDefault()); + item.addEventListener("click", () => press(b.key)); + return item; + })); + wk.hidden = false; +} + +function endLeader(text = null) { + leader = null; + clearTimeout(wkTimer); + wk.hidden = true; + if (text !== null) message(text, text.endsWith("undefined") ? "error" : "", 3000); + else message(idleText(), "", 0); +} + +function press(key) { + const b = leader.map.find((x) => x.key === key); + if (!b) return endLeader(`${leader.prefix} ${key} is undefined`); + if (b.map) { + leader = { map: b.map, prefix: `${leader.prefix} ${key}` }; + message(`${leader.prefix}-`, "", 0); + showWhichKey(); + return; + } + endLeader(); + call(b.cmd); +} + +// ── keys ────────────────────────────────────────────────────────────── + +addEventListener("keydown", (e) => { + if (help.open) return; + if (leader) { + if (["Shift", "Control", "Alt", "Meta"].includes(e.key)) return; + e.preventDefault(); + e.stopPropagation(); + if (e.key === "Escape" || (e.ctrlKey && e.key === "g")) endLeader("Quit"); + else press(e.key === " " ? "SPC" : e.key); + return; + } + if (!mini.hidden || isTyping(e)) return; + + if (e.altKey && e.code === "KeyX" && !e.ctrlKey && !e.metaKey) { + e.preventDefault(); + mx(); + } else if (e.ctrlKey && e.key === "g") { + e.preventDefault(); + call("keyboard-quit"); + } else if (e.metaKey || e.ctrlKey || e.altKey) { + // leave browser shortcuts alone + } else if (e.key === " " && !e.target.closest?.("button, a, select, summary, [tabindex]")) { + e.preventDefault(); + startLeader(); + } else if (e.key === ":") { + e.preventDefault(); + ex(); + } else if (e.key === "?") { + e.preventDefault(); + call("help"); + } else if (e.key === "Escape" && nav.classList.contains("is-open")) { + toggleMenu(false); + } +}, true); + +// ── mobile menu ─────────────────────────────────────────────────────── + +function toggleMenu(open = !nav.classList.contains("is-open")) { + nav.classList.toggle("is-open", open); + menuKey.setAttribute("aria-expanded", String(open)); +} +menuKey.addEventListener("click", () => toggleMenu()); +nav.addEventListener("click", (e) => { if (e.target.closest("a")) toggleMenu(false); }); +document.addEventListener("click", (e) => { + if (nav.classList.contains("is-open") && !e.target.closest(".nav, .menu-key")) toggleMenu(false); +}); + +// ── copy buttons: <button data-copy="selector"> ─────────────────────── + +document.addEventListener("click", async (e) => { + const b = e.target.closest("[data-copy]"); + if (!b) return; + const src = document.querySelector(b.dataset.copy); + if (!src) return; + const label = b.textContent; + try { + await navigator.clipboard.writeText(src.textContent.trim()); + b.textContent = "copied"; + message(`Copied: ${src.textContent.trim()}`, "ok", 3000); + } catch { + const r = document.createRange(); + r.selectNodeContents(src); + getSelection().removeAllRanges(); + getSelection().addRange(r); + b.textContent = "selected"; + } + setTimeout(() => { b.textContent = label; }, 2000); +}); diff --git a/src/scripts/themes.js b/src/scripts/themes.js @@ -0,0 +1,19 @@ +// Themes for M-x load-theme. The colours live in src/styles/style.css under +// :root[data-theme="…"]; keep this list, that CSS and the inline script in +// src/pages/index.astro in sync. + +export const THEMES = [ + { id: "doom-gruvbox", desc: "Gruvbox, medium contrast. The theme my own Emacs uses" }, + { id: "doom-gruvbox-light", desc: "Gruvbox's light variant" }, + { id: "doom-one", desc: "Doom Emacs's default, inspired by Atom One Dark" }, + { id: "atom-one-dark", desc: "Atom's One Dark" }, + { id: "modus-vivendi", desc: "Emacs's built-in high-contrast dark theme" }, + { id: "modus-operandi", desc: "Emacs's built-in high-contrast light theme" }, + { id: "doom-dracula", desc: "Dracula" }, + { id: "doom-nord", desc: "Nord, arctic and north-bluish" }, + { id: "catppuccin", desc: "Catppuccin, Mocha flavour" }, + { id: "doom-tokyo-night", desc: "Tokyo Night" }, + { id: "doom-solarized-light", desc: "Solarized light" }, +]; + +export const DEFAULT_THEME = "doom-gruvbox"; diff --git a/src/scripts/util.js b/src/scripts/util.js @@ -0,0 +1,90 @@ +// Small shared helpers: DOM, maths, theme colours, one animation loop, notes. + +export const $ = (sel, root = document) => root.querySelector(sel); +export const $$ = (sel, root = document) => [...root.querySelectorAll(sel)]; + +export const clamp = (x, lo, hi) => Math.min(hi, Math.max(lo, x)); +export const lerp = (a, b, t) => a + (b - a) * t; +export const ease = (t) => 1 - Math.pow(1 - clamp(t, 0, 1), 3); + +export const reducedMotion = matchMedia("(prefers-reduced-motion: reduce)"); +export const finePointer = matchMedia("(hover: hover) and (pointer: fine)"); + +// ── events ──────────────────────────────────────────────────────────── +const bus = new EventTarget(); +export const emit = (type, detail) => bus.dispatchEvent(new CustomEvent(type, { detail })); +export const on = (type, fn) => bus.addEventListener(type, (e) => fn(e.detail)); + +// ── theme colours, for canvases ─────────────────────────────────────── +let colors = null; +export function themeColors() { + if (colors) return colors; + const cs = getComputedStyle(document.documentElement); + const v = (n) => cs.getPropertyValue(n).trim(); + colors = { + bg: v("--bg"), fg: v("--fg"), dim: v("--dim"), faint: v("--faint"), rule: v("--rule"), hl: v("--hl"), + red: v("--red"), orange: v("--orange"), yellow: v("--yellow"), green: v("--green"), + cyan: v("--cyan"), blue: v("--blue"), magenta: v("--magenta"), + light: v("--glow") === "0", + }; + return colors; +} +on("theme", () => { colors = null; }); + +// ── one requestAnimationFrame loop for everything ───────────────────── +const subs = new Set(); +let raf = 0; +let last = 0; +function frame(now) { + const t = now / 1000; + const dt = last ? Math.min(0.1, t - last) : 1 / 60; + last = t; + for (const fn of subs) fn(t, dt); + raf = subs.size ? requestAnimationFrame(frame) : 0; + if (!raf) last = 0; +} +export function onFrame(fn) { + subs.add(fn); + if (!raf) raf = requestAnimationFrame(frame); + return () => subs.delete(fn); +} + +// Run fn every frame only while el is on screen. +export function frameWhileVisible(el, fn, margin = "80px") { + let off = null; + const io = new IntersectionObserver(([e]) => { + if (e.isIntersecting && !off) off = onFrame(fn); + else if (!e.isIntersecting && off) { off(); off = null; } + }, { rootMargin: margin }); + io.observe(el); +} + +// Size a canvas to its CSS box at device resolution. Returns true if it changed. +export function fitCanvas(canvas, maxDpr = 2) { + const dpr = Math.min(maxDpr, window.devicePixelRatio || 1); + const w = canvas.clientWidth; + const h = canvas.clientHeight; + const pw = Math.round(w * dpr); + const ph = Math.round(h * dpr); + if (canvas.width === pw && canvas.height === ph) return false; + canvas.width = pw; + canvas.height = ph; + canvas.getContext("2d").setTransform(dpr, 0, 0, dpr, 0, 0); + return true; +} + +export async function fontsReady() { + try { + await Promise.race([ + Promise.all([document.fonts.load('12px "JetBrains Mono"'), document.fonts.load('40px "Computer Modern"')]), + new Promise((r) => setTimeout(r, 2500)), + ]); + } catch { /* fall back to whatever is there */ } +} + +export function isTyping(e) { + const t = e.target; + return t instanceof HTMLElement && (t.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName) && t.type !== "range"); +} + +export const hex = (n, w = 2) => n.toString(16).toUpperCase().padStart(w, "0"); diff --git a/src/styles/style.css b/src/styles/style.css @@ -0,0 +1,2443 @@ +/* ───────────────────────────── fonts ───────────────────────────── */ + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono-regular.woff2") format("woff2"); + font-weight: 400; + font-display: swap; +} + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono-semibold.woff2") format("woff2"); + font-weight: 600; + font-display: swap; +} + +/* Computer Modern, via KaTeX's build of it: the same family as Latin Modern */ +@font-face { + font-family: "Computer Modern"; + src: url("/fonts/cm-regular.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Computer Modern"; + src: url("/fonts/cm-italic.woff2") format("woff2"); + font-weight: 400; + font-style: italic; + font-display: swap; +} + +/* ───────────────────────────── themes ───────────────────────────── + Real Emacs themes. Each sets a background, a modeline background, + a foreground and seven accents; everything else is mixed from those. + Keep the names in sync with src/scripts/themes.js and the script in src/pages/index.astro. */ + +:root { + color-scheme: dark; + --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace; + --serif: "Computer Modern", "Latin Modern Roman", "CMU Serif", Georgia, serif; + + --gutter: clamp(16px, 4.5vw, 56px); + --top-h: 44px; + --frame-h: 46px; + --col: 1088px; + + --bg: #282828; + --bg-alt: #3c3836; + --fg: #ebdbb2; + --red: #fb4934; + --orange: #fe8019; + --yellow: #fabd2f; + --green: #b8bb26; + --cyan: #8ec07c; + --blue: #83a598; + --magenta: #d3869b; + --glow: 1; + + --dim: color-mix(in srgb, var(--fg) 64%, var(--bg)); + --faint: color-mix(in srgb, var(--fg) 34%, var(--bg)); + --rule: color-mix(in srgb, var(--fg) 15%, var(--bg)); + --hl: color-mix(in srgb, var(--fg) 10%, var(--bg)); + --wash: color-mix(in srgb, var(--fg) 5%, transparent); + --led-off: color-mix(in srgb, var(--fg) 13%, var(--bg)); + --violet: color-mix(in oklch, var(--blue) 50%, var(--magenta)); + + --c-hw: var(--yellow); + --c-sw: var(--blue); + --c-math: var(--magenta); + --c-sec: var(--red); +} + +:root[data-theme="doom-gruvbox-light"] { + color-scheme: light; + --bg: #fbf1c7; --bg-alt: #ebdbb2; --fg: #3c3836; + --red: #9d0006; --orange: #af3a03; --yellow: #b57614; --green: #79740e; + --cyan: #427b58; --blue: #076678; --magenta: #8f3f71; + --glow: 0; +} + +:root[data-theme="doom-one"] { + --bg: #282c34; --bg-alt: #21242b; --fg: #bbc2cf; + --red: #ff6c6b; --orange: #da8548; --yellow: #ecbe7b; --green: #98be65; + --cyan: #46d9ff; --blue: #51afef; --magenta: #c678dd; +} + +:root[data-theme="atom-one-dark"] { + --bg: #282c34; --bg-alt: #21252b; --fg: #abb2bf; + --red: #e06c75; --orange: #d19a66; --yellow: #e5c07b; --green: #98c379; + --cyan: #56b6c2; --blue: #61afef; --magenta: #c678dd; +} + +:root[data-theme="modus-vivendi"] { + --bg: #000000; --bg-alt: #1e1e1e; --fg: #ffffff; + --red: #ff5f59; --orange: #fec43f; --yellow: #d0bc00; --green: #44bc44; + --cyan: #00d3d0; --blue: #2fafff; --magenta: #feacd0; +} + +:root[data-theme="modus-operandi"] { + color-scheme: light; + --bg: #ffffff; --bg-alt: #f2f2f2; --fg: #000000; + --red: #a60000; --orange: #884900; --yellow: #6f5500; --green: #006800; + --cyan: #005e8b; --blue: #0031a9; --magenta: #721045; + --glow: 0; +} + +:root[data-theme="doom-dracula"] { + --bg: #282a36; --bg-alt: #1e2029; --fg: #f8f8f2; + --red: #ff5555; --orange: #ffb86c; --yellow: #f1fa8c; --green: #50fa7b; + --cyan: #8be9fd; --blue: #61bfff; --magenta: #ff79c6; +} + +:root[data-theme="doom-nord"] { + --bg: #2e3440; --bg-alt: #3b4252; --fg: #eceff4; + --red: #bf616a; --orange: #d08770; --yellow: #ebcb8b; --green: #a3be8c; + --cyan: #88c0d0; --blue: #81a1c1; --magenta: #b48ead; +} + +:root[data-theme="catppuccin"] { + --bg: #1e1e2e; --bg-alt: #181825; --fg: #cdd6f4; + --red: #f38ba8; --orange: #fab387; --yellow: #f9e2af; --green: #a6e3a1; + --cyan: #94e2d5; --blue: #89b4fa; --magenta: #cba6f7; +} + +:root[data-theme="doom-tokyo-night"] { + --bg: #1a1b26; --bg-alt: #16161e; --fg: #c0caf5; + --red: #f7768e; --orange: #ff9e64; --yellow: #e0af68; --green: #9ece6a; + --cyan: #7dcfff; --blue: #7aa2f7; --magenta: #bb9af7; +} + +:root[data-theme="doom-solarized-light"] { + color-scheme: light; + --bg: #fdf6e3; --bg-alt: #eee8d5; --fg: #556b72; + --red: #dc322f; --orange: #cb4b16; --yellow: #b58900; --green: #859900; + --cyan: #2aa198; --blue: #268bd2; --magenta: #d33682; + --glow: 0; +} + +[data-cat="hw"] { --c: var(--c-hw); } +[data-cat="sw"] { --c: var(--c-sw); } +[data-cat="math"] { --c: var(--c-math); } +[data-cat="sec"] { --c: var(--c-sec); } + +/* ───────────────────────────── base ───────────────────────────── */ + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html { + background: var(--bg); + color: var(--fg); + scroll-behavior: smooth; + scroll-snap-type: y proximity; + scroll-padding-top: calc(var(--top-h) + 24px); + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; +} + +body { + margin: 0; + font: 400 13px/1.6 var(--mono); + font-variant-ligatures: none; + -webkit-font-smoothing: antialiased; + transition: background-color 200ms ease, color 200ms ease; +} + +::selection { + background: color-mix(in srgb, var(--blue) 35%, var(--bg)); + color: var(--fg); +} + +a { + color: inherit; + text-decoration-line: underline; + text-decoration-thickness: 1px; + text-decoration-color: var(--faint); + text-underline-offset: 0.2em; +} + +a:hover { + text-decoration-color: currentColor; +} + +button, +input, +output, +select { + font: inherit; + color: inherit; +} + +button { + cursor: pointer; +} + +:focus-visible { + outline: 1px solid var(--fg); + outline-offset: 2px; +} + +kbd { + font: inherit; + font-size: 0.95em; + padding: 0 0.45ch; + border: 1px solid var(--faint); + border-radius: 3px; +} + +code { + font-family: var(--mono); + font-size: 0.95em; +} + +.dim { + color: var(--dim); +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; +} + +.skip { + position: absolute; + left: 8px; + top: -100px; + z-index: 50; + padding: 6px 12px; + background: var(--fg); + color: var(--bg); +} + +.skip:focus { + top: 8px; +} + +.btn { + display: inline-flex; + align-items: center; + min-height: 30px; + padding: 0 14px; + border: 1px solid var(--faint); + border-radius: 0; + background: none; + font-size: 12px; + line-height: 1; + white-space: nowrap; +} + +.btn:hover { + border-color: var(--fg); +} + +.btn[aria-pressed="true"] { + border-color: var(--fg); + background: var(--fg); + color: var(--bg); +} + +/* ───────────────────────────── top line ───────────────────────────── */ + +.top { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 20; + display: flex; + align-items: center; + gap: 3ch; + height: var(--top-h); + padding: 0 var(--gutter); + font-size: 12px; + border-bottom: 1px solid transparent; + transition: background-color 200ms ease, border-color 200ms ease; +} + +.is-scrolled .top { + background: color-mix(in srgb, var(--bg) 90%, transparent); + border-bottom-color: var(--rule); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); +} + +.brand { + display: inline-flex; + align-items: center; + gap: 1.5ch; + margin-right: auto; + text-decoration: none; +} + +.logo { + width: 22px; + height: 11px; + overflow: visible; + fill: none; + stroke: currentColor; + stroke-width: 1.6; +} + +.nav { + display: flex; + gap: 2.5ch; +} + +.nav a { + color: var(--dim); + text-decoration: none; +} + +.nav a:hover, +.nav a[aria-current="true"] { + color: var(--fg); +} + +.nav a[aria-current="true"] { + text-decoration: underline; + text-decoration-color: var(--fg); + text-underline-offset: 6px; +} + +.theme-key, +.menu-key { + padding: 8px 0; + border: 0; + background: none; + color: var(--dim); + font-size: 12px; +} + +.theme-key:hover, +.menu-key:hover { + color: var(--fg); +} + +.menu-key { + display: none; +} + +/* ───────────────────────────── hero: the computer ───────────────────────────── */ + +.hero { + display: grid; + grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); + gap: 32px clamp(32px, 4vw, 64px); + align-items: center; + min-height: 100vh; + min-height: 100svh; + padding: calc(var(--top-h) + 28px) var(--gutter) calc(var(--frame-h) + 32px); + max-width: 1440px; + margin: 0 auto; +} + +.hero-name { + margin: 0 0 20px -0.04em; + font: 400 clamp(46px, 6.4vw, 96px)/0.94 var(--serif); + letter-spacing: -0.015em; +} + +/* On load the name decodes itself (src/scripts/decode.js): each letter starts as a byte + with a few bits flipped and changes one bit at a time until it is right. */ + +.boot .hero-name { + visibility: hidden; + animation: boot-failsafe 0s 2.5s forwards; +} + +@keyframes boot-failsafe { + to { visibility: visible; } +} + +/* each letter sits in a box as wide as the final letter, and whatever + character it shows is centred in it */ +.hero-name.is-cells .bc { + display: inline-block; + text-align: center; +} + +.hero-name.is-cells .bc-ch { + display: inline-block; + margin-inline: -1em; + white-space: pre; +} + +.bc-word { + white-space: nowrap; +} + +/* a wrong byte shows as a raw character in the mono face */ +.bc.is-wrong { + color: var(--dim); +} + +.bc.is-wrong .bc-ch { + font-family: var(--mono); + font-size: 0.78em; + letter-spacing: 0; +} + +.hero-lede { + max-width: 44ch; + margin: 0 0 20px; + font-size: 14px; + line-height: 1.6; +} + +.legend { + display: flex; + flex-wrap: wrap; + gap: 4px 2.5ch; + margin: 0; + padding: 0; + list-style: none; + font-size: 12px; + color: var(--dim); +} + +.legend li::before, +.features li::before { + content: ""; + display: inline-block; + width: 7px; + height: 7px; + margin-right: 1ch; + background: var(--c, var(--fg)); + vertical-align: 0.06em; +} + +/* landing: the MN-2026 pinout */ + +.hero-chip { + justify-self: center; + width: min(100%, 460px); +} + +.hero-chip .chip { + grid-template-columns: minmax(0, 1fr) 128px minmax(0, 1fr); + font-size: 13px; +} + +.hero-chip .pin { + height: 34px; +} + +.hero-chip .pin .leg { + height: 9px; +} + +.hero-chip .pin-readout { + min-height: 6.5em; +} + +/* the 8-bit computer, as the project's demo */ + +.demo-wide { + margin-top: 40px; + padding-top: 28px; + border-top: 1px solid var(--rule); +} + +.sim-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px 10px; + margin-top: 16px; + font-size: 12px; +} + +.sim-field { + display: inline-flex; + align-items: center; + gap: 1.2ch; + margin-left: 1.5ch; + color: var(--dim); +} + +.sim-field output { + min-width: 7ch; + color: var(--fg); + font-variant-numeric: tabular-nums; +} + +select { + min-height: 30px; + padding: 0 28px 0 10px; + border: 1px solid var(--faint); + border-radius: 0; + background: var(--bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23888'/%3E%3C/svg%3E") no-repeat right 10px center; + color: var(--fg); + font-size: 12px; + -webkit-appearance: none; + appearance: none; +} + +input[type="range"] { + width: 120px; + height: 22px; + margin: 0; + background: transparent; + -webkit-appearance: none; + appearance: none; +} + +input[type="range"]::-webkit-slider-runnable-track { + height: 1px; + background: var(--faint); +} + +input[type="range"]::-moz-range-track { + height: 1px; + background: var(--faint); +} + +input[type="range"]::-webkit-slider-thumb { + width: 9px; + height: 18px; + margin-top: -9px; + border: 0; + border-radius: 0; + background: var(--fg); + -webkit-appearance: none; + appearance: none; +} + +input[type="range"]::-moz-range-thumb { + width: 9px; + height: 18px; + border: 0; + border-radius: 0; + background: var(--fg); +} + +.sim-note { + max-width: 78ch; + margin: 12px 0 0; + font-size: 12px; + line-height: 1.6; + color: var(--dim); +} + +/* board: Ben Eater's layout, two columns of modules either side of the bus */ + +.board { + --led: 10px; + display: grid; + grid-template-columns: minmax(0, 1fr) 64px minmax(0, 1fr); + grid-template-areas: + "left bus right" + "ctrl ctrl ctrl"; + gap: 10px; + font-size: 11.5px; + font-variant-numeric: tabular-nums; +} + +.col { + display: flex; + flex-direction: column; + gap: 10px; +} + +.col-l { grid-area: left; } +.col-r { grid-area: right; } + +.mod { + padding: 7px 10px 9px; + border: 1px solid var(--rule); + background: color-mix(in srgb, var(--bg) 92%, var(--fg)); +} + +.mod.is-out { + border-color: var(--red); +} + +.mod.is-in { + border-color: var(--green); +} + +.mod-head { + display: flex; + align-items: baseline; + gap: 1ch; + margin-bottom: 6px; + color: var(--dim); + white-space: nowrap; +} + +.mod-name { + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; +} + +.sig { + padding: 0 0.4ch; + border-radius: 2px; + color: var(--faint); + font-size: 10.5px; +} + +.sig.on { + background: var(--blue); + color: var(--bg); +} + +.mod-body { + display: flex; + align-items: center; + justify-content: space-between; + gap: 1ch; +} + +.mod-val { + color: var(--fg); + white-space: nowrap; +} + +.leds { + display: flex; + gap: calc(var(--led) * 0.45); +} + +.led { + display: block; + flex: none; + width: var(--led); + height: var(--led); + padding: 0; + border: 0; + border-radius: 50%; + background: var(--led-off); + --lc: var(--red); +} + +.led.on { + background: var(--lc); + box-shadow: 0 0 calc(var(--glow) * 7px) calc(var(--glow) * 1px) color-mix(in srgb, var(--lc) 70%, transparent); +} + +.led.g { --lc: var(--green); } +.led.y { --lc: var(--yellow); } +.led.b { --lc: var(--blue); } + +.leds .gap { + width: calc(var(--led) * 0.4); +} + +/* RAM: the whole 16-byte memory as a matrix you can edit */ + +.ram-rows { + display: grid; + gap: 1px; +} + +.ram-row { + --led: 8px; + display: grid; + grid-template-columns: 1.5ch 2ch auto minmax(0, 1fr); + align-items: center; + gap: 0.8ch; + padding: 1px 4px; + margin: 0 -4px; + line-height: 14px; +} + +.ram-row.is-mar { + background: var(--hl); +} + +.ram-row .pc { + color: var(--green); +} + +.ram-row .addr { + color: var(--dim); +} + +.ram-row .dis { + overflow: hidden; + color: var(--dim); + white-space: nowrap; + text-overflow: ellipsis; +} + +.ram-row.is-mar .dis { + color: var(--fg); +} + +.ram-row .led { + cursor: pointer; +} + +.ram-row .led:hover { + outline: 1px solid var(--faint); + outline-offset: 1px; +} + +/* the bus: eight lanes down the middle */ + +.bus { + grid-area: bus; + display: flex; + flex-direction: column; + align-items: center; + padding: 7px 0 9px; + border: 1px solid var(--rule); +} + +.bus .mod-head { + margin-bottom: 4px; +} + +.bus-val { + margin-bottom: 8px; +} + +.lanes { + display: flex; + flex: 1; + gap: 4px; +} + +.lane { + width: 2px; + background: var(--led-off); +} + +.lane.on { + background: var(--red); + box-shadow: 0 0 calc(var(--glow) * 6px) color-mix(in srgb, var(--red) 70%, transparent); +} + +/* output: a 7-segment display */ + +.seg7 { + display: flex; + gap: 6px; +} + +.seg7 svg { + width: 22px; + height: 38px; + overflow: visible; +} + +.seg7 path { + fill: var(--led-off); +} + +.seg7 path.on { + fill: var(--red); + filter: drop-shadow(0 0 calc(var(--glow) * 3px) color-mix(in srgb, var(--red) 80%, transparent)); +} + +.mod-out .mod-body { + cursor: pointer; +} + +/* control word */ + +.ctrl { + grid-area: ctrl; +} + +.ctrl-row { + display: flex; + flex-wrap: wrap; + align-items: flex-end; + gap: 8px 18px; +} + +.cw { + display: flex; + flex-wrap: wrap; + gap: 4px; +} + +.cw-bit { + display: flex; + flex-direction: column; + align-items: center; + gap: 3px; + width: 3.4ch; + color: var(--faint); + font-size: 10px; +} + +.cw-bit.on { + color: var(--fg); +} + +.ustep { + margin-top: 8px; + color: var(--dim); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.ustep b { + color: var(--fg); + font-weight: 600; +} + +/* ───────────────────────────── sections ───────────────────────────── */ + +.sec { + max-width: var(--col); + margin: 0 auto; + padding: 136px var(--gutter) 0; +} + +.hero, +.sec > .winbar { + scroll-snap-align: start; +} + +.winbar { + display: flex; + align-items: center; + gap: 1.5ch; + margin: 0 0 56px; + font-size: 12px; + line-height: 1; + color: var(--dim); +} + +.winbar .file { + color: var(--fg); +} + +.winbar .rule { + flex: 1; + height: 1px; + background: var(--rule); +} + +.h2 { + max-width: 17em; + margin: 0 0 20px; + font: 400 clamp(36px, 5.4vw, 62px)/1.04 var(--serif); + letter-spacing: -0.01em; +} + +.lede, +.prose { + max-width: 34em; + margin: 0 0 48px; + font: 400 19px/1.55 var(--serif); +} + +.prose { + margin-bottom: 0; +} + +.lede kbd { + font: 400 13px/1 var(--mono); + vertical-align: 0.15em; +} + +.sub-h { + margin: 72px 0 8px; + font: 400 28px/1.15 var(--serif); +} + +.sub-p { + max-width: 34em; + margin: 0 0 28px; + font: 400 17px/1.55 var(--serif); +} + +/* ───────────────────────────── datasheet ───────────────────────────── */ + +.ds-head { + display: grid; + grid-template-columns: 14ch minmax(0, 1fr); + gap: 8px 2ch; + align-items: baseline; + padding-top: 16px; + border-top: 2px solid var(--fg); +} + +.ds-part { + margin: 0; + font-weight: 600; + font-size: 15px; +} + +.ds-title { + max-width: 19em; + margin: 0; + font: 400 clamp(28px, 3.8vw, 44px)/1.1 var(--serif); +} + +.ds-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 400px); + gap: 72px; + align-items: start; +} + +.ds-desc { + margin: 40px 0 0; +} + +.ds-h { + margin: 48px 0 16px; + font-size: 12px; + font-weight: 600; + line-height: 1.4; +} + +.features { + margin: 0; + padding: 0; + list-style: none; +} + +.features li { + max-width: 62ch; + margin-bottom: 8px; + padding-left: 3ch; + text-indent: -3ch; +} + +.features li::before { + margin-right: 2ch; + text-indent: 0; +} + +.pinout { + margin: 0; +} + +.chip { + display: grid; + grid-template-columns: minmax(0, 1fr) 104px minmax(0, 1fr); + font-size: 12px; +} + +.chip-side { + display: flex; + flex-direction: column; + padding: 10px 0; +} + +.chip-body { + position: relative; + border: 1px solid var(--fg); + border-radius: 2px; +} + +.chip-body::before { + content: ""; + position: absolute; + top: -1px; + left: 50%; + width: 20px; + height: 10px; + border: 1px solid var(--fg); + border-top: 0; + border-radius: 0 0 10px 10px; + background: var(--bg); + transform: translateX(-50%); +} + +.chip-body span { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + color: var(--dim); + writing-mode: vertical-rl; + letter-spacing: 0.2em; +} + +.pin { + display: grid; + align-items: center; + height: 28px; + padding: 0; + border: 0; + background: none; + color: var(--dim); + text-align: left; +} + +.chip-side.left .pin { + grid-template-columns: 1fr 3ch 16px; + text-align: right; +} + +.chip-side.right .pin { + grid-template-columns: 16px 3ch 1fr; +} + +.pin .num { + text-align: center; + font-size: 11px; +} + +.pin .leg { + height: 8px; + border: 1px solid var(--faint); +} + +.chip-side.left .leg { + border-right: 0; +} + +.chip-side.right .leg { + border-left: 0; +} + +.pin .name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.pin:hover, +.pin.is-active { + color: var(--fg); +} + +.pin.is-active .name { + color: var(--c, var(--fg)); + font-weight: 600; +} + +.pin.is-active .leg { + border-color: var(--c, var(--fg)); + background: var(--c, var(--fg)); +} + +.pin-readout { + min-height: 7.5em; + margin-top: 20px; + padding-top: 12px; + border-top: 1px solid var(--rule); + font-size: 12px; +} + +.pin-readout p { + margin: 0; +} + +.pin-readout .pr-head { + display: flex; + gap: 2ch; + margin-bottom: 6px; +} + +.pin-readout .pr-name { + color: var(--c, var(--fg)); + font-weight: 600; +} + +.pinout figcaption { + margin-top: 8px; + font-size: 12px; + color: var(--dim); +} + +.pin-list { + margin: 16px 0 0; + padding-left: 3ch; + font-size: 12px; +} + +.pinout.is-built .pin-list { + display: none; +} + +.pin-list li::before { + content: attr(data-name) " (" attr(data-type) ") "; + font-weight: 600; +} + +.ds-note { + margin: -8px 0 14px; + font-size: 12px; + color: var(--dim); +} + +.table-scroll { + overflow-x: auto; +} + +.ds-table { + width: 100%; + min-width: 560px; + border-collapse: collapse; + font-size: 12.5px; + font-variant-numeric: tabular-nums; +} + +.ds-table th, +.ds-table td { + padding: 8px 1.5ch 8px 0; + border-bottom: 1px solid var(--rule); + text-align: left; + vertical-align: baseline; +} + +.ds-table thead th { + border-top: 1px solid var(--fg); + border-bottom-color: var(--fg); + font-weight: 600; +} + +.ds-table tbody th { + font-weight: 400; +} + +.ds-table td:nth-child(2) { + color: var(--dim); +} + +.ds-table .num { + text-align: right; + padding-right: 3ch; +} + +/* experience as git log --graph --color */ + +.gitlog-cmd { + margin-bottom: 12px; + font-weight: 400; + color: var(--fg); + line-height: 1.5; + white-space: pre-wrap; + overflow-wrap: anywhere; +} + +.gitlog-cmd .prompt { + color: var(--green); +} + +.gitlog { + padding: 16px 18px; + overflow-x: auto; + border: 1px solid var(--rule); + font-size: 12px; + line-height: 1.7; + color: var(--fg); +} + +.gl-line { + width: max-content; + white-space: pre; +} + +/* one colour per branch */ +.gitlog .lm { color: var(--magenta); } /* main */ +.gitlog .lu { color: var(--green); } /* undergrad */ +.gitlog .lt { color: var(--yellow); } /* teaching-assistant */ +.gitlog .lb { color: var(--red); } /* bbd-software */ +.gitlog .li { color: var(--blue); } /* mwr-internship */ + +.gl-tip { + color: var(--fg); + font-weight: 600; +} + +.gl-refs { + color: var(--yellow); +} + +.gl-head { + color: var(--cyan); + font-weight: 600; +} + +.gl-branch { + color: var(--green); + font-weight: 600; +} + +.gl-author { + color: var(--blue); +} + +.gl-subj { + padding: 0; + border: 0; + background: none; + color: inherit; + font: inherit; + white-space: pre; + text-decoration: underline dotted; + text-decoration-color: var(--faint); + text-underline-offset: 0.25em; +} + +.gl-subj:hover, +.gl-subj[aria-expanded="true"] { + text-decoration-style: solid; + text-decoration-color: currentColor; +} + +.gl-body, +.gl-desc { + color: var(--dim); +} + +/* before the script runs (or without it), descriptions show under their commit */ +.gl-desc { + display: block; + padding-left: 4ch; +} + +.gitlog-hint { + margin: 8px 0 0; + font-size: 12px; +} + +/* ───────────────────────────── memory map ───────────────────────────── */ + +.mm { + --mm-cols: 8ch 8ch minmax(0, 1fr) 8ch; +} + +.mm-bar { + display: flex; + height: 36px; + margin-bottom: 32px; + border: 1px solid var(--rule); +} + +.mm-seg { + min-width: 3px; + padding: 0 6px; + overflow: hidden; + border-right: 1px solid var(--bg); + background: color-mix(in srgb, var(--c) 20%, transparent); + box-shadow: inset 0 2px 0 var(--c); + font-size: 11px; + line-height: 34px; + white-space: nowrap; + cursor: pointer; + transition: background-color 120ms ease; +} + +.mm-seg:last-child { + border-right: 0; +} + +.mm-seg:hover { + background: color-mix(in srgb, var(--c) 34%, transparent); +} + +.mm-seg.is-active { + background: var(--c); + color: var(--bg); +} + +.mm-cols { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); + gap: 48px; + align-items: start; +} + +.mm-head { + display: grid; + grid-template-columns: var(--mm-cols); + gap: 1.5ch; + margin: 0; + padding: 0 0 8px 12px; + border-bottom: 1px solid var(--rule); + font-size: 12px; + color: var(--dim); +} + +.mm-list { + margin: 0; + padding: 0; + list-style: none; +} + +.proj-name { + margin: 0; + font: inherit; +} + +.proj-row { + display: grid; + grid-template-columns: var(--mm-cols); + gap: 1.5ch; + align-items: baseline; + width: 100%; + padding: 11px 0 11px 12px; + border: 0; + border-bottom: 1px solid var(--rule); + background: none; + text-align: left; + font-size: 13px; + font-variant-numeric: tabular-nums; +} + +.proj-row:hover { + background: var(--wash); +} + +.proj-row .o, +.proj-row .l, +.proj-row .y { + font-size: 12px; + color: var(--dim); +} + +.proj-row .n { + font-weight: 600; +} + +.proj-row .n::before { + content: ""; + display: inline-block; + width: 7px; + height: 7px; + margin-right: 1.2ch; + background: var(--c); + vertical-align: 0.06em; +} + +.proj-row .s { + display: block; + margin-top: 2px; + font-weight: 400; + color: var(--dim); +} + +.proj-row[aria-pressed="true"] { + background: var(--wash); + box-shadow: inset 2px 0 0 var(--c); +} + +.proj-row[aria-pressed="true"] .o, +.proj-row[aria-pressed="true"] .l { + color: var(--c); +} + +.mm.is-built .proj-sum, +.mm.is-built .proj > .proj-body { + display: none; +} + +.mm-detail { + min-height: 320px; + padding-left: 32px; + border-left: 1px solid var(--rule); +} + +.mm-detail:empty { + display: none; +} + +.hex { + margin: 0 0 22px; + overflow-x: auto; + font-size: 11.5px; + line-height: 1.55; + color: var(--dim); + white-space: pre; +} + +.hex .a { + color: var(--fg); +} + +.hex .addr { + color: var(--c); +} + +.mm-detail h3 { + margin: 0 0 14px; + font: 400 32px/1.1 var(--serif); +} + +.mm-detail .proj-body p { + margin: 0 0 14px; + font: 400 17px/1.55 var(--serif); +} + +.mm-detail .proj-body .proj-stack, +.mm-detail .proj-body .proj-links { + font: 400 12px/1.6 var(--mono); +} + +.proj-stack { + color: var(--dim); +} + +.proj-links a { + margin-right: 2ch; +} + +/* project demos */ + +.demo { + margin-top: 22px; + padding-top: 18px; + border-top: 1px solid var(--rule); + font-size: 12px; +} + +.demo-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + margin-bottom: 12px; +} + +.demo-bar .dim { + margin-left: auto; +} + +.demo canvas { + display: block; + width: 100%; +} + +.demo pre { + margin: 0; + font-size: 12px; + line-height: 1.2; + user-select: none; + -webkit-user-select: none; +} + +.demo .cap { + margin: 10px 0 0; + color: var(--dim); +} + +.bc-input { + display: flex; + align-items: center; + gap: 1ch; + margin-bottom: 12px; +} + +.bc-input input { + flex: 1; + min-width: 0; + min-height: 30px; + padding: 0 10px; + border: 1px solid var(--faint); + border-radius: 0; + background: none; + font-size: 13px; +} + +.bc-input input:focus { + border-color: var(--fg); + outline: none; +} + +.bc-cols { + display: grid; + grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); + gap: 16px; +} + +.bc-code { + margin: 0; + padding: 0; + list-style: none; + font-variant-numeric: tabular-nums; +} + +.bc-code li { + display: grid; + grid-template-columns: 4ch 1fr; + gap: 1ch; + padding: 1px 6px; +} + +.bc-code li.is-pc { + background: var(--hl); +} + +.bc-code .off { + color: var(--dim); + text-align: right; +} + +.bc-code .op { + color: var(--blue); +} + +.bc-stack { + display: flex; + flex-direction: column-reverse; + justify-content: flex-start; + gap: 2px; + min-height: 120px; + padding: 6px; + border: 1px solid var(--rule); + border-top: 0; +} + +.bc-stack span { + padding: 2px 8px; + border: 1px solid var(--faint); + text-align: right; +} + +.bc-stack span:last-child { + border-color: var(--fg); +} + +.bc-err { + color: var(--red); + white-space: pre; +} + +/* othello */ + +.oth { + display: grid; + grid-template-columns: repeat(8, minmax(0, 1fr)); + gap: 2px; + width: min(100%, 336px); + aspect-ratio: 1; + padding: 2px; + background: color-mix(in srgb, var(--fg) 25%, var(--bg)); +} + +.oth-cell { + position: relative; + padding: 0; + border: 0; + border-radius: 0; + background: color-mix(in srgb, var(--green) 28%, var(--bg)); + cursor: default; +} + +.oth-cell.legal { + cursor: pointer; +} + +.oth-cell.legal::after { + content: ""; + position: absolute; + inset: 40%; + border-radius: 50%; + background: var(--fg); + opacity: 0.4; +} + +.oth-cell.last { + box-shadow: inset 0 0 0 2px var(--yellow); +} + +.oth-cell .disc { + position: absolute; + inset: 12%; + border-radius: 50%; +} + +.oth-cell .disc.b { + background: #1b1b1b; + box-shadow: 0 0 0 1px rgb(0 0 0 / 0.35); +} + +.oth-cell .disc.w { + background: #f1efe8; + box-shadow: 0 0 0 1px rgb(0 0 0 / 0.15); +} + +.oth-cell .heat { + position: absolute; + inset: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + background: color-mix(in srgb, var(--blue) var(--hp, 0%), transparent); + color: var(--fg); + font-size: 10px; +} + +.oth-cell .heat:empty { + background: none; +} + +/* rbudp */ + +.rb-canvas { + height: 200px; +} + +.rb-log { + max-height: 9.8em; + margin: 10px 0 0; + padding: 8px 10px; + overflow-y: auto; + border: 1px solid var(--rule); + list-style: none; + font-size: 11.5px; + line-height: 1.6; +} + +.rb-log li { + display: grid; + grid-template-columns: 8ch 5ch minmax(0, 1fr); + gap: 1ch; +} + +.rb-proto { + color: var(--cyan); +} + +.sched-legend { + display: flex; + flex-wrap: wrap; + gap: 4px 12px; + margin-top: 8px; + color: var(--dim); +} + +/* ───────────────────────────── posts: an Org buffer ───────────────────────────── */ + +.org { + max-width: 880px; + font-size: 13px; + line-height: 1.75; +} + +.org-kw { + margin: 0; + font: inherit; + color: var(--dim); +} + +.org-kw .v { + color: var(--fg); +} + +.org-title { + color: var(--fg); + font-weight: 600; +} + +.org-p { + max-width: 76ch; + margin: 20px 0 0; + font-size: 13px; + line-height: 1.75; +} + +.org > .org-tree { + margin-top: 20px; +} + +.org-tree { + margin: 0; + padding: 0; + list-style: none; +} + +.org-h { + display: flex; + align-items: baseline; + gap: 1ch; +} + +.org-h:focus-visible { + outline: none; + background: var(--hl); +} + +.org-stars { + flex: none; + padding: 0; + border: 0; + background: none; + color: inherit; + font: inherit; +} + +.org-h1 > .org-h { + color: var(--blue); + font-weight: 600; +} + +.org-h2 > .org-h { + color: var(--magenta); +} + +.org-h2 a { + min-width: 0; + color: inherit; + text-decoration: none; +} + +.org-h2 a:hover { + text-decoration: underline; + text-decoration-thickness: 1px; +} + +.org-h .count, +.org-ellipsis { + color: var(--dim); + font-weight: 400; +} + +.org-tags { + flex: none; + margin-left: auto; + padding-left: 2ch; + color: var(--dim); + white-space: nowrap; +} + +.org-tags .t { + color: var(--tag, var(--dim)); +} + +.org-drawer { + margin: 0 0 6px 3ch; + overflow-x: auto; + color: var(--dim); + font-size: 12px; + line-height: 1.6; + white-space: pre; +} + +.org-drawer .k { + color: var(--faint); +} + +.org-drawer .ts { + color: var(--cyan); +} + +.org-drawer a { + color: var(--fg); +} + +/* ───────────────────────────── contact ───────────────────────────── */ + +.contact { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 16px 32px; + margin-bottom: 8px; +} + +.mail { + font: 400 clamp(26px, 4.4vw, 52px)/1.1 var(--serif); + overflow-wrap: anywhere; +} + +.mail .at { + font: 400 0.42em/1 var(--mono); + color: var(--dim); + vertical-align: 0.35em; + white-space: pre; +} + +.linkish { + padding: 0; + border: 0; + background: none; + color: inherit; + font: inherit; + text-decoration: underline; + text-decoration-thickness: 1px; + text-decoration-color: var(--faint); + text-underline-offset: 0.2em; +} + +.linkish:hover { + text-decoration-color: currentColor; +} + +.contact-grid { + display: grid; + grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); + gap: 0 56px; +} + +.gpg-fp { + display: flex; + flex-wrap: wrap; + gap: 4px 2ch; + margin: 0 0 12px; +} + +.gpg-fp code { + letter-spacing: 0.02em; +} + +.gpg-cmd { + display: flex; + align-items: stretch; + gap: 8px; +} + +.gpg-cmd pre { + flex: 1; + min-width: 0; + margin: 0; + padding: 7px 12px; + overflow-x: auto; + border: 1px solid var(--rule); + background: var(--wash); + font-size: 12px; +} + +.elsewhere { + display: flex; + flex-wrap: wrap; + gap: 8px 3ch; + margin: 0; + padding: 0; + list-style: none; +} + +.ctf { + max-width: 70ch; + margin-top: 16px; +} + +.ctf p { + margin: 0 0 12px; +} + +.ctf-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 12px 2ch; +} + +.ctf-progress { + color: var(--dim); +} + +.ctf-progress.done { + color: var(--green); +} + +.foot { + max-width: var(--col); + margin: 0 auto; + padding: 160px var(--gutter) calc(var(--frame-h) + 48px); + font-size: 12px; +} + +.foot p { + margin: 0 0 4px; +} + +/* ───────────────────────────── modeline, minibuffer, which-key ───────────────────────────── */ + +.frame-bottom { + position: fixed; + left: 0; + right: 0; + bottom: 0; + z-index: 30; + padding-bottom: env(safe-area-inset-bottom, 0px); + background: var(--bg); + font-size: 12px; + white-space: nowrap; +} + +.modeline { + display: flex; + align-items: stretch; + height: 24px; + line-height: 24px; + background: var(--bg-alt); + color: var(--fg); +} + +/* doom-modeline's bar */ +.modeline::before { + content: ""; + flex: none; + width: 4px; + background: var(--blue); +} + +.modeline > span { + padding: 0 1ch; +} + +.ml-evil { + color: var(--green); + font-weight: 600; +} + +.modeline[data-evil="I"] .ml-evil { color: var(--yellow); } +.modeline[data-evil="V"] .ml-evil { color: var(--magenta); } +.modeline[data-evil="E"] .ml-evil { color: var(--cyan); } + +.ml-buf { + font-weight: 600; +} + +.ml-pos, +.ml-pct, +.ml-enc, +.ml-time { + color: var(--dim); +} + +.ml-spacer { + flex: 1; + padding: 0 !important; +} + +.ml-flags { + color: var(--green); +} + +.ml-mode { + color: var(--blue); + font-weight: 600; +} + +.ml-vc { + color: var(--green); +} + +.echo { + height: 22px; + padding: 0 1ch; + overflow: hidden; + line-height: 22px; + color: var(--dim); + text-overflow: ellipsis; +} + +.echo.is-error { + color: var(--red); +} + +.echo.is-ok { + color: var(--green); +} + +.mini:not([hidden]) ~ .echo { + display: none; +} + +.mini-prompt { + margin: 0; +} + +.mini-prompt label { + display: flex; + height: 22px; + padding: 0 1ch; + line-height: 22px; +} + +.mini-count { + min-width: 6ch; + color: var(--dim); +} + +.mini-ps { + color: var(--blue); + white-space: pre; +} + +.mini-prompt input { + flex: 1; + min-width: 0; + padding: 0; + border: 0; + outline: 0; + background: none; + color: var(--fg); + caret-color: var(--fg); + font-size: 12px; + line-height: 22px; +} + +.mini-list { + max-height: calc(10 * 21px); + margin: 0; + padding: 0; + overflow-y: auto; + list-style: none; +} + +.mini-list:empty { + display: none; +} + +.mini-list li { + display: flex; + gap: 2ch; + height: 21px; + padding: 0 1ch; + line-height: 21px; + cursor: pointer; +} + +.mini-list li[aria-selected="true"] { + background: var(--hl); +} + +.mini-list .cand { + flex: none; + min-width: 24ch; + color: var(--fg); +} + +.mini-list .cand mark { + background: none; + color: var(--magenta); + font-weight: 600; +} + +.mini-list .ann { + flex: 1; + min-width: 0; + overflow: hidden; + color: var(--dim); + text-overflow: ellipsis; +} + +.mini-list .key { + flex: none; + color: var(--blue); +} + +.which-key { + position: fixed; + left: 0; + right: 0; + bottom: var(--frame-h); + z-index: 29; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(26ch, 1fr)); + gap: 2px 2ch; + padding: 10px 2ch 12px; + border-top: 1px solid var(--rule); + background: var(--bg-alt); + font-size: 12px; +} + +.which-key[hidden] { + display: none; +} + +.wk-title { + grid-column: 1 / -1; + margin-bottom: 4px; + color: var(--dim); +} + +.wk-item { + display: flex; + gap: 1ch; + white-space: nowrap; +} + +.wk-key { + min-width: 3ch; + color: var(--magenta); + font-weight: 600; +} + +.wk-arrow { + color: var(--faint); +} + +.wk-desc { + color: var(--fg); +} + +.wk-desc.group { + color: var(--blue); +} + +/* ───────────────────────────── M-x coffee-refill ───────────────────────────── */ + +.coffee { + position: fixed; + right: 2ch; + bottom: calc(var(--frame-h) + 12px); + z-index: 28; + display: flex; + gap: 3ch; + width: min(620px, calc(100% - 4ch)); + padding: 16px 20px 18px; + border: 1px solid var(--faint); + background: var(--bg); + box-shadow: 0 12px 40px rgb(0 0 0 / 0.35); + font-size: 12px; +} + +.coffee[hidden] { + display: none; +} + +.mug { + flex: none; + margin: 0; + font-size: 12px; + line-height: 1.25; + color: var(--fg); +} + +.mug .steam { + color: var(--dim); +} + +.mug .brew { + color: var(--orange); +} + +.mug .crema { + color: var(--yellow); +} + +.coffee-info { + flex: 1; + min-width: 0; +} + +.coffee-info .winbar { + margin: 0 28px 14px 0; +} + +.coffee-info p { + margin: 0 0 10px; +} + +.vcc { + display: flex; + gap: 1.5ch; + font-variant-numeric: tabular-nums; +} + +.vbar { + color: var(--green); + letter-spacing: -0.05em; +} + +.coffee.is-over .vbar, +.coffee.is-over .volts { + color: var(--red); +} + +.coffee-msg { + min-height: 3.2em; +} + +.coffee-links { + display: flex; + flex-wrap: wrap; + gap: 4px 2ch; +} + +.coffee-close { + position: absolute; + top: 6px; + right: 8px; + padding: 2px 6px; + border: 0; + background: none; + color: var(--dim); + font-size: 16px; + line-height: 1; +} + +.coffee-close:hover { + color: var(--fg); +} + +/* ───────────────────────────── help ───────────────────────────── */ + +.help { + width: min(780px, calc(100% - 32px)); + max-height: calc(100% - 64px); + padding: 24px 28px; + border: 1px solid var(--faint); + background: var(--bg); + color: var(--fg); + font-size: 12.5px; +} + +.help::backdrop { + background: rgb(0 0 0 / 0.5); +} + +.help .winbar { + margin-bottom: 28px; +} + +.help-cols { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 40px; +} + +.help h3 { + margin: 0 0 12px; + font-size: 12px; + font-weight: 600; +} + +.help dl { + margin: 0; +} + +.help dl div { + display: grid; + grid-template-columns: 13ch 1fr; + gap: 2ch; + padding: 3px 0; +} + +.help dt { + color: var(--fg); +} + +.help dd { + margin: 0; + color: var(--dim); +} + +.help form { + margin-top: 28px; +} + +/* ───────────────────────────── responsive ───────────────────────────── */ + +@media (max-width: 1100px) { + .hero { + grid-template-columns: minmax(0, 1fr); + align-items: start; + } + + .hero-id { + max-width: 640px; + } +} + +@media (max-width: 920px) { + .nav { + display: none; + } + + .nav.is-open { + position: absolute; + top: calc(var(--top-h) - 4px); + right: var(--gutter); + display: flex; + flex-direction: column; + gap: 10px; + min-width: 18ch; + padding: 14px 18px; + border: 1px solid var(--faint); + background: var(--bg); + } + + .menu-key { + display: block; + } + + .ds-grid, + .mm-cols, + .contact-grid { + grid-template-columns: minmax(0, 1fr); + } + + .ds-grid { + gap: 0; + } + + .pinout { + max-width: 420px; + } + + .mm-detail { + min-height: 0; + margin: 4px 0 8px; + padding: 20px 0 20px 12px; + border-left: 0; + border-bottom: 1px solid var(--rule); + } + + .ml-enc, + .ml-vc, + .ml-time, + .ml-pos { + display: none; + } +} + +@media (max-width: 640px) { + .board { + --led: 8px; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + grid-template-areas: + "bus bus" + "left right" + "ctrl ctrl"; + font-size: 10.5px; + } + + .bus { + flex-direction: row; + gap: 1.5ch; + padding: 6px 10px; + } + + .bus .mod-head, + .bus-val { + margin: 0; + } + + .lanes { + flex-direction: column; + justify-content: center; + height: 26px; + gap: 1px; + } + + .lane { + width: auto; + height: 2px; + } + + .mod { + padding: 6px 8px 8px; + } + + .ram-row { + --led: 6px; + grid-template-columns: 1.5ch 2ch auto; + } + + .ram-row .dis { + display: none; + } + + .seg7 svg { + width: 16px; + height: 28px; + } + + .sim-field { + margin-left: 0; + } + + .sec { + padding-top: 104px; + } + + .winbar { + margin-bottom: 40px; + } + + .lede, + .prose { + font-size: 17px; + } + + .ds-head { + grid-template-columns: minmax(0, 1fr); + } + + .mm { + --mm-cols: 7ch 6ch minmax(0, 1fr); + } + + .mm-head span:last-child, + .proj-row .y { + display: none; + } + + .bc-cols { + grid-template-columns: minmax(0, 1fr); + } + + .gitlog { + padding: 12px; + font-size: 11.5px; + } + + .gitlog-cmd { + font-size: 11.5px; + } + + .org-tags { + display: none; + } + + .help-cols { + grid-template-columns: minmax(0, 1fr); + gap: 24px; + } + + .ml-pct { + display: none; + } + + .coffee { + right: 0; + left: 0; + width: auto; + margin: 0 8px; + flex-direction: column; + gap: 8px; + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + *, + *::before, + *::after { + transition: none !important; + } +} diff --git a/static/css/styles.css b/static/css/styles.css @@ -1,70 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Literata:ital,opsz,wght@0,7..72,200..900;1,7..72,200..900&display=swap"); - -/* fonts */ -#wrapper { - font-family: "Literata", serif; - padding: 1rem 20vw; -} - -@media (max-width: 768px) { - #wrapper { - padding: 1rem 5vw; - } -} - -/* suggestion forms */ -form.suggestion { - max-width: 400px; - font-weight: bold; - background-color: var(--bg_s); - padding: 1rem; - border-radius: 0.25rem; -} - -form.suggestion input { - width: 100%; - padding: 0.5rem; - border: 1px solid var(--fg); - border-radius: 4px; - color: var(--fg); - background-color: var(--bg); -} - -form.suggestion input:focus { - outline: 1px solid var(--fg); - background-color: var(--bg1); -} - -form.suggestion button[type="submit"] { - background-color: var(--green-dim); - color: var(--bg); - padding: 0.5rem 1rem; - border: none; - border-radius: 0.25rem; - cursor: pointer; - font-size: 16px; -} - -form.suggestion button[type="submit"]:hover { - background-color: var(--green); -} - -/* library images */ -.book-container { - clear: both; -} - -.book-container > img { - margin-left: 50px; -} - -/* footer icons */ -img.hugo-svg { - margin-left: 2px; - margin-right: 2px; - vertical-align: -1px; -} - -img.emacs-svg { - vertical-align: -5px; -} diff --git a/static/images/android-chrome-192x192.png b/static/images/android-chrome-192x192.png Binary files differ. diff --git a/static/images/android-chrome-512x512.png b/static/images/android-chrome-512x512.png Binary files differ. diff --git a/static/images/apple-touch-icon.png b/static/images/apple-touch-icon.png Binary files differ. diff --git a/static/images/badges/ad-free-site.svg b/static/images/badges/ad-free-site.svg @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg2" viewBox="0 0 45 56" version="1.1" sodipodi:docname="1.svg" inkscape:version="0.92.3 (2405546, 2018-03-11)"> - <sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1280" inkscape:window-height="732" id="namedview14" showgrid="false" inkscape:zoom="1.489975" inkscape:cx="86.923183" inkscape:cy="-12.478814" inkscape:window-x="0" inkscape:window-y="32" inkscape:window-maximized="1" inkscape:current-layer="layer1"/> - <defs id="defs4"> - <radialGradient id="radialGradient3019" gradientUnits="userSpaceOnUse" cy="1235.3" cx="-2077.1" gradientTransform="matrix(0.0311271,0,0,0.03873531,17712.527,1207.5014)" r="722.86"> - <stop id="stop3792" stop-color="#29526d" offset="0"/> - <stop id="stop3798" stop-color="#29526d" offset="0.92"/> - <stop id="stop3800" stop-color="#2f607f" offset="0.95"/> - <stop id="stop3802" stop-color="#29526d" offset="0.98"/> - <stop id="stop3794" stop-color="#29526d" offset="1"/> - </radialGradient> - <radialGradient inkscape:collect="always" xlink:href="#radialGradient3019" id="radialGradient877" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0311271,0,0,0.03873531,87.156,-19.8512)" cx="-2077.1" cy="1235.3" r="722.86"/> - </defs> - <metadata id="metadata7"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - <dc:title/> - </cc:Work> - </rdf:RDF> - </metadata> - <g id="layer1" transform="translate(-17625.371,-1227.3526)"> - <path id="path3853" fill="#FFF" d="m17648,1230c-11.241,0-20.352,11.34-20.352,25.327,0,13.988,9.111,25.326,20.352,25.326,11.24,0,20.352-11.338,20.352-25.326s-9.112-25.327-20.352-25.327z"/> - <path style="fill:url(#radialGradient877)" d="M 22.628906 0.046875 C 10.201906 0.046875 0.13085938 12.584828 0.13085938 28.048828 C 0.13085938 43.512828 10.201906 56.046875 22.628906 56.046875 C 35.055906 56.046875 45.130859 43.512828 45.130859 28.048828 C 45.130859 12.584828 35.055906 0.046875 22.628906 0.046875 z M 17.875 7.5585938 L 17.876953 7.5585938 C 18.10182 7.5592933 18.260094 7.6710337 18.339844 7.8945312 L 22.037109 16.599609 C 22.067109 16.657709 22.087891 16.724828 22.087891 16.798828 C 22.087891 16.931528 22.0375 17.046484 21.9375 17.146484 C 21.8455 17.237384 21.731656 17.283203 21.597656 17.283203 C 21.380656 17.283203 21.224766 17.183575 21.134766 16.984375 L 20.294922 14.966797 L 15.443359 14.966797 L 14.603516 16.984375 C 14.536516 17.183175 14.386344 17.283203 14.152344 17.283203 C 14.010344 17.283203 13.890781 17.237484 13.800781 17.146484 C 13.714781 17.046884 13.675781 16.931528 13.675781 16.798828 C 13.675781 16.715728 13.694844 16.644937 13.714844 16.585938 L 17.400391 7.8945312 C 17.491107 7.6710297 17.65012 7.5592894 17.875 7.5585938 z M 23.996094 7.5585938 L 26.253906 7.5585938 C 27.197906 7.5585937 28.041156 7.7666406 28.785156 8.1816406 C 29.529156 8.5967406 30.105625 9.1734094 30.515625 9.9121094 C 30.933625 10.642609 31.142578 11.478016 31.142578 12.416016 C 31.142578 13.353916 30.933625 14.190986 30.515625 14.929688 C 30.105625 15.668582 29.529156 16.245056 28.785156 16.660156 C 28.041156 17.075256 27.197906 17.283203 26.253906 17.283203 L 23.996094 17.283203 C 23.854094 17.283203 23.734531 17.237484 23.644531 17.146484 C 23.556531 17.055184 23.507812 16.939828 23.507812 16.798828 L 23.507812 8.0449219 C 23.507813 7.9038219 23.554531 7.7882656 23.644531 7.6972656 C 23.736531 7.6062656 23.854094 7.5585936 23.996094 7.5585938 z M 24.484375 8.4316406 L 24.484375 16.412109 L 26.253906 16.412109 C 27.013906 16.412109 27.690203 16.242644 28.283203 15.902344 C 28.877203 15.553644 29.341781 15.07465 29.675781 14.46875 C 30.009781 13.86275 30.175781 13.179616 30.175781 12.416016 C 30.175781 11.652316 30.009781 10.967328 29.675781 10.361328 C 29.341781 9.7554291 28.877203 9.2818068 28.283203 8.9414062 C 27.690203 8.6012066 27.013906 8.4316406 26.253906 8.4316406 L 24.484375 8.4316406 z M 17.876953 9.140625 L 15.796875 14.132812 L 19.957031 14.132812 L 17.876953 9.140625 z M 7.1816406 23.123047 L 13.060547 23.123047 C 13.202547 23.123047 13.322109 23.168766 13.412109 23.259766 C 13.500109 23.351166 13.550781 23.462903 13.550781 23.595703 C 13.550781 23.728603 13.502109 23.840641 13.412109 23.931641 C 13.320109 24.014141 13.202547 24.056641 13.060547 24.056641 L 7.6699219 24.056641 L 7.6699219 27.494141 L 11.59375 27.494141 C 11.73575 27.494141 11.855314 27.539859 11.945312 27.630859 C 12.033316 27.713859 12.082031 27.825797 12.082031 27.966797 C 12.082031 28.099697 12.035314 28.211734 11.945312 28.302734 C 11.853314 28.393734 11.73575 28.439453 11.59375 28.439453 L 7.6699219 28.439453 L 7.6699219 32.361328 C 7.6699219 32.494128 7.62125 32.610937 7.53125 32.710938 C 7.43925 32.801937 7.3236406 32.847656 7.1816406 32.847656 C 7.0486406 32.847656 6.9310781 32.801937 6.8300781 32.710938 C 6.7420781 32.611337 6.6914062 32.494128 6.6914062 32.361328 L 6.6914062 23.609375 C 6.6914062 23.468275 6.7400781 23.350766 6.8300781 23.259766 C 6.9310781 23.168966 7.0486406 23.123047 7.1816406 23.123047 z M 15.794922 23.123047 L 18.138672 23.123047 C 18.748672 23.123047 19.290578 23.252466 19.767578 23.509766 C 20.243578 23.758766 20.615813 24.111759 20.882812 24.568359 C 21.158813 25.024759 21.296875 25.544 21.296875 26.125 C 21.296875 26.7641 21.122484 27.323187 20.771484 27.804688 C 20.428484 28.286088 19.960187 28.630391 19.367188 28.837891 L 21.421875 32.101562 C 21.494875 32.225963 21.535156 32.3375 21.535156 32.4375 C 21.535156 32.562 21.486484 32.662328 21.396484 32.736328 C 21.304484 32.810428 21.183203 32.847656 21.033203 32.847656 C 20.933203 32.847656 20.853203 32.827156 20.783203 32.785156 C 20.716203 32.743656 20.657422 32.680656 20.607422 32.597656 L 18.351562 29.037109 L 18.138672 29.037109 L 16.283203 29.037109 L 16.283203 32.361328 C 16.283203 32.502428 16.234531 32.619937 16.144531 32.710938 C 16.052531 32.801937 15.936922 32.847656 15.794922 32.847656 C 15.652922 32.847656 15.533359 32.801937 15.443359 32.710938 C 15.355359 32.619636 15.304684 32.502428 15.304688 32.361328 L 15.304688 23.609375 C 15.304683 23.468275 15.353359 23.350766 15.443359 23.259766 C 15.535359 23.168966 15.652922 23.123047 15.794922 23.123047 z M 23.53125 23.123047 L 29.410156 23.123047 C 29.552156 23.123047 29.671719 23.168766 29.761719 23.259766 C 29.849719 23.351166 29.898438 23.462903 29.898438 23.595703 C 29.898438 23.728603 29.851719 23.840641 29.761719 23.931641 C 29.669719 24.014141 29.552156 24.056641 29.410156 24.056641 L 24.019531 24.056641 L 24.019531 27.494141 L 27.943359 27.494141 C 28.085359 27.494141 28.204922 27.539859 28.294922 27.630859 C 28.382922 27.722259 28.433594 27.833997 28.433594 27.966797 C 28.433594 28.099697 28.38125 28.211734 28.28125 28.302734 C 28.18925 28.393734 28.076359 28.439453 27.943359 28.439453 L 24.019531 28.439453 L 24.019531 31.914062 L 29.410156 31.914062 C 29.552156 31.914062 29.671719 31.959781 29.761719 32.050781 C 29.849719 32.133881 29.898438 32.240247 29.898438 32.373047 C 29.898438 32.505847 29.851719 32.619937 29.761719 32.710938 C 29.669719 32.801937 29.552156 32.847656 29.410156 32.847656 L 23.53125 32.847656 C 23.39725 32.847656 23.279687 32.801937 23.179688 32.710938 C 23.091688 32.611337 23.042969 32.494128 23.042969 32.361328 L 23.042969 23.609375 C 23.042969 23.468275 23.089687 23.350766 23.179688 23.259766 C 23.279687 23.168966 23.39725 23.123047 23.53125 23.123047 z M 32.199219 23.123047 L 38.078125 23.123047 C 38.220125 23.123047 38.339686 23.168766 38.429688 23.259766 C 38.517687 23.351166 38.566406 23.462903 38.566406 23.595703 C 38.566406 23.728603 38.519688 23.840641 38.429688 23.931641 C 38.337688 24.014141 38.220125 24.056641 38.078125 24.056641 L 32.6875 24.056641 L 32.6875 27.494141 L 36.611328 27.494141 C 36.753328 27.494141 36.872891 27.539859 36.962891 27.630859 C 37.050891 27.722259 37.099609 27.833997 37.099609 27.966797 C 37.099609 28.099697 37.049219 28.211734 36.949219 28.302734 C 36.857219 28.393734 36.745328 28.439453 36.611328 28.439453 L 32.6875 28.439453 L 32.6875 31.914062 L 38.078125 31.914062 C 38.220125 31.914062 38.339686 31.959781 38.429688 32.050781 C 38.517687 32.133881 38.566406 32.240247 38.566406 32.373047 C 38.566406 32.505847 38.519688 32.619937 38.429688 32.710938 C 38.337687 32.801937 38.220125 32.847656 38.078125 32.847656 L 32.199219 32.847656 C 32.065219 32.847656 31.947656 32.801937 31.847656 32.710938 C 31.759656 32.611337 31.710938 32.494128 31.710938 32.361328 L 31.710938 23.609375 C 31.710938 23.468275 31.757656 23.350766 31.847656 23.259766 C 31.947656 23.168966 32.065219 23.123047 32.199219 23.123047 z M 16.283203 24.056641 L 16.283203 28.103516 L 18.138672 28.103516 C 18.556672 28.103516 18.931625 28.019516 19.265625 27.853516 C 19.608625 27.679216 19.872641 27.443431 20.056641 27.144531 C 20.244641 26.845831 20.34375 26.504847 20.34375 26.123047 C 20.34375 25.724547 20.248641 25.368134 20.056641 25.052734 C 19.872641 24.737334 19.613297 24.492659 19.279297 24.318359 C 18.944297 24.143859 18.564672 24.056641 18.138672 24.056641 L 16.283203 24.056641 z M 12.605469 38.5625 L 12.607422 38.5625 L 12.609375 38.5625 C 13.267718 38.563088 13.847671 38.708135 14.347656 38.998047 C 14.849656 39.288547 15.241391 39.666059 15.525391 40.130859 C 15.585391 40.222159 15.615234 40.321688 15.615234 40.429688 C 15.615234 40.587387 15.540625 40.713688 15.390625 40.804688 C 15.323625 40.837687 15.244063 40.853516 15.164062 40.853516 C 15.072062 40.853516 14.982344 40.833016 14.902344 40.791016 C 14.826344 40.741216 14.764844 40.673797 14.714844 40.591797 C 14.246844 39.861297 13.539703 39.494375 12.595703 39.484375 C 11.918703 39.484375 11.383234 39.62415 10.990234 39.90625 C 10.598234 40.18855 10.400391 40.592334 10.400391 41.115234 C 10.400391 42.086334 11.191484 42.675313 12.771484 42.882812 C 13.807484 43.032113 14.579844 43.346625 15.089844 43.828125 C 15.599844 44.309525 15.853516 44.945875 15.853516 45.734375 C 15.853516 46.315475 15.711734 46.816834 15.427734 47.240234 C 15.143734 47.663534 14.754719 47.986737 14.261719 48.210938 C 13.768719 48.426737 13.217422 48.535156 12.607422 48.535156 C 11.813422 48.535156 11.106281 48.369109 10.488281 48.037109 C 9.8782812 47.696709 9.4408281 47.240569 9.1738281 46.667969 C 9.1438281 46.609869 9.1230469 46.54275 9.1230469 46.46875 C 9.1230469 46.35255 9.1680469 46.255641 9.2480469 46.181641 C 9.3400469 46.099041 9.4613281 46.058594 9.6113281 46.058594 C 9.7123281 46.058594 9.8086719 46.085531 9.8886719 46.144531 C 9.9806719 46.194431 10.049844 46.269141 10.089844 46.369141 C 10.281844 46.742641 10.599969 47.044944 11.042969 47.277344 C 11.493969 47.501444 12.015375 47.613281 12.609375 47.613281 C 13.294375 47.613281 13.845672 47.452706 14.263672 47.128906 C 14.681672 46.796906 14.890625 46.335394 14.890625 45.746094 C 14.890625 45.223094 14.693781 44.782781 14.300781 44.425781 C 13.915781 44.068781 13.336594 43.842187 12.558594 43.742188 C 11.589594 43.625987 10.823672 43.327103 10.263672 42.845703 C 9.7126719 42.356003 9.4375 41.758334 9.4375 41.052734 C 9.4375 40.554734 9.5708906 40.117641 9.8378906 39.744141 C 10.113891 39.362341 10.490797 39.072347 10.966797 38.873047 C 11.450716 38.666009 11.996115 38.562962 12.605469 38.5625 z M 18.388672 38.6875 C 18.530672 38.6875 18.650234 38.733219 18.740234 38.824219 C 18.828234 38.915419 18.878906 39.030675 18.878906 39.171875 L 18.878906 47.925781 C 18.878906 48.058681 18.830234 48.173437 18.740234 48.273438 C 18.648234 48.364237 18.530672 48.410156 18.388672 48.410156 C 18.254672 48.410156 18.137109 48.364437 18.037109 48.273438 C 17.949109 48.173738 17.900391 48.058681 17.900391 47.925781 L 17.900391 39.171875 C 17.900391 39.030675 17.947109 38.915219 18.037109 38.824219 C 18.137109 38.733219 18.254672 38.6875 18.388672 38.6875 z M 20.763672 38.6875 L 27.695312 38.6875 C 27.829313 38.6875 27.941484 38.727547 28.021484 38.810547 C 28.107484 38.893547 28.146484 39.001966 28.146484 39.134766 C 28.146484 39.259266 28.101484 39.362313 28.021484 39.445312 C 27.938484 39.527713 27.829314 39.570312 27.695312 39.570312 L 24.712891 39.570312 L 24.712891 47.925781 C 24.712891 48.058681 24.664219 48.173436 24.574219 48.273438 C 24.482219 48.364237 24.364656 48.410156 24.222656 48.410156 C 24.088656 48.410156 23.971094 48.364437 23.871094 48.273438 C 23.783094 48.173738 23.734375 48.058681 23.734375 47.925781 L 23.734375 39.570312 L 20.763672 39.570312 C 20.629672 39.570312 20.5175 39.527313 20.4375 39.445312 C 20.3515 39.362313 20.310547 39.259266 20.310547 39.134766 C 20.310547 39.001966 20.3575 38.893547 20.4375 38.810547 C 20.5205 38.728047 20.629672 38.6875 20.763672 38.6875 z M 30.068359 38.6875 L 35.947266 38.6875 C 36.089266 38.6875 36.208828 38.733219 36.298828 38.824219 C 36.386828 38.915419 36.4375 39.027356 36.4375 39.160156 C 36.4375 39.292856 36.388828 39.405094 36.298828 39.496094 C 36.206828 39.578594 36.089266 39.621094 35.947266 39.621094 L 30.556641 39.621094 L 30.556641 43.056641 L 34.480469 43.056641 C 34.622469 43.056641 34.742031 43.102359 34.832031 43.193359 C 34.920031 43.284659 34.970703 43.396497 34.970703 43.529297 C 34.970703 43.662097 34.920313 43.774234 34.820312 43.865234 C 34.728313 43.956334 34.614469 44.003906 34.480469 44.003906 L 30.556641 44.003906 L 30.556641 47.476562 L 35.328125 47.476562 C 35.470125 47.476562 35.589686 47.522281 35.679688 47.613281 C 35.767687 47.696281 35.818359 47.8046 35.818359 47.9375 C 35.818359 48.0703 35.769688 48.182437 35.679688 48.273438 C 35.587687 48.364237 35.470125 48.410156 35.328125 48.410156 L 30.068359 48.410156 C 29.935359 48.410156 29.817797 48.364437 29.716797 48.273438 C 29.628797 48.173738 29.578125 48.058681 29.578125 47.925781 L 29.578125 39.171875 C 29.578125 39.030675 29.626797 38.915219 29.716797 38.824219 C 29.817797 38.733219 29.935359 38.6875 30.068359 38.6875 z " id="use3804" transform="translate(17625.371,1227.3526)"/> - </g> -</svg> -\ No newline at end of file diff --git a/static/images/badges/created-with-emacs.jpg b/static/images/badges/created-with-emacs.jpg Binary files differ. diff --git a/static/images/badges/emacs.gif b/static/images/badges/emacs.gif Binary files differ. diff --git a/static/images/badges/gnu.gif b/static/images/badges/gnu.gif Binary files differ. diff --git a/static/images/badges/javascript.gif b/static/images/badges/javascript.gif Binary files differ. diff --git a/static/images/badges/libreboot.gif b/static/images/badges/libreboot.gif Binary files differ. diff --git a/static/images/badges/made-with-emacs.png b/static/images/badges/made-with-emacs.png Binary files differ. diff --git a/static/images/badges/sink_animated.gif b/static/images/badges/sink_animated.gif Binary files differ. diff --git a/static/images/badges/suckless.gif b/static/images/badges/suckless.gif Binary files differ. diff --git a/static/images/badges/tor.gif b/static/images/badges/tor.gif Binary files differ. diff --git a/static/images/badges/wiby.org.gif b/static/images/badges/wiby.org.gif Binary files differ. diff --git a/static/images/books/1984.webp b/static/images/books/1984.webp Binary files differ. diff --git a/static/images/books/critique-of-reason.webp b/static/images/books/critique-of-reason.webp Binary files differ. diff --git a/static/images/books/how-linux-works.webp b/static/images/books/how-linux-works.webp Binary files differ. diff --git a/static/images/books/lingua-latina.webp b/static/images/books/lingua-latina.webp Binary files differ. diff --git a/static/images/books/republic.webp b/static/images/books/republic.webp Binary files differ. diff --git a/static/images/books/short-history.webp b/static/images/books/short-history.webp Binary files differ. diff --git a/static/images/crypto/bitcoin.png b/static/images/crypto/bitcoin.png Binary files differ. diff --git a/static/images/crypto/btc-logo.svg b/static/images/crypto/btc-logo.svg @@ -1,7 +0,0 @@ -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="64" width="64" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"> -<g transform="translate(0.00630876,-0.00301984)"> -<path fill="#f7931a" d="m63.033,39.744c-4.274,17.143-21.637,27.576-38.782,23.301-17.138-4.274-27.571-21.638-23.295-38.78,4.272-17.145,21.635-27.579,38.775-23.305,17.144,4.274,27.576,21.64,23.302,38.784z"/> -<path fill="#FFF" d="m46.103,27.444c0.637-4.258-2.605-6.547-7.038-8.074l1.438-5.768-3.511-0.875-1.4,5.616c-0.923-0.23-1.871-0.447-2.813-0.662l1.41-5.653-3.509-0.875-1.439,5.766c-0.764-0.174-1.514-0.346-2.242-0.527l0.004-0.018-4.842-1.209-0.934,3.75s2.605,0.597,2.55,0.634c1.422,0.355,1.679,1.296,1.636,2.042l-1.638,6.571c0.098,0.025,0.225,0.061,0.365,0.117-0.117-0.029-0.242-0.061-0.371-0.092l-2.296,9.205c-0.174,0.432-0.615,1.08-1.609,0.834,0.035,0.051-2.552-0.637-2.552-0.637l-1.743,4.019,4.569,1.139c0.85,0.213,1.683,0.436,2.503,0.646l-1.453,5.834,3.507,0.875,1.439-5.772c0.958,0.26,1.888,0.5,2.798,0.726l-1.434,5.745,3.511,0.875,1.453-5.823c5.987,1.133,10.489,0.676,12.384-4.739,1.527-4.36-0.076-6.875-3.226-8.515,2.294-0.529,4.022-2.038,4.483-5.155zm-8.022,11.249c-1.085,4.36-8.426,2.003-10.806,1.412l1.928-7.729c2.38,0.594,10.012,1.77,8.878,6.317zm1.086-11.312c-0.99,3.966-7.1,1.951-9.082,1.457l1.748-7.01c1.982,0.494,8.365,1.416,7.334,5.553z"/> -</g> -</svg> -\ No newline at end of file diff --git a/static/images/crypto/monero.png b/static/images/crypto/monero.png Binary files differ. diff --git a/static/images/crypto/xmr-logo.svg b/static/images/crypto/xmr-logo.svg @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid"> - <g> - <path d="M127.9983,0.0005 C57.3183,0.0005 0.0003,57.3155 0.0003,127.9975 C0.0003,142.1255 2.2893,155.7145 6.5183,168.4275 L44.7993,168.4275 L44.7993,60.7335 L127.9983,143.9335 L211.1973,60.7335 L211.1973,168.4275 L249.4793,168.4275 C253.7103,155.7145 256.0003,142.1255 256.0003,127.9975 C256.0003,57.3155 198.6813,0.0005 127.9983,0.0005" fill="#FF6600"></path> - <path d="M108.8673,163.0617 L72.5573,126.7507 L72.5573,194.5157 L58.6773,194.5157 L44.7973,194.5157 L18.6233,194.5157 C41.0923,231.3787 81.6743,255.9967 127.9963,255.9967 C174.3183,255.9967 214.9033,231.3787 237.3703,194.5157 L211.1933,194.5157 L186.3673,194.5157 L183.4373,194.5157 L183.4373,126.7507 L147.1263,163.0617 L127.9963,182.1897 L108.8693,163.0617 L108.8673,163.0617 Z" fill="#4C4C4C"></path> - </g> -</svg> diff --git a/static/images/favicon-16x16.png b/static/images/favicon-16x16.png Binary files differ. diff --git a/static/images/favicon-32x32.png b/static/images/favicon-32x32.png Binary files differ. diff --git a/static/images/favicon.ico b/static/images/favicon.ico Binary files differ. diff --git a/static/images/icons/blog.svg b/static/images/icons/blog.svg @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> -<svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> -<style> - .darkmode { - svg { - fill: #93a1a1; - } - } - - svg { - fill: #586e75; - } -</style> -<path d="M17,11H16a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm0,4H16a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2ZM11,9h6a1,1,0,0,0,0-2H11a1,1,0,0,0,0,2ZM21,3H7A1,1,0,0,0,6,4V7H3A1,1,0,0,0,2,8V18a3,3,0,0,0,3,3H18a4,4,0,0,0,4-4V4A1,1,0,0,0,21,3ZM6,18a1,1,0,0,1-2,0V9H6Zm14-1a2,2,0,0,1-2,2H7.82A3,3,0,0,0,8,18V5H20Zm-9-4h1a1,1,0,0,0,0-2H11a1,1,0,0,0,0,2Zm0,4h1a1,1,0,0,0,0-2H11a1,1,0,0,0,0,2Z"/></svg> -\ No newline at end of file diff --git a/static/images/icons/categories.svg b/static/images/icons/categories.svg @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> -<svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> -<style> - .darkmode { - svg { - fill: #93a1a1; - } - } - - svg { - fill: #586e75; - } -</style> -<path d="M3.71,16.29a1,1,0,0,0-.33-.21,1,1,0,0,0-.76,0,1,1,0,0,0-.33.21,1,1,0,0,0-.21.33,1,1,0,0,0,.21,1.09,1.15,1.15,0,0,0,.33.21.94.94,0,0,0,.76,0,1.15,1.15,0,0,0,.33-.21,1,1,0,0,0,.21-1.09A1,1,0,0,0,3.71,16.29ZM7,8H21a1,1,0,0,0,0-2H7A1,1,0,0,0,7,8ZM3.71,11.29a1,1,0,0,0-1.09-.21,1.15,1.15,0,0,0-.33.21,1,1,0,0,0-.21.33.94.94,0,0,0,0,.76,1.15,1.15,0,0,0,.21.33,1.15,1.15,0,0,0,.33.21.94.94,0,0,0,.76,0,1.15,1.15,0,0,0,.33-.21,1.15,1.15,0,0,0,.21-.33.94.94,0,0,0,0-.76A1,1,0,0,0,3.71,11.29ZM21,11H7a1,1,0,0,0,0,2H21a1,1,0,0,0,0-2ZM3.71,6.29a1,1,0,0,0-.33-.21,1,1,0,0,0-1.09.21,1.15,1.15,0,0,0-.21.33.94.94,0,0,0,0,.76,1.15,1.15,0,0,0,.21.33,1.15,1.15,0,0,0,.33.21,1,1,0,0,0,1.09-.21,1.15,1.15,0,0,0,.21-.33.94.94,0,0,0,0-.76A1.15,1.15,0,0,0,3.71,6.29ZM21,16H7a1,1,0,0,0,0,2H21a1,1,0,0,0,0-2Z"/></svg> -\ No newline at end of file diff --git a/static/images/icons/contact.svg b/static/images/icons/contact.svg @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> -<svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"> -<style> - .darkmode { - svg { - fill: #93a1a1; - } - } - - svg { - fill: #586e75; - } -</style> -<path d="M17,21.63H5a3,3,0,0,1-3-3v-8a1,1,0,0,0-2,0v8a5,5,0,0,0,5,5H17a1,1,0,0,0,0-2Zm4-18H7a3,3,0,0,0-3,3v10a3,3,0,0,0,3,3H21a3,3,0,0,0,3-3v-10A3,3,0,0,0,21,3.63Zm-.41,2-5.88,5.88a1,1,0,0,1-1.42,0L7.41,5.63Zm1.41,11a1,1,0,0,1-1,1H7a1,1,0,0,1-1-1V7l5.88,5.88a3,3,0,0,0,4.24,0L22,7Z"/></svg> -\ No newline at end of file diff --git a/static/images/icons/copied.svg b/static/images/icons/copied.svg @@ -1,4 +0,0 @@ -<svg aria-hidden="true" focusable="false" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible;" class="octicon octicon-check js-clipboard-check-icon color-text-success d-none m-2"> -<path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"> -</path> -</svg> -\ No newline at end of file diff --git a/static/images/icons/copy.svg b/static/images/icons/copy.svg @@ -1,6 +0,0 @@ -<svg aria-hidden="true" focusable="false" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" style="display:inline-block;user-select:none;vertical-align:text-bottom;overflow:visible;" class="octicon octicon-copy js-clipboard-copy-icon m-2"> -<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"> -</path> -<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"> -</path> -</svg> -\ No newline at end of file diff --git a/static/images/icons/emacs-alt.svg b/static/images/icons/emacs-alt.svg @@ -1,286 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:space="preserve" - id="svg4768" - viewBox="0.171 0.201 512 512" - height="48" - width="48" - version="1.0"><metadata - id="metadata70"><rdf:RDF><cc:Work - rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><!-- Gnu Emacs Icon - Copyright (C) 2008-2017 Free Software Foundation, Inc. - - Author: Nicolas Petton <nicolas@petton.fr> - - This file is part of GNU Emacs. - - GNU Emacs is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - GNU Emacs is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. - ---><!-- Created with Inkscape (http://www.inkscape.org/) --><defs - id="defs4770"><linearGradient - id="linearGradient4292"><stop - id="stop4294" - offset="0" - style="stop-color:#411f5d;stop-opacity:1" /><stop - id="stop4296" - offset="1" - style="stop-color:#5b2a85;stop-opacity:1" /></linearGradient><linearGradient - id="linearGradient4284"><stop - offset="0" - style="stop-color:#8381c5;stop-opacity:1" - id="stop4286" /><stop - id="stop4290" - style="stop-color:#7e55b3;stop-opacity:0.99607843" - offset="0.56639391" /><stop - offset="1" - style="stop-color:#a52ecb;stop-opacity:0.99215686" - id="stop4288" /></linearGradient><linearGradient - id="linearGradient4898"><stop - id="stop4278" - style="stop-color:#bab8db;stop-opacity:1" - offset="0" /><stop - id="stop4280" - style="stop-color:#5955a9;stop-opacity:0.99159664" - offset="1" /></linearGradient><linearGradient - id="linearGradient3294"><stop - offset="0" - style="stop-color:#6376e6;stop-opacity:1" - id="stop3296" /><stop - offset="0.50094414" - style="stop-color:#222989;stop-opacity:1" - id="stop3302" /><stop - offset="1" - style="stop-color:#00003d;stop-opacity:1" - id="stop3298" /></linearGradient><linearGradient - id="linearGradient3284"><stop - offset="0" - style="stop-color:#000000;stop-opacity:1" - id="stop3286" /><stop - offset="0.84845906" - style="stop-color:#000000;stop-opacity:0.49803922" - id="stop3292" /><stop - offset="1" - style="stop-color:#000000;stop-opacity:0" - id="stop3288" /></linearGradient><linearGradient - id="linearGradient3274"><stop - offset="0" - style="stop-color:#000000;stop-opacity:1" - id="stop3276" /><stop - offset="1" - style="stop-color:#000000;stop-opacity:0" - id="stop3278" /></linearGradient><linearGradient - id="linearGradient3262"><stop - offset="0" - style="stop-color:#000000;stop-opacity:1" - id="stop3264" /><stop - offset="1" - style="stop-color:#000000;stop-opacity:0" - id="stop3266" /></linearGradient><linearGradient - id="linearGradient3242"><stop - offset="0" - style="stop-color:#282828;stop-opacity:1" - id="stop3244" /><stop - offset="0.39253417" - style="stop-color:#808080;stop-opacity:1" - id="stop3252" /><stop - offset="1" - style="stop-color:#d9d9d9;stop-opacity:1" - id="stop3246" /></linearGradient><linearGradient - id="linearGradient3202"><stop - offset="0" - style="stop-color:#2b2b2b;stop-opacity:1" - id="stop3204" /><stop - offset="0.5" - style="stop-color:#828383;stop-opacity:1" - id="stop3250" /><stop - offset="1" - style="stop-color:#dadbdb;stop-opacity:1" - id="stop3206" /></linearGradient><linearGradient - id="linearGradient4966"><stop - offset="0" - style="stop-color:#b6b3d8;stop-opacity:1" - id="stop4968" /><stop - offset="1" - style="stop-color:#b6b3d8;stop-opacity:0" - id="stop4970" /></linearGradient><linearGradient - id="linearGradient4938"><stop - offset="0" - style="stop-color:#000000;stop-opacity:1" - id="stop4940" /><stop - offset="1" - style="stop-color:#000000;stop-opacity:0" - id="stop4942" /></linearGradient><linearGradient - id="linearGradient4282"><stop - offset="0" - style="stop-color:#bab8db;stop-opacity:1" - id="stop4900" /><stop - offset="1" - style="stop-color:#5955a9;stop-opacity:0.99159664" - id="stop4902" /></linearGradient><linearGradient - id="linearGradient4876"><stop - offset="0" - style="stop-color:#d3d2e8;stop-opacity:1" - id="stop4878" /><stop - offset="1" - style="stop-color:#5955a9;stop-opacity:0.99159664" - id="stop4880" /></linearGradient><radialGradient - gradientTransform="matrix(0.6817439,0,0,0.5905355,-3.8523706,-28.935273)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient4898" - id="radialGradient4892" - fy="-108.96888" - fx="20.951529" - r="266.76535" - cy="-108.96888" - cx="20.951529" /><radialGradient - gradientTransform="matrix(1,0,0,0.1854103,0,383.88493)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient4938" - id="radialGradient4944" - fy="471.26172" - fx="233.8876" - r="170.49393" - cy="471.26172" - cx="233.8876" /><radialGradient - gradientTransform="matrix(1,0,0,0.9121621,0,32.654948)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient4966" - id="radialGradient4972" - fy="371.76376" - fx="299.70135" - r="76.696358" - cy="371.76376" - cx="299.70135" /><radialGradient - gradientTransform="matrix(0.414705,0.3300575,-0.5059004,0.6356454,346.95314,49.479585)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient3202" - id="radialGradient3210" - fy="390.45248" - fx="289.44067" - r="17.67668" - cy="390.45248" - cx="289.44067" /><radialGradient - gradientTransform="matrix(0.414705,0.3300575,-0.5059004,0.6356454,448.41009,-65.398074)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient3202" - id="radialGradient3238" - fy="382.14804" - fx="283.50717" - r="17.67668" - cy="382.14804" - cx="283.50717" /><radialGradient - gradientTransform="matrix(-6.5565014e-2,-5.9721765e-2,1.6871024,-1.8521705,171.90774,540.51473)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient3242" - id="radialGradient3248" - fy="181.18982" - fx="418.45551" - r="63.068935" - cy="181.18982" - cx="418.45551" /><radialGradient - gradientTransform="matrix(0.4055116,-3.3440123e-2,0.1034174,4.3988695,177.23251,-1191.6649)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient3262" - id="radialGradient3268" - fy="357.33591" - fx="354.51709" - r="33.712105" - cy="357.33591" - cx="354.51709" /><radialGradient - gradientTransform="matrix(-0.1339874,-0.1146812,0.3079048,-0.3597394,444.23592,395.03849)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient3274" - id="radialGradient3280" - fy="223.55537" - fx="510.58469" - r="132.28336" - cy="223.55537" - cx="510.58469" /><radialGradient - gradientTransform="matrix(-1.2497569,1.3798305,-9.6289463e-2,-7.2974479e-2,674.3826,-70.590682)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient3284" - id="radialGradient3290" - fy="-158.17821" - fx="284.4671" - r="110.2972" - cy="-158.17821" - cx="284.4671" /><radialGradient - gradientTransform="matrix(-0.1008165,-8.0872321e-2,1.0745309,-1.3395252,13.843287,784.79288)" - gradientUnits="userSpaceOnUse" - xlink:href="#linearGradient3294" - id="radialGradient3300" - fy="356.62274" - fx="425.51019" - r="143.34167" - cy="356.62274" - cx="425.51019" /><filter - height="1.088351" - y="-0.044175496" - width="1.0892536" - x="-0.044626798" - id="filter4350" - style="color-interpolation-filters:sRGB"><feGaussianBlur - id="feGaussianBlur4352" - stdDeviation="8.7848425" /></filter><linearGradient - y2="300.73987" - x2="236.61363" - y1="-161.8512" - x1="-122.20192" - spreadMethod="pad" - gradientTransform="matrix(0.87385837,0,0,0.82818057,246.00762,250.28138)" - gradientUnits="userSpaceOnUse" - id="linearGradient4245" - xlink:href="#linearGradient4284" /><linearGradient - y2="66.018341" - x2="173.94518" - y1="396.6066" - x1="447.80933" - gradientTransform="matrix(0.98684959,0,0,0.98684959,3.0344187,2.5250397)" - gradientUnits="userSpaceOnUse" - id="linearGradient4247" - xlink:href="#linearGradient4292" /></defs><rect - style="fill:none;display:none" - id="rect4772" - y="0.20100001" - x="0.171" - height="512" - width="512" /><g - style="display:none" - id="g4788"><g - style="display:inline" - id="g4790" /></g><g - style="display:none" - id="g4806"><g - style="display:inline" - id="g4808"><path - style="fill:#050505;display:none" - id="path4810" - d="M 349.098,256.651 C 348.833,256.397 386.735,284.256 388.519,281.663 C 394.881,272.411 470.565,188.526 473.303,165.427 C 473.545,163.424 472.787,161.331 472.787,161.331 C 472.787,161.331 471.597,161.187 466.462,157.017 C 463.77,154.825 460.979,152.436 460.979,152.436 C 444.925,153.434 403.094,193.995 349.917,256.004" /></g></g><path - style="opacity:0.40500004;fill:#211f46;fill-opacity:0.99607843;stroke:#0a0b1b;stroke-width:8.53333378;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter4350)" - id="path4233" - d="m 491.66937,257.75916 c 0,131.79436 -105.76,238.63481 -236.22155,238.63481 -130.46155,0 -236.221539,-106.84045 -236.221539,-238.63481 0,-131.79437 105.759989,-238.634808 236.221539,-238.634808 130.46155,0 236.22155,106.840438 236.22155,238.634808 z" - transform="matrix(0.98684957,0,0,0.98684957,3.0344041,2.5250397)" /><path - d="m 488.23812,256.89456 c 0,130.06121 -104.3692,235.49665 -233.1151,235.49665 -128.7459,0 -233.115201,-105.43544 -233.115201,-235.49665 0,-130.06123 104.369301,-235.49666 233.115201,-235.49666 128.7459,0 233.1151,105.43543 233.1151,235.49666 z" - id="path4235" - style="opacity:1;fill:url(#linearGradient4245);fill-opacity:1;stroke:url(#linearGradient4247);stroke-width:13.33816814;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><path - d="m 175.0003,422.31057 c 0,0 19.7385,1.39634 45.1312,-0.84159 10.2834,-0.9063 49.3267,-4.74128 78.5169,-11.14289 0,0 35.5899,-7.61669 54.6301,-14.63335 19.9225,-7.34185 30.7636,-13.57304 35.6433,-22.40243 -0.2128,-1.80907 1.5024,-8.22438 -7.685,-12.07788 -23.4887,-9.85199 -50.73,-8.06998 -104.6338,-9.21285 -59.7772,-2.05391 -79.6627,-12.05971 -90.2556,-20.11838 -10.1579,-8.17519 -5.05,-30.79254 38.4742,-50.71499 21.9244,-10.60898 107.8705,-30.18698 107.8705,-30.18698 -28.9451,-14.30725 -82.9186,-39.45893 -94.0134,-44.89023 -9.7308,-4.76348 -25.303,-11.93595 -28.6785,-20.61368 -3.8271,-8.33089 9.0383,-15.50726 16.2248,-17.56236 23.1448,-6.67602 55.8182,-10.82538 85.5548,-11.29122 14.9472,-0.23417 17.3734,-1.19586 17.3734,-1.19586 20.6243,-3.42116 34.2014,-17.53175 28.5446,-39.87876 -5.0783,-22.81046 -31.8617,-36.21365 -57.3138,-31.57361 -23.9682,4.36956 -81.7378,21.15007 -81.7378,21.15007 71.4075,-0.61803 83.3592,0.57378 88.697,8.03676 3.1523,4.40742 -1.4324,10.45068 -20.4765,13.56099 -20.733,3.38616 -63.8312,7.46399 -63.8312,7.46399 -41.3449,2.4554 -70.4682,2.61974 -79.203,21.11314 -5.7065,12.08196 6.0854,22.7633 11.2538,29.4493 21.8407,24.28905 53.3882,37.38879 73.6948,47.03553 7.6405,3.62963 30.0586,10.48407 30.0586,10.48407 -65.8782,-3.62335 -113.4003,16.6055 -141.2764,39.89622 -31.5288,29.16261 -17.581403,63.92354 47.0124,85.3268 38.1517,12.6416 57.0725,18.58695 113.9815,13.46232 33.52,-1.80673 38.8041,-0.73155 39.1383,2.01892 0.4705,3.87242 -37.2311,13.49165 -47.524,16.4606 -26.1853,7.55306 -94.8276,22.80438 -95.1712,22.87835 z" - id="path4237" - style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /></svg> diff --git a/static/images/icons/emacs.svg b/static/images/icons/emacs.svg @@ -1,239 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://web.resource.org/cc/" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - id="svg6612" - sodipodi:version="0.32" - inkscape:version="0.45.1" - width="270" - height="217" - version="1.0" - sodipodi:docbase="/home/sphinx/images" - sodipodi:docname="Emacs-logo.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <metadata - id="metadata6617"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <cc:license - rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" /> - <dc:creator> - <cc:Agent> - <dc:title>Dmitry Dzhus</dc:title> - </cc:Agent> - </dc:creator> - <dc:date>2007-07</dc:date> - <dc:title>Emacs logo</dc:title> - <dc:subject> - <rdf:Bag> - <rdf:li>emacs</rdf:li> - <rdf:li>logo</rdf:li> - </rdf:Bag> - </dc:subject> - <dc:description>Emacs logo by Luis Fernandes was created in 2001. This is an SVG version created by hand from scratch in Inkscape.</dc:description> - <dc:language>en</dc:language> - </cc:Work> - <cc:License - rdf:about="http://creativecommons.org/licenses/GPL/2.0/"> - <cc:permits - rdf:resource="http://web.resource.org/cc/Reproduction" /> - <cc:permits - rdf:resource="http://web.resource.org/cc/Distribution" /> - <cc:requires - rdf:resource="http://web.resource.org/cc/Notice" /> - <cc:permits - rdf:resource="http://web.resource.org/cc/DerivativeWorks" /> - <cc:requires - rdf:resource="http://web.resource.org/cc/ShareAlike" /> - <cc:requires - rdf:resource="http://web.resource.org/cc/SourceCode" /> - </cc:License> - </rdf:RDF> - </metadata> - <defs - id="defs6615" /> - <sodipodi:namedview - inkscape:window-height="990" - inkscape:window-width="1276" - inkscape:pageshadow="2" - inkscape:pageopacity="0.0" - guidetolerance="10.0" - gridtolerance="10.0" - objecttolerance="10.0" - borderopacity="1.0" - bordercolor="#666666" - pagecolor="#ffffff" - id="base" - inkscape:zoom="1.7926268" - inkscape:cx="227.95993" - inkscape:cy="149.03165" - inkscape:window-x="0" - inkscape:window-y="0" - inkscape:current-layer="svg6612" /> - <g - id="g2240" - style="fill:#000000;fill-opacity:1;stroke:none" - transform="translate(-4.7334344,4.3389815)"> - <path - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 176.57988,37.972907 C 174.9871,39.007967 168.87448,51.953525 168.7783,53.533221 C 180.64186,73.113933 202.57955,40.078784 206.55381,24.980764 C 206.55381,24.980764 196.17124,43.179003 186.77317,43.526939 C 175.75676,43.93479 178.17554,36.935973 176.57988,37.972907 z " - id="path2242" - sodipodi:nodetypes="cccsz" /> - <path - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 22.47173,15.758997 L 15.81003,32.485756 C 15.81003,32.485756 19.89052,42.218104 26.49069,42.838195 C 41.61737,44.259359 58.45245,15.619537 63.19409,15.758997 C 67.93574,15.898457 77.55353,23.422298 82.6657,33.922656 C 89.39535,20.759071 97.58642,14.911225 111.16839,24.667015 C 119.07042,30.342966 135.58934,52.795226 145.47559,53.901349 C 156.18021,55.099037 165.37798,44.912817 169.81138,26.288239 C 163.67513,34.237468 161.1768,37.806706 155.0286,38.212082 C 148.68317,38.630462 149.241,39.885604 127.06684,16.874679 C 104.89268,-6.1362469 94.43317,4.8811053 87.87854,14.643316 C 86.41421,13.039524 78.99699,1.01863 70.05858,1.1156811 C 63.72511,1.1844483 53.17415,16.174161 46.86414,21.616488 C 40.30897,27.270272 36.37856,28.267647 33.99471,28.294944 C 30.30074,28.339067 25.84923,26.450798 22.47173,15.758997 z " - id="path2244" - sodipodi:nodetypes="ccsscsscsscsssc" /> - <path - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 76.60517,33.616604 C 59.9071,53.934058 59.23819,54.418087 50.46092,68.860929 C 41.68365,83.303771 39.35397,92.905012 43.4733,96.486252 C 47.62389,100.09467 55.01913,100.29382 64.07871,93.597586 C 76.68602,83.936084 93.51416,70.148169 98.13382,58.409876 C 99.33455,55.358876 77.4725,76.054153 68.69926,81.186233 C 63.43563,84.265304 56.36004,85.075126 52.55923,81.397725 C 44.80291,73.893236 79.52343,36.77475 76.60517,33.616604 z " - id="path2246" - sodipodi:nodetypes="csscsssc" /> - <path - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 101.40617,64.709511 C 101.3713,63.070854 109.84351,50.554306 111.30784,50.066195 C 132.55351,64.354287 121.48844,101.10862 114.51543,104.3162 C 114.51543,104.3162 115.7357,88.557199 112.56298,78.655527 C 109.39026,68.753854 101.4411,66.351131 101.40617,64.709511 z " - id="path2248" - sodipodi:nodetypes="cccsz" /> - <path - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 212.01995,32.790058 C 210.0143,24.25611 219.12924,1.1854142 230.75546,1.1854142 C 259.78347,1.1854142 245.6869,47.473559 240.02956,64.570053 C 226.22301,100.34158 217.47477,153.8249 216.87918,158.42673 C 216.15214,164.0442 207.47903,179.09487 211.85861,154.24293 C 216.23819,129.39099 224.1069,100.38994 233.56074,66.549824 C 238.51906,48.801431 244.54954,17.14762 227.7868,17.100791 C 219.23545,16.991458 219.72047,23.025811 212.01995,32.790058 z " - id="path2250" - sodipodi:nodetypes="cscssscc" /> - </g> - <g - id="g2233" - style="stroke:none"> - <path - sodipodi:nodetypes="cccsz" - id="path9706" - d="M 176.57988,37.972907 C 174.9871,39.007967 168.87448,51.953525 168.7783,53.533221 C 180.64186,73.113933 202.57955,40.078784 206.55381,24.980764 C 206.55381,24.980764 196.17124,43.179003 186.77317,43.526939 C 175.75676,43.93479 178.17554,36.935973 176.57988,37.972907 z " - style="fill:#c64e3b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - <path - sodipodi:nodetypes="ccsscsscsscsssc" - id="path7673" - d="M 22.47173,15.758997 L 15.81003,32.485756 C 15.81003,32.485756 19.89052,42.218104 26.49069,42.838195 C 41.61737,44.259359 58.45245,15.619537 63.19409,15.758997 C 67.93574,15.898457 77.55353,23.422298 82.6657,33.922656 C 89.39535,20.759071 97.58642,14.911225 111.16839,24.667015 C 119.07042,30.342966 135.58934,52.795226 145.47559,53.901349 C 156.18021,55.099037 165.37798,44.912817 169.81138,26.288239 C 163.67513,34.237468 161.1768,37.806706 155.0286,38.212082 C 148.68317,38.630462 149.241,39.885604 127.06684,16.874679 C 104.89268,-6.1362469 94.43317,4.8811053 87.87854,14.643316 C 86.41421,13.039524 78.99699,1.01863 70.05858,1.1156811 C 63.72511,1.1844483 53.17415,16.174161 46.86414,21.616488 C 40.30897,27.270272 36.37856,28.267647 33.99471,28.294944 C 30.30074,28.339067 25.84923,26.450798 22.47173,15.758997 z " - style="fill:#c64e3b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - <path - sodipodi:nodetypes="csscsssc" - id="path8693" - d="M 76.60517,33.616604 C 59.9071,53.934058 59.23819,54.418087 50.46092,68.860929 C 41.68365,83.303771 39.35397,92.905012 43.4733,96.486252 C 47.62389,100.09467 55.01913,100.29382 64.07871,93.597586 C 76.68602,83.936084 93.51416,70.148169 98.13382,58.409876 C 99.33455,55.358876 77.4725,76.054153 68.69926,81.186233 C 63.43563,84.265304 56.36004,85.075126 52.55923,81.397725 C 44.80291,73.893236 79.52343,36.77475 76.60517,33.616604 z " - style="fill:#c64e3b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - <path - sodipodi:nodetypes="cccsz" - id="path9704" - d="M 101.40617,64.709511 C 101.3713,63.070854 109.84351,50.554306 111.30784,50.066195 C 132.55351,64.354287 121.48844,101.10862 114.51543,104.3162 C 114.51543,104.3162 115.7357,88.557199 112.56298,78.655527 C 109.39026,68.753854 101.4411,66.351131 101.40617,64.709511 z " - style="fill:#c64e3b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - <path - sodipodi:nodetypes="cscssscc" - id="path2171" - d="M 212.01995,32.790058 C 210.0143,24.25611 219.12924,1.1854142 230.75546,1.1854142 C 259.78347,1.1854142 245.6869,47.473559 240.02956,64.570053 C 226.22301,100.34158 217.47477,153.8249 216.87918,158.42673 C 216.15214,164.0442 207.47903,179.09487 211.85861,154.24293 C 216.23819,129.39099 224.1069,100.38994 233.56074,66.549824 C 238.51906,48.801431 244.54954,17.14762 227.7868,17.100791 C 219.23545,16.991458 219.72047,23.025811 212.01995,32.790058 z " - style="fill:#c64e3b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - </g> - <g - style="fill:#000000;fill-opacity:1;stroke:none" - id="g2256" - transform="translate(0.8166413,4.3944529)"> - <path - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M 79.886738,152.50463 C 67.822172,155.61715 50.502331,192.18769 49.743523,198.14195 C 52.532726,198.83925 111.02019,130.19512 80.295208,193.81167 C 102.57324,174.95912 124.9556,141.04167 107.8027,183.94795 C 103.74903,194.08781 123.59559,194.09426 142.96938,172.96563 C 137.88975,176.22186 112.22868,191.62171 126.35499,159.60889 C 133.77483,142.79418 109.21923,159.41447 102.3683,165.83729 C 103.80096,159.33343 108.94433,147.78354 100.61675,150.98227 C 92.289176,154.181 83.310373,160.6892 67.937825,175.11509 C 76.765795,160.89643 77.224181,159.40756 79.886738,152.50463 z " - id="path2258" - sodipodi:nodetypes="cccscscscc" /> - <path - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M 248.85492,188.50638 C 263.21933,186.53398 284.36437,164.67209 255.21207,163.30784 C 223.17817,161.81588 262.88238,150.47751 262.88238,150.47751 C 245.58932,149.36183 214.14946,168.68613 239.80172,165.74839 C 265.63062,162.76646 265.93049,186.17596 239.24388,186.14445 C 235.50916,186.14004 236.66387,182.41388 236.66387,182.41388 L 225.77752,187.22526 C 236.0826,190.18366 240.70876,189.62494 248.85492,188.50638 z " - id="path2260" - sodipodi:nodetypes="cscssccs" /> - <path - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M 35.422878,148.66454 C 20.150885,157.04591 -6.2772909,190.95274 6.2647537,199.01662 C 17.984924,206.55208 68.941642,170.29445 77.667057,153.75538 C 4.3035383,211.52619 14.065561,174.90254 27.008448,162.02628 C 35.805465,151.30801 64.004057,143.68513 71.481066,128.52052 C 32.789119,149.29474 30.405114,131.50519 62.642197,110.82103 C 68.569623,107.02504 107.74937,89.042889 77.768775,114.28261 C 95.502651,106.02716 110.52675,93.267855 98.941531,90.767173 C 83.884151,87.517022 60.202847,105.92694 48.092626,115.80927 C 40.969928,121.62162 11.868522,145.38354 35.422878,148.66454 z " - id="path2262" - sodipodi:nodetypes="cscccscssc" /> - <g - style="fill:#000000;fill-opacity:1;stroke:none" - id="g2264"> - <path - sodipodi:nodetypes="ccc" - id="path2266" - d="M 153.52386,181.54504 C 114.3973,212.57672 133.43947,164.59338 180.00502,149.95001 C 144.43247,174.12306 139.76476,184.61018 153.52386,181.54504 z " - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> - <path - sodipodi:nodetypes="ccc" - id="path2268" - d="M 196.30981,176.96638 C 156.1373,209.46239 150.29865,172.10195 184.30492,155.10468 C 167.14111,181.92747 183.59666,177.6607 196.30981,176.96638 z " - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> - </g> - <path - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M 229.3687,178.97034 C 185.57023,211.04797 178.47643,161.27557 237.30661,150.27509 C 188.34589,179.18978 219.44475,183.56954 229.3687,178.97034 z " - id="path2270" - sodipodi:nodetypes="ccc" /> - </g> - <g - id="g2201" - style="fill:#2076c1;fill-opacity:1;stroke:none"> - <path - sodipodi:nodetypes="cccscscscc" - id="path2173" - d="M 79.886738,152.50463 C 67.822172,155.61715 50.502331,192.18769 49.743523,198.14195 C 52.532726,198.83925 111.02019,130.19512 80.295208,193.81167 C 102.57324,174.95912 124.9556,141.04167 107.8027,183.94795 C 103.74903,194.08781 123.59559,194.09426 142.96938,172.96563 C 137.88975,176.22186 112.22868,191.62171 126.35499,159.60889 C 133.77483,142.79418 109.21923,159.41447 102.3683,165.83729 C 103.80096,159.33343 108.94433,147.78354 100.61675,150.98227 C 92.289176,154.181 83.310373,160.6892 67.937825,175.11509 C 76.765795,160.89643 77.224181,159.40756 79.886738,152.50463 z " - style="fill:#2076c1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" /> - <path - sodipodi:nodetypes="cscssccs" - id="path2183" - d="M 248.85492,188.50638 C 263.21933,186.53398 284.36437,164.67209 255.21207,163.30784 C 223.17817,161.81588 262.88238,150.47751 262.88238,150.47751 C 245.58932,149.36183 214.14946,168.68613 239.80172,165.74839 C 265.63062,162.76646 265.93049,186.17596 239.24388,186.14445 C 235.50916,186.14004 236.66387,182.41388 236.66387,182.41388 L 225.77752,187.22526 C 236.0826,190.18366 240.70876,189.62494 248.85492,188.50638 z " - style="fill:#2076c1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" /> - <path - sodipodi:nodetypes="cscccscssc" - id="path6069" - d="M 35.422878,148.66454 C 20.150885,157.04591 -6.2772909,190.95274 6.2647537,199.01662 C 17.984924,206.55208 68.941642,170.29445 77.667057,153.75538 C 4.3035383,211.52619 14.065561,174.90254 27.008448,162.02628 C 35.805465,151.30801 64.004057,143.68513 71.481066,128.52052 C 32.789119,149.29474 30.405114,131.50519 62.642197,110.82103 C 68.569623,107.02504 107.74937,89.042889 77.768775,114.28261 C 95.502651,106.02716 110.52675,93.267855 98.941531,90.767173 C 83.884151,87.517022 60.202847,105.92694 48.092626,115.80927 C 40.969928,121.62162 11.868522,145.38354 35.422878,148.66454 z " - style="fill:#2076c1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" /> - <g - id="g2188" - style="fill:#2076c1;fill-opacity:1;stroke:none"> - <path - style="fill:#2076c1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" - d="M 153.52386,181.54504 C 114.3973,212.57672 133.43947,164.59338 180.00502,149.95001 C 144.43247,174.12306 139.76476,184.61018 153.52386,181.54504 z " - id="path2175" - sodipodi:nodetypes="ccc" /> - <path - style="fill:#2076c1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" - d="M 196.30981,176.96638 C 156.1373,209.46239 150.29865,172.10195 184.30492,155.10468 C 167.14111,181.92747 183.59666,177.6607 196.30981,176.96638 z " - id="path2177" - sodipodi:nodetypes="ccc" /> - </g> - <path - sodipodi:nodetypes="ccc" - id="path2179" - d="M 229.3687,178.97034 C 185.57023,211.04797 178.47643,161.27557 237.30661,150.27509 C 188.34589,179.18978 219.44475,183.56954 229.3687,178.97034 z " - style="fill:#2076c1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" /> - </g> - <path - sodipodi:nodetypes="cscsss" - id="path2252" - d="M 124.1858,189.83823 C 119.19632,187.34349 148.26509,119.15484 152.29057,142.10943 C 154.09525,152.40027 170.73124,123.57014 170.73124,123.57014 C 170.73124,123.57014 183.79749,99.804357 184.43848,101.87524 C 187.48343,111.71277 149.00775,175.41789 146.27516,159.36674 C 143.51342,143.14437 124.77748,190.13407 124.1858,189.83823 z " - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - <path - style="fill:#c64e3b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 127.36915,186.62713 C 122.37967,184.13239 151.44844,115.94374 155.47392,138.89833 C 157.2786,149.18917 173.91459,120.35904 173.91459,120.35904 C 173.91459,120.35904 186.98084,96.593259 187.62183,98.664137 C 190.66678,108.50167 152.1911,172.20679 149.45851,156.15564 C 146.69677,139.93327 127.96083,186.92297 127.36915,186.62713 z " - id="path3158" - sodipodi:nodetypes="cscsss" /> - <path - sodipodi:nodetypes="cscsc" - id="path2254" - d="M 56.312166,214.04162 C 56.312166,214.04162 56.065636,199.44685 80.768246,168.4823 C 100.68005,143.52298 123.7636,107.53934 123.7636,107.53934 C 123.7636,107.53934 119.97892,126.52044 103.15975,148.19092 C 83.527796,173.4855 56.312166,214.04162 56.312166,214.04162 z " - style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - <path - style="fill:#c64e3b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 59.52326,215.22497 C 59.52326,215.22497 59.27673,200.6302 83.97934,169.66565 C 103.89115,144.70633 126.9747,108.72269 126.9747,108.72269 C 126.9747,108.72269 123.19002,127.70379 106.37085,149.37427 C 86.73889,174.66885 59.52326,215.22497 59.52326,215.22497 z " - id="path4129" - sodipodi:nodetypes="cscsc" /> -</svg> diff --git a/static/images/icons/github.svg b/static/images/icons/github.svg @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> -<svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"> -<style> - .darkmode { - svg { - fill: #93a1a1; - } - } - - svg { - fill: #586e75; - } -</style> -<path d="M10.07031,20.50291a1.00008,1.00008,0,0,0-1.18115-.9834c-1.30908.24024-2.96191.27637-3.40137-.958a5.70754,5.70754,0,0,0-1.83691-2.415,1.20073,1.20073,0,0,1-.1665-.10938,1,1,0,0,0-.93067-.64551H2.54883a.99965.99965,0,0,0-1,.99512c-.00391.81543.811,1.33789,1.1416,1.51465a4.4408,4.4408,0,0,1,.92383,1.35937c.36426,1.02344,1.42285,2.57617,4.46582,2.376.001.03516.00195.06836.00244.09863l.00439.26758a1,1,0,0,0,2,0l-.00488-.31836C10.07715,21.4951,10.07031,21.22068,10.07031,20.50291Zm10.667-15.126c.03174-.125.063-.26367.09034-.41992a6.27792,6.27792,0,0,0-.40821-3.293,1.002,1.002,0,0,0-.61572-.58007c-.356-.12012-1.67041-.35645-4.18408,1.25a13.86918,13.86918,0,0,0-6.354,0C6.76221.751,5.45459.9658,5.10205,1.07908a.99744.99744,0,0,0-.63135.584,6.3003,6.3003,0,0,0-.40332,3.35644c.02442.12793.05078.2461.07813.35449A6.26928,6.26928,0,0,0,2.89014,9.20311a8.42168,8.42168,0,0,0,.04248.92187c.334,4.60254,3.334,5.98438,5.42431,6.459-.04345.125-.083.25878-.11816.40039a1.00023,1.00023,0,0,0,1.94238.47851,1.6784,1.6784,0,0,1,.46778-.87793.99947.99947,0,0,0-.5459-1.74512c-3.4541-.39453-4.95362-1.80175-5.1792-4.89843a6.61076,6.61076,0,0,1-.03369-.73828,4.25769,4.25769,0,0,1,.91943-2.71289,3.022,3.022,0,0,1,.1958-.23145.99988.99988,0,0,0,.188-1.02441,3.3876,3.3876,0,0,1-.15527-.55567A4.09356,4.09356,0,0,1,6.1167,3.06346a7.54263,7.54263,0,0,1,2.415,1.17968,1.00877,1.00877,0,0,0,.82764.13282,11.77716,11.77716,0,0,1,6.17285.001,1.00549,1.00549,0,0,0,.83056-.13769,7.572,7.572,0,0,1,2.40528-1.19043,4.03977,4.03977,0,0,1,.0874,1.57812,3.205,3.205,0,0,1-.16895.60743.9999.9999,0,0,0,.188,1.02441c.07715.08691.1543.18066.22363.26855A4.12186,4.12186,0,0,1,20,9.20311a7.03888,7.03888,0,0,1-.0376.77734c-.22021,3.05566-1.72558,4.46387-5.1958,4.85937a1,1,0,0,0-.54541,1.7461,1.63079,1.63079,0,0,1,.46631.9082,3.06079,3.06079,0,0,1,.09229.81934v2.334C14.77,21.2949,14.77,21.78025,14.77,22.00291a1,1,0,1,0,2,0c0-.2168,0-.69238.00977-1.33984V18.31346a4.8815,4.8815,0,0,0-.15479-1.31153,4.25638,4.25638,0,0,0-.11621-.416,6.51258,6.51258,0,0,0,5.44531-6.42383A8.69677,8.69677,0,0,0,22,9.20311,6.13062,6.13062,0,0,0,20.7373,5.37693Z"/></svg> -\ No newline at end of file diff --git a/static/images/icons/hugo.svg b/static/images/icons/hugo.svg @@ -1,14 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" stroke-miterlimit="1.414" viewBox="0 0 1500 410" clip-rule="evenodd" stroke-linejoin="round" aria-label="Logo"> - <path fill="#FF4088" d="M335.1 261.86V139.606c0-15.898-8.42-30.606-22.126-38.66-29.417-17.283-81.387-47.818-113.215-66.52-16.81-9.872-37.69-9.65-54.28.58-28.17 17.37-72.12 44.47-100.49 61.967-17.11 10.55-27.53 29.21-27.53 49.31v125.172c0 19.938 10.58 38.376 27.79 48.437l104.72 61.212c13.92 8.14 31.11 8.317 45.2.47 30.58-17.036 84.74-47.196 115.94-64.575 14.8-8.25 23.97-23.86 23.97-40.8v-14.34z"/> - <path fill="#C9177E" d="M173.24 13.676h.277l.247.003h1.414l.247.01h.03l.247.01h.027l.25.01h.02l.25.01h.03l.24.01h.03l.24.01h.02l.25.01h.03l.25.02h.03l.24.02h.02l.24.02h.03l.25.02h.02l.24.02h.03l.25.02h.03l.25.02h.03l.25.02h.03l.24.02h.03l.24.02h.03l.25.02h.03l.25.03h.03l.25.03h.02l.24.03h.03l.24.03h.03l.25.03h.03l.25.03h.02l.24.03h.03l.25.03h.03l.24.04.03.01.25.04h.03l.24.04h.02l.25.04h.03l.24.04h.03l.24.04h.02l.25.04h.03l.24.04.03.01.24.04.03.01.24.05h.03l.24.04h.03l.24.05h.03l.25.05h.02l.24.05h.03l.24.05h.02l.25.05.03.01.25.05h.02l.24.06.03.01.24.06h.03l.25.06.02.01.24.05.03.01.24.05.02.01.24.06h.03l.24.06.03.01.24.06.02.01.25.06.02.01.24.06.03.01.24.06h.02l.24.07h.03l.25.06.03.01.24.06h.03l.24.07.03.01.24.07.03.01.24.07.03.01.24.07.02.01.24.07.03.01.24.07.03.01.24.07.03.01.24.08.02.01.24.08h.03l.24.08h.03l.24.08.03.01.24.08.03.01.24.08.02.01.24.08.03.01.24.08.02.01.24.08.02.01.23.08.03.01.23.08.03.01.23.09.03.01.24.09.03.01.23.09.02.01.24.08.02.01.24.09.03.01.24.09.03.01.23.09.03.01.23.1.02.01.24.09.03.01.23.1.03.01.24.1.03.01.24.1.02.01.24.1.02.01.23.1.02.01.23.1.02.01.24.1.02.01.23.1.03.01.23.1.03.01.23.1.02.01.23.11.03.01.23.11.03.01.23.11.02.01.23.11.02.01.23.11.03.01.23.11.03.01.23.11.03.01.23.11.02.01.23.12.02.02.23.11.02.01.22.12.03.01.23.11.02.01.23.12.03.01.22.12.03.02.23.12.03.01.23.12.02.01.22.12.03.02.23.12.02.02.22.13.02.02.22.13.03.01.22.13.02.01.22.13.02.02.22.13.03.02.21.13h.02l113.3 66.57.19.11.02.02.19.11.03.01.18.12.02.02.18.11.02.02.18.11.02.01.18.11.02.01.18.11.02.01.18.11.03.01.18.12.02.01.18.12.03.01.18.11.02.01.18.12.02.02.18.12.02.02.17.11.03.01.18.12.02.01.18.12.02.01.17.12.02.01.17.12.02.01.17.12.02.02.17.12.02.01.17.13.03.02.17.12.02.01.17.12.02.01.17.12.02.02.17.12.02.01.17.12.02.02.17.12.02.02.17.13.03.02.16.13.03.02.17.13.03.01.17.13.02.02.17.13.02.02.16.13.03.02.17.14.03.03.32.26.04.03.32.27.04.03.33.27.04.03.33.27.04.03.32.27.04.04.32.27.04.03.31.28.04.03.31.28.04.03.31.29.04.03.3.28.04.03.31.29.04.04.3.29.04.04.3.29.04.04.29.29.04.04.29.3.04.04.29.3.03.04.29.3.04.04.28.3.04.04.28.3.04.04.28.3.04.04.28.31.04.04.27.32.03.04.28.31.04.04.27.32.04.04.27.32.03.04.27.32.04.04.26.32.03.04.26.32.04.04.26.33.03.04.25.33.03.04.25.33.03.04.25.33.03.05.25.34.03.04.25.33.03.05.24.34.03.04.24.34.03.04.24.34.03.05.23.34.03.05.23.35.03.05.22.34.03.04.22.34.03.04.23.35.03.04.22.35.03.05.21.35.03.05.22.35.03.05.21.35.03.05.21.36.03.04.2.36.03.05.2.36.03.05.2.36.03.05.2.36.02.05.2.37.02.05.19.37.02.05.19.37.03.04.18.38.02.05.19.37.02.05.18.37.03.05.17.38.02.05.17.38.02.05.17.38.02.05.17.38.02.05.16.38.02.05.16.38.02.05.15.39.02.05.15.38.02.05.15.39.02.05.15.39.02.05.15.39.02.05.14.39.02.05.13.39.02.05.13.39.02.05.13.39.02.05.13.4.01.05.12.39.02.05.12.4.01.05.12.4.02.05.12.4.02.05.11.4.02.05.11.4.01.05.1.4.02.06.11.41.01.05.1.41.02.05.09.41.02.05.1.41.01.06.09.41.01.05.09.41.01.05.08.41.01.05.08.41.01.05.08.41.01.05.07.42.01.05.07.41.01.06.07.42.01.06.06.42.01.06.06.41v.04l.03.22v.02l.02.21v.03l.03.21v.02l.03.21v.03l.03.21.01.03.03.21v.03l.02.21.01.02.02.21.01.03.02.21v.03l.02.21.01.03.02.21.01.03.02.21v.03l.02.21v.03l.02.21v.03l.02.21v.03l.02.21v.03l.01.21v.03l.01.22v.03l.02.22v.02l.01.21v.03l.01.21v.03l.01.21v.03l.01.21v.03l.01.22v.03l.01.21v.03l.01.21v.02l.01.21v139.6l-.01.23v.29l-.01.23v.03l-.01.22v.02l-.01.23v.03l-.01.22v.02l-.01.22v.03l-.01.22-.01.03-.01.22v.03l-.01.22v.02l-.01.23v.03l-.02.23v.02l-.02.23v.03l-.02.22v.03l-.01.22v.03l-.02.22v.03l-.02.22v.03l-.02.22v.03l-.02.22-.01.02-.02.23-.01.03-.02.22v.03l-.02.22-.01.03-.03.22v.03l-.03.22v.02l-.03.22v.03l-.03.22-.01.03-.03.23-.01.03-.03.22-.01.03-.03.22v.03l-.03.22v.03l-.03.22-.01.03-.03.22-.01.03-.04.22v.02l-.03.22v.02l-.04.22-.01.03-.03.22-.01.03-.03.22v.02l-.04.22v.02l-.04.22v.02l-.04.22v.03l-.04.21-.01.03-.04.21-.01.03-.04.22-.01.03-.05.22v.02l-.05.22v.02l-.04.21v.03l-.05.22v.02l-.04.22-.01.02-.05.21v.02l-.05.21v.03l-.05.21-.01.03-.05.21-.01.03-.05.21-.01.02-.05.21-.01.02-.05.21-.01.03-.06.21-.01.03-.05.21-.01.03-.06.21v.03l-.06.22-.01.03-.06.21v.03l-.06.21-.01.03-.06.21-.01.03-.06.22-.01.02-.06.21-.01.02-.06.21-.01.03-.07.21-.01.03-.06.21-.01.02-.06.21-.01.03-.06.21-.01.02-.07.21-.01.03-.07.21-.01.03-.07.21-.01.03-.07.21-.01.03-.07.21-.01.02-.07.21-.01.03-.07.21-.01.03-.07.21-.01.02-.07.21-.01.03-.07.21-.01.03-.08.2-.01.03-.07.2-.01.03-.07.2-.01.03-.07.21-.01.03-.08.21-.01.03-.08.2-.01.03-.08.2-.01.03-.08.2-.01.03-.08.2-.01.03-.08.2-.01.03-.08.2-.01.02-.09.2-.01.03-.09.21-.01.03-.08.2-.01.03-.09.2-.01.03-.09.2-.01.03-.09.2-.01.02-.09.2-.01.03-.09.2-.01.02-.09.2-.01.02-.09.2-.01.02-.09.2-.01.02-.1.2-.01.02-.1.19-.01.03-.09.2-.01.02-.1.19-.01.03-.09.2-.01.02-.1.2-.01.03-.1.2-.01.02-.1.19-.01.02-.1.2-.01.03-.1.2-.01.03-.1.2-.02.03-.1.19-.01.02-.1.2-.01.03-.1.2-.01.03-.11.19-.02.02-.11.19-.01.02-.11.19-.01.02-.11.19-.01.02-.11.19-.01.02-.11.19-.01.03-.11.19-.01.02-.11.19-.01.03-.11.19-.02.02-.11.19-.02.02-.11.19-.01.02-.11.19-.01.03-.12.19-.01.02-.11.18-.01.03-.11.18-.02.02-.12.19-.01.03-.12.18-.02.02-.12.18-.01.02-.12.19-.02.03-.12.18-.02.02-.12.18-.01.02-.12.19-.01.02-.12.18-.02.02-.13.18-.01.02-.12.18-.01.02-.13.18-.01.02-.12.18-.02.02-.12.18-.02.02-.13.18-.02.02-.12.18-.01.02-.13.18-.02.03-.12.18-.02.02-.13.18-.02.02-.13.18-.02.02-.13.18-.02.02-.13.18-.01.02-.13.17-.02.02-.13.17-.01.02-.14.17-.02.02-.13.17-.01.02-.13.18-.02.02-.14.18-.02.02-.14.17-.02.02-.14.17-.01.02-.14.17-.02.02-.14.17-.02.02-.14.17-.02.02-.14.17-.02.02-.14.17-.01.02-.14.17-.02.02-.15.17-.02.02-.14.17-.02.02-.14.17-.02.02-.14.17-.02.02-.14.17-.02.02-.14.16-.02.02-.15.17-.02.02-.14.17-.02.02-.15.17-.02.02-.14.17-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.16.16-.02.02-.15.16-.02.02-.15.15-.02.02-.16.16-.03.02-.16.16-.02.02-.16.15-.02.02-.16.16-.02.02-.16.15-.02.02-.16.15-.02.02-.16.15-.02.02-.16.15-.02.02-.16.15-.02.02-.16.15-.02.02-.17.15-.02.01-.16.15-.02.02-.17.15-.02.02-.17.15-.02.01-.17.15-.02.02-.17.14-.03.02-.17.14-.02.02-.17.15-.02.02-.17.15-.02.02-.17.15-.02.02-.17.14-.02.02-.18.14-.02.01-.17.14-.02.02-.17.14-.03.02-.17.14-.02.02-.17.14-.02.02-.17.14-.02.02-.18.14-.02.02-.17.13-.02.02-.18.14-.02.02-.18.14-.02.02-.18.14-.02.02-.18.14-.02.01-.18.13-.02.01-.18.13-.02.01-.18.13-.03.01-.18.13-.02.02-.18.13-.02.02-.18.13-.02.02-.18.13-.03.02-.18.13-.02.01-.19.13-.03.01-.19.13-.02.02-.19.13-.02.02-.19.12-.02.02-.19.13-.02.02-.18.13-.03.02-.19.12-.02.01-.19.12-.03.01-.19.12-.02.02-.19.12-.02.02-.19.12-.02.01-.19.12-.03.01-.19.12-.02.02-.19.12-.03.01-.19.12-.03.02-.19.12-.03.02-.2.12-.02.02-.19.11-.03.01-.19.11-.02.02-.2.12-.03.02-.2.11-.02.02-.19.11-.03.01-.2.11-.03.01-.2.11-.02.01-.19.11-.01.01-115.93 64.6h-.01l-.18.11-.03.01-.19.11-.03.02-.19.1-.03.01-.19.1-.02.01-.19.1-.03.01-.19.1-.03.01-.19.1-.03.01-.19.1-.02.01-.19.1-.02.01-.19.09-.02.01-.2.1-.02.02-.19.1-.02.01-.19.09-.02.01-.19.09-.02.01-.19.1-.02.01-.2.09-.02.01-.19.09-.02.01-.2.09-.02.01-.19.09-.02.01-.19.09-.03.02-.2.09-.02.01-.2.08-.02.01-.2.09-.02.02-.2.09-.03.01-.19.08-.02.01-.2.09-.02.01-.2.08-.02.01-.2.08-.02.01-.2.08-.03.01-.2.08-.03.01-.2.08-.03.01-.19.08-.02.01-.2.07-.02.01-.2.08-.03.01-.2.08-.03.01-.2.08-.03.01-.2.07-.03.01-.2.08-.03.01-.2.07-.02.01-.2.07-.03.01-.2.07-.03.01-.2.07-.03.01-.2.07-.02.01-.2.07-.2.07-.03.01-.21.06-.03.01-.2.06-.02.01-.2.07-.02.01-.21.06-.03.01-.2.06-.03.01-.2.06-.03.01-.21.07-.04.01-.4.12-.05.02-.41.12-.05.01-.41.12-.05.01-.41.11-.05.02-.41.11-.05.01-.41.11-.06.01-.41.1-.05.01-.41.1-.06.01-.41.1-.05.01-.41.09-.05.01-.42.09-.06.01-.42.09-.05.01-.42.08-.05.01-.41.07-.05.01-.41.08-.05.01-.42.07-.05.01-.42.07-.05.01-.42.06-.05.01-.42.06-.05.01-.42.06-.05.01-.42.06-.06.01-.42.05-.05.01-.42.05-.05.01-.42.05-.42.04h-.05l-.42.03-.05.01-.42.03h-.05l-.42.03h-.05l-.42.03-.06.01-.42.03h-.05l-.42.02h-.05l-.42.02h-.06l-.42.01h-.05l-.42.01h-.05l-.42.01h-1.48l-.42-.01-.42-.01h-.06l-.42-.01H171l-.42-.02-.05-.01-.42-.02h-.05l-.42-.02-.05-.01-.42-.02h-.05l-.42-.03-.05-.01-.42-.04-.06-.01-.42-.04-.06-.01-.42-.04-.05-.01-.42-.04h-.05l-.42-.04-.05-.01-.42-.05h-.06l-.42-.05-.06-.01-.42-.06-.05-.01-.42-.06-.05-.01-.42-.06-.05-.01-.42-.06-.05-.01-.41-.07H163l-.42-.08-.054-.01-.41-.08-.05-.01-.41-.08-.05-.01-.41-.08-.06-.01-.416-.08-.05-.01-.41-.09-.06-.02-.41-.09-.05-.01-.41-.1-.056-.02-.41-.1-.05-.02-.41-.11-.05-.01-.41-.11-.05-.02-.41-.11-.05-.02-.41-.11-.05-.02-.41-.12-.06-.02-.41-.12-.05-.02-.41-.12-.05-.02-.41-.12-.05-.01-.398-.13-.04-.01-.21-.07h-.027l-.2-.06-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.02-.01-.2-.07-.02-.01-.2-.07-.02-.01-.2-.08-.03-.01-.2-.08-.03-.01-.2-.08-.02-.01-.2-.08-.03-.01-.2-.08-.02-.01-.2-.08-.03-.01-.2-.08-.02-.01-.2-.08-.02-.01-.2-.08-.03-.01-.2-.08-.03-.01-.2-.08-.03-.01-.2-.08-.03-.01-.2-.08-.02-.01-.2-.09-.03-.01-.19-.09-.02-.01-.2-.09-.02-.01-.2-.09-.02-.01-.2-.08-.03-.01-.19-.09-.03-.01-.2-.09-.03-.01-.19-.09-.02-.02-.19-.09-.02-.01-.19-.09-.02-.01-.2-.09-.02-.02-.2-.1-.02-.02-.19-.09-.03-.01-.2-.09-.02-.02-.19-.1-.03-.01-.2-.1-.02-.01-.19-.1-.03-.01-.19-.1-.02-.01-.19-.1-.03-.02-.19-.1-.02-.01-.19-.1-.02-.01-.19-.1-.03-.02-.19-.1-.02-.01-.19-.11-.03-.02-.19-.1-.03-.01-.19-.1-.03-.01-.19-.1-.03-.01-.19-.11-.03-.01-.18-.11-.03-.01-.18-.11-.01-.01-104.8-61.17-.01-.01-.22-.13-.02-.01-.22-.13-.03-.01-.23-.13-.03-.01-.22-.14-.02-.01-.22-.14-.02-.02-.22-.14-.02-.02-.22-.14-.03-.01-.22-.13-.03-.02-.22-.14-.02-.02-.22-.14H36l-.22-.14-.03-.02-.22-.14-.02-.02-.22-.14-.028-.02-.22-.15-.03-.02-.22-.15-.02-.02-.22-.14-.02-.02-.22-.15-.02-.02-.22-.15-.02-.02-.21-.15-.03-.02-.215-.15-.02-.02-.21-.15-.025-.02-.21-.15-.027-.02-.21-.15-.02-.01-.21-.15-.02-.02-.207-.15-.02-.02-.206-.15-.03-.01-.21-.15-.02-.02-.21-.16-.02-.02-.21-.15-.026-.02-.21-.16-.026-.02-.2-.16-.02-.02-.2-.16-.02-.01-.2-.16-.02-.02-.2-.16-.02-.02-.2-.16-.02-.02-.2-.16-.02-.02-.2-.16-.02-.02-.2-.16-.02-.02-.2-.17-.02-.01-.2-.16-.02-.02-.194-.16-.02-.02-.2-.17-.02-.02-.2-.16-.02-.02-.2-.17-.02-.01-.196-.16-.02-.02-.19-.16-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.19-.18-.02-.01-.19-.17-.03-.02-.185-.18-.02-.02-.19-.17-.02-.02-.186-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.19-.18-.02-.02-.19-.18-.02-.01-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.17-.18-.02-.02-.18-.18-.02-.02-.18-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.18-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.01-.02-.16-.19-.02-.02-.17-.19-.02-.02-.18-.2-.02-.02-.17-.19-.02-.02-.17-.2-.02-.02-.16-.19-.01-.02-.16-.19-.02-.02-.16-.2-.02-.02-.17-.2-.02-.02-.16-.19-.02-.02-.17-.19-.02-.02-.16-.19-.02-.02-.16-.2-.02-.02-.16-.2-.02-.02-.16-.2-.02-.02-.16-.2-.02-.02-.16-.2-.01-.02-.15-.2-.02-.02-.15-.2-.01-.02-.15-.2-.02-.02-.15-.21-.02-.02-.15-.2-.02-.02-.15-.2-.01-.02-.15-.21-.01-.02-.15-.21-.01-.02-.15-.2-.01-.02-.15-.2-.02-.02-.15-.21-.02-.02-.15-.21-.02-.03-.14-.21-.02-.02-.14-.21-.02-.02-.14-.21-.02-.02-.14-.21-.01-.02-.14-.21-.02-.03-.14-.21-.02-.02-.14-.21-.02-.02-.14-.21-.02-.02-.14-.21-.02-.02-.13-.21-.01-.02-.13-.21-.02-.03-.14-.21-.02-.03-.14-.21-.01-.02-.14-.22-.01-.03-.13-.21-.02-.02-.13-.21-.02-.02-.13-.22-.02-.03-.13-.21-.01-.02-.13-.22-.01-.02-.13-.21-.02-.03-.13-.22-.02-.03-.13-.22-.02-.03-.12-.22-.02-.02-.13-.22-.01-.02-.12-.22-.01-.02-.12-.22-.01-.03-.12-.22-.02-.03-.12-.22-.01-.03-.12-.23-.01-.02-.12-.22-.01-.03-.12-.22-.01-.03-.12-.22-.01-.03-.11-.23-.01-.02-.12-.23-.01-.03-.12-.23-.02-.02-.11-.23-.01-.02-.11-.22-.01-.03-.11-.23v.01l-.11-.23-.02-.03-.11-.23-.01-.03-.11-.22-.01-.03-.11-.23-.01-.02-.11-.23-.01-.02-.1-.23-.01-.02-.11-.23-.01-.02-.11-.23-.01-.02-.11-.23-.01-.03-.1-.23-.01-.02-.11-.23-.01-.03-.11-.23-.01-.02-.1-.23-.01-.02-.1-.23-.01-.03-.1-.23-.01-.02-.09-.23-.01-.02-.1-.23-.01-.03-.09-.24-.01-.02-.1-.23-.01-.03-.09-.22-.01-.03-.1-.24-.01-.02-.09-.24-.01-.03-.09-.24-.01-.02-.09-.24-.01-.03-.09-.24-.01-.02-.09-.24-.01-.02-.08-.24-.01-.03-.09-.24-.01-.02-.08-.24-.01-.03-.08-.24-.01-.03-.09-.24-.01-.03-.08-.24-.01-.02-.08-.24-.01-.02-.08-.24-.01-.03-.08-.24-.01-.03-.08-.24-.01-.03-.08-.24-.01-.03-.08-.24L7 292l-.07-.24-.01-.02-.08-.25-.01-.03-.07-.25-.01-.03-.07-.24-.01-.03-.07-.24-.01-.03-.07-.25-.01-.03-.07-.25-.01-.02-.07-.25-.01-.01-.07-.25-.01-.02-.06-.24-.01-.02-.06-.24v-.02l-.07-.25v-.03l-.06-.24-.01-.03-.06-.24-.01-.03-.06-.25h.01l-.06-.25-.01-.02-.06-.25-.01-.02-.06-.25-.01-.02-.06-.25.01-.01-.06-.25-.01-.03-.06-.25-.01-.03-.05-.25-.01-.03-.06-.25-.01-.02-.05-.25-.01-.03-.05-.25-.01-.03-.05-.25-.05-.25v-.03l-.05-.26v-.03l-.05-.25-.01-.03-.06-.24v-.03l-.05-.27-.01-.03-.05-.26-.01-.03-.04-.25-.01-.03-.04-.25v-.03l-.04-.25v-.03l-.04-.25-.01-.03-.04-.25v.01l-.04-.25v-.02l-.04-.25v-.03l-.04-.25v-.03l-.04-.25v-.02l-.03-.26v-.03l-.03-.25v-.02l-.04-.26-.01-.03-.03-.25v-.03l-.03-.26-.01-.03-.03-.26v-.03l-.03-.26-.01-.03-.03-.26v-.03l-.03-.26-.01-.02-.03-.26-.02-.26v-.03l-.03-.26-.01-.03-.03-.26v-.03l-.02-.26-.01-.03-.02-.26v-.03l-.02-.26v-.03l-.02-.26-.02-.26v-.03l-.02-.26v-.03l-.02-.26v-.323l-.01-.26v-.03l-.01-.26v-.03l-.01-.26-.01-.03-.01-.26v-.28l-.01-.26v-.03l-.01-.26v-126.6l.01-.25v-.32l.01-.26v-.92l.01-.26v-.02l.01-.26v-.03l.01-.26v-.03l.01-.26v-.02l.01-.26v-.03l.01-.26v-.03l.02-.27v-.03l.02-.26v-.02l.01-.26v-.03l.02-.26v-.03l.01-.26v-.03l.01-.26v-.03l.02-.26v-.03l.02-.26v-.03l.03-.26v-.03l.02-.26.01-.02.02-.26v-.02l.03-.26v-.02l.03-.26.01-.03.03-.26v-.03l.03-.26v-.02l.03-.26v-.02l.03-.26.01-.03.03-.26v-.03l.03-.25v-.03l.03-.26v-.03l.03-.26.01-.03.03-.25v-.03l.04-.26v-.03l.03-.26.01-.03.03-.25.01-.03.04-.26.01-.02.04-.26v-.02l.04-.26v-.02l.04-.25.01-.03.04-.25v-.03l.07-.26.01-.03.04-.25v-.03l.05-.25v-.02l.05-.25v-.02l.05-.26.01-.02.05-.25.01-.02.05-.25.01-.03.05-.25.01-.03.05-.25v-.03l.05-.25v-.02l.05-.25.01-.02.05-.25.01-.02.06-.25v-.03l.06-.25.01-.03.05-.25.01-.03.06-.25v-.03l.06-.25.01-.03.06-.25v-.03l.06-.25.01-.02.06-.25v-.02l.06-.25.01-.03.07-.25v-.02l.07-.25v-.02l.07-.25.01-.03.07-.25v-.03l.07-.25.01-.03.07-.24.01-.02.07-.25.01-.025.07-.25.01-.03.07-.244.01-.02.08-.25.01-.02.07-.24.01-.02.07-.243.01-.02.07-.248.01-.03.08-.244.01-.03.08-.24v-.02l.08-.24v-.03l.08-.24.01-.02.08-.24.01-.03.08-.24.01-.03.08-.24.01-.03.08-.24.01-.02.09-.24.01-.02.08-.24.01-.025.08-.24.01-.02.09-.24.01-.02.09-.24v-.02l.09-.24.01-.02.09-.24.01-.03.09-.24.01-.02.09-.24.01-.03.1-.23.01-.02.1-.24.01-.02.1-.24.01-.03.1-.24.01-.03.1-.24.01-.03.1-.24.01-.03.1-.24.01-.03.1-.24.01-.025.1-.23.01-.03.1-.23.01-.03.1-.24.01-.02.11-.24.01-.02.11-.23.01-.02.1-.23.01-.03.11-.23.01-.02.11-.23.01-.02.11-.23.01-.02.11-.23.01-.03.11-.23.01-.02.11-.23.01-.03.11-.23.01-.02.11-.23.01-.02.11-.23.01-.02.11-.23.01-.02.12-.22.01-.02.12-.23.02-.03.12-.23.01-.02.12-.23.01-.03.12-.22.01-.02.12-.22.01-.02.12-.22.01-.03.12-.22.02-.02.12-.22.01-.03.12-.22.02-.02.12-.22.01-.02.12-.22.02-.03.13-.22.01-.02.12-.22.01-.02.13-.22.01-.02.13-.22.01-.02.13-.22.02-.02.13-.22.01-.02.13-.22.02-.02.13-.22.01-.02.13-.22.02-.02.13-.22.01-.02.14-.22.02-.03.14-.22.01-.02.13-.21.02-.02.14-.21.02-.02.13-.22.01-.02.14-.21.01-.02.14-.21.02-.02.14-.22.02-.02.14-.21.01-.03.14-.21.01-.02.14-.21.01-.02.15-.21.02-.02.14-.21.02-.02.15-.21.01-.02.15-.21.01-.02.15-.21.01-.02.15-.21.02-.02.15-.21.01-.02.15-.21.02-.02.15-.2.01-.02.15-.21.02-.02.15-.2.02-.02.15-.2.02-.02.15-.2.02-.02.15-.2.01-.02.15-.2.02-.02.16-.2.02-.02.16-.2.02-.02.16-.2.02-.02.16-.2.02-.02.16-.2.02-.03.16-.2.01-.02.16-.2.02-.02.16-.2.02-.02.16-.19.02-.02.16-.2.02-.02.16-.2.02-.02.17-.19.02-.02.16-.2.02-.02.16-.19.02-.02.16-.2.02-.02.17-.2.01-.02.17-.19.02-.02.17-.19.02-.02.17-.19.02-.02.17-.19.01-.02.17-.19.02-.02.17-.19.02-.02.17-.19.01-.02.17-.19.02-.02.18-.19.01-.02.18-.19.02-.02.19-.18.02-.02.18-.19.02-.02.18-.19.02-.02.18-.18.02-.02.18-.18.02-.02.18-.18.02-.02.19-.18.02-.02.18-.18.02-.02.18-.18.02-.02.18-.18.02-.02.18-.18.02-.02.18-.18.02-.02.18-.18.02-.02.18-.18.02-.02.19-.17.02-.02.19-.17.02-.02.19-.18.02-.02.19-.18.02-.01.19-.17.02-.01.19-.17.02-.02.19-.17.02-.02.19-.17.02-.02.19-.17.02-.01.2-.17.02-.02.2-.17.02-.02.2-.17.02-.02.2-.16.02-.02.2-.16.02-.02.19-.16.02-.02.2-.16.02-.02.2-.16.02-.01.2-.16.02-.02.2-.16.02-.02.2-.16.02-.02.21-.16.02-.02.2-.16.02-.02.21-.16.02-.02.21-.16.02-.02.2-.16.02-.01.21-.16.02-.02.2-.16.02-.02.21-.15.02-.02.21-.16.02-.02.21-.15.02-.01.21-.15.03-.02.21-.15.02-.01.21-.15.02-.02.21-.16.02-.01.22-.15.02-.02.21-.15.03-.01.21-.15.02-.01.21-.15.02-.01.22-.15.02-.02.21-.15.02-.01.22-.14.02-.01.21-.15.03-.02.22-.14.02-.02.22-.15.02-.02.22-.14.03-.01.22-.14.02-.02.22-.14.02-.01.22-.14.02-.01.22-.14.02-.01.22-.14.03-.01.22-.13h.01l100.51-62 .01-.01.21-.13.02-.01.22-.14.03-.02.22-.13.03-.02.22-.13.03-.02.22-.13.03-.01.23-.13.02-.02.22-.13.03-.01.22-.13.02-.01.23-.12.02-.02.23-.12.02-.02.22-.12.03-.01.23-.12.02-.02.22-.12.03-.02.22-.12.03-.02.22-.12.02-.02.23-.12.02-.01.22-.12.03-.01.22-.12.03-.01.23-.12.03-.01.23-.12.02-.01.23-.11.03-.01.23-.11.03-.01.22-.11.03-.01.23-.11.02-.01.23-.11.03-.01.23-.11.03-.02.23-.11.03-.01.23-.11.03-.01.23-.1.03-.01.23-.1.02-.02.23-.1.02-.01.23-.1.03-.02.23-.1.03-.01.23-.1.03-.01.23-.1.03-.01.23-.1.03-.01.23-.1.03-.01.23-.09.03-.01.23-.1.03-.01.24-.1.03-.01.24-.1.03-.02.23-.09.02-.01.24-.09.03-.01.23-.09.02-.01.24-.09.03-.01.24-.08.03-.01.24-.09.03-.01.24-.09.03-.01.24-.08.03-.01.24-.08.03-.01.23-.08.03-.01.24-.08.03-.01.23-.08.03-.01.24-.08.02-.01.24-.08.03-.01.24-.08.03-.01.24-.08.03-.01.24-.07.02-.01.24-.07.03-.01.24-.07h.03l.24-.07.03-.01.24-.07.02-.01.24-.07.02-.01.24-.07.03-.01.24-.07.03-.01.24-.07.03-.01.24-.06.03-.01.24-.06.02-.01.24-.07.024-.01.25-.06h.02l.24-.07h.03l.247-.06.03-.01.25-.06.03-.01.24-.06h.03l.25-.06h.03l.24-.06.03-.01.24-.05.03-.01.24-.06.03-.01.24-.05h.03l.24-.05.03-.01.24-.05h.02l.24-.05.03-.01.25-.05h.02l.25-.05.02-.01.25-.05.03-.01.25-.05.03-.01.25-.04h.03l.24-.04.03-.01.25-.05.03-.01.25-.04h.03l.24-.04.03-.01.25-.04.03-.01.24-.04h.02l.24-.04h.03l.25-.04.03-.01.25-.04h.03l.25-.04h.03l.25-.04h.03l.25-.03h.03l.24-.03h.03l.25-.03.03-.01.25-.03.02-.01.25-.02h.03l.24-.03h.03l.24-.03h.03l.25-.03h.03l.25-.03h.03l.24-.02h.03l.25-.03.03-.01.25-.02.03-.01.25-.02h.03l.246-.02h.03l.25-.02h.03l.25-.01.03-.01.25-.02.02-.01.25-.01h.03l.25-.02h.02l.25-.01h.03l.25-.01h.03l.25-.01h.03l.25-.01.03-.01.25-.01h.03l.25-.01h.03l.25-.01h.03l.25-.01h.03l.25-.01h.02l.25-.01h.31l.25-.01h.58zm-.23 27h-.164l-.164.002h-.163l-.17.004-.17.004-.17.005-.17.01-.17.01-.17.01-.16.01-.17.01-.16.01-.16.01-.16.01-.17.01-.16.01-.17.02-.17.02-.16.02-.17.02-.17.02-.17.02-.16.02-.17.02-.16.02-.16.02-.17.02-.16.02-.16.02-.16.02-.16.02-.17.02-.16.03-.16.02-.17.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.02-.17.03-.16.03-.17.03-.16.03-.16.03-.16.03-.16.04-.16.04-.16.04-.16.03-.16.03-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.05-.16.04-.16.05-.15.05-.16.05-.16.05-.16.05-.16.05-.16.05-.15.05-.16.05-.16.06-.16.05-.16.05-.16.06-.16.05-.16.05-.15.05-.16.06-.16.06-.16.06-.15.06-.16.06-.15.06-.15.06-.16.07-.16.06-.16.06-.16.06-.15.07-.15.06-.16.07-.15.07-.15.07-.15.07-.16.07-.15.07-.16.07-.15.07-.15.07-.15.07-.16.07-.15.07-.15.07-.15.08-.15.08-.15.07-.15.08-.15.07-.15.08-.15.08-.15.08-.15.08-.15.08-.15.09-.14.08-.15.08-.14.08-.15.09-.15.09-.15.09-.14.08-.15.09-.14.09-.15.09-.15.09-.16.1-100.4 61.88-.17.11-.16.1-.15.1-.15.1-.15.1-.15.1-.15.1-.15.1-.15.1-.15.1-.15.1-.15.1-.15.11-.14.1-.14.1-.15.1-.14.1-.14.1-.14.1-.14.1-.14.1-.14.1-.14.11-.14.1-.14.11-.14.11-.14.11-.14.11-.14.11-.14.11-.13.11-.14.11-.14.11-.13.11-.14.11-.14.11-.13.11-.14.11-.13.11-.13.11-.13.12-.13.12-.13.11-.13.11-.13.12-.13.12-.13.12-.13.12-.13.12-.13.12-.13.12-.13.12-.13.12-.13.12-.13.12-.12.12-.13.12-.12.13-.13.12-.12.13-.12.12-.12.13-.12.12-.12.13-.12.13-.13.13-.12.12-.12.13-.12.13-.12.13-.11.13-.12.13-.12.13-.12.13-.12.14-.12.13-.11.13-.11.13-.12.14-.11.13-.12.13-.11.14-.11.13-.11.14-.11.14-.11.14-.11.14-.11.14-.11.14-.1.14-.11.14-.11.14-.11.14-.11.14-.1.14-.1.14-.1.14-.1.15-.1.14-.1.14-.1.15-.1.14-.1.14-.1.14-.1.14-.09.15-.1.15-.1.14-.1.15-.09.15-.09.14-.09.15-.09.15-.09.15-.09.15-.1.15-.1.15-.09.15-.09.15-.09.15-.09.15-.09.15-.09.15-.09.15-.09.15-.09.15-.09.15-.09.16-.09.15-.09.15-.09.16-.08.15-.08.16-.08.16-.08.16-.08.15-.08.15-.08.16-.08.15-.08.16-.07.15-.08.16-.08.16-.08.16-.08.16-.08.16-.07.16-.07.16-.07.16-.07.16-.07.16-.07.16-.07.16-.07.16-.07.16-.06.16-.07.16-.07.17-.07.16-.07.16-.07.16-.06.16-.07.17-.07.16-.06.16-.06.17-.06.16-.06.17-.06.16-.06.17-.06.17-.06.17-.05.17-.06.16-.06.17-.05.17-.05.16-.05.17-.06.17-.05.16-.05.16-.05.17-.06.17-.05.17-.05.16-.05.17-.05.17-.05.17-.05.17-.05.17-.04.17-.04.17-.05.17-.04.17-.05.17-.04.17-.04.17-.04.18-.04.17-.04.17-.04.17-.04.17-.04.17-.04.17-.03.17-.04.17-.03.17-.03.18-.03.18-.03.18-.03.18-.03.17-.03.17-.03.18-.03.18-.03.17-.03.17-.03.17-.03.18-.02.18-.02.18-.02.17-.03.18-.03.17-.02.18-.02.18-.02.18-.02.18-.02.18-.02.18-.02.17-.02.18-.02.18-.01.18-.02.18-.02.18-.01.18-.01.18-.01.18-.01.18-.01.18-.01.18-.01.18-.01.18-.01.18-.01.18v.18l-.01.18-.01.18v.18l-.01.18v126.8l.01.18v.54l.01.17.01.18.01.18.01.18.01.18.01.18.01.18.01.18.01.18.02.18.01.18.01.18.01.18.02.17.02.18.02.17.01.18.02.17.02.17.02.17.02.17.02.18.02.17.02.17.02.18.02.18.02.17.02.18.03.17.03.17.03.17.03.17.03.18.03.17.03.17.03.17.03.17.04.17.03.17.03.17.03.17.04.17.04.17.03.17.04.17.04.17.04.17.04.17.04.17.04.17.04.17.04.16.05.16.04.17.04.17.04.17.05.17.04.16.04.17.04.16.05.17.04.16.05.17.05.17.05.16.05.17.05.17.05.16.05.17.06.16.06.16.06.16.06.16.05.16.06.17.06.16.06.16.06.16.06.16.06.16.06.16.06.16.06.16.06.16.07.16.07.16.06.16.06.16.06.16.06.16.06.16.07.16.07.16.07.16.07.16.07.16.07.16.07.16.07.16.07.16.07.16.07.16.07.15.08.16.08.15.08.16.08.15.08.15.08.15.08.15.08.15.08.15.09.15.08.15.08.15.08.15.09.15.09.15.08.15.08.15.08.15.09.15.08.15.09.14.09.15.09.14.09.15.09.15.09.14.09.14.09.14.09.14.09.15.09.15.1.14.09.14.09.15.09.14.09.14.1.14.1.14.1.15.1.14.1.14.1.14.1.14.1.14.1.14.1.14.11.14.11.14.1.14.1.14.1.14.1.14.11.13.11.13.11.14.11.13.11.14.11.13.11.13.11.13.11.13.11.13.11.13.11.13.11.13.11.13.11.13.11.13.12.13.12.13.11.13.12.12.12.13.12.12.12.13.11.13.12.13.12.12.12.12.12.12.12.12.12.13.12.12.12.12.12.12.12.12.12.12.13.12.12.12.12.12.13.12.12.12.12.12.13.12.13.11.13.11.13.12.13.12.13.11.13.11.13.12.13.12.13.11.14.11.14.11.14.11.13.11.13.11.14.11.13.11.14.1.13.11.14.11.14.11.14.11.13.1.14.11.14.1.14.11.14.11.14.1.14.1.15.1.14.1.14.1.14.1.14.1.14.1.14.1.15.1.15.09.15.1.14.1.15.1.15.1.14.09.15.09.15.09.15.09.15.09.15.09.16.09.15.09.15.09.17.1 104.68 61.2.13.08.11.06.12.06.12.06.12.06.11.07.12.06.12.06.12.06.12.07.12.06.12.06.12.06.12.06.12.06.12.06.12.06.12.06.11.06.12.06.12.06.12.05.12.06.12.05.12.05.12.05.12.06.12.06.12.05.12.06.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.04.13.05.12.05.12.05.12.05.12.05.12.04.12.05.12.04.12.04.13.04.12.04.11.04.26.08.25.08.25.07.25.07.25.07.25.07.25.07.25.07.25.07.25.06.25.06.25.06.25.05.25.06.25.05.25.05.25.05.25.04.25.05.25.04.25.04.26.04.25.04.26.03.26.03.26.03.26.02.25.02.26.02.25.02.26.02.26.02.25.02.25.01.25.01.26.01h1.28l.26-.01h.26l.26-.01.26-.01.26-.02.26-.02.26-.01.26-.02.26-.02.26-.02.25-.02.26-.03.26-.03.25-.03.26-.03.25-.04.26-.04.25-.04.26-.04.25-.04.25-.05.25-.04.26-.05.25-.05.25-.06.25-.05.25-.06.25-.06.25-.06.25-.06.25-.07.25-.07.25-.07.25-.07.26-.08.12-.04.12-.04.12-.04.13-.04.12-.04.13-.04.12-.04.12-.04.13-.04.12-.04.12-.04.13-.05.12-.04.13-.04.12-.05.12-.04.12-.04.12-.04.13-.05.12-.04.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.06.12-.06.12-.05.12-.06.12-.06.12-.05.12-.06.12-.06.12-.06.11-.06.12-.06.12-.06.12-.06.12-.06.12-.06.12-.06.12-.06.12-.06.11-.06.12-.06.12-.06.13-.07 115.97-64.63.14-.07.13-.07.12-.07.12-.07.12-.07.12-.08.13-.07.12-.07.12-.07.12-.07.12-.08.12-.08.12-.07.12-.07.12-.07.12-.08.12-.08.12-.07.12-.08.12-.07.11-.08.11-.08.11-.08.11-.08.11-.08.12-.08.11-.08.12-.08.11-.08.11-.08.11-.08.11-.08.11-.08.12-.08.11-.09.11-.08.11-.09.11-.08.11-.09.11-.09.11-.09.11-.08.11-.08.11-.09.1-.09.11-.09.11-.09.1-.08.11-.09.11-.1.1-.09.11-.09.1-.09.1-.09.1-.1.11-.09.1-.1.1-.09.1-.1.1-.1.1-.09.1-.1.1-.09.1-.1.1-.1.1-.1.1-.1.09-.1.1-.1.09-.1.1-.1.1-.1.1-.1.09-.1.09-.1.09-.1.09-.1.1-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.11.09-.11.09-.11.09-.1.09-.1.09-.1.09-.11.09-.1.09-.11.08-.1.08-.11.08-.11.08-.1.09-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.07-.11.07-.12.08-.12.08-.11.07-.11.07-.11.08-.12.08-.11.07-.11.07-.12.07-.12.07-.12.07-.12.07-.11.07-.12.07-.12.07-.11.07-.12.07-.12.07-.12.06-.12.06-.12.07-.12.07-.12.06-.12.07-.12.07-.12.06-.12.06-.12.06-.13.06-.12.07-.12.07-.12.06-.12.06-.12.06-.12.06-.13.06-.12.06-.12.06-.13.06-.12.06-.12.06-.13.06-.13.06-.13.06-.12.05-.12.05-.13.05-.13.05-.13.05-.12.05-.13.05-.13.05-.13.05-.12.05-.13.05-.13.05-.13.05-.13.05-.13.04-.13.04-.13.04-.13.04-.13.05-.13.05-.13.05-.13.05-.13.04-.13.05-.13.04-.13.04-.13.05-.13.04-.13.04-.13.04-.13.04-.13.03-.13.04-.13.04-.13.04-.13.04-.13.03-.13.03-.14.04-.13.03-.13.03-.14.04-.13.03-.13.03-.13.03-.13.03-.14.03-.13.03-.13.02-.14.03-.14.03-.13.02-.14.03-.13.03-.14.03-.14.03-.13.03-.14.02-.14.03-.14.02-.13.03-.13.02-.14.02-.14.02-.14.02-.14.02-.14.02-.14.02-.14.01-.14.02-.13.01-.14.02-.14.02-.13.02-.14.01-.14.01-.14.01-.14.01-.14.02-.14.01-.14.01-.14.01-.14.01-.14.01-.14.01-.14.01-.14.01-.14.01-.14.01-.14.01-.14v-.28l.01-.14V138.8l-.01-.123-.01-.13v-.13l-.01-.13v-.13l-.01-.13v-.13l-.01-.13-.01-.12-.01-.13-.01-.13-.01-.13-.01-.12-.01-.13-.01-.12-.01-.13-.02-.13-.01-.12-.01-.12-.02-.12-.01-.12-.02-.13-.01-.12-.02-.12-.02-.13-.01-.13-.01-.12-.02-.11-.04-.263-.03-.255-.04-.26-.04-.25-.05-.25-.05-.25-.04-.25-.05-.25-.06-.25-.06-.25-.06-.25-.06-.25-.06-.25-.06-.25-.06-.25-.07-.25-.07-.25-.07-.25-.08-.25-.07-.24-.08-.24-.08-.24-.08-.24-.08-.24-.09-.24-.09-.24-.09-.23-.09-.24-.09-.24-.09-.24-.1-.23-.09-.24-.1-.23-.1-.23-.1-.23-.11-.23-.1-.23-.11-.23-.11-.23-.11-.22-.12-.23-.11-.23-.12-.23-.12-.22-.12-.22-.12-.22-.12-.22-.12-.22-.13-.22-.13-.22-.13-.22-.14-.22-.13-.21-.13-.21-.14-.21-.14-.21-.14-.21-.14-.21-.14-.21-.14-.21-.15-.2-.15-.2-.15-.2-.15-.2-.15-.2-.16-.2-.16-.2-.16-.2-.16-.2-.16-.19-.17-.19-.16-.19-.17-.19-.17-.19-.17-.19-.17-.19-.17-.19-.18-.18-.18-.18-.18-.18-.18-.18-.18-.18-.19-.18-.19-.18-.19-.17-.19-.17-.19-.17-.19-.17-.19-.17-.2-.17-.2-.16-.2-.16-.19-.16-.21-.17-.09-.07-.1-.08-.1-.08-.1-.08-.1-.08-.1-.07-.1-.08-.1-.08-.11-.08-.11-.08-.1-.08-.1-.08-.1-.08-.1-.07-.1-.08-.11-.08-.1-.07-.1-.07-.11-.08-.11-.07-.11-.07-.1-.07-.11-.07-.11-.07-.11-.07-.11-.07-.11-.07-.11-.07-.11-.07-.11-.07-.11-.07-.11-.06-.11-.06-.13-.07L193 46.09l-.16-.098-.145-.08-.15-.09-.15-.09-.147-.083-.15-.08-.145-.08-.15-.08-.15-.08-.15-.08-.147-.08-.15-.08-.15-.08-.15-.08-.15-.08-.15-.08-.15-.08-.153-.07-.15-.08-.15-.07-.15-.07-.15-.08-.155-.07-.15-.07-.15-.07-.156-.07-.15-.07-.15-.06-.155-.07-.152-.07-.15-.07-.155-.06-.15-.06-.16-.06-.154-.07-.158-.06-.16-.07-.16-.06-.155-.06-.155-.06-.157-.06-.16-.06-.16-.06-.15-.06-.15-.05-.15-.05-.16-.06-.16-.05-.15-.05-.16-.05-.16-.05-.15-.05-.16-.05-.16-.05-.16-.05-.15-.05-.16-.05-.16-.05-.16-.05-.16-.04-.16-.05-.16-.04-.16-.05-.16-.04-.16-.04-.16-.04-.16-.05-.16-.04-.16-.04-.16-.03-.16-.04-.16-.04-.16-.04-.16-.03-.16-.04-.16-.03-.16-.03-.16-.04-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.17-.03-.16-.02-.16-.02-.16-.02-.16-.02-.16-.03-.16-.03-.16-.02-.17-.03-.16-.02-.16-.03-.16-.02-.16-.02-.16-.02-.16-.02-.16-.02-.17-.02-.16-.01-.16-.02-.16-.02-.16-.01-.16-.01-.16-.01-.16-.01-.16-.01-.17-.01-.17-.01-.16-.01-.16-.01h-.16l-.16-.01-.16-.01h-.17l-.16-.01-.16-.01-.15-.01-.16-.01h-.33l-.16-.01h-.32z"/> - <path fill="#fff" fill-rule="nonzero" d="M96.91 309.916v-207.22h43.354v75.48h71.916v-75.48h43.48v207.22h-43.48V219.31h-71.916v90.606H96.91z"/> - <path fill="#0594CB" d="M715.9 259.25V136.59c0-15.645-8.285-30.12-21.774-38.046L580.56 31.818c-16.805-9.873-37.69-9.65-54.28.58l-96.142 59.286c-19.81 12.215-31.87 33.823-31.87 57.095v120.06c0 19.93 10.58 38.37 27.792 48.43l104.718 61.21c13.925 8.14 31.113 8.31 45.204.47l115.945-64.58c14.798-8.25 23.973-23.86 23.973-40.8v-14.34z"/> - <path fill="#0083C0" d="M554.04 11.067h.278l.247.003h.027l.25.003h.027l.25.004h.02l.25.006h.03l.24.007h.03l.24.008h.03l.25.01h.03l.25.01h.03l.25.01.02.002.25.01.02.003.25.013h.03l.25.014.02.002.25.014h.02l.25.017.02.002.25.017h.03l.25.02h.02l.24.02.03.003.25.018.03.003.25.02.03.003.24.02h.02l.25.02h.03l.25.02h.03l.25.02h.03l.24.02h.02l.25.03h.03l.24.03h.03l.25.03h.03l.25.03h.03l.25.03h.03l.24.03h.02l.24.03h.03l.24.03h.03l.24.03h.03l.25.03h.02l.25.03h.03l.25.04h.03l.24.04h.02l.25.04h.03l.24.04h.03l.25.04h.03l.25.04h.03l.24.05h.02l.25.05h.03l.24.04h.03l.24.05.03.01.25.05.03.01.25.05.03.01.24.05h.02l.24.05h.02l.25.05h.03l.24.05h.03l.24.06h.03l.24.06.02.01.24.06.03.01.24.06h.03l.24.06.02.01.24.06.02.01.24.07h.03l.24.06.03.01.24.06h.03l.24.06h.02l.24.06.03.01.24.06.03.01.24.07.02.01.24.07h.03l.24.07.03.01.24.07.02.01.24.07.03.01.24.07.03.01.24.07.03.01.24.07.03.01.24.07.02.01.24.08.02.01.24.08h.03l.24.08.03.01.24.08.02.01.24.08.02.01.24.08.03.01.24.08.03.01.24.08.03.01.24.08.02.01.24.08.03.01.24.09.03.01.24.09.03.01.23.09.03.01.24.09.03.01.23.09.03.01.24.09.03.01.23.1.03.01.23.1.03.01.23.1.02.01.24.09.02.01.23.1.03.01.24.1.02.01.23.1.02.01.23.1.03.01.24.1.03.01.23.1.02.01.23.11.03.01.23.1.02.01.23.11.02.01.23.11.03.01.24.1.02.02.23.11.02.01.23.11.02.01.23.11.03.01.23.11.03.01.23.11.02.01.23.11.03.01.22.12.02.02.23.12.03.01.23.12.02.01.23.12.03.01.23.12.03.02.22.12.03.01.23.12.02.01.22.12.02.01.23.12.02.01.22.12.03.01.22.13.02.01.22.13.02.02.22.13.02.02.22.13.03.02.23.13 113.7 66.88.18.11.03.01.18.11.03.02.18.11.02.02.18.11.02.01.18.11.02.02.18.11.02.02.18.11.02.01.17.11.02.01.18.11.02.01.17.11.02.01.17.11.02.01.17.12.03.01.17.12.02.01.18.12.03.02.34.23.05.03.35.24.05.03.34.24.04.03.34.24.05.03.34.24.05.03.33.25.04.03.33.25.04.03.33.25.04.03.33.25.04.04.33.26.04.04.32.26.04.03.32.26.04.03.32.26.04.04.32.27.04.03.32.27.04.03.31.27.04.03.31.27.04.03.31.27.04.03.3.28.04.03.3.28.04.04.3.28.04.04.29.28.04.04.3.29.04.04.29.29.04.04.29.29.04.04.29.29.03.04.29.3.04.04.28.3.04.04.28.3.04.04.28.3.04.04.28.31.03.04.27.31.03.04.27.31.04.04.27.31.03.04.26.31.03.04.27.31.04.04.26.31.03.05.26.32.03.04.25.32.03.05.25.32.03.04.25.33.03.04.24.33.04.04.24.33.03.04.24.33.03.04.24.33.03.04.23.34.03.05.23.34.03.05.23.34.03.04.23.34.03.05.22.34.03.05.22.34.03.05.22.35.03.05.22.35.03.05.21.34.03.05.21.35.02.05.21.35.03.04.2.35.03.05.21.36.03.05.2.36.03.04.19.36.02.05.2.36.02.05.19.36.03.05.18.36.02.05.19.37.02.04.18.37.02.05.18.37.02.05.17.37.02.05.18.37.02.05.17.37.03.05.16.37.02.05.16.38.02.05.16.38.03.05.16.38.02.05.16.38.02.05.15.38.02.05.15.38.02.05.14.38.02.05.14.38.02.05.14.39.02.05.13.39.02.05.13.39.02.05.13.39.02.05.13.39.02.05.12.39.01.05.12.39.02.05.12.39.01.05.11.4.02.05.11.39.02.05.11.4.02.05.1.4.01.05.1.4.01.05.1.4.01.05.1.4.01.06.09.4.02.05.09.41.01.05.09.4.01.05.09.41.01.05.08.41.01.05.08.41.01.06.07.41v.06l.07.41.01.05.06.41.01.06.06.41.01.06.06.41.01.05.06.41.01.06.05.42.01.06.05.41v.06l.05.41.01.05.04.42.01.05.04.42v.06l.04.42.01.05.03.41.01.06.03.42v.06l.02.41v.04l.01.21v.02l.01.21v.03l.01.21v.03l.01.21v.03l.01.21v.03l.01.21v.27l.01.21v139.28l-.01.22v.02l-.01.22v.28l-.01.22v.03l-.01.23v.02l-.01.22v.03l-.01.22v.03l-.01.22-.01.03-.01.22v.03l-.01.23v.03l-.01.22v.03l-.02.22-.01.03-.02.23v.03l-.01.23v.03l-.02.23v.03l-.01.22v.03l-.02.23v.03l-.02.22-.01.03-.02.22v.03l-.02.23v.02l-.02.22-.01.03-.02.22-.01.03-.02.22v.03l-.03.23v.03l-.03.22v.03l-.03.22v.03l-.03.22-.01.03-.03.22-.01.03-.03.22-.01.03-.03.22v.03l-.03.22v.03l-.03.22v.02l-.03.22v.03l-.03.22v.03l-.03.22-.01.03-.03.22-.01.03-.04.22v.02l-.04.22v.03l-.03.22v.02l-.04.22-.01.03-.04.22v.03l-.04.22-.01.03-.04.21-.01.03-.05.22v.03l-.05.22-.01.02-.04.22-.01.03-.04.21-.01.03-.05.22-.01.02-.05.22v.03l-.05.22v.02l-.05.22-.01.03-.05.21-.01.02-.05.22-.01.03-.05.22-.01.03-.06.21-.01.03-.05.21-.01.02-.05.22v.03l-.06.22-.01.03-.05.21-.01.03-.06.21v.03l-.06.21-.01.03-.06.21v.03l-.06.21v.03l-.06.21-.01.03-.06.21-.01.03-.06.21-.01.02-.06.21-.01.03-.07.21-.01.03-.07.21-.01.03-.07.21-.01.03-.07.21-.01.02-.07.21-.01.03-.07.21-.01.03-.07.21-.01.02-.07.21-.01.02-.07.21-.01.03-.07.21-.01.03-.07.21-.01.03-.08.21-.01.03-.07.21-.01.03-.07.21-.01.02-.08.21-.01.02-.08.21-.01.03-.08.2-.01.03-.08.21-.01.02-.08.2-.01.03-.08.21-.01.03-.08.2-.01.03-.08.2-.01.03-.08.2-.01.03-.08.2-.01.03-.08.2-.01.03-.09.21-.01.03-.09.2-.01.03-.09.2-.01.02-.09.2-.01.03-.09.2-.01.03-.09.2-.01.02-.09.2-.01.02-.09.2-.02.03-.09.2-.01.02-.1.19-.01.03-.09.2-.02.02-.09.2-.01.02-.1.2-.01.02-.09.19-.01.02-.1.2-.02.03-.1.19-.01.03-.1.19-.01.02-.1.2-.01.02-.1.19-.01.02-.1.2-.01.03-.1.19-.02.03-.11.19-.01.02-.11.2-.01.02-.1.19-.01.03-.11.19-.01.02-.1.2-.01.02-.11.19-.01.03-.11.19-.02.03-.1.19-.02.03-.11.19-.02.02-.11.19-.01.02-.11.19-.02.02-.11.19-.02.02-.11.19-.01.03-.11.19-.01.02-.11.19-.01.02-.11.19-.01.03-.12.19-.02.02-.12.19-.02.02-.12.18-.02.03-.12.19-.02.03-.11.18-.01.02-.12.19-.01.02-.12.18-.02.02-.12.18-.01.03-.12.18-.01.03-.12.18-.01.02-.12.18-.01.02-.12.18-.01.02-.12.18-.01.03-.13.18-.02.02-.12.18-.02.02-.12.18-.02.03-.13.18-.02.02-.13.18-.01.02-.13.18-.02.02-.13.18-.01.02-.13.18-.01.02-.13.18-.02.02-.14.17-.02.02-.13.18-.02.02-.13.17-.02.02-.13.18-.02.02-.14.18-.02.02-.13.17-.02.02-.13.17-.02.02-.13.17-.02.02-.14.17-.02.02-.14.17-.01.02-.14.17-.02.02-.14.17-.02.02-.14.17-.02.02-.14.17-.01.02-.14.17-.02.02-.14.17-.01.02-.14.17-.01.02-.14.17-.02.02-.15.17-.02.02-.15.16-.01.02-.15.16-.02.02-.14.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.16.16-.02.02-.15.16-.02.02-.15.16-.01.02-.16.16-.02.02-.15.16-.02.02-.15.16-.02.02-.16.16-.02.02-.16.15-.02.02-.16.15-.02.02-.16.16-.02.02-.16.15-.02.02-.16.15-.02.02-.16.15-.02.02-.16.15-.02.02-.17.16-.02.02-.16.15-.02.02-.16.15-.02.02-.16.15-.02.02-.17.15-.02.02-.17.15-.02.02-.17.14-.02.02-.17.15-.02.01-.17.14-.02.02-.17.15-.02.02-.17.14-.02.02-.17.14-.02.02-.17.14-.02.02-.17.15-.02.01-.17.14-.02.02-.17.14-.02.02-.17.14-.02.02-.17.14-.02.02-.17.14-.02.01-.17.14-.02.02-.17.14-.02.02-.18.14-.03.02-.18.14-.03.02-.18.14-.02.02-.17.14-.03.01-.18.14-.02.01-.18.14-.03.02-.18.13-.02.02-.18.13-.02.01-.18.13-.02.01-.18.13-.03.01-.18.14-.03.01-.18.13-.03.01-.18.13-.02.02-.19.13-.02.01-.19.13-.03.02-.19.12-.02.02-.18.13-.02.02-.18.12-.02.02-.19.12-.02.02-.18.12-.02.01-.19.13-.03.02-.19.12-.02.01-.19.12-.02.01-.19.12-.03.01-.19.12-.02.01-.19.12-.03.02-.19.12-.02.02-.19.11-.02.02-.19.12-.02.01-.19.12-.02.01-.19.12-.02.01-.19.12-.03.02-.2.12-.02.01-.19.12-.02.01-.2.12-.02.02-.2.11-.03.01-.2.12-.02.01-.19.11-.02.01-115.97 64.59-.01.01-.18.1-.02.01-.19.1-.03.01-.19.1-.02.02-.19.11-.03.01-.19.11-.02.02-.19.1-.03.02-.19.1-.02.01-.2.1-.02.01-.19.1-.02.01-.19.09-.02.02-.2.09-.03.01-.19.1-.02.01-.2.1-.02.01-.19.09-.03.02-.2.09-.02.01-.19.09-.03.01-.2.09-.03.01-.19.09-.02.01-.2.09-.02.01-.2.09-.03.01-.2.09-.03.01-.19.09-.02.01-.19.09-.02.01-.2.09-.02.01-.19.08-.03.01-.2.09-.03.01-.2.09-.02.01-.2.08-.03.01-.2.08-.02.01-.2.08-.03.01-.2.08-.02.01-.2.08-.02.01-.2.08-.03.01-.2.07-.02.01-.19.08-.02.01-.2.08-.02.01-.2.07-.03.01-.2.07-.03.01-.2.08-.02.01-.2.07-.03.01-.2.08-.02.01-.2.07-.02.01-.2.07-.02.01-.2.07-.03.01-.2.06-.02.01-.2.07-.03.01-.2.07-.03.01-.2.07-.03.01-.2.07-.03.01-.21.06-.03.01-.21.07h-.02l-.21.06-.04.01-.4.12-.05.01-.41.12-.06.01-.4.11-.06.01-.41.11-.05.02-.41.11-.05.01-.41.1-.05.01-.41.1-.06.02-.41.1-.06.01-.41.1-.06.01-.41.09-.05.01-.41.09-.05.01-.41.09-.05.01-.42.08-.05.01-.41.07-.05.01-.42.08-.05.01-.42.07-.05.01-.42.07-.05.01-.41.06h-.06l-.41.06-.05.01-.41.06h-.05l-.41.06-.05.01-.42.05-.05.01-.42.05-.05.01-.42.05h-.05l-.42.04-.06.01-.42.04h-.05l-.42.04h-.05l-.42.03-.05.01-.42.02-.06.01-.42.02h-.06l-.42.02-.05.005-.42.02h.01l-.42.01h-.05l-.42.02-.42.004h-.06l-.42.01h-1l-.42-.01h-.06l-.42-.01h-.05l-.42-.013-.05-.01-.42-.01h-.05l-.42-.02h-.05l-.42-.02-.05-.01-.42-.03h-.05l-.42-.03h-.05l-.42-.03-.05-.01-.42-.04h-.05l-.42-.04-.05-.01-.42-.05-.05-.01-.42-.05-.05-.01-.41-.05h-.05l-.42-.05h-.05l-.42-.06-.05-.01-.42-.06-.05-.01-.41-.06-.05-.01-.41-.06-.05-.01-.42-.07-.05-.01-.42-.07-.05-.01-.41-.08-.05-.01-.41-.08-.05-.01-.41-.08-.06-.01-.41-.08-.05-.01-.41-.09-.05-.01-.42-.09-.05-.01-.41-.1-.05-.01-.41-.1-.06-.01-.41-.1-.06-.01-.41-.1-.05-.02-.41-.11-.05-.01-.41-.11-.05-.02-.41-.12-.05-.01-.4-.12-.06-.01-.4-.12-.05-.01-.4-.13-.05-.01-.39-.13-.03-.01-.21-.07-.02-.01-.2-.06-.02-.01-.2-.07-.02-.01-.2-.06-.03-.01-.2-.07-.02-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.08-.03-.01-.2-.07-.02-.01-.2-.07-.03-.01-.2-.08-.02-.01-.2-.08-.03-.01-.2-.08-.03-.01-.2-.08-.02-.01-.2-.08-.03-.01-.2-.08-.03-.01-.2-.09-.03-.01-.2-.08-.03-.01-.2-.08-.02-.02-.2-.08-.03-.01-.19-.08-.03-.01-.19-.08-.02-.01-.19-.09-.03-.01-.2-.09-.03-.01-.2-.09-.03-.01-.19-.09-.026-.01-.2-.09-.02-.01-.19-.09-.02-.01-.2-.09-.03-.02-.19-.09-.03-.01-.2-.09-.02-.01-.19-.1-.03-.02-.19-.09-.02-.01-.2-.1-.02-.02-.19-.1-.03-.01-.19-.1-.03-.01-.19-.1-.03-.02-.19-.1-.02-.01-.19-.1-.02-.01-.19-.1-.02-.01-.19-.11-.03-.02-.19-.1-.02-.01-.19-.1-.03-.02-.19-.11-.03-.02-.19-.11-.02-.02-.19-.1-.03-.01-.19-.11-.02-.01-.19-.11-.02-.01-.19-.11-.03-.02-.18-.11-.01-.01-104.78-61.2-.02-.01-.22-.13-.03-.02-.23-.14-.02-.01-.22-.13-.02-.02-.22-.14-.02-.01-.22-.13-.02-.01-.23-.14-.02-.01-.22-.13-.02-.01-.22-.14-.02-.01-.22-.14-.02-.01-.22-.14-.02-.02-.22-.14-.02-.01-.22-.15-.02-.01-.21-.14-.02-.02-.22-.15-.03-.02-.21-.14-.02-.01-.22-.15-.02-.02-.22-.14-.02-.02-.21-.14-.02-.01-.22-.15-.02-.02-.21-.15-.02-.02-.21-.15-.02-.01-.21-.15-.03-.02-.21-.15-.02-.02-.21-.15-.03-.02-.21-.16-.02-.02-.21-.15-.02-.02-.21-.16-.02-.02-.21-.15-.02-.02-.2-.16-.02-.02-.21-.16-.02-.02-.21-.16-.02-.02-.21-.16-.02-.02-.2-.16-.03-.01-.2-.16-.03-.02-.2-.16-.02-.02-.2-.16-.02-.02-.2-.17-.02-.02-.2-.16-.02-.02-.2-.17-.02-.02-.2-.16-.02-.02-.2-.16-.02-.02-.197-.17-.02-.02-.2-.16-.02-.02-.2-.17-.02-.02-.2-.16-.02-.02-.2-.17-.02-.01-.19-.17-.02-.02-.19-.17-.02-.02-.2-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.19-.18-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.18-.18-.02-.01-.19-.18-.02-.02-.18-.17-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.17-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.19-.02-.02-.17-.18-.01-.02-.18-.19-.02-.02-.18-.18-.02-.02-.17-.18-.02-.02-.18-.18-.02-.02-.17-.19-.02-.02-.18-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.16-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.16-.19-.02-.02-.16-.19-.02-.02-.16-.2-.02-.02-.17-.2-.02-.02-.17-.2-.01-.02-.16-.19-.02-.02-.16-.2-.01-.02-.16-.2-.01-.02-.16-.2-.02-.02-.16-.2-.02-.02-.16-.2-.01-.02-.15-.2-.01-.02-.16-.2-.02-.02-.15-.207-.02-.02-.15-.21-.01-.02-.15-.2-.02-.02-.15-.21-.02-.02-.15-.21-.02-.03-.15-.2-.01-.02-.15-.2-.02-.02-.15-.21-.01-.02-.15-.21-.02-.02-.145-.2-.01-.02-.15-.21-.02-.02-.15-.2-.01-.02-.15-.21-.02-.03-.14-.21-.01-.02-.14-.21-.02-.03-.14-.21-.017-.02-.14-.21-.01-.02-.14-.21-.02-.02-.14-.21-.01-.02-.14-.21-.01-.02-.14-.22-.01-.02-.14-.22-.01-.02-.13-.21-.01-.02-.13-.22-.01-.02-.13-.22-.01-.02-.13-.21-.01-.02-.13-.22-.01-.02-.13-.22-.02-.02-.12-.21-.02-.03-.13-.22-.01-.02-.13-.22-.01-.02-.13-.22-.01-.02-.13-.22-.01-.03-.13-.22-.02-.02-.12-.22-.01-.02-.12-.22-.01-.02-.13-.22-.01-.02-.12-.22-.01-.02-.12-.22-.01-.02-.12-.22-.01-.02-.12-.22-.01-.03-.12-.22-.01-.02-.12-.22-.02-.03-.11-.22-.01-.02-.11-.22-.01-.03-.12-.23-.01-.03-.11-.23-.01-.03-.11-.22-.01-.02-.11-.23-.01-.02-.11-.23-.01-.03-.11-.23-.01-.03-.11-.23-.01-.03-.11-.23-.01-.02-.1-.23-.01-.03-.11-.23-.01-.03-.11-.23-.02-.03-.1-.23-.01-.03-.1-.23-.01-.03-.1-.23-.01-.02-.1-.23-.01-.02-.1-.23-.01-.03-.1-.24-.01-.02-.1-.23-.01-.03-.09-.23-.01-.02-.1-.23-.01-.02-.1-.23-.01-.03-.1-.24-.01-.02-.09-.24-.01-.03-.09-.23-.01-.03-.09-.23-.01-.03-.09-.24-.01-.02-.09-.24-.01-.03-.09-.24-.01-.03-.09-.24-.01-.02-.09-.24-.01-.02-.09-.24-.01-.03-.08-.24-.01-.02-.08-.24-.01-.03-.09-.24-.01-.03-.08-.24-.01-.03-.08-.24-.01-.03-.08-.24-.01-.03-.08-.24-.01-.03-.08-.24-.01-.03-.08-.24v-.03l-.08-.25v-.03l-.08-.24-.01-.03-.08-.24-.01-.02-.08-.24-.01-.03-.07-.24-.01-.02-.07-.24-.01-.03-.07-.24-.01-.03-.07-.24-.01-.03-.07-.24-.01-.02-.07-.25-.01-.03-.06-.25-.01-.03-.06-.25-.01-.02-.07-.24-.01-.03-.06-.25v-.03l-.06-.25v-.03l-.06-.25-.01-.03-.06-.25-.01-.03-.06-.25-.01-.03-.06-.25-.01-.02-.06-.25v-.03l-.06-.25-.01-.03-.06-.25-.01-.03-.06-.25-.01-.03-.06-.25-.01-.02-.05-.25-.01-.03-.05-.25v-.03l-.05-.25-.01-.02-.05-.25-.01-.03-.05-.25-.05-.25-.01-.03-.05-.25-.01-.03-.05-.25v-.03l-.05-.26v-.03l-.04-.26-.01-.03-.04-.25v-.03l-.04-.25-.01-.03-.04-.25-.01-.02-.04-.25v-.03l-.04-.26v-.02l-.04-.25-.04-.25-.01-.03-.03-.25v-.03l-.04-.26-.01-.03-.04-.26-.03-.26-.01-.03-.03-.25v-.02l-.04-.25-.03-.25v-.03l-.03-.25v-.03l-.03-.25-.01-.02-.03-.25v-.03l-.03-.25v-.03l-.03-.26v-.03l-.02-.26V275l-.02-.26v-.02l-.03-.26-.01-.03-.02-.26-.01-.02-.01-.26v-.03l-.02-.26v-.03l-.02-.26v-.02l-.02-.26V273l-.02-.26v-.03l-.01-.26v-.03l-.02-.26v-.03l-.01-.26-.01-.26v-.023l-.01-.26-.01-.03v-.29l-.01-.26v-.02l-.01-.26v-.03l-.01-.26v-.03l-.01-.26V148.12l.01-.3v-.03l.01-.298v-.027l.01-.3v-.027l.01-.296v-.027l.01-.3v-.027l.01-.3v-.028l.01-.298v-.027l.01-.298v-.03l.01-.297v-.03l.02-.297v-.027l.01-.3v-.025l.01-.29v-.02l.01-.29v-.02l.01-.29v-.03l.02-.3v-.02l.02-.3v-.02l.02-.3v-.03l.02-.29v-.03l.03-.29.01-.03.02-.3v-.02l.03-.29v-.03l.03-.29V141l.03-.296v-.026l.03-.295v-.03l.04-.296v-.03l.04-.3v-.025l.03-.292.01-.03.03-.29.01-.023.04-.29v-.03l.04-.29.01-.027.04-.297.01-.027.04-.29v-.03l.04-.29v-.03l.04-.29v-.03l.04-.293v-.028l.05-.29v-.03l.05-.29.01-.02.05-.29.01-.03.05-.29v-.03l.05-.29v-.03l.05-.29v-.026l.05-.29.01-.03.05-.29v-.03l.05-.29.01-.03.05-.29.01-.03.05-.29.01-.03.05-.29V133l.05-.29.01-.02.06-.29v-.03l.06-.29.01-.03.06-.29.01-.03.06-.29v-.03l.06-.28.01-.03.06-.29.01-.03.07-.29v-.03l.07-.29v-.03l.07-.28.01-.03.07-.29.01-.02.07-.28v-.02l.07-.29.01-.03.07-.29.01-.03.07-.29v-.03l.07-.29.01-.03.08-.29v-.03l.08-.28.01-.02.08-.28.01-.03.08-.28v-.02l.08-.28.01-.03.08-.28.01-.03.08-.28.01-.02.08-.28.01-.03.08-.28.01-.02.09-.28.01-.03.08-.28v-.03l.09-.28.01-.02.09-.28v-.02l.09-.28.01-.02.09-.28.01-.02.09-.28.01-.03.09-.27.01-.02.09-.27.01-.02.1-.27.01-.03.1-.28.01-.03.1-.27.01-.03.1-.28.01-.02.1-.28.01-.03.1-.28.01-.03.1-.27.01-.02.1-.28.01-.02.1-.28.01-.02.11-.27.01-.03.11-.27.01-.03.11-.27.01-.03.11-.27.01-.03.11-.27.01-.03.11-.27.01-.02.11-.27.01-.03.11-.27.01-.03.12-.27.01-.02.11-.26.01-.02.12-.26.01-.03.11-.26.01-.03.12-.27.01-.02.12-.26.01-.03.12-.26.02-.02.12-.26.01-.02.12-.26.01-.03.12-.26.01-.02.12-.27.01-.02.13-.27.01-.02.13-.26.01-.03.12-.26.01-.02.12-.26.01-.03.13-.26.01-.02.13-.26.01-.02.13-.26.02-.02.14-.26.02-.02.13-.26.01-.02.14-.26.01-.03.13-.26.01-.02.13-.26.02-.03.13-.25.01-.02.13-.26.01-.03.14-.26.01-.03.14-.25.01-.02.14-.25.01-.03.15-.26.01-.02.14-.25.01-.02.15-.25.01-.03.15-.26.01-.02.15-.25.01-.03.15-.25.01-.02.15-.25.02-.02.15-.25.01-.02.15-.25.02-.03.15-.25.01-.02.15-.25.01-.02.15-.25.02-.02.15-.24.02-.02.16-.25.01-.02.15-.25.01-.02.16-.25.015-.02.15-.25.02-.02.16-.24.01-.02.16-.24.02-.02.16-.24.02-.02.16-.24.01-.02.16-.24.02-.02.16-.24.01-.02.16-.24.01-.02.16-.24.01-.02.17-.24.02-.02.16-.24.01-.02.17-.23.01-.02.17-.23.01-.02.17-.24.01-.02.17-.23.01-.02.17-.24.02-.02.17-.23.02-.02.17-.23.02-.02.18-.23.01-.02.17-.23.01-.02.17-.23.02-.02.18-.23.02-.02.17-.23.02-.02.18-.23.01-.02.18-.23.02-.02.18-.23.02-.02.19-.23.02-.02.18-.23.01-.02.18-.22.02-.02.18-.23.02-.02.18-.23.01-.02.19-.23.02-.02.18-.22.02-.02.19-.22.02-.02.19-.22.02-.02.19-.22.01-.02.19-.22.02-.02.19-.22.02-.02.19-.22.02-.02.19-.22.01-.02.19-.22.02-.02.19-.21.02-.02.2-.22.02-.02.19-.22.02-.02.2-.22.02-.02.2-.22.01-.02.21-.21.02-.02.2-.21.02-.02.2-.21.02-.02.2-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.2.02-.02.2-.21.01-.02.21-.21.02-.02.21-.2.02-.02.21-.2.02-.02.21-.2.02-.02.21-.2.02-.02.22-.2.02-.02.21-.2.02-.02.21-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.19.02-.02.22-.19.02-.02.22-.19.02-.02.22-.19.02-.02.22-.19.02-.02.23-.19.02-.02.22-.19.02-.02.22-.2.02-.02.23-.19.02-.02.23-.19.02-.01.23-.18.02-.02.23-.19.02-.02.23-.19.02-.02.23-.19.02-.02.23-.19.02-.02.23-.18.02-.01.23-.18.02-.02.24-.18.02-.02.237-.18.02-.02.24-.18.03-.02.24-.18.02-.02.24-.18.02-.02.24-.18.02-.02.24-.18.03-.01.24-.18.02-.01.24-.18.02-.02.24-.17.02-.02.25-.17.03-.01.24-.17.02-.02.24-.17.02-.01.24-.17.02-.02.24-.17.02-.02.24-.17.02-.01.25-.17.02-.01.24-.17.02-.01.24-.17.02-.01.25-.17.02-.02.25-.17.03-.01.25-.16.03-.02.25-.16.03-.01.25-.16.03-.01.25-.16.02-.02.26-.16.03-.01.25-.16.02-.02.25-.15.01-.01L519 20.82l.01-.01.22-.13.02-.02.22-.13.03-.01.22-.14.02-.01.23-.13.03-.01.22-.13.03-.02.22-.13.02-.02.23-.13.02-.01.22-.13.03-.02.22-.13.02-.01.23-.13.03-.01.22-.13.02-.02.224-.12.03-.01.22-.12.03-.01.23-.12.03-.02.23-.12.02-.01.23-.12.02-.01.23-.12.02-.02.23-.11.03-.02.23-.12.02-.01.23-.11.02-.02.22-.11.03-.02.23-.11.03-.01.23-.12.03-.01.23-.11.03-.01.23-.11.03-.01.23-.11.03-.01.23-.11.02-.01.23-.11.03-.01.23-.11.03-.01.23-.1.03-.01.23-.11.03-.01.23-.1.03-.01.23-.1.03-.01.23-.1.03-.01.23-.1.02-.01.23-.1.02-.01.24-.1.03-.01.23-.1.03-.01.23-.09.03-.01.24-.1.03-.01.23-.1.03-.01.24-.09.03-.01.24-.09.03-.01.23-.09.03-.01.24-.09.025-.01.23-.09.02-.01.24-.09.03-.01.24-.09.03-.01.24-.09h.03l.24-.08.03-.01.24-.08.03-.01.24-.08.02-.01.24-.08.03-.01.24-.08.03-.01.24-.08.02-.01.24-.08.03-.01.24-.07.02-.01.24-.08.02-.01.24-.07.03-.01.24-.07.03-.01.24-.08.03-.01.24-.07h.02l.24-.07.03-.01.24-.07h.03l.24-.07h.03l.24-.07.03-.01.24-.07.02-.01.24-.07.03-.01.24-.07.03-.01.24-.06.03-.01.24-.07.03-.01.24-.06.03-.01.24-.06h.03l.24-.06.03-.006.24-.06.03-.01.24-.06.03-.01.25-.06.02-.01.25-.06.03-.01.24-.055.03-.01.24-.06.03-.01.24-.05.03-.01.24-.05.02-.01.25-.05h.03l.25-.05h.03l.25-.05h.03l.24-.05.03-.01.24-.04.03-.01.25-.04.03-.01.24-.04h.02l.24-.05.03-.01.24-.04h.03l.25-.04.03-.01.24-.04.03-.01.25-.04.03-.01.25-.03h.03l.25-.03h.03l.24-.04h.03l.24-.03h.03l.25-.04h.03l.24-.03h.03l.24-.03h.03l.24-.03h.03l.24-.03h.03l.24-.03h.03l.25-.03h.03l.25-.03h.03l.24-.03h.03l.25-.02h.03l.25-.02h.03l.25-.02h.03l.25-.02h.03l.25-.02h.03l.25-.02h.03l.24-.02h.03l.25-.02h.03l.25-.02h.03l.25-.01h.03l.25-.01h.03l.25-.02h.03l.25-.01h.04l.25-.01h.03l.25-.01h.03l.25-.01h.03l.25-.01h2zm-.23 27h-.163l-.163.002h-1.162l-.164.01h-.163l-.166.01-.17.01-.17.01-.16.01-.17.01-.17.01-.17.01-.17.01-.17.01-.17.01-.17.01-.17.01-.16.01-.17.02-.17.02-.16.02-.16.01-.17.02-.16.02-.17.02-.17.02-.17.02-.16.02-.16.02-.17.02-.16.02-.17.03-.16.02-.16.03-.16.03-.16.02-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.17.03-.16.03-.16.04-.16.03-.16.04-.16.03-.17.04-.16.04-.16.03-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.15.04-.16.04-.16.04-.16.05-.16.05-.16.05-.16.05-.16.05-.16.05-.15.05-.16.05-.15.05-.16.05-.16.05-.16.05-.16.05-.15.06-.15.06-.16.05-.16.05-.15.06-.16.06-.15.05-.16.06-.15.06-.15.06-.16.07-.15.06-.16.06-.15.06-.16.06-.16.07-.16.06-.15.07-.15.07-.15.07-.15.07-.15.07-.15.07-.15.07-.15.07-.15.07-.15.07-.15.08-.15.08-.15.07-.15.08-.15.08-.15.08-.15.08-.15.08-.15.08-.15.08-.15.08-.15.08-.15.08-.15.08-.15.08-.15.08-.15.08-.15.09-.15.08-.15.09-.14.09-.15.09-.16.1L437.07 103l-.19.12-.19.11-.18.12-.18.11-.18.12-.18.12-.18.12-.18.12-.18.12-.18.12-.18.12-.18.12-.18.13-.17.12-.18.13-.17.12-.17.13-.18.12-.17.12-.18.13-.18.13-.17.13-.17.13-.17.13-.17.13-.17.13-.17.13-.17.13-.17.13-.17.135-.16.136-.16.13-.17.13-.17.14-.17.13-.16.14-.16.14-.16.14-.16.14-.16.14-.16.14-.16.14-.16.15-.16.14-.16.14-.16.14-.15.15-.16.14-.16.14-.15.14-.16.15-.16.15-.16.14-.15.14-.15.15-.15.15-.15.15-.15.15-.15.15-.15.15-.15.15-.15.15-.15.15-.15.15-.14.16-.14.15-.15.16-.15.16-.14.16-.14.15-.14.16-.14.16-.14.16-.14.16-.14.16-.14.16-.14.16-.14.16-.13.16-.14.16-.13.17-.13.16-.13.16-.13.16-.14.17-.13.16-.13.16-.13.17-.13.17-.13.17-.13.17-.13.17-.13.16-.13.17-.12.17-.12.17-.13.17-.12.17-.12.18-.12.17-.12.17-.12.17-.12.17-.12.17-.12.18-.12.18-.12.18-.12.18-.12.18-.12.18-.11.18-.12.17-.12.18-.11.17-.11.18-.11.18-.11.18-.11.18-.11.18-.11.18-.11.18-.11.18-.11.18-.1.19-.11.18-.11.19-.1.19-.1.19-.11.18-.1.18-.1.19-.1.18-.1.18-.1.19-.1.19-.09.19-.1.19-.1.19-.09.19-.09.18-.09.19-.1.19-.09.19-.09.19-.09.19-.09.19-.09.19-.08.2-.09.19-.09.19-.08.19-.08.2-.08.2-.08.19-.08.2-.09.2-.08.19-.08.19-.08.2-.08.19-.08.2-.08.2-.08.2-.08.2-.07.2-.08.2-.07.2-.07.2-.07.2-.07.2-.07.2-.07.2-.07.2-.07.2-.07.2-.07.2-.07.2-.07.2-.06.2-.06.2-.068.21-.06.2-.06.2-.06.21-.06.2-.06.2-.06.2-.056.21-.06.21-.06.21-.05.2-.06.2-.056.21-.06.21-.05.21-.05.21-.05.2-.05.21-.05.21-.05.21-.05.21-.043.21-.04.21-.04.21-.04.21-.04.21-.04.21-.05.21-.04.21-.04.21-.04.21-.04.21-.03.21-.04.21-.04.21-.03.21-.04.21-.03.21-.04.21-.03.22-.03.22-.03.21-.03.21-.03.21-.03.21-.03.21-.03.21-.024.22-.02.21-.03.22-.02.21-.02.21-.02.22-.02.21-.02.22-.02.21-.02.22-.02.21-.02.21-.02.22-.02.22-.01.22-.01.21-.01.22-.01.22-.01.22-.01.22v.22l-.01.21-.01.21-.01.21v.22l-.006.22v121.27l.01.18v.35l.01.18v.35l.01.17.01.18.01.17.01.18.01.18.01.17.01.18.01.18.02.17.01.18.01.17.02.17.02.17.01.17.02.17.02.17.02.17.02.17.02.18.02.17.02.17.02.17.02.17.02.17.03.17.03.17.02.17.03.17.03.17.02.18.03.17.03.17.03.17.03.17.03.17.03.17.03.17.03.17.033.17.04.17.03.17.04.17.04.17.035.17.04.17.04.17.04.17.04.17.04.17.04.16.04.17.045.17.04.17.05.17.04.16.05.17.05.16.045.17.05.16.05.16.04.17.05.17.05.16.05.17.05.17.05.16.06.16.05.17.05.16.05.16.05.16.06.17.06.16.06.16.06.16.06.16.06.16.06.16.06.17.06.16.06.16.06.16.06.17.068.16.065.16.07.16.07.16.07.16.07.16.07.16.06.16.07.16.07.16.07.16.07.16.07.16.07.16.07.15.07.16.07.15.07.15.08.15.08.16.08.16.08.15.07.15.08.15.08.15.08.15.08.15.08.15.08.15.08.15.08.15.08.15.08.15.09.15.08.15.09.15.09.15.09.15.09.14.09.15.09.14.09.15.09.15.09.15.09.15.09.15.1.14.09.15.09.15.095.14.09.14.1.14.09.15.09.14.1.14.094.15.1.14.09.14.1.14.09.14.1.14.1.14.1.14.1.14.104.14.1.14.11.14.1.13.1.14.1.14.11.14.11.14.11.13.11.14.11.14.11.14.11.13.11.13.1.14.12.13.11.13.11.13.11.13.11.13.11.13.12.13.12.13.12.13.12.12.12.13.12.13.11.13.12.12.12.12.12.13.12.13.12.12.12.12.12.12.12.12.12.13.13.13.12.12.12.12.13.12.12.12.13.12.13.12.12.12.13.12.13.11.13.12.13.11.13.12.13.12.13.11.13.11.13.12.13.11.13.12.13.12.13.11.14.11.14.11.13.11.14.11.14.11.14.11.14.11.14.11.14.11.14.11.14.11.13.1.14.1.14.11.14.1.14.1.14.1.14.11.14.1.14.1.14.1.14.11.14.1.14.1.15.1.15.1.14.1.14.1.14.1.15.09.15.1.14.1.15.1.15.09.15.1.15.1.15.09.15.09.15.09.15.1.15.09.16.1 104.69 61.19.13.07.12.07.12.07.12.06.11.07.11.06.11.06.12.07.12.06.12.06.12.06.12.06.12.06.12.06.12.06.12.06.12.05.12.06.12.05.12.06.12.06.12.06.12.05.12.06.12.05.12.05.12.06.12.05.12.05.12.06.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.13.05.12.04.13.05.12.04.12.04.12.05.12.04.12.04.12.05.12.04.12.04.13.04.12.04.11.04.26.08.25.08.25.08.25.07.25.07.25.07.25.06.25.07.25.06.25.06.25.06.25.06.25.05.26.05.25.05.25.05.25.05.25.04.26.04.26.04.26.04.26.04.26.03.25.03.26.03.26.03.26.02.25.02.26.03.26.02.26.02.25.02.25.01.25.01.26.01.26.01.26.01h.78l.26-.01h.26l.26-.01.26-.01.25-.01.26-.02.26-.02.26-.02.26-.02.26-.02.26-.02.26-.03.25-.03.26-.03.25-.03.26-.03.26-.03.25-.04.26-.04.25-.04.25-.05.25-.05.25-.04.26-.05.25-.05.25-.05.26-.06.25-.06.26-.06.25-.06.25-.07.25-.07.25-.07.25-.07.25-.08.26-.08.11-.03.13-.04.12-.04.12-.04.12-.04.13-.04.12-.04.12-.04.12-.04.13-.05.12-.05.12-.04.13-.04.12-.04.12-.04.12-.04.12-.05.12-.05.12-.04.12-.05.12-.05.12-.05.12-.05.12-.05.13-.05.12-.05.12-.05.12-.06.12-.05.12-.05.12-.05.12-.05.12-.06.12-.06.12-.05.12-.05.12-.05.12-.05.12-.06.11-.06.12-.06.12-.06.12-.06.11-.06.12-.06.12-.06.12-.07.11-.06.12-.06.11-.07.12-.07.13-.07 115.92-64.56.14-.07.12-.07.12-.07.13-.07.12-.07.12-.08.12-.08.12-.07.12-.07.12-.07.12-.08.12-.07.12-.08.12-.07.12-.08.12-.08.11-.08.12-.08.12-.08.12-.08.12-.08.11-.08.11-.08.12-.08.12-.08.12-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.09.11-.08.11-.08.11-.08.11-.08.11-.09.11-.09.11-.09.11-.09.11-.08.11-.09.11-.09.1-.08.1-.09.1-.09.11-.09.1-.09.1-.09.1-.09.1-.09.1-.09.1-.09.1-.1.1-.09.1-.1.1-.09.1-.09.1-.09.1-.1.1-.1.1-.09.09-.09.1-.1.1-.1.1-.1.1-.1.09-.1.09-.1.09-.1.1-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.1-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.08-.11.09-.11.08-.1.09-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.12.08-.11.08-.11.08-.11.08-.11.08-.11.08-.12.08-.11.08-.11.08-.11.08-.11.07-.12.07-.11.07-.12.07-.11.07-.12.07-.12.08-.12.07-.12.07-.11.07-.12.07-.12.07-.12.07-.12.06-.12.07-.12.07-.12.07-.12.07-.12.07-.12.07-.12.07-.12.07-.12.06-.12.07-.12.07-.12.06-.12.06-.12.06-.12.06-.12.06-.12.06-.12.06-.13.06-.12.05-.13.06-.12.06-.13.05-.12.06-.12.05-.12.06-.12.06-.13.05-.12.06-.13.06-.13.05-.13.05-.13.05-.13.05-.13.05-.13.06-.13.05-.13.05-.12.05-.13.05-.13.05-.13.05-.13.05-.12.04-.13.05-.12.05-.13.05-.13.04-.13.04-.13.04-.13.05-.13.04-.13.05-.13.04-.12.04-.13.04-.13.04-.13.04-.13.04-.13.04-.14.04-.13.04-.13.03-.13.04-.13.03-.13.04-.13.03-.14.04-.13.03-.13.03-.13.03-.13.03-.13.03-.13.03-.14.03-.13.03-.13.03-.13.03-.13.03-.14.03-.14.03-.14.02-.14.03-.13.03-.13.03-.13.03-.14.02-.14.02-.14.02-.14.02-.14.02-.14.02-.14.02-.13.02-.14.02-.14.02-.14.02-.14.01-.13.01-.14.02-.14.02-.13.02-.14.01-.14.01-.14.01-.14.01-.14.02-.14.01-.14.01-.13.01-.14.01-.14.01-.14.01-.14.01-.14v-.14l.01-.14.01-.14.01-.14.01-.14v-.83l.01-.16V136.6l-.01-.14v-.507l-.01-.13-.01-.125-.01-.125v-.255l-.01-.128v-.252l-.01-.11-.02-.268-.02-.25-.02-.25-.03-.254-.02-.25-.03-.25-.03-.248-.03-.25-.03-.248-.03-.248-.04-.248-.04-.248-.04-.25-.04-.245-.04-.24-.05-.24-.04-.24-.05-.24-.05-.24-.05-.24-.06-.24-.06-.24-.06-.24-.06-.24-.06-.24-.06-.24-.07-.23-.07-.23-.07-.24-.07-.24-.08-.23-.07-.23-.08-.24-.08-.23-.08-.23-.08-.23-.09-.23-.09-.23-.09-.23-.09-.23-.09-.23-.09-.22-.1-.23-.1-.22-.1-.22-.1-.22-.11-.22-.1-.22-.11-.22-.11-.22-.11-.22-.11-.22-.12-.21-.12-.22-.11-.22-.12-.21-.12-.21-.12-.21-.13-.21-.12-.21-.13-.21-.13-.21-.13-.2-.14-.2-.14-.21-.13-.2-.13-.2-.14-.2-.14-.2-.15-.2-.14-.2-.15-.19-.15-.2-.15-.19-.15-.2-.16-.19-.16-.19-.15-.19-.16-.19-.16-.19-.16-.18-.17-.18-.17-.19-.17-.19-.17-.18-.17-.18-.17-.18-.18-.18-.18-.17-.17-.18-.18-.17-.18-.17-.18-.17-.18-.17-.18-.17-.19-.17-.18-.17-.18-.17-.19-.16-.19-.16-.19-.16-.19-.16-.2-.16-.19-.16-.19-.15-.2-.15-.2-.15-.2-.15-.2-.15-.21-.14-.21-.14-.2-.14-.21-.14-.22-.15-.1-.07-.1-.07-.11-.07-.11-.07-.1-.07-.11-.07-.11-.07-.11-.07-.11-.06-.11-.06-.11-.07-.1-.07-.11-.07-.13-.07-113.4-66.79-.16-.09-.15-.09-.15-.08-.15-.08-.14-.08-.14-.08-.15-.08-.15-.08-.15-.08-.15-.08-.15-.08-.15-.08-.15-.08-.15-.07-.15-.07-.15-.07-.15-.07-.15-.08-.15-.07-.15-.08-.15-.07-.15-.08-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.16-.07-.15-.07-.15-.07-.16-.07-.15-.07-.15-.06-.15-.07-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.16-.06-.16-.06-.15-.05-.16-.06-.15-.06-.16-.05-.16-.05-.16-.06-.16-.05-.15-.05-.15-.05-.16-.05-.15-.05-.16-.05-.16-.05-.16-.05-.16-.04-.16-.04-.16-.04-.16-.04-.16-.04-.16-.05-.16-.04-.16-.04-.16-.04-.16-.04-.16-.03-.16-.04-.16-.04-.16-.04-.16-.04-.16-.04-.16-.03-.16-.04-.16-.04-.17-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.17-.03-.17-.03-.16-.03-.16-.02-.16-.02-.16-.03-.16-.02-.16-.03-.17-.02-.16-.02-.16-.02-.16-.02-.16-.02-.16-.01-.17-.02-.16-.02-.17-.01-.16-.02-.17-.01-.16-.01-.16-.01-.17-.01-.16-.02-.16-.01-.16-.01-.16-.01-.17-.01-.16-.01h-.16l-.17-.01h-.4l-.16-.01-.16-.01-.17-.01h-.65z"/> - <path fill="#fff" fill-rule="nonzero" d="M477.32 109.382h42.288V221.55c0 17.8.488 29.335 1.468 34.61 1.69 8.476 4.814 14.367 11.177 19.5 6.364 5.13 13.795 6.586 24.832 6.586 11.214 0 14.968-1.736 20.664-6.587 5.69-4.86 9.12-9.47 10.28-16.54 1.15-7.07 3.07-18.79 3.07-35.18V109.38h42.28v108.78c0 24.862-1.07 42.425-3.21 52.69-2.14 10.267-6.08 18.932-11.82 25.995-5.74 7.064-13.42 12.69-23.03 16.88-9.62 4.192-22.16 6.287-37.65 6.287-18.69 0-32.87-2.284-42.52-6.85-9.66-4.568-17.29-10.502-22.9-17.8-5.61-7.3-9.3-14.952-11.08-22.957-2.58-11.865-3.88-29.383-3.88-52.552v-110.47z"/> - <path fill="#33BA91" d="M1099.375 259.25V136.945c0-15.835-8.485-30.456-22.232-38.313-29.61-16.92-81.932-46.823-113.668-64.96-16.524-9.444-36.86-9.23-53.18.56-26.532 15.913-67.455 40.46-95.98 57.567-20.207 12.12-32.573 33.96-32.573 57.52v119.53c0 19.93 10.58 38.37 27.793 48.43l104.718 61.21c13.925 8.14 31.113 8.31 45.204.47l115.943-64.58c14.8-8.25 23.98-23.85 23.98-40.79v-14.35z"/> - <path fill="#00A88A" d="M937.492 13.234h.272l.242.003h.027l.243.004h.027l.244.01h.027l.243.01h.027l.244.01h.028l.242.01h.028l.242.01h.028l.244.01h.027l.243.01h.027l.243.01.028.01.243.01.03.01.25.02h.03l.25.02h.03l.25.02.03.01.24.02h.03l.24.02h.03l.24.02.03.01.24.01.03.01.24.02h.03l.24.02h.03l.24.02h.03l.24.02h.03l.24.02.03.01.25.02.03.01.24.03h.03l.24.02.03.01.24.03h.03l.24.03h.03l.25.03h.03l.24.03.03.01.24.03h.03l.24.03h.03l.24.03.03.01.24.04.03.01.24.04.03.01.24.04.03.01.24.04h.03l.24.04.03.01.24.04.03.01.24.04.03.01.24.04.03.01.24.04.03.01.24.05h.03l.24.05.03.01.24.04h.03l.24.04.03.01.24.04.03.01.24.05.03.01.24.05h.02l.24.05h.03l.24.05.03.01.24.05.03.01.24.05.03.01.24.05.03.01.24.05h.02l.24.06.03.01.24.06.03.01.24.06.03.01.24.06h.02l.24.06.03.01.24.06.03.01.24.07h.03l.24.06h.03l.24.07.02.01.24.06.03.01.24.07h.03l.24.07.03.01.24.07.03.01.24.07.03.01.24.07h.03l.24.08.03.01.24.07.03.01.23.08.03.01.24.07h.03l.24.07.03.01.24.08.03.01.24.08.02.01.24.08.03.01.23.08.03.01.23.08.03.01.23.08.03.01.23.08.03.01.23.08.03.01.23.09.03.01.23.08.03.01.23.09.03.01.23.09.02.01.23.09.03.01.23.09.03.01.23.09.03.01.23.09.03.01.23.09.03.01.23.09.02.01.23.1.02.01.23.09.03.01.23.1.03.01.23.1.03.01.23.1.02.01.23.1.03.01.23.1.03.01.23.1.02.02.23.1.03.01.22.1.03.01.23.11.03.01.22.11.03.01.22.11.03.01.23.11.02.01.23.11.02.01.22.11.03.01.22.11.03.01.22.11.03.01.22.12.03.01.23.11.03.02.22.11.02.01.22.12.03.02.22.12.02.01.22.12.02.01.22.12.02.01.22.12.03.02.22.12.03.02.22.12.02.02.22.12.02.02.22.13.03.01.22.13 113.6 64.9.19.11.03.01.19.11.03.01.18.11.03.02.18.11.02.02.19.11.03.01.19.11.03.01.18.11.03.02.18.11.02.01.18.11.02.01.18.12.02.01.19.11.03.02.18.11.03.02.17.11.02.01.18.11.03.01.18.11.02.02.18.11.03.02.18.12.02.01.18.12.03.01.18.12.02.01.18.12.02.01.17.12.03.01.17.12.02.02.17.12.03.02.17.12.02.01.17.12.02.01.17.12.03.02.17.13.03.02.17.12.03.02.17.13.02.01.17.13.02.02.18.13.02.01.17.13.02.02.17.13.02.02.17.13.02.01.17.13.02.02.17.13.02.02.16.13.02.02.17.13.02.01.16.14.02.02.17.14.02.02.17.13.02.02.16.13.02.02.16.14.02.01.17.14.03.02.32.26.04.04.32.28.04.04.31.27.04.04.31.28.05.04.31.28.04.04.31.29.05.04.3.29.04.04.3.29.04.04.3.29.04.04.3.29.04.04.3.3.04.04.29.3.04.04.29.3.04.04.29.3.04.04.28.31.04.04.28.3.04.04.28.31.03.04.28.31.04.05.27.31.04.04.27.32.04.05.27.32.04.04.26.32.04.04.26.32.03.04.26.32.03.04.26.33.04.04.26.33.03.04.25.33.03.05.25.33.03.05.25.34.03.05.24.34.03.04.24.34.03.04.23.34.03.05.24.34.03.04.23.34.03.05.23.35.03.05.23.35.03.05.22.35.03.04.22.35.03.05.22.36.03.05.22.35.03.04.21.36.03.05.21.35.03.04.2.36.03.05.21.36.03.05.2.36.02.04.2.36.03.05.19.36.02.05.19.37.03.05.19.37.03.05.19.37.02.05.18.37.03.05.18.37.03.05.18.37.02.05.17.37.03.05.17.37.02.06.17.38.02.05.16.38.02.06.16.38.02.05.16.38.02.05.15.39.02.05.15.39.02.05.15.39.02.05.15.39.02.05.14.39.02.05.14.39.02.06.14.39.02.05.13.39.02.05.13.39.02.05.12.4.02.05.12.39.02.05.12.4.02.05.12.4.02.05.12.4.01.06.11.4.01.05.11.4.02.05.11.41.01.06.1.41.01.05.1.41.01.06.09.41.01.05.09.41.01.06.09.41.01.05.08.41.02.06.08.41.01.06.07.4.01.04.04.22v.03l.04.21.01.03.03.21.01.03.03.21.01.02.03.21.01.02.03.21.01.03.04.21.01.03.03.21.01.02.03.21v.03l.03.21.01.03.02.21.01.02.03.2v.03l.03.21v.03l.03.21v.02l.02.21v.03l.03.21.01.03.02.21v.03l.03.2v.02l.02.21.01.03.02.21v.03l.02.21v.03l.02.21v.02l.02.21.01.03.02.21.01.02.02.21.01.04.02.21v.03l.01.21.01.03.01.21v.02l.01.21v.03l.01.22v.03l.01.21.01.03.01.21v.02l.01.21v.03l.01.22v.03l.01.21v.03l.01.22v.03l.01.21v.27l.01.21v.26l.01.21v138.4l-.01.22v.54l-.01.23v.03l-.01.22v.03l-.01.23v.03l-.01.22v.03l-.01.22v.03l-.01.23-.01.03-.01.22v.02l-.02.23v.02l-.02.23v.03l-.02.23v.03l-.02.23v.03l-.01.23v.03l-.02.22v.03l-.02.22v.03l-.02.22v.03l-.02.22-.01.03-.02.23-.01.03-.02.22v.03l-.02.22-.01.03-.03.22v.03l-.02.22-.01.03-.03.22v.03l-.03.22v.03l-.03.23v.03l-.03.22v.03l-.03.22v.03l-.03.22-.01.04-.03.22v.02l-.03.22-.01.04-.03.23-.01.03-.03.22-.01.02-.03.22-.01.03-.04.22v.03l-.04.22-.01.03-.04.22v.02l-.04.22v.02l-.04.22-.01.03-.04.22v.03l-.04.22v.03l-.04.22v.03l-.04.22-.01.03-.04.22-.01.02-.05.22-.01.03-.04.22-.01.02-.05.21v.03l-.05.22-.01.03-.05.22v.03l-.05.22v.02l-.05.21-.01.02-.05.21-.01.02-.05.22v.03l-.06.22-.01.03-.05.21v.03l-.06.22-.01.03-.05.21-.01.02-.06.21v.03l-.06.22v.03l-.06.21-.01.02-.06.21v.03l-.06.21-.01.03-.06.22-.01.03-.06.21-.01.03-.06.21-.01.02-.06.21-.01.03-.06.21-.01.02-.06.21-.01.03-.06.21-.01.03-.06.2v.02l-.07.21-.01.03-.07.21-.01.03-.07.21-.01.03-.07.21-.01.03-.08.21-.01.02-.07.21-.01.03-.07.2-.01.02-.07.21-.01.03-.07.21-.01.02-.07.21-.01.03-.08.21-.02.02-.08.21-.01.03-.08.21-.01.03-.08.2-.01.02-.08.2-.01.02-.08.2-.01.03-.08.2-.01.02-.08.2-.01.03-.08.21-.01.03-.08.2-.01.03-.08.21-.01.03-.09.2-.01.02-.09.21-.01.03-.09.2-.01.03-.09.2-.02.02-.08.2-.01.02-.09.2-.01.03-.09.2-.01.03-.09.2-.02.03-.09.2-.01.02-.09.2-.01.03-.09.2-.02.03-.1.2-.01.02-.1.19-.01.03-.1.2-.01.03-.1.2-.01.03-.1.19-.01.02-.1.2-.01.02-.1.2-.01.03-.1.19-.01.02-.1.19-.02.02-.11.19-.01.02-.1.2-.01.02-.11.19-.01.02-.1.2-.01.02-.11.2-.01.03-.11.2-.01.02-.11.19-.01.02-.11.19-.01.02-.11.19-.01.02-.11.19-.02.02-.11.19-.01.03-.11.19-.02.02-.11.19-.01.03-.11.19-.01.02-.11.19-.01.02-.11.19-.01.02-.12.19-.01.02-.12.18-.01.02-.12.19-.02.02-.11.19-.02.03-.12.18-.01.02-.12.19-.02.03-.12.19-.01.02-.12.18-.02.03-.12.19-.01.03-.12.18-.01.02-.12.18-.01.02-.12.18-.02.03-.12.18-.02.02-.12.18-.01.02-.13.18-.01.02-.12.18-.02.02-.13.18-.02.02-.13.18-.02.03-.13.18-.02.02-.12.18-.02.03-.13.17-.02.02-.13.18-.01.02-.13.18-.02.02-.13.18-.02.02-.13.18-.01.02-.13.17-.02.02-.13.17-.01.02-.13.18-.02.03-.14.17-.01.02-.14.17-.02.02-.14.17-.02.03-.14.17-.02.02-.13.17-.02.02-.14.17-.02.03-.14.17-.02.02-.14.17-.02.02-.15.17-.02.02-.14.17-.02.02-.14.17-.02.02-.14.17-.02.02-.15.17-.02.03-.14.17-.01.02-.14.16-.02.02-.15.16-.02.02-.14.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.03-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.16.16-.01.02-.15.16-.02.02-.16.16-.02.03-.16.16-.02.02-.15.16-.02.02-.16.16-.02.02-.16.16-.02.02-.16.15-.02.02-.16.16-.02.02-.16.16-.02.02-.16.15-.02.02-.16.15-.03.02-.16.15-.02.02-.16.15-.02.02-.16.15-.02.02-.16.15-.02.02-.17.15-.02.02-.16.15-.02.02-.17.14-.02.02-.17.15-.02.02-.17.15-.02.01-.17.14-.02.02-.17.15-.02.02-.17.15-.02.01-.17.14-.02.02-.17.15-.02.01-.17.14-.02.01-.17.14-.02.02-.17.14-.02.01-.17.14-.02.02-.17.14-.02.02-.18.14-.02.02-.17.14-.02.02-.18.14-.02.02-.17.14-.02.02-.18.14-.02.02-.18.13-.02.02-.18.14-.02.02-.18.13-.02.01-.18.13-.02.02-.18.14-.02.02-.18.13-.02.01-.18.13-.02.02-.18.13-.02.01-.18.13-.02.01-.19.13-.02.02-.18.13-.02.01-.18.13-.02.01-.18.13-.02.02-.19.12-.03.02-.18.13-.02.02-.19.13-.03.02-.19.13-.02.02-.19.13-.02.02-.18.12-.02.01-.19.12-.02.02-.19.12-.03.02-.19.12-.02.01-.19.12-.02.02-.19.12-.02.01-.19.12-.02.02-.19.12-.02.01-.19.12-.02.02-.19.12-.03.01-.2.11-.03.02-.19.12-.03.02-.2.11-.02.02-.2.11-.03.01-.2.12-.03.02-.19.11-.02.02-.2.12-.03.02-.19.11-.01.01-115.96 64.58-.01.01-.18.1-.03.01-.19.11-.03.01-.19.11-.03.01-.19.1-.02.02-.19.11-.02.01-.19.1-.03.01-.19.1-.03.01-.19.1-.02.01-.19.1-.03.01-.19.1-.03.02-.19.1-.02.01-.19.1-.03.01-.2.1-.03.01-.2.09-.02.02-.19.09-.03.01-.2.09-.03.01-.19.09-.02.01-.19.09-.03.01-.2.09-.03.01-.19.09-.03.01-.19.09-.03.01-.2.08-.03.01-.19.09-.02.01-.19.09-.03.01-.2.09-.03.01-.19.09-.03.01-.2.08-.02.01-.2.09-.03.01-.19.08-.03.01-.2.08-.03.02-.2.08-.02.01-.2.08-.03.01-.2.08-.02.01-.2.08-.02.01-.2.08-.03.01-.2.08-.02.01-.2.08-.03.01-.2.08-.03.01-.2.07-.03.01-.2.07-.03.01-.2.07-.03.01-.2.07-.02.01-.2.07-.03.01-.2.07-.03.01-.2.07-.02.01-.2.07-.03.01-.2.07-.03.01-.2.06-.03.01-.21.06h-.02l-.2.06-.03.01-.21.07h-.1l-.21.06-.04.01-.4.12-.05.02-.41.12-.05.01-.41.12-.05.02-.41.11-.05.01-.41.11-.06.01-.41.1-.05.01-.41.1-.053.01-.41.09-.06.01-.41.09-.05.01-.41.09-.06.01-.412.09-.06.01-.41.09-.05.01-.41.08-.05.02-.42.08-.05.01-.41.07-.05.01-.42.07-.05.01-.42.06-.05.01-.42.06h-.05l-.42.06-.06.01-.41.06h-.05l-.42.06-.06.01-.42.05-.05.01-.42.05-.06.01-.42.04h-.05l-.42.04h-.05l-.42.04-.06.01-.42.03-.05.01-.42.03h-.06l-.42.02h-.05l-.42.03-.05.01-.42.02-.05.01-.42.02h-.06l-.42.02h-.05l-.42.01h-.05l-.42.01h-.05l-.42.01h-1l-.42-.01h-.06l-.41-.01h-.1l-.42-.01h-.06l-.42-.01h-.1l-.42-.02h-.05l-.42-.02h-.05l-.42-.02h-.06l-.42-.03-.06-.01-.42-.03h-.05l-.42-.03h-.05l-.42-.04-.05-.01-.41-.04-.052-.01-.42-.04h-.05l-.42-.05h-.06l-.42-.05h-.05l-.42-.06-.06-.01-.42-.06-.05-.01-.42-.07-.06-.01-.42-.07-.06-.01-.42-.07-.05-.01-.41-.08-.06-.01-.42-.08-.05-.01-.42-.08-.05-.01-.42-.09-.06-.01-.41-.09-.06-.01-.42-.09-.05-.01-.41-.09-.05-.01-.41-.1-.05-.01-.41-.1-.05-.02-.41-.1-.05-.01-.41-.11-.05-.01-.41-.11-.05-.01-.41-.12-.05-.01-.41-.12-.05-.02-.4-.12-.05-.01-.4-.13-.05-.01-.41-.13-.05-.02-.4-.13-.04-.01-.21-.07-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.02-.01-.2-.07-.03-.01-.2-.07-.02-.01-.2-.07-.02-.01-.2-.07-.02-.01-.2-.07-.02-.01-.2-.08-.03-.01-.2-.07-.03-.01-.2-.08-.02-.01-.2-.08-.03-.01-.2-.08-.02-.01-.2-.08-.02-.01-.2-.08-.02-.01-.2-.08-.02-.01-.2-.08-.03-.01-.2-.08-.02-.01-.19-.09-.03-.01-.2-.09-.03-.02-.19-.08-.02-.01-.19-.08-.02-.01-.2-.09-.03-.01-.19-.09-.03-.01-.19-.09-.02-.01-.2-.09-.03-.01-.19-.09-.03-.01-.19-.09-.03-.01-.19-.09-.03-.01-.2-.09-.03-.01-.2-.1-.03-.01-.2-.09-.03-.01-.19-.1-.03-.01-.19-.09-.02-.01-.19-.1-.03-.01-.19-.1-.03-.01-.19-.1-.02-.01-.19-.1-.03-.01-.19-.1-.03-.01-.19-.1-.02-.01-.19-.1-.02-.02-.19-.1-.02-.01-.19-.1-.03-.01-.19-.11-.02-.01-.19-.1-.02-.02-.19-.11-.02-.01-.19-.11-.03-.01-.19-.11-.02-.02-.19-.11-.02-.01-.18-.1-.01-.01-105-61.25-.01-.01-.22-.13-.02-.01-.22-.13-.03-.01-.22-.14-.02-.01-.23-.14-.03-.01-.22-.13-.02-.01-.22-.14-.03-.02-.22-.14-.02-.01-.22-.14-.02-.02-.22-.14-.03-.02-.22-.14-.03-.01-.22-.14-.02-.02-.22-.14-.03-.02-.22-.15-.02-.02-.22-.15-.02-.02-.22-.14-.02-.01-.21-.15-.02-.02-.21-.15-.02-.02-.21-.15-.02-.02-.22-.15-.02-.01-.21-.15-.02-.02-.21-.15-.02-.01-.21-.15-.02-.02-.21-.15-.02-.01-.21-.15-.02-.01-.21-.15-.02-.02-.21-.16-.02-.02-.21-.15-.02-.02-.21-.16-.02-.02-.2-.16-.02-.02-.2-.16-.02-.02-.2-.15-.02-.02-.21-.16-.03-.02-.2-.16-.02-.01-.21-.16-.02-.02-.2-.16-.02-.02-.2-.16-.02-.02-.2-.16-.03-.02-.2-.16-.02-.02-.2-.17-.02-.02-.2-.17-.02-.02-.2-.16-.02-.02-.2-.17-.02-.02-.2-.17-.02-.02-.19-.17-.02-.01-.2-.17-.02-.02-.19-.17-.02-.02-.2-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.2-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.19-.18-.02-.02-.19-.17-.02-.02-.19-.17-.02-.02-.19-.18-.02-.02-.18-.17-.02-.02-.18-.18-.01-.01-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.17-.18-.02-.02-.18-.19-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.17-.19-.02-.02-.18-.18-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.16-.19-.01-.02-.17-.2-.02-.02-.17-.19-.02-.02-.16-.19-.01-.02-.17-.19-.01-.02-.16-.19-.02-.02-.16-.2-.02-.02-.16-.2-.02-.02-.16-.2-.01-.02-.16-.19-.02-.03-.16-.19-.02-.02-.16-.2-.02-.02-.15-.2-.02-.02-.16-.2-.02-.02-.15-.2-.02-.02-.16-.21-.02-.02-.15-.2-.02-.02-.15-.2-.02-.02-.15-.21-.02-.02-.15-.2-.02-.02-.15-.203-.02-.03-.15-.21-.01-.02-.15-.2-.02-.02-.14-.21-.02-.02-.14-.21-.02-.02-.15-.204-.01-.02-.15-.2-.02-.03-.15-.21-.01-.02-.14-.21-.02-.02-.14-.21-.01-.03-.14-.21-.02-.02-.14-.21-.02-.02-.14-.21-.02-.02-.14-.21-.02-.02-.14-.21-.01-.02-.14-.21-.01-.02-.14-.21-.02-.03-.14-.22-.01-.02-.14-.22-.01-.02-.13-.21-.01-.02-.13-.22-.01-.02-.13-.22-.02-.03-.13-.21-.01-.02-.13-.22-.02-.03-.13-.21-.01-.02-.12-.21-.02-.02-.13-.22-.02-.02-.13-.22-.01-.03-.13-.22-.01-.03-.12-.22-.01-.02-.12-.22-.01-.02-.13-.22-.01-.02-.12-.22-.01-.02-.13-.22-.02-.03-.12-.22-.01-.02-.12-.22-.015-.02-.12-.22-.01-.02-.11-.23-.01-.02-.12-.22-.01-.02-.12-.22-.01-.03-.12-.23-.01-.02-.11-.22-.01-.03-.12-.22-.01-.02-.11-.22-.01-.025-.11-.23-.01-.02-.11-.23-.01-.02-.11-.23-.01-.03-.11-.23-.01-.02-.11-.23-.01-.03-.11-.23-.02-.03-.11-.23-.01-.03-.1-.23-.02-.03-.1-.23-.01-.03-.1-.23-.01-.03-.1-.23-.01-.03-.1-.23-.01-.03-.1-.23-.01-.03-.1-.23-.01-.02-.1-.23-.01-.02-.1-.24-.01-.02-.09-.23-.01-.03-.1-.24-.01-.02-.1-.24-.01-.03-.1-.24-.01-.03-.09-.24-.01-.02-.09-.23-.01-.03-.09-.24-.01-.03-.09-.23-.01-.02-.09-.24-.01-.025-.09-.24-.01-.03-.09-.24-.01-.03-.09-.23-.01-.03-.09-.24-.01-.02-.09-.24-.01-.02-.09-.24v-.02l-.09-.24-.01-.03-.09-.24-.01-.02-.08-.24-.01-.02-.08-.24-.01-.02-.08-.24-.01-.03-.08-.24-.01-.02-.07-.24-.01-.03-.07-.24-.01-.03-.08-.24-.01-.03-.07-.24-.01-.03-.07-.24-.01-.03-.08-.25v-.03l-.07-.24-.01-.03-.07-.25-.01-.03-.07-.24-.01-.03-.07-.24-.01-.03-.07-.24v-.03l-.07-.25-.01-.03-.07-.25-.01-.03-.06-.24-.01-.02-.07-.25-.01-.03-.06-.25v-.02l-.06-.25-.01-.03-.06-.25v-.03l-.06-.25v-.02l-.06-.25-.01-.03-.06-.25v-.03l-.06-.25-.01-.02-.06-.25-.01-.03-.06-.25-.01-.03-.06-.25-.01-.02-.05-.25v-.1l-.05-.25v-.03l-.05-.25-.01-.03-.05-.25-.01-.02-.05-.25-.01-.03-.05-.25-.01-.03-.05-.25-.01-.03-.05-.25-.01-.03-.04-.25v-.03l-.04-.25-.01-.03-.04-.25v-.03l-.04-.26-.01-.02-.04-.26-.01-.03-.04-.26v-.03l-.04-.25-.01-.03-.03-.25-.005-.02-.04-.26-.01-.03-.03-.26v-.03l-.03-.26V278l-.03-.26-.01-.03-.03-.25v-.03l-.03-.26v-.03l-.03-.25v-.02l-.03-.26-.01-.03-.02-.26-.01-.03-.028-.26-.01-.03-.02-.26-.01-.03-.02-.26-.01-.03-.02-.26v-.03l-.02-.25v-.03l-.02-.26v-.03l-.02-.26v-.03l-.02-.26v.02l-.02-.26v-.03l-.01-.26v-.03l-.02-.26v-.03l-.01-.26v-.03l-.01-.26v-.03l-.02-.26v-.03l-.01-.26v-.1l-.01-.26v-.02l-.01-.26v-.03l-.01-.26v-.1l-.01-.26v-.025l-.01-.26v-.03l-.01-.26v-.03l-.01-.26V148.61l.01-.31v-.35l.01-.3v-.36l.01-.3.01-.3v-.03l.01-.3v-.03l.02-.3v-.023l.01-.31v-.03l.02-.31v-.03l.01-.3V145l.02-.3v-.03l.02-.3v-.03l.02-.3v-.03l.02-.3v-.03l.02-.3v-.03l.02-.3v-.03l.03-.3.01-.03.02-.3v-.03l.03-.3.01-.026.03-.3v-.028l.023-.3v-.02l.03-.3v-.03l.03-.3v-.03l.03-.3v-.02l.04-.3v-.03l.04-.3v-.03l.04-.3v-.02l.03-.3v-.03l.04-.29v-.03l.04-.29v-.02l.04-.29v-.02l.05-.3v-.03l.04-.29.01-.03.04-.3v-.03l.044-.3.01-.02.04-.29v-.02l.05-.29.01-.03.05-.292v-.02l.05-.29.01-.03.05-.29.01-.03.05-.3v-.03l.06-.292.01-.03.05-.29.01-.025.05-.29.01-.02.06-.29.01-.03.06-.29v-.03l.06-.29.01-.03.06-.29.01-.02.06-.29.01-.026.06-.29v-.03l.07-.29v-.02l.07-.29.01-.03.06-.29.01-.03.07-.29v-.02l.07-.29v-.03l.07-.29v-.03l.07-.29.01-.03.07-.29.01-.02.07-.29.01-.03.07-.29.01-.03.08-.29.006-.03.08-.28.01-.03.08-.29.01-.02.08-.28.01-.02.08-.29.01-.03.08-.28v-.02l.08-.29.01-.03.08-.28.01-.03.08-.29.01-.02.09-.28.01-.03.09-.28.01-.02.09-.28.01-.03.09-.28v-.02l.09-.28.01-.02.1-.28.01-.03.09-.28.01-.03.1-.28v-.02l.09-.28.01-.03.09-.28.01-.03.09-.28.01-.03.1-.28.01-.02.1-.28.01-.02.1-.28.01-.02.1-.27.01-.03.11-.28.01-.02.1-.27.01-.03.1-.28.01-.02.1-.28.01-.03.1-.28.01-.03.11-.28.01-.02.11-.27.01-.02.11-.27.01-.02.11-.27.01-.03.11-.27.01-.02.11-.27.01-.03.12-.28.01-.02.11-.27.02-.03.12-.27.01-.02.12-.27.01-.03.12-.27.01-.02.12-.27.01-.02.12-.27.01-.02.12-.27.01-.02.12-.27.01-.03.12-.27.01-.02.12-.26.01-.03.13-.26.01-.02.13-.26.01-.03.13-.27.01-.03.13-.26.01-.02.13-.26.01-.03.13-.27.01-.02.13-.26.02-.02.13-.27.01-.02.13-.26.01-.03.14-.26.01-.02.13-.26.01-.03.14-.26.01-.02.14-.26.01-.03.14-.26.01-.02.14-.26.02-.02.14-.25.01-.02.14-.26.02-.02.14-.25.01-.02.15-.26.01-.02.15-.26.01-.03.14-.26.02-.02.15-.26.01-.02.15-.25.02-.02.15-.25.01-.03.15-.25.02-.02.15-.25.01-.02.15-.25.01-.02.15-.25.017-.02.15-.25.01-.02.15-.25.01-.02.16-.25.01-.02.16-.25.02-.03.15-.25.02-.02.16-.25.01-.02.16-.25.02-.03.16-.25.01-.02.16-.24.02-.02.16-.24.01-.02.17-.24.01-.03.16-.24.02-.03.16-.25.02-.02.17-.24.02-.02.17-.24.02-.02.17-.24.01-.02.17-.24.02-.02.17-.24.02-.02.17-.23.01-.02.17-.24.02-.02.18-.24.01-.02.17-.23.01-.02.18-.23.02-.03.17-.24.02-.02.18-.24.01-.02.18-.23.02-.02.18-.23.02-.02.18-.24.01-.02.18-.23.02-.02.18-.24.02-.02.188-.23.02-.02.18-.23.02-.02.19-.23.01-.02.19-.23.02-.02.19-.23.02-.02.19-.23.02-.02.19-.22.02-.02.19-.23.02-.02.19-.22.02-.02.19-.22.02-.02.2-.22.02-.02.2-.23.02-.02.19-.22.01-.02.2-.22.02-.02.2-.22.02-.02.2-.22.01-.02.2-.22.02-.02.2-.22.01-.01.2-.21.02-.03.2-.22.02-.02.2-.21.02-.02.21-.21.02-.02.21-.22.02-.02.21-.21.02-.02.21-.22.02-.02.2-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.21.02-.01.21-.21.02-.02.21-.21.02-.02.22-.21.02-.02.22-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.19.02-.02.22-.19.02-.02.22-.2.02-.02.23-.19.02-.02.23-.19.02-.02.22-.19.02-.02.23-.19.02-.02.22-.2.02-.02.23-.19.02-.02.23-.19.02-.02.23-.19.02-.02.24-.19.02-.01.23-.18.02-.02.24-.18.02-.02.23-.19.03-.02.24-.19.02-.02.23-.18.02-.01.24-.18.02-.02.23-.18.03-.02.24-.18.02-.02.24-.18.02-.02.24-.18.02-.02.24-.18.02-.01.24-.17.02-.01.24-.18.02-.02.24-.18.02-.02.24-.18.02-.02.25-.17.02-.02.24-.17.02-.02.25-.17.02-.01.25-.17.02-.02.25-.17.03-.01.246-.17.03-.02.25-.17.02-.02.25-.17.02-.01.25-.17.03-.02.25-.16.02-.01.25-.16.02-.02.25-.16.02-.02.26-.17.02-.01.26-.16.02-.01.25-.16.02-.01.26-.16.02-.02.26-.16.02-.01.26-.16.02-.02.26-.16.03-.01.25-.15.02-.01 96-57.54h.015l.21-.12.03-.02.21-.12.02-.01.22-.12.02-.01.22-.12.02-.02.22-.12.02-.02.22-.13.02-.01.22-.12.02-.02.22-.12.02-.02.22-.12.02-.02.22-.12.02-.01.22-.12.03-.01.22-.12.02-.01.22-.11.03-.01.22-.11.02-.01.22-.11.02-.02.22-.12.03-.01.22-.11.03-.01.22-.11.03-.01.23-.11.02-.01.22-.11.02-.02.23-.1.02-.02.23-.11.02-.02.22-.1.03-.01.23-.11.02-.01.23-.1.03-.01.22-.11.03-.01.23-.1.03-.01.23-.11.02-.01.23-.11.02-.01.23-.1.02-.01.23-.1.03-.01.23-.1.02-.01.23-.1.03-.01.23-.1.02-.01.23-.09.03-.01.23-.1.03-.01.23-.09.02-.01.23-.1.02-.01.23-.09.02-.01.23-.1.03-.01.23-.09.03-.01.23-.08.02-.01.23-.09.02-.01.23-.08.03-.01.23-.08h.02l.23-.09.03-.01.23-.09.03-.01.23-.08.03-.01.24-.08.02-.01.23-.08.03-.01.23-.08.02-.01.23-.08.02-.01.24-.08.02-.01.23-.08.03-.01.23-.07.03-.01.23-.07.03-.01.23-.08.03-.01.24-.07.02-.01.24-.07.03-.01.23-.07.03-.01.24-.07.03-.01.24-.07.03-.01.23-.07h.02l.24-.06.02-.01.24-.06.03-.01.24-.07.03-.01.23-.06.02-.01.24-.06.03-.01.24-.06h.03l.24-.06.03-.01.24-.06.03-.01.23-.06.03-.01.24-.06.03-.01.24-.06.02-.01.24-.06.03-.01.24-.06h.03l.24-.05.03-.01.24-.05.03-.01.24-.06h.03l.24-.05.03-.01.24-.05.03-.01.24-.05h.02l.24-.05.03-.01.24-.05.03-.01.24-.04.02-.01.24-.04.03-.01.24-.04.03-.01.24-.04h.03l.24-.04.03-.01.24-.04.03-.01.24-.04h.03l.24-.04h.03l.24-.04h.03l.24-.04h.03l.24-.03.03-.01.24-.03h.02l.24-.03h.03l.25-.03.02-.01.24-.03h.03l.24-.03h.03l.24-.03h.03l.25-.03h.03l.24-.02h.03l.24-.03h.03l.24-.02h.03l.24-.02.03-.01.24-.02h.03l.24-.02h.03l.24-.02h.03l.24-.02.03-.01.24-.02h.02l.24-.02h.03l.25-.02h.03l.24-.02h.02l.24-.02h.02l.24-.01h.03l.24-.01h.03l.25-.01h.04l.24-.02h.03l.24-.01h.03l.24-.01h.03l.24-.01h.57l.24-.01h1.62zm-.22 27l-.16.002h-.162l-.16.002-.16.003-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.02-.16.02-.16.01-.158.01-.16.02-.16.02-.16.02-.16.02-.158.02-.16.02-.16.02-.157.02-.16.02-.16.02-.158.03-.16.02-.16.03-.16.03-.16.03-.16.02-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.03-.16.04-.16.04-.16.04-.16.04-.15.04-.16.04-.16.04-.16.04-.16.05-.15.05-.15.04-.16.05-.16.05-.16.05-.16.05-.16.04-.15.05-.16.05-.16.05-.16.05-.15.05-.16.05-.16.05-.15.05-.15.05-.15.05-.15.06-.16.06-.16.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.07-.15.07-.15.07-.15.07-.14.07-.15.07-.15.07-.15.07-.15.07-.15.07-.15.07-.15.07-.15.08-.15.07-.15.07-.15.08-.15.07-.15.07-.15.08-.14.08-.14.07-.14.08-.15.08-.14.08-.14.08-.14.08-.15.08-.15.08-.14.08-.14.08-.15.08-.14.08-.16.09-95.95 57.55-.2.12-.19.12-.19.12-.19.12-.19.12-.19.11-.18.12-.18.12-.18.12-.18.12-.19.12-.18.12-.18.12-.18.13-.18.12-.18.13-.18.12-.18.13-.18.13-.18.13-.18.13-.18.13-.17.13-.18.13-.17.13-.18.13-.18.13-.17.13-.18.13-.17.14-.17.13-.17.13-.17.14-.17.13-.17.13-.17.14-.17.14-.16.14-.17.14-.16.14-.16.14-.16.14-.16.15-.16.14-.17.14-.16.15-.16.14-.16.14-.16.14-.16.15-.16.15-.16.15-.16.15-.15.15-.16.15-.16.15-.15.15-.15.15-.15.15-.15.15-.15.15-.15.16-.15.15-.15.15-.15.16-.15.16-.14.16-.14.16-.15.16-.14.16-.15.16-.15.16-.14.15-.14.16-.14.16-.14.16-.14.16-.14.16-.14.16-.14.16-.14.16-.14.16-.14.16-.14.16-.13.17-.14.17-.14.17-.13.16-.13.17-.14.17-.13.16-.13.17-.13.17-.13.17-.13.17-.12.17-.13.17-.12.17-.13.17-.13.17-.13.17-.13.17-.12.18-.12.17-.13.17-.12.18-.12.18-.12.18-.12.18-.12.18-.12.18-.12.18-.12.18-.12.18-.12.18-.12.18-.11.18-.11.18-.11.18-.11.18-.11.18-.11.18-.11.18-.11.18-.11.19-.11.18-.11.18-.1.18-.11.19-.11.19-.1.18-.11.19-.1.19-.1.19-.1.19-.1.19-.1.19-.1.19-.1.19-.1.19-.09.19-.09.19-.09.19-.09.19-.09.19-.09.2-.09.19-.09.19-.09.19-.09.2-.09.19-.09.19-.09.2-.09.19-.08.2-.08.2-.08.19-.08.2-.08.2-.08.2-.08.19-.08.2-.08.2-.08.2-.07.2-.07.2-.08.2-.08.2-.08.2-.07.2-.08.2-.07.2-.07.2-.07.21-.07.2-.07.2-.07.2-.07.2-.07.21-.07.2-.07.21-.07.2-.06.2-.06.21-.06.21-.06.2-.06.21-.06.21-.05.21-.05.21-.06.21-.05.21-.06.21-.05.21-.05.21-.05.21-.05.21-.05.21-.05.21-.05.21-.05.21-.04.21-.05.21-.04.21-.05.21-.05.21-.04.21-.04.21-.05.21-.04.22-.04.21-.04.21-.04.21-.04.21-.04.21-.03.21-.03.21-.03.21-.03.22-.04.21-.03.21-.03.21-.03.21-.03.21-.03.21-.03.22-.02.22-.03.21-.02.22-.03.21-.02.22-.02.22-.02.21-.02.22-.02.22-.02.22-.02.22-.02.22-.02.22-.02.22-.01.22-.01.22-.02.22-.01.22-.01.22-.01.22-.01.22-.01.21v.22l-.01.22v.44l-.01.22v121.16l.01.18.01.18.01.18.01.17.01.18.01.18.01.18.01.18.01.17.01.18.01.17.01.18.01.18.01.17.01.17.01.17.01.18.02.17.02.17.02.17.02.17.02.18.02.18.02.17.02.18.02.17.02.17.03.17.03.17.03.18.02.17.02.18.03.17.03.17.03.17.03.17.03.17.03.17.03.18.03.17.03.17.03.17.03.17.03.17.04.17.04.16.04.16.04.18.04.17.04.17.04.17.04.17.04.16.04.17.04.16.04.17.05.17.04.17.05.17.05.17.04.17.05.16.05.17.05.17.05.16.05.17.05.17.05.17.05.17.05.17.05.16.05.17.05.17.05.16.06.16.06.16.06.17.05.16.06.16.06.17.06.16.06.16.06.16.06.16.07.16.06.16.07.16.06.16.06.16.06.16.07.16.07.16.07.16.07.16.07.16.07.16.06.16.07.16.07.15.07.16.07.16.08.16.07.15.07.15.08.16.08.16.07.15.08.15.08.15.08.16.08.15.08.15.08.16.08.15.08.15.08.15.08.15.08.15.08.15.08.15.09.15.09.15.08.15.08.15.09.15.09.15.09.15.09.14.09.15.09.15.09.15.09.14.1.14.09.15.09.15.09.15.09.14.1.14.1.15.1.14.1.15.09.14.09.15.1.14.1.14.1.14.1.14.1.14.1.14.1.14.11.14.1.14.1.13.11.14.1.14.1.13.11.13.11.14.11.13.11.13.1.13.11.13.11.13.1.14.11.13.11.13.11.13.11.13.11.13.11.13.12.13.11.13.11.13.12.13.11.13.12.13.12.13.11.13.12.12.12.13.11.12.12.12.12.13.12.13.12.13.12.12.12.12.12.12.12.12.13.12.12.12.12.12.13.12.12.12.13.12.12.12.13.11.13.12.13.11.13.12.13.12.13.11.13.11.13.11.13.11.13.11.13.11.14.12.14.11.13.11.13.11.13.11.13.11.14.11.13.11.13.11.13.11.14.11.13.1.14.11.14.1.14.1.14.1.14.11.14.11.14.1.14.11.14.1.14.1.15.11.14.1.14.1.15.1.15.1.14.1.14.09.15.09.14.09.15.1.14.09.15.1.15.09.15.1.15.09.15.09.15.09.15.09.15.09.15.09.17.1 104.7 61.21.13.07.12.06.12.07.12.07.12.06.11.06.12.07.12.06.12.07.12.06.11.06.12.06.12.07.12.06.12.06.12.06.11.06.12.06.12.06.12.06.12.06.12.06.12.05.12.06.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.13.05.12.05.12.05.12.05.12.05.12.04.12.04.12.05.13.05.12.05.12.04.12.04.13.04.12.04.12.04.12.04.11.03.26.08.25.08.25.08.25.08.25.07.25.07.25.07.25.06.25.06.25.06.25.06.25.06.25.05.25.06.26.05.26.05.25.04.26.04.25.04.25.04.25.04.26.04.25.04.26.03.25.03.25.03.26.02.25.02.26.02.25.02.26.02.26.01.26.01.26.01.26.01.25.01.26.01h.26l.26.01h.26l.25-.01h.26l.26-.01.26-.01.25-.01.26-.01.26-.01.26-.01.26-.02.25-.02.26-.02.25-.03.26-.03.25-.03.26-.03.26-.03.25-.04.26-.04.25-.04.25-.04.25-.04.25-.04.26-.05.26-.05.25-.05.25-.06.26-.06.26-.06.25-.06.26-.06.25-.07.25-.07.25-.07.25-.07.25-.07.26-.08.12-.03.13-.04.12-.04.12-.04.12-.04.12-.04.12-.04.12-.04.12-.04.12-.05.12-.04.12-.04.12-.05.12-.04.12-.05.12-.04.12-.04.13-.04.12-.04.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.06.12-.06.12-.05.12-.05.12-.06.12-.06.12-.06.12-.06.12-.05.12-.06.12-.06.12-.06.12-.05.12-.06.12-.06.11-.06.12-.06.12-.06.12-.06.12-.07.11-.06.12-.06.12-.07.13-.07 115.93-64.56.13-.07.12-.07.12-.07.13-.07.12-.07.12-.07.12-.07.12-.07.12-.07.12-.07.12-.08.12-.07.12-.08.12-.08.12-.07.12-.07.11-.07.11-.08.12-.08.11-.08.11-.08.12-.08.12-.08.11-.08.11-.07.12-.08.12-.08.12-.08.11-.08.11-.08.11-.08.11-.09.12-.08.11-.09.1-.08.11-.09.11-.08.11-.09.11-.09.11-.09.1-.08.1-.09.11-.09.11-.09.11-.09.11-.09.1-.09.11-.09.11-.09.1-.09.1-.09.11-.09.1-.09.1-.09.1-.1.1-.09.1-.09.11-.09.1-.09.1-.09.1-.09.1-.09.1-.1.1-.09.1-.1.1-.1.1-.1.1-.1.1-.1.09-.09.1-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.09-.1.1-.11.09-.1.09-.1.09-.1.09-.1.09-.1.09-.11.09-.1.09-.11.09-.1.09-.11.08-.1.09-.1.09-.1.08-.11.09-.1.09-.11.08-.1.08-.1.08-.11.08-.11.08-.11.09-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.11.08-.12.08-.11.08-.11.08-.11.07-.11.07-.11.08-.12.08-.11.07-.11.08-.12.08-.11.07-.12.08-.12.07-.11.07-.11.07-.11.07-.12.08-.12.07-.11.07-.12.07-.12.06-.12.06-.12.07-.11.06-.12.07-.12.07-.12.06-.12.07-.12.06-.12.06-.12.06-.12.06-.12.06-.12.06-.13.06-.12.06-.12.06-.13.06-.12.06-.12.06-.13.05-.12.06-.12.06-.13.05-.13.05-.12.05-.13.05-.12.06-.12.05-.13.06-.13.05-.12.06-.13.05-.13.05-.13.06-.12.05-.12.05-.13.05-.13.05-.12.05-.13.05-.13.05-.13.04-.13.05-.13.05-.13.05-.12.05-.13.05-.13.04-.13.04-.13.05-.13.04-.13.05-.13.04-.13.04-.13.04-.13.05-.14.04-.13.04-.13.04-.13.04-.12.04-.13.04-.14.03-.13.04-.12.04-.14.03-.14.03-.13.03-.14.04-.13.03-.14.04-.13.03-.14.03-.13.03-.13.03-.13.03-.13.03-.13.03-.13.03-.14.02-.13.03-.14.03-.14.03-.14.03-.13.02-.14.02-.14.03-.13.02-.14.02-.14.02-.13.02-.13.02-.14.02-.14.02-.13.02-.14.02-.14.02-.13.02-.14.02-.14.02-.14.02-.13.02-.15.01-.14.02-.13.01-.13.02-.14.01-.14.01-.14.01-.14.01-.14.01-.14.01-.14v-.29l.01-.14.01-.14.01-.14.01-.14.01-.13.01-.15.01-.14v-.14l.01-.14v-138l-.01-.13V136l-.01-.13v-.25l-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.12-.01-.13-.01-.12-.01-.12-.01-.12-.02-.13-.01-.14-.01-.12-.01-.13-.02-.13-.02-.13-.01-.12-.02-.13-.02-.12-.02-.13-.02-.13-.02-.12-.02-.12-.02-.12-.02-.12-.02-.12-.02-.12-.02-.12-.02-.11-.05-.26-.05-.25-.05-.24-.06-.25-.06-.24-.05-.24-.06-.25-.06-.25-.06-.24-.07-.24-.07-.24-.07-.24-.07-.24-.08-.24-.08-.24-.07-.24-.07-.24-.08-.24-.09-.24-.08-.23-.08-.24-.08-.23-.09-.23-.09-.23-.09-.23-.09-.23-.1-.23-.09-.23-.1-.23-.1-.23-.1-.22-.11-.23-.11-.22-.11-.22-.11-.228-.12-.22-.11-.23-.12-.22-.12-.22-.12-.22-.12-.216-.12-.22-.13-.22-.13-.21-.13-.21-.13-.21-.13-.22-.14-.21-.14-.21-.14-.21-.14-.21-.14-.21-.14-.2-.15-.2-.15-.2-.15-.2-.15-.2-.16-.2-.15-.195-.15-.2-.16-.19-.16-.2-.16-.19-.16-.19-.16-.19-.17-.19-.17-.19-.17-.18-.17-.18-.17-.19-.17-.18-.17-.18-.17-.18-.18-.18-.18-.18-.17-.17-.18-.18-.19-.17-.19-.17-.19-.17-.18-.17-.19-.17-.19-.16-.2-.17-.09-.08-.1-.09-.1-.08-.1-.08-.1-.08-.1-.08-.1-.08-.09-.08-.1-.08-.1-.08-.1-.08-.1-.08-.1-.08-.1-.07-.1-.07-.1-.08-.1-.07-.11-.07-.1-.08-.11-.08-.1-.07-.11-.08-.1-.08-.11-.07-.11-.07-.1-.07-.11-.07-.1-.07-.11-.07-.11-.07-.11-.07-.11-.07-.11-.07-.1-.07-.11-.07-.11-.06-.11-.07-.11-.07-.11-.07-.11-.07-.11-.06-.11-.07-.11-.07-.12-.07L956.7 45.4l-.16-.09-.15-.08-.15-.08-.14-.08-.15-.08-.14-.08-.15-.08-.15-.08-.15-.08-.15-.08-.15-.08-.15-.07-.15-.07-.14-.077-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.14-.07-.15-.07-.15-.07-.15-.07-.15-.06-.15-.07-.15-.06-.15-.07-.15-.06-.16-.06-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.16-.05-.15-.05-.15-.05-.15-.05-.15-.05-.16-.05-.16-.05-.15-.05-.15-.05-.15-.05-.15-.05-.15-.05-.16-.05-.16-.043-.16-.05-.15-.05-.16-.05-.16-.05-.16-.04-.16-.05-.15-.04-.16-.04-.15-.05-.16-.04-.156-.04-.16-.04-.16-.04-.155-.04-.16-.04-.15-.04-.15-.03-.16-.038-.16-.03-.16-.03-.15-.04-.16-.03-.16-.04-.16-.03-.15-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.028-.16-.023-.16-.03-.16-.02-.16-.03-.15-.02-.16-.02-.16-.02-.16-.03-.16-.03-.16-.02-.16-.02-.16-.02-.16-.02-.16-.02-.16-.02-.16-.02-.16-.01-.15-.02-.16-.01-.16-.02-.16-.02-.16-.02-.16-.01-.16-.02-.16-.01-.16-.01h-.16l-.16-.01-.16-.01-.16-.01-.16-.01-.16-.01-.16-.01h-.16l-.16-.01-.16-.01h-.32l-.16-.01h-.48z"/> - <path fill="#EBB951" d="M1482.54 259.914V137.607c0-15.834-8.486-30.455-22.233-38.312L1346.64 34.333c-16.525-9.444-36.86-9.23-53.18.56l-95.98 57.568c-20.208 12.13-32.574 33.96-32.574 57.53v119.52c0 19.94 10.58 38.38 27.793 48.44 29.94 17.51 77.02 45.02 104.71 61.21 13.92 8.14 31.11 8.32 45.2.47l115.94-64.57c14.8-8.24 23.97-23.85 23.97-40.79v-14.35z"/> - <path fill="#FCD804" d="M1320.656 13.897h.27l.243.003h.02l.24.004h.03l.24.004h.03l.24.005h.02l.24.007h.02l.24.007h.02l.24.01h.03l.24.01h.03l.24.01h.03l.24.012h.03l.24.01h.02l.24.01h.02l.24.01h.03l.24.01h.03l.25.01h.03l.24.02h.03l.24.01h.03l.24.02h.03l.24.02h.03l.24.02h.03l.24.02h.03l.24.02h.02l.24.02h.03l.24.03h.02l.24.02h.03l.24.02h.03l.24.03h.03l.24.03.03.01.24.03h.03l.24.03h.03l.25.03h.02l.24.03h.03l.24.03h.02l.24.03h.03l.24.03h.02l.24.03h.03l.24.04h.03l.24.03.02.01.24.04h.03l.24.04.03.01.24.04h.03l.24.04h.03l.24.04h.03l.24.04h.03l.24.04h.03l.24.05.03.01.24.04h.03l.24.05.03.01.24.05.03.01.24.05.03.01.24.05.03.01.24.05.03.01.24.05h.03l.24.05h.02l.24.06h.03l.24.05.03.01.23.06.02.01.24.06h.03l.24.06.03.01.23.06.03.01.23.06.03.01.24.06h.03l.23.06h.03l.24.07h.02l.24.07h.03l.24.07.03.01.24.07h.03l.23.07h.03l.23.07.03.01.23.07.03.01.23.07.03.01.23.07.03.01.23.08.02.01.23.07.03.01.24.08.02.01.24.08.03.01.24.08.03.01.23.08h.02l.23.08.03.01.23.08.02.01.23.08.02.01.23.08.03.01.23.08.03.01.23.08.02.01.23.09.02.01.23.08.03.01.23.09.02.01.23.09.03.01.23.09.02.01.23.09.03.01.23.09.02.01.23.09.03.01.23.09.03.01.23.09.03.01.23.09.02.02.23.09.02.01.23.09.02.01.23.1.03.01.23.1.02.01.23.1.02.01.22.1.02.01.23.11.02.01.23.1.02.01.22.1.02.01.22.11.03.01.22.11.03.01.22.11.03.01.23.11.03.02.23.11.02.01.22.11.03.01.22.11.03.01.22.11.03.01.22.11.03.01.23.12.03.01.22.11.02.02.22.12.02.01.22.12.03.02.22.12.03.01.22.12.02.02.22.12.02.02.22.12.02.01.22.12.03.02.22.12.03.02.22.13 113.68 65 .19.11.02.02.18.11.02.01.19.11.03.01.18.11.02.01.18.11.03.01.18.11.02.01.18.11.03.01.18.11.02.02.18.12.03.02.18.11.02.01.18.12.02.01.18.11.02.01.18.11.02.02.18.12.02.01.17.12.03.02.18.12.02.01.18.11.03.02.17.12.02.02.17.12.03.01.17.12.02.02.17.12.02.01.17.12.02.02.17.12.02.02.17.12.03.02.17.13.02.02.17.12.02.01.17.12.02.02.17.12.02.02.17.12.02.01.17.12.02.02.17.13.02.01.17.13.02.02.16.13.02.01.17.13.02.02.17.13.03.02.16.12.02.01.16.13.02.02.16.13.02.02.17.14.02.02.16.13.02.02.16.13.02.02.16.14.02.02.16.14.02.02.16.14.03.03.31.27.04.04.31.27.04.04.32.28.04.03.31.28.04.04.31.28.04.04.31.28.04.04.31.29.04.04.3.29.04.04.3.29.04.04.3.29.04.04.3.3.04.04.29.3.04.04.29.3.04.04.28.3.04.04.28.3.04.04.28.31.04.04.28.31.04.04.28.31.03.04.27.32.03.04.27.31.04.04.27.31.04.04.27.32.03.04.27.32.04.05.26.32.03.04.26.33.03.04.26.33.03.05.25.33.03.04.25.33.03.05.24.33.03.04.24.33.03.04.24.34.03.05.23.34.03.04.24.34.03.05.23.34.03.04.23.35.03.05.22.34.03.05.22.35.03.04.22.35.03.05.22.35.03.05.22.36.03.04.21.36.03.05.21.36.03.05.21.35.02.05.2.37.02.05.2.36.02.05.2.36.03.05.19.36.03.05.19.37.02.05.19.37.03.05.19.37.02.05.19.37.02.05.18.37.02.05.18.37.03.05.17.37.02.05.17.38.03.05.17.38.02.05.16.38.02.05.16.38.02.05.16.38.02.05.15.39.02.05.15.39.02.05.15.39.02.06.14.39.02.05.14.39.02.05.14.39.02.05.14.39.01.05.13.39.02.05.13.39.02.05.13.4.01.05.12.39.01.05.13.4.01.05.11.4.02.05.11.4.01.05.11.4.02.05.11.4.01.05.11.41.01.06.1.4.02.06.1.4.01.06.09.41.01.05.09.4.01.06.09.41.01.05.08.41.01.06.08.41.01.05.08.41v.05l.04.21.01.02.04.2.01.03.04.21.01.03.03.2.01.03.03.21v.02l.04.21v.03l.03.21v.03l.03.21v.02l.03.21.01.03.03.21v.03l.03.21.01.03.03.21v.04l.03.21.01.02.03.21v.02l.03.21v.03l.03.2v.02l.03.21.01.03.02.21v.03l.02.21v.03l.02.21v.03l.02.21v.03l.02.21v.03l.02.21v.03l.02.21.01.03.02.21v.03l.02.21v.02l.01.21v.03l.02.21v.02l.01.21v.04l.01.22v.02l.01.21v.03l.02.21v.04l.01.21v.03l.01.21v.02l.01.21v.03l.01.22v.26l.01.22v.03l.01.21v.27l.01.21V275l-.01.23v.27l-.01.22v.03l-.01.22v.03l-.01.23v.03l-.01.23v.03l-.01.23-.01.03-.01.23v.03l-.01.23v.03l-.02.227v.02l-.01.227v.04l-.02.23v.03l-.02.227v.03l-.02.22v.03l-.02.22v.04l-.02.23v.03l-.02.23-.01.03-.02.22-.01.03-.02.22v.03l-.02.22v.03l-.02.23v.02l-.02.22-.01.03-.02.23-.01.03-.03.22v.03l-.03.22v.03l-.03.22v.03l-.03.22v.03l-.03.23-.01.03-.03.22v.03l-.03.22-.01.03-.03.22v.02l-.03.22-.01.03-.03.22v.03l-.03.22-.01.03-.03.23-.01.04-.04.22v.02l-.04.22-.01.03-.04.22v.03l-.04.22v.02l-.04.22v.03l-.04.22-.01.03-.04.21-.01.03-.05.22v.02l-.05.22-.01.03-.04.22-.01.02-.05.21v.03l-.05.22v.03l-.05.22-.01.03-.04.22v.02l-.05.22-.01.03-.05.22v.02l-.05.22-.01.03-.05.22-.01.03-.05.22-.01.03-.05.21-.01.02-.05.21-.01.03-.06.22-.01.03-.06.21-.01.02-.06.22-.01.03-.06.21-.01.03-.06.21-.01.03-.06.21v.03l-.06.21-.01.03-.06.21-.01.02-.06.21-.01.02-.07.22-.01.03-.07.22v.02l-.06.21-.01.02-.07.21-.01.03-.07.21-.01.02-.07.21-.01.03-.07.21-.01.03-.07.21-.01.02-.07.2-.01.03-.07.21-.01.03-.07.21-.01.03-.07.21-.01.03-.08.21-.01.02-.08.21-.01.03-.08.2-.01.02-.08.21-.01.02-.07.21-.01.03-.08.2-.01.03-.08.21-.01.02-.08.21-.01.03-.08.21-.01.02-.08.2-.01.03-.08.21-.01.03-.08.21-.01.03-.09.2-.01.02-.08.2-.01.03-.08.21-.01.02-.09.2-.01.03-.08.2-.01.03-.09.2-.01.02-.09.2-.01.03-.09.2-.01.03-.09.2-.01.03-.09.2-.01.02-.09.2-.01.03-.09.2-.01.02-.09.2-.01.02-.1.2-.01.03-.09.2-.01.02-.1.2-.01.03-.1.2-.01.03-.1.2-.01.02-.1.19-.01.02-.1.2-.01.02-.1.2-.02.03-.1.2-.02.02-.1.2-.01.02-.1.19-.01.02-.1.19-.01.03-.1.19-.02.02-.1.19-.02.03-.1.19-.01.03-.11.2-.01.02-.11.19-.02.03-.11.19-.01.03-.1.19-.02.02-.11.19-.01.03-.11.19-.01.02-.11.19-.01.02-.11.19-.02.02-.11.19-.02.03-.12.19-.01.03-.11.19-.02.02-.11.19-.01.02-.11.19-.01.02-.12.18-.02.03-.12.18-.01.02-.11.18-.02.02-.12.19-.02.02-.12.19-.01.02-.12.18-.02.02-.12.18-.02.02-.12.19-.02.02-.12.18-.02.03-.12.18-.01.02-.12.18-.01.02-.12.19-.01.02-.12.18-.02.02-.12.18-.01.03-.13.18-.01.02-.13.18-.01.02-.13.18-.01.02-.13.18-.01.02-.13.18-.02.03-.13.18-.02.02-.13.17-.02.02-.13.17-.02.02-.14.18-.02.03-.13.18-.02.02-.13.18-.02.02-.13.18-.02.02-.13.18-.02.02-.13.17-.02.02-.14.18-.01.02-.13.17-.02.02-.14.18-.02.02-.14.17-.02.02-.14.17-.02.02-.14.17-.02.02-.14.17-.02.02-.14.16-.01.02-.14.17-.02.03-.14.17-.02.02-.14.17-.02.02-.14.16-.02.02-.14.16-.02.02-.14.17-.02.02-.15.17-.02.02-.15.16-.02.02-.15.16-.02.02-.15.16-.02.02-.15.17-.02.02-.15.17-.01.02-.15.16-.02.03-.15.16-.02.02-.15.16-.02.02-.16.16-.02.02-.15.16-.02.02-.15.16-.02.02-.16.15-.02.02-.16.16-.02.02-.16.16-.02.02-.16.16-.02.02-.16.15-.02.02-.16.16-.02.02-.16.15-.02.01-.16.15-.02.02-.16.16-.02.02-.16.15-.02.02-.16.15-.02.02-.16.15-.03.02-.17.15-.02.02-.16.15-.03.02-.17.15-.02.02-.16.15-.02.01-.16.15-.02.02-.16.15-.02.02-.17.14-.02.02-.17.15-.02.02-.17.15-.02.02-.17.15-.02.02-.17.14-.02.02-.17.15-.02.02-.17.14-.02.02-.17.14-.03.02-.17.14-.02.02-.17.14-.02.02-.17.14-.02.02-.18.14-.02.01-.17.14-.02.02-.18.14-.02.02-.18.13-.02.02-.18.13-.02.02-.18.14-.02.02-.18.13-.02.02-.17.13-.02.01-.18.13-.02.02-.18.13-.02.02-.19.13-.02.02-.18.13-.02.01-.19.13-.03.02-.18.13-.02.01-.19.12-.02.02-.19.13-.02.01-.18.13-.03.02-.19.13-.03.02-.19.13-.02.01-.18.12-.02.02-.19.13-.02.02-.19.13-.02.02-.19.13-.02.01-.19.13-.02.01-.19.13-.02.02-.19.12-.02.02-.19.12-.02.02-.19.12-.02.01-.19.11-.03.02-.19.12-.03.01-.19.12-.02.02-.19.12-.03.01-.19.12-.02.01-.2.11-.03.01-.2.11-.02.01-.2.11-.03.01-.2.11-.03.01-.2.11-.03.01-.2.11-.02.02-.19.11-.01.01-115.96 64.58-.01.01-.19.1-.03.02-.19.1-.02.01-.19.11-.03.01-.19.1-.02.01-.19.11-.02.02-.19.1-.03.02-.2.1-.03.01-.19.1-.02.01-.19.1-.03.01-.2.09-.02.01-.19.09-.02.01-.19.1-.03.02-.2.09-.02.01-.2.1-.03.01-.19.09-.02.01-.19.09-.03.01-.2.09-.02.01-.2.09-.03.02-.2.09-.03.01-.2.09-.03.01-.2.09-.03.01-.2.09-.03.01-.19.08-.03.01-.19.08-.03.01-.2.09-.02.01-.19.08-.03.01-.2.08-.02.01-.2.09-.03.01-.2.08-.02.01-.2.08-.03.01-.2.08-.02.01-.2.08-.03.01-.2.08-.02.01-.19.08-.02.01-.2.08-.03.01-.2.07-.03.01-.2.07-.03.01-.2.08-.02.01-.2.07-.02.01-.2.07-.02.01-.2.07-.03.01-.21.07-.02.01-.2.07-.03.01-.2.07-.03.01-.2.07-.03.01-.2.07-.02.01-.2.07-.03.01-.2.06-.03.01-.2.06-.02.01-.2.07-.21.06-.03.01-.21.06-.04.01-.4.12-.05.02-.41.12-.05.02-.41.11-.05.01-.41.11-.06.01-.41.11-.05.01-.41.11-.05.01-.41.1-.05.01-.41.1-.05.02-.41.09-.05.01-.41.09-.06.01-.41.09-.05.01-.41.08-.05.01-.41.08-.05.01-.42.08-.05.01-.42.08-.05.01-.41.07-.05.01-.42.06-.06.01-.42.07-.05.01-.42.06-.05.01-.42.06-.05.01-.42.06h-.05l-.41.05h-.05l-.42.05-.06.01-.42.04-.06.01-.42.04-.06.01-.42.03-.05.01-.42.03-.05.01-.42.03h-.05l-.42.03h-.04l-.42.03-.06.01-.42.02-.05.01-.42.02-.05.01-.42.01h-.06l-.42.01h-.05l-.42.01h-1.46l-.42-.01h-.05l-.42-.01h-.05l-.42-.01h-.05l-.42-.02h-.05l-.42-.02-.05-.01-.42-.02h-.05l-.42-.03h-.05l-.42-.03h-.06l-.42-.03h-.05l-.42-.04h-.06l-.42-.04h-.05l-.42-.04h-.05l-.42-.05h-.05l-.42-.05-.05-.01-.42-.05h-.05l-.42-.06-.05-.01-.42-.06-.06-.01-.42-.06-.06-.01-.41-.06-.05-.01-.41-.07-.05-.01-.42-.07-.05-.01-.42-.08-.05-.01-.42-.08-.05-.01-.41-.09-.06-.01-.41-.08-.06-.02-.42-.09-.05-.01-.41-.09-.05-.01-.41-.09-.06-.01-.41-.1-.05-.01-.41-.1-.05-.02-.41-.11-.05-.01-.41-.11-.05-.01-.41-.11-.05-.02-.41-.12-.05-.02-.41-.12-.05-.02-.41-.12-.05-.02-.4-.13-.06-.02-.4-.13-.04-.01-.21-.07-.03-.01-.2-.07-.02-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.07-.03-.01-.2-.08-.02-.01-.2-.07-.02-.01-.2-.07-.02-.01-.2-.07-.02-.01-.2-.08-.03-.01-.2-.07-.03-.01-.2-.08-.03-.01-.2-.08-.03-.01-.2-.08-.02-.01-.2-.08-.03-.01-.2-.08-.03-.01-.2-.08-.03-.01-.2-.08-.02-.01-.2-.08-.02-.01-.2-.08-.02-.01-.2-.09-.03-.01-.19-.09-.03-.01-.2-.09-.03-.01-.19-.09-.03-.01-.2-.08-.03-.01-.19-.09-.03-.01-.19-.09-.02-.01-.19-.09-.02-.01-.2-.09-.02-.02-.19-.09-.03-.01-.2-.1-.02-.01-.2-.1-.02-.02-.19-.1-.02-.01-.2-.1-.02-.01-.19-.1-.03-.01-.19-.1-.03-.01-.19-.1-.03-.01-.19-.1-.03-.01-.19-.1-.03-.01-.19-.1-.03-.01-.19-.1-.03-.01-.19-.11-.02-.01-.19-.1-.02-.01-.19-.11-.02-.01-.19-.1-.02-.02-.19-.11-.02-.02-.19-.11-.02-.01-.19-.11-.03-.01-.19-.11-.03-.01-.18-.1-.01-.01-104.73-61.21h-.02l-.22-.13-.03-.02-.23-.14-.03-.01-.22-.13-.03-.02-.23-.13-.03-.01-.23-.14-.03-.01-.22-.14-.02-.01-.22-.14-.03-.01-.22-.14-.02-.02-.22-.14-.02-.02-.22-.14-.02-.02-.22-.14-.02-.01-.22-.15-.03-.01-.22-.14-.02-.01-.22-.15-.02-.01-.21-.14-.02-.02-.22-.15-.03-.02-.22-.14-.02-.02-.22-.14-.03-.02-.21-.15-.02-.02-.21-.14-.02-.01-.21-.15-.03-.02-.21-.15-.02-.02-.21-.15-.02-.02-.21-.15-.02-.02-.21-.15-.02-.01-.21-.15-.02-.01-.2-.15-.03-.02-.2-.16-.02-.02-.2-.15-.02-.01-.21-.16-.02-.02-.2-.16-.02-.01-.2-.16-.02-.01-.2-.16-.02-.01-.2-.16-.03-.02-.2-.16-.02-.02-.2-.16-.02-.02-.2-.16-.02-.01-.2-.17-.02-.02-.2-.16-.02-.02-.2-.16-.02-.01-.2-.17-.02-.02-.19-.16-.02-.02-.19-.17-.03-.02-.2-.17-.02-.02-.19-.17-.02-.02-.19-.17-.02-.01-.19-.17-.02-.01-.19-.17-.02-.01-.19-.17-.03-.02-.19-.17-.02-.02-.19-.17-.02-.01-.19-.18-.02-.02-.18-.17-.02-.02-.19-.18-.02-.02-.19-.18-.02-.02-.19-.17-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.01-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.18-.18-.02-.02-.17-.18-.02-.02-.18-.18-.02-.01-.17-.19-.02-.03-.18-.19-.02-.02-.18-.19-.02-.02-.18-.18-.02-.02-.17-.19-.01-.02-.18-.19-.02-.02-.17-.19-.02-.02-.17-.18-.02-.02-.17-.19-.02-.03-.17-.19-.02-.02-.17-.19-.02-.02-.17-.19-.02-.02-.16-.19-.02-.02-.17-.2-.02-.02-.17-.19-.02-.03-.17-.19-.02-.02-.16-.19-.01-.02-.16-.2-.02-.02-.16-.2-.02-.02-.16-.19-.01-.02-.16-.2-.02-.02-.16-.19-.02-.02-.16-.2-.02-.02-.16-.2-.02-.02-.16-.2-.01-.02-.15-.2-.02-.02-.15-.2-.02-.02-.16-.2-.02-.02-.15-.2-.018-.02-.16-.2-.01-.02-.15-.2-.01-.02-.157-.2-.01-.02-.15-.2-.02-.03-.15-.21-.01-.02-.15-.2-.01-.03-.15-.21-.02-.02-.15-.21-.02-.02-.15-.21-.02-.02-.15-.21-.01-.03-.14-.21-.02-.02-.14-.21-.01-.02-.14-.21-.02-.02-.14-.2-.01-.02-.14-.21-.01-.03-.14-.21-.01-.02-.14-.21-.02-.03-.14-.21-.01-.02-.14-.22-.02-.02-.14-.21-.01-.02-.14-.21-.01-.02-.14-.21-.02-.02-.14-.21-.01-.03-.13-.21-.01-.02-.13-.21-.016-.02-.13-.22-.02-.02-.13-.21-.01-.02-.13-.21-.02-.02-.13-.21-.01-.02-.13-.22-.01-.02-.13-.21-.02-.02-.13-.22-.01-.03-.12-.22-.01-.02-.13-.22-.02-.02-.12-.22-.01-.02-.13-.22-.01-.03-.13-.22-.01-.02-.12-.22-.02-.02-.12-.22-.01-.02-.12-.22-.01-.03-.12-.23-.01-.02-.12-.22-.01-.02-.12-.22-.01-.03-.11-.23-.01-.02-.11-.22-.01-.02-.12-.22-.01-.02-.12-.23-.01-.02-.11-.23-.01-.02-.11-.23-.01-.03-.12-.23-.01-.03-.11-.23-.01-.03-.11-.23-.01-.02-.11-.22-.01-.03-.11-.23-.01-.02-.11-.23-.01-.02-.11-.23-.01-.03-.1-.23-.01-.03-.1-.23-.01-.03-.11-.23-.01-.02-.1-.24-.01-.02-.1-.23-.01-.02-.1-.24-.01-.03-.1-.23-.01-.02-.1-.23-.01-.02-.1-.23-.01-.03-.1-.24-.01-.02-.1-.23-.01-.03-.1-.24-.01-.03-.09-.23v-.02l-.09-.24-.01-.03-.1-.24-.01-.03-.09-.24-.01-.03-.09-.24-.01-.02-.09-.24v-.02l-.09-.24-.01-.03-.09-.24-.01-.03-.09-.24-.01-.02-.08-.24-.01-.03-.08-.24-.01-.02-.09-.24-.01-.03-.08-.24-.01-.03-.08-.24-.01-.02-.08-.24-.01-.03-.08-.25-.01-.02-.08-.24-.01-.02-.07-.24-.01-.03-.07-.24-.01-.03-.08-.24-.01-.03-.08-.24-.01-.03-.07-.25v-.03l-.07-.25-.01-.03-.07-.24V289l-.08-.24-.01-.03-.07-.25-.01-.03-.07-.24-.01-.02-.07-.24-.01-.027-.06-.24-.01-.03-.07-.25v-.03l-.07-.24-.01-.03-.07-.25-.01-.02-.06-.24-.01-.03-.06-.25-.01-.02-.06-.25-.01-.03-.06-.25-.01-.02-.05-.25-.01-.03-.06-.25-.01-.02-.06-.25-.01-.03-.06-.25-.01-.02-.06-.25-.01-.03-.06-.25v-.02l-.05-.25v-.03l-.05-.25-.01-.03-.05-.26-.01-.03-.05-.25v-.02l-.05-.25v-.03l-.05-.25-.01-.03-.05-.25v-.02l-.05-.25-.01-.03-.04-.25-.01-.02-.04-.25v-.03l-.05-.26v-.03l-.04-.26v-.02l-.04-.25v-.03l-.04-.26-.01-.03-.04-.25v-.03l-.04-.25v-.03l-.04-.26v-.03l-.04-.26v.03l-.04-.25-.01-.03-.04-.26v-.02l-.03-.26v-.03l-.03-.26-.01-.03-.03-.26v-.02l-.03-.26v-.03l-.03-.26v-.02l-.03-.26v-.03l-.03-.26v-.03l-.02-.26v-.03l-.03-.26v-.03l-.02-.26v-.03l-.02-.26v-.03l-.02-.25-.02-.26v-.03l-.02-.26v-.02l-.02-.26v-.03l-.02-.26v-.03l-.02-.26-.01-.03-.02-.26v-.03l-.01-.26v-.1l-.01-.26v-.03l-.01-.27v-.03l-.01-.26v-.03l-.01-.256v-.03l-.01-.26v-.03l-.01-.27v-.03l-.01-.26v-.03l-.01-.26v-.03l-.01-.27V149.3l.01-.31v-.69l.01-.3v-.02l.01-.3v-.03l.01-.303v-.03l.01-.306v.02l.01-.3v-.03l.01-.3v-.03l.02-.3v-.02l.01-.3v-.03l.02-.3v-.03l.02-.3v-.02l.02-.3.006-.03.02-.3v-.03l.02-.31v-.03l.03-.3v-.02l.02-.3v-.02l.03-.3v-.03l.03-.3v-.02l.03-.3v-.03l.03-.3v-.03l.03-.3v-.03l.03-.3v-.03l.03-.29.01-.02.04-.29v-.03l.03-.29v-.03l.04-.3v-.02l.04-.3.01-.03.04-.3v-.02l.04-.3.01-.02.04-.3v-.03l.04-.29.01-.02.04-.3.01-.03.05-.29.01-.03.04-.29v-.02l.04-.29.01-.03.05-.29v-.03l.05-.29v-.03l.05-.29.01-.03.05-.3V136l.05-.298.01-.03.05-.295v-.02l.06-.297.01-.03.06-.29v-.03l.06-.29v-.03l.06-.29.01-.03.06-.29v-.026l.06-.29.01-.022.06-.29v-.03l.06-.29v-.02l.07-.29.01-.03.07-.29v-.03l.07-.29.01-.03.07-.29.01-.03.06-.29.01-.03.07-.29v-.03l.07-.29.01-.02.07-.28.01-.03.07-.29.01-.03.07-.29.01-.026.07-.29.01-.03.08-.29.01-.02.07-.28.01-.022.08-.29v-.02l.08-.29.01-.024.08-.28.01-.03.08-.28.01-.03.08-.285.01-.026.08-.29.01-.02.09-.29.01-.03.09-.28v-.03l.09-.28.01-.03.09-.28.01-.03.08-.28.01-.03.09-.28.01-.03.09-.28v-.02l.09-.28.01-.03.1-.28.01-.02.09-.28.01-.03.1-.28.01-.02.1-.28.01-.03.1-.28.01-.03.09-.28.01-.03.1-.28.01-.03.107-.28.01-.02.1-.28.01-.03.11-.27.01-.03.1-.27.01-.03.1-.28.01-.03.1-.27.01-.03.11-.27.01-.03.11-.27.01-.03.11-.27.01-.03.12-.28.01-.02.11-.27.01-.02.11-.27.01-.03.11-.27.01-.03.12-.27.01-.03.12-.27.01-.02.12-.27.01-.03.11-.27.01-.03.12-.27.01-.03.12-.27.01-.02.13-.27.01-.02.13-.26.01-.02.123-.26.01-.03.13-.27.01-.02.13-.26.01-.03.13-.27.01-.02.13-.27.01-.02.13-.27.01-.02.13-.27.01-.02.13-.26.01-.02.14-.27.01-.02.13-.26.01-.03.14-.26.01-.02.14-.26.015-.03.13-.26.01-.03.14-.26.01-.02.14-.26.01-.03.14-.26.01-.02.14-.25.02-.02.14-.26.02-.03.14-.26.01-.02.15-.25.01-.02.15-.25.01-.02.14-.25.02-.03.15-.26.01-.02.15-.26.01-.02.15-.26.01-.02.15-.25.015-.02.15-.26.01-.03.15-.25.01-.02.15-.25.01-.02.15-.25.02-.02.16-.25.01-.03.16-.25.01-.02.16-.25.01-.02.16-.25.01-.02.16-.25.01-.02.16-.25.02-.03.16-.25.01-.02.17-.25.02-.02.16-.25.02-.02.16-.25.02-.02.17-.25.01-.02.16-.24.02-.03.17-.24.01-.02.17-.24.02-.02.17-.24.02-.02.17-.24.02-.02.17-.24.02-.02.17-.24.01-.02.17-.24.01-.02.17-.24.01-.02.18-.24.02-.02.18-.24.01-.02.18-.24.02-.02.18-.23.02-.02.18-.23.02-.02.18-.24.01-.02.18-.24.02-.02.19-.23.02-.02.18-.23.01-.02.18-.23.02-.02.19-.24.02-.02.19-.23.02-.02.18-.23.02-.03.19-.23.02-.02.19-.23.01-.02.19-.23.01-.02.19-.23.02-.03.19-.22.01-.02.2-.22.02-.03.19-.23.01-.02.19-.22.02-.02.19-.23.02-.02.2-.23.01-.02.2-.22.02-.02.19-.22.02-.02.2-.22.02-.02.2-.21.02-.02.2-.22.02-.03.2-.22.02-.02.2-.22.02-.02.2-.22.02-.02.2-.21.02-.02.2-.21.02-.02.2-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.21.02-.02.21-.21.01-.02.21-.21.02-.02.22-.21.02-.02.21-.2.02-.02.22-.2.02-.02.22-.2.02-.02.22-.21.02-.02.22-.21.02-.02.22-.2.02-.02.22-.2.02-.02.22-.2.02-.01.22-.2.02-.01.22-.2.02-.02.22-.19.02-.02.23-.2.02-.02.23-.2.02-.02.23-.19.02-.02.23-.2.02-.01.23-.2.02-.02.23-.19.02-.02.23-.19.02-.02.23-.19.02-.02.23-.19.02-.02.23-.19.02-.02.23-.19.02-.02.24-.18.02-.02.23-.18.02-.02.23-.19.02-.01.24-.19.02-.02.24-.19.02-.01.24-.18.02-.02.24-.18.02-.02.24-.18.02-.02.24-.18.02-.01.24-.18.02-.02.24-.18.02-.02.24-.18.03-.01.25-.18.03-.02.24-.18.02-.02.25-.18.02-.01.25-.17.03-.01.24-.17.02-.02.25-.17.02-.02.25-.17.02-.01.25-.17.02-.01.25-.17.02-.01.25-.17.02-.01.25-.16.02-.01.25-.16.03-.02.25-.17.02-.02.26-.16.02-.01.26-.16.02-.01.26-.16.02-.02.26-.16.02-.02.26-.16.02-.02.26-.16.03-.01.26-.16.02-.01.25-.15.01-.01 96-57.57.01-.01.21-.13.02-.02.21-.13.03-.02.21-.13.02-.01.22-.13.02-.01.22-.12.02-.01.22-.12.03-.02.22-.12.02-.02.22-.12.02-.01.21-.12.02-.01.22-.12.02-.01.22-.12.03-.01.22-.12.02-.01.22-.12.03-.01.22-.11.02-.02.22-.11.03-.01.23-.11.03-.02.22-.11.02-.01.22-.11.02-.01.22-.11.02-.02.23-.11.02-.01.23-.11.03-.01.22-.11.02-.01.22-.11.02-.01.22-.11.03-.02.22-.1.03-.01.22-.11.02-.01.23-.1.03-.01.23-.1.02-.02.23-.1.02-.01.23-.1.02-.01.23-.1.02-.01.23-.1.03-.01.22-.1.03-.01.23-.1.02-.01.23-.1.02-.01.23-.09.03-.01.23-.1.03-.01.23-.1.02-.01.23-.09.03-.01.23-.09.03-.01.23-.09.02-.01.23-.09.03-.01.23-.09.03-.01.23-.08.02-.01.23-.09.03-.01.24-.09.03-.01.23-.08.03-.01.23-.08.02-.01.23-.08.03-.01.23-.08.02-.01.24-.08.03-.01.23-.08.03-.01.24-.08.03-.01.23-.07.03-.01.24-.08.02-.01.24-.07.03-.01.24-.07.02-.01.23-.07.03-.01.23-.07.03-.01.23-.07.03-.01.24-.07.03-.01.24-.07.03-.01.24-.07.02-.01.24-.07.03-.01.23-.07.03-.01.24-.07.02-.01.23-.06.02-.01.24-.06.02-.01.23-.06h.02l.23-.06.03-.01.24-.06.03-.01.24-.06.03-.01.24-.06.03-.01.24-.06.02-.01.24-.06h.03l.24-.05.03-.01.24-.05.03-.01.24-.05.02-.01.24-.05.03-.01.24-.05h.03l.24-.05h.03l.24-.05.03-.01.24-.05h.03l.24-.05.03-.01.24-.04h.03l.24-.05h.03l.24-.04.02-.01.24-.04.02-.01.24-.04.03-.01.24-.04h.03l.24-.04.03-.01.24-.04h.03l.24-.04h.03l.24-.04.03-.01.24-.03h.03l.24-.04.03-.01.25-.04.03-.01.24-.04h.03l.24-.03h.03l.24-.03h.03l.24-.03h.03l.24-.03.03-.01.24-.03h.03l.24-.02h.03l.24-.03h.03l.24-.02h.03l.24-.03h.03l.25-.03h.03l.24-.02h.02l.24-.02h.03l.24-.02h.03l.25-.02h.03l.25-.02h.03l.25-.01h.02l.24-.02.03-.01.24-.02h.03l.24-.01h.03l.24-.01h.03l.24-.02h.03l.25-.01h.03l.24-.01h.03l.24-.01h.03l.25-.01h.02l.25-.01h.03l.24-.01h.29l.24-.01h.03l.24-.01h.84zm-.22 27l-.16.002h-1.282l-.16.01h-.48l-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.16.01-.158.01-.16.01-.16.01-.16.01-.158.01-.16.01-.16.02-.16.01-.16.02-.158.02-.158.02-.16.02-.158.02-.16.02-.158.02-.16.02-.157.02-.16.03-.16.03-.16.03-.16.02-.16.02-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.03-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.04-.16.05-.16.04-.15.04-.16.04-.16.05-.16.05-.16.05-.15.05-.16.05-.16.05-.15.05-.16.05-.16.05-.15.05-.16.05-.15.05-.15.06-.15.05-.15.05-.16.06-.15.05-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.06-.15.07-.15.07-.15.07-.15.06-.15.07-.15.07-.15.07-.15.07-.15.07-.15.08-.15.07-.15.07-.15.08-.15.08-.14.07-.15.08-.15.08-.15.07-.15.08-.15.08-.15.08-.15.08-.14.08-.15.08-.15.08-.15.08-.14.08-.14.08-.14.08-.15.09-95.95 57.56-.21.12-.19.11-.19.12-.19.11-.19.12-.19.12-.18.12-.19.12-.19.12-.18.12-.18.13-.18.12-.19.13-.18.13-.18.12-.18.12-.18.13-.18.12-.18.13-.18.12-.17.12-.18.13-.18.13-.18.13-.18.13-.18.13-.18.13-.17.13-.18.13-.17.13-.17.13-.17.14-.17.13-.17.14-.17.14-.17.13-.16.13-.17.14-.17.14-.17.13-.16.14-.16.14-.16.14-.16.14-.17.15-.17.14-.16.15-.16.15-.16.14-.16.14-.16.14-.16.15-.16.15-.16.15-.16.15-.15.15-.16.15-.16.15-.15.16-.15.15-.15.15-.16.15-.15.15-.15.16-.15.16-.15.16-.15.16-.15.16-.15.16-.15.16-.14.16-.15.16-.14.16-.15.16-.15.16-.14.16-.14.16-.14.16-.14.16-.14.16-.13.16-.14.16-.14.16-.14.16-.13.17-.14.17-.13.17-.13.16-.13.17-.13.17-.13.16-.14.17-.13.17-.13.17-.13.17-.13.17-.13.17-.12.17-.13.17-.13.17-.12.17-.13.17-.13.17-.12.17-.12.18-.12.18-.12.18-.12.18-.12.18-.12.18-.12.18-.12.17-.12.18-.12.18-.11.18-.12.18-.11.18-.11.18-.12.19-.11.18-.11.18-.11.19-.11.18-.11.19-.11.18-.11.18-.11.19-.1.19-.1.18-.1.19-.11.18-.1.19-.1.18-.1.18-.11.2-.09.18-.1.19-.1.2-.1.19-.1.19-.09.19-.1.19-.09.19-.09.19-.09.19-.09.2-.09.19-.09.19-.09.2-.09.19-.09.19-.08.19-.08.19-.09.2-.09.2-.08.2-.08.2-.09.19-.08.2-.08.2-.08.2-.08.2-.08.2-.08.2-.07.2-.08.2-.08.2-.07.2-.08.2-.07.2-.08.21-.07.2-.07.21-.07.2-.07.2-.06.2-.07.2-.07.2-.06.2-.06.21-.07.21-.06.2-.07.2-.06.21-.06.21-.06.2-.06.21-.06.21-.06.2-.05.21-.06.21-.05.21-.06.21-.06.21-.05.2-.06.21-.05.21-.05.21-.05.21-.05.21-.05.21-.05.21-.05.21-.04.21-.04.21-.04.21-.05.22-.04.22-.04.21-.04.21-.04.21-.04.22-.04.21-.03.21-.03.22-.04.22-.03.21-.04.21-.03.21-.03.21-.03.22-.03.22-.03.21-.03.22-.02.21-.02.21-.02.22-.03.21-.03.21-.03.22-.02.22-.02.21-.02.21-.02.22-.02.22-.02.21-.02.22-.02.22-.02.22-.02.22-.01.22-.01.22-.01.21-.02.22-.01.22-.01.22-.01.22-.01.22-.01.22-.01.22v.22l-.01.22v121.1l.01.18v.18l.01.17.01.17.01.18v.34l.01.18v.18l.01.17.01.18.01.17.01.17.02.18.01.18.02.17.01.17.02.17.01.17.02.17.02.17.02.17.02.17.02.17.02.17.02.17.02.18.02.17.03.17.03.17.02.17.03.17.03.18.03.18.03.17.02.17.03.17.03.17.03.17.03.17.03.18.03.16.03.17.04.17.04.17.04.17.04.17.04.17.03.17.04.16.04.17.04.17.04.16.04.17.04.17.04.17.05.16.04.16.04.17.05.17.05.16.05.17.04.16.05.16.05.17.05.17.05.16.05.16.05.17.05.17.05.17.05.16.05.16.05.16.05.17.05.17.05.16.06.16.06.16.06.16.06.16.06.16.06.16.06.17.06.17.06.16.06.16.07.16.06.16.07.16.06.16.06.16.07.16.07.16.07.16.06.16.07.15.07.15.07.16.08.15.07.15.07.15.07.16.07.15.08.15.08.16.07.15.07.16.07.15.08.15.08.16.08.15.08.15.08.15.08.15.08.16.08.15.08.15.08.15.08.15.08.15.09.15.09.15.08.14.09.15.09.15.09.15.09.14.08.15.09.15.09.15.09.14.09.15.09.14.09.15.09.14.1.14.09.14.1.14.1.14.09.14.09.14.1.14.1.15.1.14.1.14.1.14.1.14.1.14.1.14.1.14.1.14.1.14.1.14.1.13.11.14.1.14.1.14.11.13.1.14.1.14.11.13.11.13.11.13.1.13.11.13.11.13.11.13.11.13.11.14.11.13.11.13.11.13.12.13.11.13.11.13.12.13.12.13.12.13.12.13.11.13.12.12.12.13.12.13.12.12.12.13.12.12.12.12.12.12.13.12.12.12.12.12.13.12.12.12.12.12.13.12.13.12.13.12.13.12.13.11.13.12.13.12.12.11.13.12.13.11.13.11.13.11.13.11.13.11.14.11.13.12.13.11.13.11.13.11.14.11.14.11.14.11.14.11.14.11.14.11.13.11.14.1.14.1.14.1.14.1.14.11.15.11.14.1.14.11.14.1.14.1.15.1.14.11.15.1.15.1.15.1.15.09.15.1.15.1.14.1.15.09.14.09.15.09.15.1.15.09.15.09.16.09.15.09.15.09.15.09.15.1.17.1 104.7 61.19.12.07.12.07.11.07.12.06.12.07.12.07.12.06.11.06.11.06.12.06.12.06.12.06.11.06.12.06.12.06.12.06.12.06.12.06.12.05.12.05.12.05.12.05.12.06.12.05.12.05.12.06.12.06.12.05.12.06.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.05.12.04.12.04.12.05.12.05.12.05.12.05.12.05.12.04.12.04.12.04.13.04.11.03.26.09.25.08.25.07.24.08.25.07.25.07.25.07.25.06.25.06.25.06.25.06.26.05.25.05.26.05.26.05.25.05.26.04.26.05.26.05.26.04.26.04.25.04.25.04.26.03.26.03.26.03.26.03.26.02.25.02.26.02.25.02.26.01.26.01.26.01.25.01.26.01.26.01h.25l.26.01h1.03l.26-.01.25-.01.26-.02.25-.02.26-.01.25-.02.26-.02.26-.02.25-.03.25-.03.26-.03.26-.03.25-.03.26-.04.26-.04.26-.04.25-.04.26-.04.26-.05.25-.05.25-.05.26-.05.25-.06.25-.06.25-.06.25-.06.25-.06.25-.07.25-.06.25-.07.25-.07.24-.08.27-.08.11-.03.13-.04.12-.04.12-.04.12-.04.12-.04.12-.04.12-.04.13-.04.12-.04.13-.05.13-.04.12-.04.12-.04.13-.04.12-.05.12-.04.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.05.12-.06.12-.06.12-.05.12-.06.12-.06.12-.06.12-.06.12-.06.12-.06.11-.06.12-.06.12-.06.12-.06.12-.06.12-.06.12-.06.12-.07.11-.06.13-.07 116-64.44.13-.08.12-.07.12-.07.12-.07.13-.07.12-.07.12-.07.13-.07.12-.08.12-.07.12-.08.11-.07.12-.07.12-.07.12-.07.12-.07.11-.07.11-.07.11-.07.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.08.11-.09.11-.08.11-.08.11-.09.1-.08.11-.09.11-.08.11-.09.11-.09.11-.08.1-.09.1-.09.1-.09.1-.09.11-.09.1-.09.1-.09.11-.09.1-.09.1-.1.1-.1.1-.09.1-.09.1-.09.1-.09.1-.09.1-.09.1-.09.1-.09.1-.1.1-.09.1-.09.1-.1.09-.09.09-.1.1-.1.1-.1.1-.1.1-.09.09-.1.1-.1.09-.1.09-.1.09-.1.09-.1.09-.1.1-.1.09-.1.09-.1.09-.1.09-.11.09-.1.08-.1.09-.11.09-.11.09-.1.09-.1.08-.11.08-.1.09-.11.08-.11.08-.1.08-.11.09-.11.08-.11.09-.11.09-.1.08-.11.08-.1.08-.11.08-.12.08-.1.08-.11.08-.11.07-.11.08-.11.08-.11.08-.11.07-.11.07-.11.08-.11.08-.11.08-.12.07-.11.07-.12.07-.11.07-.11.07-.12.07-.11.07-.12.07-.12.07-.11.07-.11.07-.11.07-.11.07-.12.07-.12.07-.12.07-.12.07-.12.07-.12.06-.12.07-.12.07-.12.07-.12.07-.12.06-.12.06-.12.06-.12.06-.12.07-.12.06-.13.07-.13.06-.13.06-.12.06-.12.06-.12.05-.12.06-.12.05-.12.05-.12.06-.12.05-.12.06-.12.06-.13.06-.13.05-.12.06-.13.05-.13.05-.13.05-.12.05-.13.05-.13.05-.12.05-.13.05-.13.05-.13.05-.12.05-.13.05-.13.04-.13.05-.13.04-.13.04-.13.04-.13.05-.13.04-.13.04-.13.04-.13.04-.13.04-.13.04-.13.04-.13.04-.13.04-.13.04-.14.03-.13.04-.13.04-.13.03-.13.04-.13.04-.14.04-.14.03-.13.03-.13.03-.14.03-.13.03-.13.03-.14.03-.13.03-.14.03-.13.03-.13.03-.13.02-.14.03-.14.02-.13.03-.138.03-.13.03-.14.03-.13.03-.13.02-.13.03-.14.02-.14.02-.13.02-.14.02-.14.02-.14.02-.14.02-.14.02-.14.02-.14.01-.14.02-.14.02-.14.02-.14.01-.14.01-.14.01-.14.02-.14.01-.14.01-.13.01-.14.01-.14.01-.14.01-.15.01-.14.01-.13.01-.14v-.2l.01-.14.01-.14.01-.14.01-.14.01-.14v-.3l.01-.14V137.1l-.01-.13v-.51l-.01-.126v-.135l-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.01-.13-.02-.13-.02-.13-.01-.13-.02-.13-.02-.13-.02-.13-.02-.13-.02-.12-.01-.12-.02-.13-.02-.13-.02-.12-.02-.12-.02-.13-.02-.13-.02-.13-.02-.13-.02-.13-.02-.11-.05-.26-.05-.24-.05-.25-.06-.25-.06-.25-.06-.25-.06-.24-.06-.25-.06-.24-.06-.24-.06-.24-.07-.25-.07-.24-.07-.24-.07-.24-.07-.24-.08-.23-.08-.24-.08-.24-.09-.23-.09-.23-.09-.23-.09-.23-.09-.23-.1-.24-.1-.23-.1-.23-.1-.23-.1-.22-.1-.23-.11-.23-.1-.23-.11-.23-.11-.23-.11-.22-.12-.23-.12-.22-.12-.22-.12-.22-.12-.22-.12-.22-.13-.22-.13-.21-.13-.21-.13-.21-.13-.22-.14-.21-.13-.21-.14-.21-.13-.21-.14-.21-.14-.2-.15-.21-.14-.2-.15-.2-.15-.2-.15-.2-.15-.2-.15-.2-.16-.19-.16-.2-.16-.2-.15-.19-.16-.19-.16-.2-.16-.19-.16-.19-.17-.19-.17-.19-.17-.18-.17-.18-.18-.18-.18-.18-.18-.18-.18-.17-.18-.17-.19-.18-.18-.17-.18-.17-.19-.17-.19-.17-.19-.16-.19-.16-.21-.17-.09-.08-.1-.08-.1-.08-.1-.08-.1-.08-.1-.08-.1-.08-.1-.08-.1-.08-.1-.07-.1-.08-.1-.07-.09-.08-.1-.08-.1-.08-.1-.08-.1-.07-.11-.08-.11-.08-.1-.07-.1-.07-.1-.08-.11-.07-.1-.07-.1-.08-.1-.07-.1-.07-.11-.07-.1-.07-.1-.07-.11-.07-.11-.06-.11-.07-.11-.07-.11-.07-.1-.06-.11-.07-.11-.07-.11-.07-.11-.06-.11-.07-.12-.07-.11-.06-.12-.08L1340 46.05l-.154-.09-.14-.08-.144-.08-.145-.08-.145-.07-.145-.08-.148-.077-.15-.08-.15-.077-.15-.08-.15-.075-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.15-.07-.15-.06-.15-.07-.15-.07-.15-.07-.15-.06-.15-.06-.15-.07-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.15-.06-.16-.06-.15-.06-.15-.05-.15-.05-.16-.06-.16-.06-.16-.05-.15-.06-.16-.05-.15-.05-.15-.05-.15-.05-.16-.05-.15-.05-.16-.05-.15-.05-.16-.05-.15-.04-.15-.05-.15-.04-.16-.04-.16-.04-.16-.05-.16-.04-.15-.04-.15-.04-.16-.05-.16-.04-.16-.04-.16-.04-.15-.04-.16-.04-.15-.04-.16-.04-.16-.03-.16-.04-.15-.04-.16-.03-.16-.04-.15-.03-.15-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.03-.16-.02-.16-.02-.16-.03-.16-.02-.16-.02-.16-.02-.16-.02-.16-.02-.16-.02-.16-.02-.16-.02-.16-.02-.15-.02-.16-.01-.16-.02-.16-.02-.16-.02-.16-.02-.16-.01-.16-.01-.16-.02-.16-.01-.16-.01-.16-.01-.16-.01-.16-.01-.16-.01-.16-.01-.16-.01h-.32l-.16-.01h-.8l-.16-.01h-.48z"/> - <path fill="#fff" fill-rule="nonzero" d="M1039.925 204.026c0 47.187-8.943 60.934-26.816 80.584-17.87 19.65-41.57 27.567-71.1 27.567-26.99 0-48.75-9.575-67.61-26.23-20.88-18.446-36.08-47.037-36.08-78.945 0-31.37 11.72-58.485 32.49-78.676 18.22-17.667 45.34-29.177 73.31-29.177 33.76 0 68.82 15.98 90.43 47.53l-31.73 26.82c-13.45-25.03-32.94-33.46-60.82-34.26-30.83-.88-64.77 28.53-62.25 67.75 1.4 21.94 11.65 59.65 60.96 66.57 25.91 3.63 55.36-24.02 55.36-39.04H947.4v-37.5h92.508V204z"/> - <path fill="#fff" d="M1323.723 99.15c58.784 0 106.52 47.728 106.52 106.514 0 58.787-47.736 106.514-106.52 106.514-58.783 0-106.52-47.727-106.52-106.514 0-58.786 47.737-106.514 106.52-106.514zm0 39.572c36.946 0 66.936 29.996 66.936 66.942s-29.99 66.94-66.94 66.94-66.94-29.994-66.94-66.94 29.99-66.942 66.93-66.942z"/> -</svg> diff --git a/static/images/icons/rss.svg b/static/images/icons/rss.svg @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> -<svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> -<style> - .darkmode { - svg { - fill: #93a1a1; - } - } - - svg { - fill: #586e75; - } -</style> -<path d="M2.88,16.88a3,3,0,0,0,0,4.24,3,3,0,0,0,4.24,0,3,3,0,0,0-4.24-4.24Zm2.83,2.83a1,1,0,0,1-1.42-1.42,1,1,0,0,1,1.42,0A1,1,0,0,1,5.71,19.71ZM5,12a1,1,0,0,0,0,2,5,5,0,0,1,5,5,1,1,0,0,0,2,0,7,7,0,0,0-7-7ZM5,8a1,1,0,0,0,0,2,9,9,0,0,1,9,9,1,1,0,0,0,2,0,11.08,11.08,0,0,0-3.22-7.78A11.08,11.08,0,0,0,5,8Zm10.61.39A15.11,15.11,0,0,0,5,4,1,1,0,0,0,5,6,13,13,0,0,1,18,19a1,1,0,0,0,2,0A15.11,15.11,0,0,0,15.61,8.39Z"/></svg> -\ No newline at end of file diff --git a/static/images/icons/search.svg b/static/images/icons/search.svg @@ -1,3 +0,0 @@ -<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search Button-visual"> -<path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> -</svg> -\ No newline at end of file diff --git a/static/images/icons/tags.svg b/static/images/icons/tags.svg @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> -<svg width="1em" height="1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> -<style> - .darkmode { - svg { - fill: #93a1a1; - } - } - - svg { - fill: #586e75; - } -</style> -<path d="M7.5,6A1.5,1.5,0,1,0,9,7.5,1.5,1.5,0,0,0,7.5,6Zm13.62,4.71L12.71,2.29A1,1,0,0,0,12,2H3A1,1,0,0,0,2,3v9a1,1,0,0,0,.29.71l8.42,8.41a3,3,0,0,0,4.24,0L21.12,15a3,3,0,0,0,0-4.24Zm-1.41,2.82h0l-6.18,6.17a1,1,0,0,1-1.41,0L4,11.59V4h7.59l8.12,8.12a1,1,0,0,1,.29.71A1,1,0,0,1,19.71,13.53Z"/></svg> -\ No newline at end of file diff --git a/static/images/logo.webp b/static/images/logo.webp Binary files differ. diff --git a/static/images/redragon_mouse.webp b/static/images/redragon_mouse.webp Binary files differ. diff --git a/static/images/wacom_tablet.webp b/static/images/wacom_tablet.webp Binary files differ. diff --git a/tsconfig.json b/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/base", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +}