Seth Michael Larsonhttp://sethmlarson.dev/feed2024-03-09T00:00:00ZSeth Michael Larsonhttps://sethmlarson.devsethmichaellarson@gmail.comhttps://github.com/sethmlarson.pnghttps://github.com/sethmlarson.pngWerkzeugRegex character “$” doesn't mean “end-of-string”http://sethmlarson.dev/regex-%24-matches-end-of-string-or-newline?date=2024-03-092024-03-09T00:00:00Z2024-03-09T00:00:00ZSeth Michael Larson<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Regex character “$” doesn't mean “end-of-string”</title>
<meta name="description" content="Python, open source, and the internet">
<meta name="keywords" content="python pypi open source maintainer urllib3 requests http networking security oss">
<meta name="author" content="Seth Michael Larson">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no"/>
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed"/>
<link rel="alternate" type="application/atom+xml" title="Atom Feed" href="/feed"/>
<link rel="icon" href="/static/favicon.ico">
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="/static/style.css">
<link rel="webmention" href="https://webmention.io/sethmlarson.dev/webmention" />
<meta property="og:site_name" content="Seth Michael Larson"/>
<meta property="og:author" content="Seth Michael Larson"/>
<meta property="og:type" content="article"/>
<meta property="og:title" content="Regex character “$” doesn't mean “end-of-string”"/>
<meta property="og:description" content="This article is about a bit of surprising behavior I recently discovered
using Python's regex module (re) while developing SBOM tooling for CPython.
Folks who've worked with regular expressions be..."/>
<meta property="og:image" content="https://github.com/sethmlarson.png"/>
<meta name="twitter:card" content="summary"/>
<meta name="twitter:site" content="@sethmlarson"/>
<meta name="twitter:creator" content="@sethmlarson"/>
<meta name="twitter:title" content="Regex character “$” doesn't mean “end-of-string”"/>
<meta name="twitter:description" content="This article is about a bit of surprising behavior I recently discovered
using Python's regex module (re) while developing SBOM tooling for CPython.
Folks who've worked with regular expressions be..."/>
<meta name="twitter:image" content="https://github.com/sethmlarson.png"/>
</head>
<body>
<div class="header">
<div class="container">
<div class="row">
<a href="/">About</a> •
<a href="/blog">Blog</a> •
<a href="https://buttondown.email/sethmlarson">Newsletter</a> •
<a href="/links">Links</a>
</div>
<div class="row">
<h1>Regex character “$” doesn't mean “end-of-string”</h1>
<p><nobr>Published 2024-03-09</nobr> <nobr>by Seth Larson</nobr><br>
Reading time: minutes <a href="https://webmention.io/api/mentions.html?target=https://sethmlarson.dev/"><span id="webmentions"></span></a></p>
</div>
</div>
</div>
<div class="container">
<p>This article is about a bit of surprising behavior I recently discovered
using Python's regex module (<code>re</code>) while <a href="https://github.com/python/release-tools/pull/92#discussion_r1484470272">developing SBOM tooling for CPython</a>.</p>
<p>Folks who've worked with regular expressions before might know about <code>^</code> meaning "start-of-string"
and correspondingly see <code>$</code> as "end-of-string". So the pattern <code>cat$</code> would match the string <code>"lolcat"</code> but not <code>"internet cat video"</code>.</p>
<p>The behavior of <code>^</code> made me think that <code>$</code> was similar, but they aren't always symmetrical
and the behavior is <em>platform-dependent</em>. Specifically for Python with multiline mode <em>disabled</em>
the <code>$</code> character can match either the end of a string <em>or a trailing newline before the end of a string</em>.</p>
<p>So if you're trying to match a string without a newline at the end, <strong>you can't only use <code>$</code> in Python!</strong>
My expectation was having multiline mode disabled wouldn't have had this newline-matching behavior, but that isn't the case.</p>
<p>Next logical question is how does one match the end of a string without a newline in Python?</p>
<p>After doing more research on <a href="https://docs.python.org/3/library/re.html#regular-expression-syntax">Python</a>
and <a href="https://www.regular-expressions.info/anchors.html">other regular expression syntaxes</a>
I also found <code>\z</code> and <code>\Z</code> as candidates for "end-of-string" characters.</p>
<p>Multi-line mode is enabled with <a href="https://docs.python.org/3/library/re.html#re.MULTILINE"><code>re.MULTILINE</code></a> in Python, the docs have the following to say:</p>
<blockquote>
<p>When <code>re.MULTILINE</code> is specified the pattern character '$' matches at the end of the string and at the end of each
line (immediately preceding each newline). By default, '$' only matches at the end of the string and immediately before the newline (if any) at the end of the string.</p>
</blockquote>
<p>Let's see how these features work together across multiple platforms:</p>
<table>
<thead>
<tr>
<th>Pattern matches <code>"cat\n"</code>?</th>
<th><code>"cat$"</code> multiline</th>
<th><code>"cat$"</code> no multiline</th>
<th><code>"cat\z"</code></th>
<th><code>"cat\Z"</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>PHP</td>
<td>✅</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td>ECMAScript</td>
<td>✅</td>
<td>❌</td>
<td>⚠️</td>
<td>⚠️</td>
</tr>
<tr>
<td>Python</td>
<td>✅</td>
<td>✅</td>
<td>⚠️</td>
<td>❌</td>
</tr>
<tr>
<td>Golang</td>
<td>✅</td>
<td>❌</td>
<td>❌</td>
<td>⚠️</td>
</tr>
<tr>
<td>Java 8</td>
<td>✅</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td>.NET 7.0</td>
<td>✅</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<td>Rust</td>
<td>✅</td>
<td>❌</td>
<td>❌</td>
<td>⚠️</td>
</tr>
</tbody>
</table>
<ul>
<li>✅: Pattern matches the string <code>"cat\n"</code></li>
<li>❌: Pattern does not match the string <code>"cat\n"</code></li>
<li>⚠️: Pattern is invalid or character not supported.</li>
</ul>
<p>Summarizing the above table, if matching a trailing newline is acceptable then <code>$</code> with multiline mode works consistently across all platforms,
but if we wanted to <em>not match</em> a trailing newline then things get more complicated.</p>
<p>To not match a trailing newline, use <code>\z</code> on all platforms except Python and
ECMAScript where you'll need to use <code>\Z</code> or <code>$</code> without multiline mode respectively.
Hope you learned something about regular expressions today!</p>
<p>Note: The table of data was gathered from <a href="https://regex101.com">regex101.com</a>, I didn't test using the actual runtimes.</p>
<blockquote>
<p>
<strong>Thanks for reading!</strong> ♡ Did you find this article helpful and want more content like it?
<nobr>Get notified of new posts</nobr> by subscribing to the <a href="/feed">RSS feed</a> or the <a href="https://buttondown.email/sethmlarson">email newsletter</a>.
<form
action="https://buttondown.email/api/emails/embed-subscribe/sethmlarson"
method="post"
target="popupwindow"
onsubmit="window.open('https://buttondown.email/sethmlarson', 'popupwindow')"
>
<center>
<input type="email" name="email" id="bd-email" placeholder="Email address here" style="max-width: 100%; width: 16em; margin-bottom: 0.5em;" required/><br>
<input type="submit" value="Subscribe" style="max-width: 100%; width: 16em;"/>
</center>
</form>
</p>
</blockquote>
<div>
<center>
<p xmlns:cc="http://creativecommons.org/ns#" >This work is licensed under <nobr><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-SA 4.0</a> <a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></nobr></p>
</center>
</div>
<script>
fetch("https://webmention.io/api/count?target=https://sethmlarson.dev/")
.then(response => response.json()).then(responseJson => {
if (responseJson.count) {
var webmentionsElement = document.getElementById("webmentions");
webmentionsElement.classList.add("webmentions-fade-in");
webmentionsElement.innerHTML = "❤ × " + String(responseJson.count);
};
});
</script>
</div>
<script data-goatcounter="https://sethmlarson-dev.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
</body>
</html>Security Developer-in-Residence Weekly Report #31http://sethmlarson.dev/security-developer-in-residence-weekly-report-31?date=2024-02-282024-02-28T00:00:00Z2024-02-28T00:00:00ZSeth Michael Larson<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Security Developer-in-Residence Weekly Report #31</title>
<meta name="description" content="Python, open source, and the internet">
<meta name="keywords" content="python pypi open source maintainer urllib3 requests http networking security oss">
<meta name="author" content="Seth Michael Larson">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no"/>
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed"/>
<link rel="alternate" type="application/atom+xml" title="Atom Feed" href="/feed"/>
<link rel="icon" href="/static/favicon.ico">
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="/static/style.css">
<link rel="webmention" href="https://webmention.io/sethmlarson.dev/webmention" />
<meta property="og:site_name" content="Seth Michael Larson"/>
<meta property="og:author" content="Seth Michael Larson"/>
<meta property="og:type" content="article"/>
<meta property="og:title" content="Security Developer-in-Residence Weekly Report #31"/>
<meta property="og:description" content="Windows CPython SBOMs
I've finished up work for Software Bill-of-Materials for generating Windows CPython artifacts,
these PRs are being reviewed by Windows release managers. A few things left to ..."/>
<meta property="og:image" content="https://github.com/sethmlarson.png"/>
<meta name="twitter:card" content="summary"/>
<meta name="twitter:site" content="@sethmlarson"/>
<meta name="twitter:creator" content="@sethmlarson"/>
<meta name="twitter:title" content="Security Developer-in-Residence Weekly Report #31"/>
<meta name="twitter:description" content="Windows CPython SBOMs
I've finished up work for Software Bill-of-Materials for generating Windows CPython artifacts,
these PRs are being reviewed by Windows release managers. A few things left to ..."/>
<meta name="twitter:image" content="https://github.com/sethmlarson.png"/>
</head>
<body>
<div class="header">
<div class="container">
<div class="row">
<a href="/">About</a> •
<a href="/blog">Blog</a> •
<a href="https://buttondown.email/sethmlarson">Newsletter</a> •
<a href="/links">Links</a>
</div>
<div class="row">
<h1>Security Developer-in-Residence Weekly Report #31</h1>
<p><nobr>Published 2024-02-28</nobr> <nobr>by Seth Larson</nobr><br>
Reading time: minutes <a href="https://webmention.io/api/mentions.html?target=https://sethmlarson.dev/"><span id="webmentions"></span></a></p>
</div>
</div>
</div>
<div class="container">
<h2>Windows CPython SBOMs</h2>
<p>I've finished up work for Software Bill-of-Materials for generating Windows CPython artifacts,
these PRs are being reviewed by Windows release managers. A few things left to do:</p>
<ul>
<li>Run integration tests for the proposed Azure Pipelines definition.</li>
<li>Add small change to upload procedure for Windows artifacts to also upload the new SBOM artifacts.</li>
</ul>
<p>After Windows is complete the only platform left is macOS which I've asked release managers about the best way to get started for this platform.</p>
<h2>Conferences and Talks</h2>
<p>I'm locked in for conference season in 2024, I'll be attending the following conferences
so if you are too then <a href="https://sethmlarson.dev/">let me know</a>!</p>
<ul>
<li>Registered for <a href="https://events.linuxfoundation.org/open-source-summit-north-america/">OSS Summit North America</a>, <a href="https://events.linuxfoundation.org/soss-community-day-north-america/">SOSS Community Day NA</a>, and <a href="https://us.pycon.org/2024/">PyCon US 2024</a>.</li>
<li>Speaking at SOSS Community Day NA, <a href="https://openssf.org/blog/2024/02/26/soss-community-day-north-america-na-agenda-live/">which just published its schedule</a>.
My talk is titled "Embrace the Differences: Securing Open Source Ecosystems Where They Are".</li>
<li>Speaking at a sponsored talk by Alpha-Omega with Alpha-Omega cofounder <strong>Michael Wisner</strong> at PyCon US 2024 which also <a href="https://us.pycon.org/2024/schedule/">just published its schedule</a>.
The talk title is "<a href="https://us.pycon.org/2024/schedule/presentation/148/">State of Python Supply Chain Security</a>".</li>
<li>I'm planning on running an open space at PyCon US 2024 with <strong>Madison Oliver</strong> on the Open Source vulnerability ecosystem and tools specifically for open source maintainers.
Look forward to that if you're attending PyCon US 2024.</li>
</ul>
<h2>Other items</h2>
<ul>
<li><a href="https://www.whitehouse.gov/oncd/briefing-room/2024/02/26/press-release-technical-report/">White House published a report on memory safety</a> this week.
I read the report and interested folks may be interested in <a href="https://sethmlarson.dev/security-developer-in-residence-weekly-report-21">my own writing on Python as a memory safe programming language</a>.
From my analytics this article is receiving more attention following the White Houses' publication.</li>
<li>Linux was announced as a CVE Numbering Authority this week. The guide I authored on becoming a <a href="https://openssf.org/blog/2023/11/27/openssf-introduces-guide-to-becoming-a-cve-numbering-authority-as-an-open-source-project/">CVE Numbering Authority as an Open Source
project</a>
was highlighted by Greg Kroah-Hartman in a <a href="http://www.kroah.com/log/blog/2024/02/13/linux-is-a-cna/">blog post</a> and on the <a href="https://opensourcesecurity.io/2024/02/25/episode-417-linux-kernel-security-with-greg-k-h/">Open Source Security podcast</a>.</li>
<li>Reviewed the Python package lock file updated proposal from <strong>Brett Cannon</strong>.</li>
<li>Coming up with potential security-related projects for Python and Google Summer of Code.</li>
<li>Working on grant renewal with Alpha-Omega for the Python Software Foundation.</li>
</ul>
<p>I'll be taking a break from weekly updates in March because I'll be traveling in early and late March
meaning I'll only have ~5 normal work days, so if you're curious why there aren't any weekly updates
that will be why. ✈️</p>
<p>That's all for this week! 👋 If you're interested in more you can read <a href="https://sethmlarson.dev/security-developer-in-residence-weekly-report-30">last week's report</a>.</p>
<blockquote>
<p>
<strong>Thanks for reading!</strong> ♡ Did you find this article helpful and want more content like it?
<nobr>Get notified of new posts</nobr> by subscribing to the <a href="/feed">RSS feed</a> or the <a href="https://buttondown.email/sethmlarson">email newsletter</a>.
<form
action="https://buttondown.email/api/emails/embed-subscribe/sethmlarson"
method="post"
target="popupwindow"
onsubmit="window.open('https://buttondown.email/sethmlarson', 'popupwindow')"
>
<center>
<input type="email" name="email" id="bd-email" placeholder="Email address here" style="max-width: 100%; width: 16em; margin-bottom: 0.5em;" required/><br>
<input type="submit" value="Subscribe" style="max-width: 100%; width: 16em;"/>
</center>
</form>
</p>
</blockquote>
<div>
<center>
<p xmlns:cc="http://creativecommons.org/ns#" >This work is licensed under <nobr><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-SA 4.0</a> <a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></nobr></p>
</center>
</div>
<script>
fetch("https://webmention.io/api/count?target=https://sethmlarson.dev/")
.then(response => response.json()).then(responseJson => {
if (responseJson.count) {
var webmentionsElement = document.getElementById("webmentions");
webmentionsElement.classList.add("webmentions-fade-in");
webmentionsElement.innerHTML = "❤ × " + String(responseJson.count);
};
});
</script>
</div>
<script data-goatcounter="https://sethmlarson-dev.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
</body>
</html>Windows SBOM work and Alpha-Omega 2023 annual reporthttp://sethmlarson.dev/security-developer-in-residence-weekly-report-30?date=2024-02-222024-02-22T00:00:00Z2024-02-22T00:00:00ZSeth Michael Larson<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Windows SBOM work and Alpha-Omega 2023 annual report</title>
<meta name="description" content="Python, open source, and the internet">
<meta name="keywords" content="python pypi open source maintainer urllib3 requests http networking security oss">
<meta name="author" content="Seth Michael Larson">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no"/>
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed"/>
<link rel="alternate" type="application/atom+xml" title="Atom Feed" href="/feed"/>
<link rel="icon" href="/static/favicon.ico">
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="/static/style.css">
<link rel="webmention" href="https://webmention.io/sethmlarson.dev/webmention" />
<meta property="og:site_name" content="Seth Michael Larson"/>
<meta property="og:author" content="Seth Michael Larson"/>
<meta property="og:type" content="article"/>
<meta property="og:title" content="Windows SBOM work and Alpha-Omega 2023 annual report"/>
<meta property="og:description" content="
This critical role would not be possible without funding from the Alpha-Omega project. Massive thank-you to Alpha-Omega for investing in the security of the Python ecosystem!
Starting on SBOMs..."/>
<meta property="og:image" content="https://github.com/sethmlarson.png"/>
<meta name="twitter:card" content="summary"/>
<meta name="twitter:site" content="@sethmlarson"/>
<meta name="twitter:creator" content="@sethmlarson"/>
<meta name="twitter:title" content="Windows SBOM work and Alpha-Omega 2023 annual report"/>
<meta name="twitter:description" content="
This critical role would not be possible without funding from the Alpha-Omega project. Massive thank-you to Alpha-Omega for investing in the security of the Python ecosystem!
Starting on SBOMs..."/>
<meta name="twitter:image" content="https://github.com/sethmlarson.png"/>
</head>
<body>
<div class="header">
<div class="container">
<div class="row">
<a href="/">About</a> •
<a href="/blog">Blog</a> •
<a href="https://buttondown.email/sethmlarson">Newsletter</a> •
<a href="/links">Links</a>
</div>
<div class="row">
<h1>Windows SBOM work and Alpha-Omega 2023 annual report</h1>
<p><nobr>Published 2024-02-22</nobr> <nobr>by Seth Larson</nobr><br>
Reading time: minutes <a href="https://webmention.io/api/mentions.html?target=https://sethmlarson.dev/"><span id="webmentions"></span></a></p>
</div>
</div>
</div>
<div class="container">
<blockquote>
<center>This critical role would not be possible without funding from the <a href="https://alpha-omega.dev">Alpha-Omega project</a>. Massive thank-you to Alpha-Omega for investing in the security of the Python ecosystem!</center>
</blockquote>
<h2>Starting on SBOMs for Python Windows artifacts</h2>
<p>Windows artifacts for CPython get built <a href="https://github.com/python/release-tools/tree/master/windows-release">using Azure Pipelines</a>
so the generation of the final SBOM for Windows artifacts should also be added to these workflows.</p>
<p>Part of the workflows is to <a href="https://github.com/python/cpython-source-deps">download source code</a> for dependencies like OpenSSL, libffi, and more.
These dependencies and their versions are tracked in a <a href="https://github.com/python/cpython/blob/main/PCbuild/get_externals.bat">file named <code>get_externals.bat</code></a> in a unintentionally parseable format
that the CPython SBOM tooling can <a href="https://github.com/python/cpython/pull/115789">extract and generate an SBOM file for</a>. This works in a similar way
to the "checked-in" source dependencies where any changes require the partial SBOM to be regenerated
and acknowledged by core developers during PR review.</p>
<p>The plan is to find this SBOM during the Windows release build and then depending on
which libraries have been pulled locally by <code>get_externals.bat</code> an SBOM will be generated
for the Windows artifact.</p>
<p>After chatting with <strong>Steve Dower</strong> it seems that the Windows build happens once
and then is repackaged into all the different distribution methods (python.org, Windows store, Nuget, etc)
so we'll only need to generate the Windows-specific SBOM once and then reuse it for each distribution method.</p>
<p>I also <a href="https://github.com/python/cpython/pull/115790">removed <code>regen-sbom</code> makefile target from <code>regen-all</code></a> to avoid breaking downstream distributors.</p>
<h2>Alpha-Omega published 2023 Annual Report</h2>
<p>Alpha-Omega <a href="https://openssf.org/blog/alpha-omega/2024/02/16/alpha-omega-2023-annual-report/">published its 2023 annual report</a> this week
and there's a ton of goodness inside, including lots of mentions of the Python Software Foundation and my own work.
I contributed content to this report last year, so I'm excited to see it published.</p>
<p>One quote regarding my current role:</p>
<blockquote>
<p>Alpha-Omega has helped fund security champion roles at the <strong>Python
Software Foundation</strong>, the Eclipse Foundation, and the Rust Foundation. In all
cases, we are seeing significant impact as these individuals are incubating a
security culture in their respective communities.</p>
</blockquote>
<p>Both Deb Nicholson, the executive director of the PSF and I were quoted in the report,
take a look if you're interested in what Alpha-Omega has next in 2024.</p>
<h2>Other items</h2>
<ul>
<li>Working on grant renewal with Alpha-Omega for the Python Software Foundation.</li>
<li><a href="https://www.python.org/downloads/release/python-3130a4/">CPython 3.13.0a4 was released</a> which also included SBOM documents.</li>
<li>Draft and submit talk for Alpha-Omega at PyCon US 2024.</li>
<li>Reviewed the <a href="https://openssf.org/blog/2024/02/14/linux-kernel-achieves-cve-numbering-authority-status/">OpenSSF announcement blog post for Linux becoming a CNA</a></li>
<li><a href="https://discuss.python.org/t/lock-files-again-but-this-time-w-sdists/46593/17">Reviewed the lock file with sdists proposal</a> from <strong>Brett Cannon</strong></li>
</ul>
<p>That's all for this week! 👋 If you're interested in more you can read <a href="https://sethmlarson.dev/security-developer-in-residence-weekly-report-31">next week's report</a> or <a href="https://sethmlarson.dev/security-developer-in-residence-weekly-report-29">last week's report</a>.</p>
<blockquote>
<p>
<strong>Thanks for reading!</strong> ♡ Did you find this article helpful and want more content like it?
<nobr>Get notified of new posts</nobr> by subscribing to the <a href="/feed">RSS feed</a> or the <a href="https://buttondown.email/sethmlarson">email newsletter</a>.
<form
action="https://buttondown.email/api/emails/embed-subscribe/sethmlarson"
method="post"
target="popupwindow"
onsubmit="window.open('https://buttondown.email/sethmlarson', 'popupwindow')"
>
<center>
<input type="email" name="email" id="bd-email" placeholder="Email address here" style="max-width: 100%; width: 16em; margin-bottom: 0.5em;" required/><br>
<input type="submit" value="Subscribe" style="max-width: 100%; width: 16em;"/>
</center>
</form>
</p>
</blockquote>
<div>
<center>
<p xmlns:cc="http://creativecommons.org/ns#" >This work is licensed under <nobr><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-SA 4.0</a> <a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></nobr></p>
</center>
</div>
<script>
fetch("https://webmention.io/api/count?target=https://sethmlarson.dev/")
.then(response => response.json()).then(responseJson => {
if (responseJson.count) {
var webmentionsElement = document.getElementById("webmentions");
webmentionsElement.classList.add("webmentions-fade-in");
webmentionsElement.innerHTML = "❤ × " + String(responseJson.count);
};
});
</script>
</div>
<script data-goatcounter="https://sethmlarson-dev.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
</body>
</html>Websites without servers or networkinghttp://sethmlarson.dev/websites-without-servers-or-networking?date=2024-02-192024-02-19T00:00:00Z2024-02-19T00:00:00ZSeth Michael Larson<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Websites without servers or networking</title>
<meta name="description" content="Python, open source, and the internet">
<meta name="keywords" content="python pypi open source maintainer urllib3 requests http networking security oss">
<meta name="author" content="Seth Michael Larson">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no"/>
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed"/>
<link rel="alternate" type="application/atom+xml" title="Atom Feed" href="/feed"/>
<link rel="icon" href="/static/favicon.ico">
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="/static/style.css">
<link rel="webmention" href="https://webmention.io/sethmlarson.dev/webmention" />
<meta property="og:site_name" content="Seth Michael Larson"/>
<meta property="og:author" content="Seth Michael Larson"/>
<meta property="og:type" content="article"/>
<meta property="og:title" content="Websites without servers or networking"/>
<meta property="og:description" content="
Note that this article is about a feature that, at the time of writing,
has been almost universally disabled or hampered on many platforms.
Expect some or all things to not work.
Everyone ..."/>
<meta property="og:image" content="https://github.com/sethmlarson.png"/>
<meta name="twitter:card" content="summary"/>
<meta name="twitter:site" content="@sethmlarson"/>
<meta name="twitter:creator" content="@sethmlarson"/>
<meta name="twitter:title" content="Websites without servers or networking"/>
<meta name="twitter:description" content="
Note that this article is about a feature that, at the time of writing,
has been almost universally disabled or hampered on many platforms.
Expect some or all things to not work.
Everyone ..."/>
<meta name="twitter:image" content="https://github.com/sethmlarson.png"/>
</head>
<body>
<div class="header">
<div class="container">
<div class="row">
<a href="/">About</a> •
<a href="/blog">Blog</a> •
<a href="https://buttondown.email/sethmlarson">Newsletter</a> •
<a href="/links">Links</a>
</div>
<div class="row">
<h1>Websites without servers or networking</h1>
<p><nobr>Published 2024-02-19</nobr> <nobr>by Seth Larson</nobr><br>
Reading time: minutes <a href="https://webmention.io/api/mentions.html?target=https://sethmlarson.dev/"><span id="webmentions"></span></a></p>
</div>
</div>
</div>
<div class="container">
<blockquote>
<p>Note that this article is about a feature that, at the time of writing,
<strong>has been almost universally disabled or hampered on many platforms</strong>.
Expect some or all things to not work.</p>
</blockquote>
<p>Everyone in tech at one point has joked about serverless websites <em>actually</em> using servers behind the scenes.
<em>This isn't that</em>, this is web content you can access with a URL <em>that doesn't require any networking</em>.</p>
<div class="row">
<div class="col-7">
<center>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="481px" viewBox="-0.5 -0.5 481 361" style="max-width:100%;max-height:361px;"><defs/><g><rect x="380" y="0" width="100" height="170" fill="#f5f5f5" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 7px; margin-left: 381px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #333; "><div style="display: inline-block; font-size: 16px; font-family: monospace; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Server</div></div></div></foreignObject><text x="430" y="23" fill="#333" font-family="monospace" font-size="16px" text-anchor="middle">Server</text></switch></g><rect x="240" y="0" width="120" height="170" fill="#f5f5f5" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 7px; margin-left: 241px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #333; "><div style="display: inline-block; font-size: 16px; font-family: monospace; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Internet</div></div></div></foreignObject><text x="300" y="23" fill="#333" font-family="monospace" font-size="16px" text-anchor="middle">Internet</text></switch></g><rect x="0" y="0" width="220" height="170" fill="#f5f5f5" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 7px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #333; "><div style="display: inline-block; font-size: 16px; font-family: monospace; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Networked Web</div></div></div></foreignObject><text x="110" y="23" fill="#333" font-family="monospace" font-size="16px" text-anchor="middle">Networked Web</text></switch></g><path d="M 90 70 L 103.63 70" fill="none" stroke="#000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 108.88 70 L 101.88 73.5 L 103.63 70 L 101.88 66.5 Z" fill="#000" stroke="#000" stroke-miterlimit="10" pointer-events="all"/><rect x="10" y="40" width="80" height="120" fill="rgb(255, 255, 255)" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 100px; margin-left: 11px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: monospace; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Browser</div></div></div></foreignObject><text x="50" y="104" fill="rgb(0, 0, 0)" font-family="monospace" font-size="12px" text-anchor="middle">Browser</text></switch></g><path d="M 390 130 L 356.37 130" fill="none" stroke="#000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 351.12 130 L 358.12 126.5 L 356.37 130 L 358.12 133.5 Z" fill="#000" stroke="#000" stroke-miterlimit="10" pointer-events="all"/><rect x="390" y="40" width="80" height="120" fill="rgb(255, 255, 255)" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 100px; margin-left: 391px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: monospace; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HTTP Server</div></div></div></foreignObject><text x="430" y="104" fill="rgb(0, 0, 0)" font-family="monospace" font-size="12px" text-anchor="middle">HTTP Server</text></switch></g><path d="M 210 70 L 243.63 70" fill="none" stroke="#000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 248.88 70 L 241.88 73.5 L 243.63 70 L 241.88 66.5 Z" fill="#000" stroke="#000" stroke-miterlimit="10" pointer-events="all"/><rect x="110" y="50" width="100" height="40" fill="rgb(255, 255, 255)" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 70px; margin-left: 111px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: monospace; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Parse URL</div></div></div></foreignObject><text x="160" y="74" fill="rgb(0, 0, 0)" font-family="monospace" font-size="12px" text-anchor="middle">Parse URL</text></switch></g><path d="M 350 70 L 383.63 70" fill="none" stroke="#000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 388.88 70 L 381.88 73.5 L 383.63 70 L 381.88 66.5 Z" fill="#000" stroke="#000" stroke-miterlimit="10" pointer-events="all"/><rect x="250" y="50" width="100" height="40" fill="rgb(255, 255, 255)" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 70px; margin-left: 251px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: monospace; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HTTP GET /</div></div></div></foreignObject><text x="300" y="74" fill="rgb(0, 0, 0)" font-family="monospace" font-size="12px" text-anchor="middle">HTTP GET /</text></switch></g><path d="M 110 130 L 96.37 130" fill="none" stroke="#000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 91.12 130 L 98.12 126.5 L 96.37 130 L 98.12 133.5 Z" fill="#000" stroke="#000" stroke-miterlimit="10" pointer-events="all"/><rect x="110" y="110" width="100" height="40" fill="rgb(255, 255, 255)" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 130px; margin-left: 111px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: monospace; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Render Content</div></div></div></foreignObject><text x="160" y="134" fill="rgb(0, 0, 0)" font-family="monospace" font-size="12px" text-anchor="middle">Render Content</text></switch></g><path d="M 250 130 L 216.37 130" fill="none" stroke="#000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 211.12 130 L 218.12 126.5 L 216.37 130 L 218.12 133.5 Z" fill="#000" stroke="#000" stroke-miterlimit="10" pointer-events="all"/><rect x="250" y="110" width="100" height="40" fill="#dae8fc" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 130px; margin-left: 251px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: monospace; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">HTTP 200 OK</div></div></div></foreignObject><text x="300" y="134" fill="rgb(0, 0, 0)" font-family="monospace" font-size="12px" text-anchor="middle">HTTP 200 OK</text></switch></g><rect x="0" y="190" width="220" height="170" fill="#f5f5f5" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 218px; height: 1px; padding-top: 197px; margin-left: 1px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #333; "><div style="display: inline-block; font-size: 16px; font-family: monospace; color: rgb(51, 51, 51); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Local Web</div></div></div></foreignObject><text x="110" y="213" fill="#333" font-family="monospace" font-size="16px" text-anchor="middle">Local Web</text></switch></g><path d="M 90 260 L 103.63 260" fill="none" stroke="#000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 108.88 260 L 101.88 263.5 L 103.63 260 L 101.88 256.5 Z" fill="#000" stroke="#000" stroke-miterlimit="10" pointer-events="all"/><rect x="10" y="230" width="80" height="120" fill="rgb(255, 255, 255)" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 290px; margin-left: 11px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: monospace; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Browser</div></div></div></foreignObject><text x="50" y="294" fill="rgb(0, 0, 0)" font-family="monospace" font-size="12px" text-anchor="middle">Browser</text></switch></g><path d="M 160 280 L 160 293.63" fill="none" stroke="#000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 160 298.88 L 156.5 291.88 L 160 293.63 L 163.5 291.88 Z" fill="#000" stroke="#000" stroke-miterlimit="10" pointer-events="all"/><rect x="110" y="240" width="100" height="40" fill="#dae8fc" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 260px; margin-left: 111px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: monospace; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Parse URL</div></div></div></foreignObject><text x="160" y="264" fill="rgb(0, 0, 0)" font-family="monospace" font-size="12px" text-anchor="middle">Parse URL</text></switch></g><path d="M 110 320 L 96.37 320" fill="none" stroke="#000" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 91.12 320 L 98.12 316.5 L 96.37 320 L 98.12 323.5 Z" fill="#000" stroke="#000" stroke-miterlimit="10" pointer-events="all"/><rect x="110" y="300" width="100" height="40" fill="rgb(255, 255, 255)" stroke="#000" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 320px; margin-left: 111px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: monospace; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Render Content</div></div></div></foreignObject><text x="160" y="324" fill="rgb(0, 0, 0)" font-family="monospace" font-size="12px" text-anchor="middle">Render Content</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
<br>
<small><i>Blue boxes are the sources of content in each scheme</i></small>
</center>
</div>
<div class="col-5">
<p>I'll call the web as we know it today the "networked" web, because it relies on HTTP and the internet to deliver
content to browsers and other user agents. The "local" web I'll be theory-crafting in this article doesn't require networking or HTTP
at all, instead embedding content directly into the URL.</p>
<p>The basis of this is based on a web feature that still works on some platforms, below there's a tool for creating your own "local web" URL:</p>
</div>
</div>
<p></p>
<div class="row">
<div class="col-12">
<textarea id="webcontent" style="width: 100%; min-height: 12em; font-family: monospace;" placeholder="<marquee>No HTTP needed!</marquee>"><marquee>No HTTP needed!</marquee></textarea>
</div>
</div>
<div class="row">
<div class="col-12" style="display: flex">
<input id="dataurl-content" style="flex-grow: 1; font-family: monospace;"/>
<button style="width: 10em; margin-left: 1em;" id="copy-dataurl">Copy URL</button>
</div>
</div>
<p>
<blockquote id="mobile-warning">Note that pasting the URL into a <i>mobile browser</i> is unlikely to work. You might have to try on a desktop browser like Firefox, or simply trust that it works and continue onwards.</blockquote>
</p>
<script>
// Detect mobile phones by screen size.
// https://stackoverflow.com/a/10364620
if (!window.matchMedia("only screen and (max-width: 760px)").matches) {
document.getElementById("mobile-warning").style.display = "none";
}
</script>
<p>To use the tool, try making some edits in the text area, click the "Copy URL" button, and pasting it into
a new browser tab navigation bar.</p>
<p>You should see whatever web content you wrote appear in your browser.
Taking a look in the browser inspector network tab will show no activity.</p>
<h2>What is a data URL?</h2>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs">Data URLs</a>
are URLs prefixed with the <code>data:</code> scheme and allow embedding content directly into the URL itself
instead of indicating where a browser should request data from. Data URLs are capable
are encoding any content type, including HTML content (i.e. <code>text/html</code>).</p>
<p>Data URLs are made of 3 components, a mime-type, an optional base64 encoding "flag", and the data value
which is either encoded as text or base64-encoded bytes depending on the base64 flag:</p>
<pre><code>data:<mime-type>[,base64];<data>
</code></pre>
<p>For example, below is the data URL encoding the data for <code>Hello, world!</code> with the mime type <code>text/plain</code>:</p>
<pre><code>data:text/plain,Hello,%20world!
</code></pre>
<h2>What would a local web look like?</h2>
<p>I love networking as much as the next person and there are obvious benefits, but there
are also downsides to serving most websites across networks:</p>
<ul>
<li>Websites require a server <em>somewhere</em> and (unless your <a href="https://1.1.1.1/">name is an IP address</a>) likely a domain name. Both of these things cost money to run.</li>
<li>URLs don't encode the information of the resource, only its potential location. This means resources referenced by URLs can be lost if the server at the other end ceases to exist.</li>
<li>All web content requires electricity and connectivity for both client and server to work.</li>
<li>Geographically distant users or users with worse network conditions have degraded performance.</li>
</ul>
<p>The combination of <strong>browsers, HTML, CSS, and JavaScript are an incredible platform for building experiences</strong>, it'd be great if we could
take advantage of those benefits without any of the downsides listed above. <em>Let's build a local web with data URLs?</em></p>
<blockquote>
<p>Referring to top-level <code>data:</code> URLs as being part of the "web" is
an oxymoron, the web is meant to be an interconnected graph where our data URLs
are functionally isolated nodes on that graph.</p>
</blockquote>
<h3>Sharing URLs</h3>
<p>Right away data URLs have an ergonomics problem. Because they encode all the information in the URL itself it's tough to
imagine typing one out with the same ease that you'd type out "example.com". If we're assuming that we're completely offline
we also can't use a search index like DuckDuckGo or Google.</p>
<div class="row">
<div class="col-6">
<p>Luckily there's already a mechanism for getting long URLs into the browser: <nobr><strong>QR codes</strong>!</nobr></p>
<p>QR codes mean we can encode our data URLs into an image that can be scanned with a camera. Unfortunately this would mean that our data URLs are only shareable to devices with cameras (sorry laptops)
but given the circumstances of "no internet" I think it's more likely interested users would be using a phone instead of a laptop.
</p>
</div>
<div class="col-6">
<center>
<svg viewBox="0 0 125 125" width="250" height="250" fill="#000" shape-rendering="crispEdges" xmlns="http://www.w3.org/2000/svg" version="1.1"><path transform="matrix(1,0,0,1,4,4)" d="M116,116h1v1h-1v-1zM109,116h5v1h-5v-1zM102,116h1v1h-1v-1zM100,116h1v1h-1v-1zM95,116h3v1h-3v-1zM92,116h1v1h-1v-1zM90,116h1v1h-1v-1zM85,116h1v1h-1v-1zM78,116h5v1h-5v-1zM74,116h2v1h-2v-1zM70,116h2v1h-2v-1zM64,116h5v1h-5v-1zM60,116h2v1h-2v-1zM58,116h1v1h-1v-1zM56,116h1v1h-1v-1zM53,116h2v1h-2v-1zM48,116h3v1h-3v-1zM46,116h1v1h-1v-1zM44,116h1v1h-1v-1zM40,116h1v1h-1v-1zM36,116h2v1h-2v-1zM34,116h1v1h-1v-1zM31,116h1v1h-1v-1zM28,116h1v1h-1v-1zM25,116h2v1h-2v-1zM22,116h1v1h-1v-1zM18,116h1v1h-1v-1zM13,116h3v1h-3v-1zM11,116h1v1h-1v-1zM8,116h2v1h-2v-1zM0,116h7v1h-7v-1zM111,115h3v1h-3v-1zM109,115h1v1h-1v-1zM107,115h1v1h-1v-1zM105,115h1v1h-1v-1zM102,115h2v1h-2v-1zM100,115h1v1h-1v-1zM93,115h1v1h-1v-1zM90,115h2v1h-2v-1zM88,115h1v1h-1v-1zM85,115h1v1h-1v-1zM81,115h2v1h-2v-1zM78,115h2v1h-2v-1zM76,115h1v1h-1v-1zM73,115h2v1h-2v-1zM69,115h2v1h-2v-1zM67,115h1v1h-1v-1zM64,115h2v1h-2v-1zM62,115h1v1h-1v-1zM57,115h1v1h-1v-1zM54,115h2v1h-2v-1zM52,115h1v1h-1v-1zM49,115h2v1h-2v-1zM40,115h4v1h-4v-1zM38,115h1v1h-1v-1zM33,115h1v1h-1v-1zM31,115h1v1h-1v-1zM28,115h1v1h-1v-1zM26,115h1v1h-1v-1zM21,115h3v1h-3v-1zM17,115h3v1h-3v-1zM14,115h1v1h-1v-1zM10,115h2v1h-2v-1zM8,115h1v1h-1v-1zM6,115h1v1h-1v-1zM0,115h1v1h-1v-1zM114,114h1v1h-1v-1zM112,114h1v1h-1v-1zM109,114h2v1h-2v-1zM106,114h1v1h-1v-1zM103,114h1v1h-1v-1zM101,114h1v1h-1v-1zM94,114h4v1h-4v-1zM87,114h1v1h-1v-1zM82,114h4v1h-4v-1zM79,114h1v1h-1v-1zM75,114h2v1h-2v-1zM72,114h1v1h-1v-1zM70,114h1v1h-1v-1zM61,114h1v1h-1v-1zM58,114h2v1h-2v-1zM55,114h1v1h-1v-1zM51,114h3v1h-3v-1zM46,114h4v1h-4v-1zM43,114h1v1h-1v-1zM39,114h2v1h-2v-1zM37,114h1v1h-1v-1zM34,114h2v1h-2v-1zM31,114h2v1h-2v-1zM28,114h1v1h-1v-1zM24,114h2v1h-2v-1zM13,114h8v1h-8v-1zM9,114h3v1h-3v-1zM6,114h1v1h-1v-1zM2,114h3v1h-3v-1zM0,114h1v1h-1v-1zM112,113h5v1h-5v-1zM109,113h2v1h-2v-1zM99,113h4v1h-4v-1zM96,113h1v1h-1v-1zM94,113h1v1h-1v-1zM91,113h2v1h-2v-1zM84,113h3v1h-3v-1zM82,113h1v1h-1v-1zM76,113h4v1h-4v-1zM71,113h4v1h-4v-1zM67,113h3v1h-3v-1zM57,113h1v1h-1v-1zM55,113h1v1h-1v-1zM52,113h1v1h-1v-1zM48,113h1v1h-1v-1zM41,113h4v1h-4v-1zM38,113h2v1h-2v-1zM34,113h2v1h-2v-1zM31,113h1v1h-1v-1zM28,113h2v1h-2v-1zM24,113h2v1h-2v-1zM22,113h1v1h-1v-1zM19,113h2v1h-2v-1zM17,113h1v1h-1v-1zM11,113h4v1h-4v-1zM6,113h1v1h-1v-1zM2,113h3v1h-3v-1zM0,113h1v1h-1v-1zM116,112h1v1h-1v-1zM107,112h6v1h-6v-1zM102,112h3v1h-3v-1zM95,112h4v1h-4v-1zM93,112h1v1h-1v-1zM91,112h1v1h-1v-1zM82,112h5v1h-5v-1zM79,112h2v1h-2v-1zM74,112h2v1h-2v-1zM70,112h3v1h-3v-1zM67,112h1v1h-1v-1zM62,112h3v1h-3v-1zM56,112h5v1h-5v-1zM49,112h3v1h-3v-1zM45,112h1v1h-1v-1zM41,112h3v1h-3v-1zM38,112h2v1h-2v-1zM36,112h1v1h-1v-1zM29,112h6v1h-6v-1zM24,112h2v1h-2v-1zM17,112h6v1h-6v-1zM8,112h2v1h-2v-1zM6,112h1v1h-1v-1zM2,112h3v1h-3v-1zM0,112h1v1h-1v-1zM115,111h2v1h-2v-1zM112,111h1v1h-1v-1zM108,111h1v1h-1v-1zM105,111h1v1h-1v-1zM100,111h4v1h-4v-1zM98,111h1v1h-1v-1zM90,111h2v1h-2v-1zM88,111h1v1h-1v-1zM86,111h1v1h-1v-1zM82,111h1v1h-1v-1zM79,111h1v1h-1v-1zM76,111h2v1h-2v-1zM73,111h2v1h-2v-1zM70,111h1v1h-1v-1zM66,111h2v1h-2v-1zM64,111h1v1h-1v-1zM60,111h1v1h-1v-1zM56,111h1v1h-1v-1zM54,111h1v1h-1v-1zM52,111h1v1h-1v-1zM49,111h2v1h-2v-1zM47,111h1v1h-1v-1zM45,111h1v1h-1v-1zM40,111h1v1h-1v-1zM34,111h1v1h-1v-1zM28,111h3v1h-3v-1zM26,111h1v1h-1v-1zM21,111h1v1h-1v-1zM15,111h5v1h-5v-1zM13,111h1v1h-1v-1zM11,111h1v1h-1v-1zM8,111h2v1h-2v-1zM6,111h1v1h-1v-1zM0,111h1v1h-1v-1zM115,110h1v1h-1v-1zM112,110h2v1h-2v-1zM110,110h1v1h-1v-1zM106,110h3v1h-3v-1zM103,110h1v1h-1v-1zM99,110h1v1h-1v-1zM97,110h1v1h-1v-1zM94,110h2v1h-2v-1zM92,110h1v1h-1v-1zM89,110h1v1h-1v-1zM86,110h2v1h-2v-1zM84,110h1v1h-1v-1zM81,110h2v1h-2v-1zM70,110h4v1h-4v-1zM67,110h2v1h-2v-1zM63,110h2v1h-2v-1zM60,110h2v1h-2v-1zM58,110h1v1h-1v-1zM56,110h1v1h-1v-1zM52,110h1v1h-1v-1zM48,110h1v1h-1v-1zM46,110h1v1h-1v-1zM43,110h2v1h-2v-1zM34,110h4v1h-4v-1zM32,110h1v1h-1v-1zM30,110h1v1h-1v-1zM22,110h4v1h-4v-1zM9,110h6v1h-6v-1zM0,110h7v1h-7v-1zM115,109h2v1h-2v-1zM112,109h2v1h-2v-1zM107,109h2v1h-2v-1zM104,109h2v1h-2v-1zM96,109h3v1h-3v-1zM93,109h1v1h-1v-1zM91,109h1v1h-1v-1zM89,109h1v1h-1v-1zM86,109h1v1h-1v-1zM80,109h3v1h-3v-1zM78,109h1v1h-1v-1zM76,109h1v1h-1v-1zM73,109h2v1h-2v-1zM69,109h1v1h-1v-1zM67,109h1v1h-1v-1zM60,109h2v1h-2v-1zM56,109h1v1h-1v-1zM52,109h1v1h-1v-1zM47,109h3v1h-3v-1zM36,109h10v1h-10v-1zM34,109h1v1h-1v-1zM30,109h1v1h-1v-1zM27,109h2v1h-2v-1zM24,109h1v1h-1v-1zM20,109h2v1h-2v-1zM17,109h1v1h-1v-1zM11,109h1v1h-1v-1zM8,109h2v1h-2v-1zM116,108h1v1h-1v-1zM114,108h1v1h-1v-1zM108,108h5v1h-5v-1zM104,108h3v1h-3v-1zM101,108h2v1h-2v-1zM99,108h1v1h-1v-1zM94,108h2v1h-2v-1zM81,108h11v1h-11v-1zM78,108h1v1h-1v-1zM75,108h1v1h-1v-1zM72,108h1v1h-1v-1zM66,108h4v1h-4v-1zM56,108h6v1h-6v-1zM52,108h3v1h-3v-1zM49,108h1v1h-1v-1zM46,108h2v1h-2v-1zM44,108h1v1h-1v-1zM39,108h4v1h-4v-1zM37,108h1v1h-1v-1zM29,108h6v1h-6v-1zM25,108h3v1h-3v-1zM20,108h2v1h-2v-1zM17,108h2v1h-2v-1zM12,108h2v1h-2v-1zM9,108h1v1h-1v-1zM6,108h1v1h-1v-1zM1,108h2v1h-2v-1zM110,107h2v1h-2v-1zM107,107h2v1h-2v-1zM105,107h1v1h-1v-1zM103,107h1v1h-1v-1zM100,107h1v1h-1v-1zM97,107h2v1h-2v-1zM93,107h1v1h-1v-1zM90,107h2v1h-2v-1zM87,107h2v1h-2v-1zM84,107h1v1h-1v-1zM81,107h1v1h-1v-1zM76,107h4v1h-4v-1zM74,107h1v1h-1v-1zM69,107h2v1h-2v-1zM67,107h1v1h-1v-1zM64,107h2v1h-2v-1zM59,107h3v1h-3v-1zM50,107h3v1h-3v-1zM47,107h1v1h-1v-1zM42,107h2v1h-2v-1zM40,107h1v1h-1v-1zM38,107h1v1h-1v-1zM33,107h1v1h-1v-1zM31,107h1v1h-1v-1zM28,107h2v1h-2v-1zM25,107h2v1h-2v-1zM17,107h1v1h-1v-1zM15,107h1v1h-1v-1zM12,107h2v1h-2v-1zM10,107h1v1h-1v-1zM8,107h1v1h-1v-1zM5,107h1v1h-1v-1zM2,107h1v1h-1v-1zM114,106h2v1h-2v-1zM111,106h1v1h-1v-1zM109,106h1v1h-1v-1zM106,106h2v1h-2v-1zM104,106h1v1h-1v-1zM94,106h3v1h-3v-1zM89,106h1v1h-1v-1zM85,106h1v1h-1v-1zM82,106h1v1h-1v-1zM80,106h1v1h-1v-1zM75,106h2v1h-2v-1zM73,106h1v1h-1v-1zM70,106h1v1h-1v-1zM68,106h1v1h-1v-1zM63,106h2v1h-2v-1zM61,106h1v1h-1v-1zM57,106h1v1h-1v-1zM55,106h1v1h-1v-1zM48,106h2v1h-2v-1zM45,106h2v1h-2v-1zM43,106h1v1h-1v-1zM41,106h1v1h-1v-1zM39,106h1v1h-1v-1zM36,106h2v1h-2v-1zM33,106h1v1h-1v-1zM29,106h3v1h-3v-1zM27,106h1v1h-1v-1zM18,106h8v1h-8v-1zM15,106h2v1h-2v-1zM13,106h1v1h-1v-1zM10,106h1v1h-1v-1zM4,106h5v1h-5v-1zM2,106h1v1h-1v-1zM0,106h1v1h-1v-1zM116,105h1v1h-1v-1zM114,105h1v1h-1v-1zM108,105h4v1h-4v-1zM105,105h2v1h-2v-1zM94,105h4v1h-4v-1zM90,105h3v1h-3v-1zM86,105h1v1h-1v-1zM84,105h1v1h-1v-1zM82,105h1v1h-1v-1zM80,105h1v1h-1v-1zM78,105h1v1h-1v-1zM75,105h1v1h-1v-1zM68,105h1v1h-1v-1zM64,105h2v1h-2v-1zM57,105h1v1h-1v-1zM55,105h1v1h-1v-1zM53,105h1v1h-1v-1zM50,105h1v1h-1v-1zM47,105h2v1h-2v-1zM44,105h2v1h-2v-1zM42,105h1v1h-1v-1zM35,105h5v1h-5v-1zM31,105h3v1h-3v-1zM27,105h3v1h-3v-1zM22,105h4v1h-4v-1zM17,105h3v1h-3v-1zM14,105h1v1h-1v-1zM11,105h2v1h-2v-1zM7,105h1v1h-1v-1zM4,105h2v1h-2v-1zM2,105h1v1h-1v-1zM114,104h3v1h-3v-1zM112,104h1v1h-1v-1zM110,104h1v1h-1v-1zM104,104h1v1h-1v-1zM98,104h2v1h-2v-1zM96,104h1v1h-1v-1zM94,104h1v1h-1v-1zM89,104h3v1h-3v-1zM83,104h4v1h-4v-1zM80,104h2v1h-2v-1zM78,104h1v1h-1v-1zM74,104h1v1h-1v-1zM72,104h1v1h-1v-1zM68,104h2v1h-2v-1zM66,104h1v1h-1v-1zM62,104h1v1h-1v-1zM59,104h2v1h-2v-1zM55,104h1v1h-1v-1zM52,104h1v1h-1v-1zM47,104h1v1h-1v-1zM45,104h1v1h-1v-1zM41,104h3v1h-3v-1zM37,104h2v1h-2v-1zM34,104h1v1h-1v-1zM32,104h1v1h-1v-1zM28,104h1v1h-1v-1zM26,104h1v1h-1v-1zM23,104h1v1h-1v-1zM20,104h1v1h-1v-1zM16,104h2v1h-2v-1zM13,104h2v1h-2v-1zM11,104h1v1h-1v-1zM8,104h1v1h-1v-1zM3,104h4v1h-4v-1zM0,104h1v1h-1v-1zM115,103h2v1h-2v-1zM110,103h2v1h-2v-1zM108,103h1v1h-1v-1zM105,103h1v1h-1v-1zM100,103h4v1h-4v-1zM98,103h1v1h-1v-1zM94,103h1v1h-1v-1zM88,103h4v1h-4v-1zM86,103h1v1h-1v-1zM81,103h3v1h-3v-1zM75,103h5v1h-5v-1zM69,103h2v1h-2v-1zM67,103h1v1h-1v-1zM64,103h1v1h-1v-1zM62,103h1v1h-1v-1zM57,103h4v1h-4v-1zM54,103h2v1h-2v-1zM52,103h1v1h-1v-1zM50,103h1v1h-1v-1zM45,103h1v1h-1v-1zM43,103h1v1h-1v-1zM40,103h2v1h-2v-1zM37,103h1v1h-1v-1zM33,103h1v1h-1v-1zM29,103h2v1h-2v-1zM19,103h1v1h-1v-1zM17,103h1v1h-1v-1zM10,103h5v1h-5v-1zM8,103h1v1h-1v-1zM4,103h2v1h-2v-1zM1,103h2v1h-2v-1zM111,102h3v1h-3v-1zM109,102h1v1h-1v-1zM106,102h1v1h-1v-1zM99,102h3v1h-3v-1zM96,102h2v1h-2v-1zM94,102h1v1h-1v-1zM92,102h1v1h-1v-1zM88,102h1v1h-1v-1zM82,102h1v1h-1v-1zM70,102h4v1h-4v-1zM67,102h1v1h-1v-1zM63,102h2v1h-2v-1zM61,102h1v1h-1v-1zM51,102h2v1h-2v-1zM49,102h1v1h-1v-1zM46,102h1v1h-1v-1zM39,102h1v1h-1v-1zM35,102h2v1h-2v-1zM33,102h1v1h-1v-1zM27,102h5v1h-5v-1zM22,102h4v1h-4v-1zM17,102h1v1h-1v-1zM12,102h3v1h-3v-1zM6,102h1v1h-1v-1zM4,102h1v1h-1v-1zM0,102h2v1h-2v-1zM108,101h4v1h-4v-1zM100,101h4v1h-4v-1zM91,101h3v1h-3v-1zM86,101h1v1h-1v-1zM83,101h1v1h-1v-1zM81,101h1v1h-1v-1zM77,101h1v1h-1v-1zM68,101h1v1h-1v-1zM64,101h1v1h-1v-1zM54,101h3v1h-3v-1zM51,101h1v1h-1v-1zM48,101h2v1h-2v-1zM38,101h5v1h-5v-1zM33,101h1v1h-1v-1zM29,101h1v1h-1v-1zM25,101h2v1h-2v-1zM21,101h2v1h-2v-1zM16,101h4v1h-4v-1zM10,101h4v1h-4v-1zM7,101h2v1h-2v-1zM4,101h2v1h-2v-1zM0,101h3v1h-3v-1zM116,100h1v1h-1v-1zM113,100h2v1h-2v-1zM110,100h1v1h-1v-1zM108,100h1v1h-1v-1zM106,100h1v1h-1v-1zM104,100h1v1h-1v-1zM98,100h1v1h-1v-1zM92,100h1v1h-1v-1zM90,100h1v1h-1v-1zM88,100h1v1h-1v-1zM84,100h3v1h-3v-1zM81,100h2v1h-2v-1zM71,100h8v1h-8v-1zM68,100h2v1h-2v-1zM66,100h1v1h-1v-1zM61,100h4v1h-4v-1zM57,100h3v1h-3v-1zM55,100h1v1h-1v-1zM50,100h1v1h-1v-1zM48,100h1v1h-1v-1zM46,100h1v1h-1v-1zM43,100h1v1h-1v-1zM36,100h4v1h-4v-1zM31,100h2v1h-2v-1zM28,100h1v1h-1v-1zM26,100h1v1h-1v-1zM23,100h2v1h-2v-1zM19,100h3v1h-3v-1zM17,100h1v1h-1v-1zM12,100h3v1h-3v-1zM9,100h1v1h-1v-1zM6,100h2v1h-2v-1zM4,100h1v1h-1v-1zM115,99h1v1h-1v-1zM110,99h3v1h-3v-1zM105,99h4v1h-4v-1zM100,99h4v1h-4v-1zM97,99h2v1h-2v-1zM88,99h4v1h-4v-1zM84,99h3v1h-3v-1zM81,99h2v1h-2v-1zM79,99h1v1h-1v-1zM76,99h1v1h-1v-1zM74,99h1v1h-1v-1zM69,99h1v1h-1v-1zM66,99h2v1h-2v-1zM64,99h1v1h-1v-1zM61,99h2v1h-2v-1zM58,99h2v1h-2v-1zM55,99h1v1h-1v-1zM52,99h2v1h-2v-1zM49,99h1v1h-1v-1zM42,99h3v1h-3v-1zM40,99h1v1h-1v-1zM37,99h1v1h-1v-1zM31,99h2v1h-2v-1zM28,99h2v1h-2v-1zM26,99h1v1h-1v-1zM22,99h1v1h-1v-1zM19,99h2v1h-2v-1zM17,99h1v1h-1v-1zM14,99h1v1h-1v-1zM12,99h1v1h-1v-1zM10,99h1v1h-1v-1zM8,99h1v1h-1v-1zM5,99h1v1h-1v-1zM3,99h1v1h-1v-1zM0,99h2v1h-2v-1zM113,98h3v1h-3v-1zM111,98h1v1h-1v-1zM109,98h1v1h-1v-1zM106,98h1v1h-1v-1zM104,98h1v1h-1v-1zM99,98h1v1h-1v-1zM93,98h5v1h-5v-1zM81,98h2v1h-2v-1zM75,98h2v1h-2v-1zM72,98h2v1h-2v-1zM70,98h1v1h-1v-1zM67,98h2v1h-2v-1zM64,98h2v1h-2v-1zM58,98h1v1h-1v-1zM55,98h1v1h-1v-1zM51,98h1v1h-1v-1zM49,98h1v1h-1v-1zM45,98h3v1h-3v-1zM39,98h2v1h-2v-1zM37,98h1v1h-1v-1zM34,98h1v1h-1v-1zM28,98h1v1h-1v-1zM24,98h2v1h-2v-1zM21,98h2v1h-2v-1zM17,98h2v1h-2v-1zM14,98h2v1h-2v-1zM8,98h5v1h-5v-1zM5,98h2v1h-2v-1zM0,98h1v1h-1v-1zM114,97h2v1h-2v-1zM111,97h1v1h-1v-1zM108,97h1v1h-1v-1zM105,97h1v1h-1v-1zM103,97h1v1h-1v-1zM100,97h2v1h-2v-1zM98,97h1v1h-1v-1zM95,97h2v1h-2v-1zM92,97h2v1h-2v-1zM90,97h1v1h-1v-1zM86,97h2v1h-2v-1zM84,97h1v1h-1v-1zM82,97h1v1h-1v-1zM79,97h2v1h-2v-1zM74,97h1v1h-1v-1zM71,97h2v1h-2v-1zM67,97h3v1h-3v-1zM64,97h2v1h-2v-1zM61,97h1v1h-1v-1zM59,97h1v1h-1v-1zM57,97h1v1h-1v-1zM55,97h1v1h-1v-1zM53,97h1v1h-1v-1zM50,97h2v1h-2v-1zM48,97h1v1h-1v-1zM42,97h2v1h-2v-1zM38,97h2v1h-2v-1zM35,97h2v1h-2v-1zM33,97h1v1h-1v-1zM29,97h2v1h-2v-1zM24,97h1v1h-1v-1zM21,97h1v1h-1v-1zM17,97h2v1h-2v-1zM13,97h2v1h-2v-1zM8,97h3v1h-3v-1zM1,97h2v1h-2v-1zM115,96h2v1h-2v-1zM109,96h5v1h-5v-1zM106,96h1v1h-1v-1zM103,96h2v1h-2v-1zM99,96h1v1h-1v-1zM96,96h2v1h-2v-1zM93,96h2v1h-2v-1zM88,96h1v1h-1v-1zM86,96h1v1h-1v-1zM84,96h1v1h-1v-1zM82,96h1v1h-1v-1zM78,96h2v1h-2v-1zM76,96h1v1h-1v-1zM72,96h3v1h-3v-1zM67,96h1v1h-1v-1zM65,96h1v1h-1v-1zM59,96h5v1h-5v-1zM53,96h3v1h-3v-1zM49,96h2v1h-2v-1zM44,96h2v1h-2v-1zM41,96h1v1h-1v-1zM37,96h2v1h-2v-1zM33,96h3v1h-3v-1zM28,96h2v1h-2v-1zM26,96h1v1h-1v-1zM23,96h2v1h-2v-1zM19,96h1v1h-1v-1zM14,96h2v1h-2v-1zM10,96h2v1h-2v-1zM6,96h3v1h-3v-1zM4,96h1v1h-1v-1zM0,96h3v1h-3v-1zM115,95h2v1h-2v-1zM111,95h2v1h-2v-1zM106,95h4v1h-4v-1zM102,95h2v1h-2v-1zM100,95h1v1h-1v-1zM97,95h1v1h-1v-1zM95,95h1v1h-1v-1zM93,95h1v1h-1v-1zM91,95h1v1h-1v-1zM88,95h2v1h-2v-1zM83,95h3v1h-3v-1zM81,95h1v1h-1v-1zM76,95h4v1h-4v-1zM73,95h2v1h-2v-1zM69,95h2v1h-2v-1zM64,95h4v1h-4v-1zM62,95h1v1h-1v-1zM60,95h1v1h-1v-1zM56,95h1v1h-1v-1zM54,95h1v1h-1v-1zM52,95h1v1h-1v-1zM49,95h2v1h-2v-1zM45,95h1v1h-1v-1zM43,95h1v1h-1v-1zM39,95h3v1h-3v-1zM34,95h1v1h-1v-1zM32,95h1v1h-1v-1zM28,95h3v1h-3v-1zM25,95h1v1h-1v-1zM23,95h1v1h-1v-1zM20,95h1v1h-1v-1zM16,95h1v1h-1v-1zM12,95h2v1h-2v-1zM9,95h2v1h-2v-1zM7,95h1v1h-1v-1zM0,95h1v1h-1v-1zM115,94h1v1h-1v-1zM111,94h1v1h-1v-1zM106,94h4v1h-4v-1zM103,94h2v1h-2v-1zM101,94h1v1h-1v-1zM96,94h2v1h-2v-1zM94,94h1v1h-1v-1zM91,94h2v1h-2v-1zM85,94h3v1h-3v-1zM83,94h1v1h-1v-1zM79,94h3v1h-3v-1zM70,94h2v1h-2v-1zM68,94h1v1h-1v-1zM63,94h2v1h-2v-1zM61,94h1v1h-1v-1zM58,94h1v1h-1v-1zM55,94h1v1h-1v-1zM53,94h1v1h-1v-1zM51,94h1v1h-1v-1zM46,94h2v1h-2v-1zM42,94h3v1h-3v-1zM37,94h1v1h-1v-1zM31,94h3v1h-3v-1zM27,94h1v1h-1v-1zM25,94h1v1h-1v-1zM22,94h1v1h-1v-1zM19,94h1v1h-1v-1zM13,94h2v1h-2v-1zM11,94h1v1h-1v-1zM2,94h5v1h-5v-1zM114,93h1v1h-1v-1zM109,93h2v1h-2v-1zM105,93h2v1h-2v-1zM103,93h1v1h-1v-1zM92,93h1v1h-1v-1zM89,93h2v1h-2v-1zM85,93h3v1h-3v-1zM83,93h1v1h-1v-1zM80,93h1v1h-1v-1zM75,93h1v1h-1v-1zM72,93h2v1h-2v-1zM66,93h5v1h-5v-1zM64,93h1v1h-1v-1zM60,93h3v1h-3v-1zM55,93h3v1h-3v-1zM53,93h1v1h-1v-1zM50,93h1v1h-1v-1zM48,93h1v1h-1v-1zM43,93h2v1h-2v-1zM37,93h2v1h-2v-1zM31,93h3v1h-3v-1zM28,93h1v1h-1v-1zM26,93h1v1h-1v-1zM24,93h1v1h-1v-1zM20,93h1v1h-1v-1zM12,93h2v1h-2v-1zM8,93h3v1h-3v-1zM5,93h1v1h-1v-1zM2,93h1v1h-1v-1zM116,92h1v1h-1v-1zM111,92h2v1h-2v-1zM108,92h2v1h-2v-1zM104,92h2v1h-2v-1zM102,92h1v1h-1v-1zM97,92h4v1h-4v-1zM94,92h1v1h-1v-1zM91,92h2v1h-2v-1zM89,92h1v1h-1v-1zM84,92h2v1h-2v-1zM82,92h1v1h-1v-1zM77,92h2v1h-2v-1zM75,92h1v1h-1v-1zM71,92h1v1h-1v-1zM67,92h1v1h-1v-1zM61,92h5v1h-5v-1zM57,92h2v1h-2v-1zM53,92h2v1h-2v-1zM50,92h1v1h-1v-1zM48,92h1v1h-1v-1zM43,92h1v1h-1v-1zM41,92h1v1h-1v-1zM39,92h1v1h-1v-1zM37,92h1v1h-1v-1zM33,92h2v1h-2v-1zM31,92h1v1h-1v-1zM28,92h1v1h-1v-1zM25,92h1v1h-1v-1zM17,92h7v1h-7v-1zM14,92h1v1h-1v-1zM11,92h2v1h-2v-1zM9,92h1v1h-1v-1zM5,92h2v1h-2v-1zM1,92h3v1h-3v-1zM116,91h1v1h-1v-1zM112,91h1v1h-1v-1zM108,91h3v1h-3v-1zM105,91h1v1h-1v-1zM102,91h2v1h-2v-1zM100,91h1v1h-1v-1zM93,91h1v1h-1v-1zM90,91h2v1h-2v-1zM88,91h1v1h-1v-1zM83,91h2v1h-2v-1zM81,91h1v1h-1v-1zM79,91h1v1h-1v-1zM76,91h1v1h-1v-1zM73,91h2v1h-2v-1zM69,91h1v1h-1v-1zM64,91h4v1h-4v-1zM59,91h3v1h-3v-1zM49,91h9v1h-9v-1zM38,91h6v1h-6v-1zM34,91h1v1h-1v-1zM32,91h1v1h-1v-1zM28,91h3v1h-3v-1zM21,91h1v1h-1v-1zM19,91h1v1h-1v-1zM17,91h1v1h-1v-1zM13,91h1v1h-1v-1zM11,91h1v1h-1v-1zM8,91h2v1h-2v-1zM3,91h2v1h-2v-1zM0,91h1v1h-1v-1zM115,90h1v1h-1v-1zM112,90h2v1h-2v-1zM106,90h2v1h-2v-1zM103,90h2v1h-2v-1zM99,90h3v1h-3v-1zM97,90h1v1h-1v-1zM94,90h1v1h-1v-1zM85,90h4v1h-4v-1zM82,90h1v1h-1v-1zM79,90h1v1h-1v-1zM75,90h2v1h-2v-1zM73,90h1v1h-1v-1zM70,90h2v1h-2v-1zM68,90h1v1h-1v-1zM63,90h1v1h-1v-1zM61,90h1v1h-1v-1zM57,90h2v1h-2v-1zM45,90h3v1h-3v-1zM43,90h1v1h-1v-1zM40,90h1v1h-1v-1zM34,90h4v1h-4v-1zM30,90h2v1h-2v-1zM28,90h1v1h-1v-1zM25,90h2v1h-2v-1zM22,90h2v1h-2v-1zM18,90h1v1h-1v-1zM13,90h3v1h-3v-1zM11,90h1v1h-1v-1zM9,90h1v1h-1v-1zM2,90h6v1h-6v-1zM0,90h1v1h-1v-1zM115,89h1v1h-1v-1zM113,89h1v1h-1v-1zM111,89h1v1h-1v-1zM108,89h2v1h-2v-1zM105,89h2v1h-2v-1zM103,89h1v1h-1v-1zM101,89h1v1h-1v-1zM97,89h1v1h-1v-1zM93,89h2v1h-2v-1zM91,89h1v1h-1v-1zM88,89h1v1h-1v-1zM82,89h5v1h-5v-1zM79,89h2v1h-2v-1zM76,89h2v1h-2v-1zM73,89h1v1h-1v-1zM71,89h1v1h-1v-1zM68,89h1v1h-1v-1zM65,89h2v1h-2v-1zM60,89h2v1h-2v-1zM55,89h3v1h-3v-1zM50,89h4v1h-4v-1zM43,89h6v1h-6v-1zM41,89h1v1h-1v-1zM38,89h2v1h-2v-1zM35,89h2v1h-2v-1zM32,89h2v1h-2v-1zM27,89h2v1h-2v-1zM25,89h1v1h-1v-1zM20,89h1v1h-1v-1zM18,89h1v1h-1v-1zM12,89h4v1h-4v-1zM0,89h6v1h-6v-1zM115,88h1v1h-1v-1zM113,88h1v1h-1v-1zM108,88h1v1h-1v-1zM104,88h3v1h-3v-1zM100,88h3v1h-3v-1zM95,88h3v1h-3v-1zM92,88h1v1h-1v-1zM84,88h1v1h-1v-1zM82,88h1v1h-1v-1zM76,88h5v1h-5v-1zM74,88h1v1h-1v-1zM71,88h1v1h-1v-1zM67,88h2v1h-2v-1zM62,88h3v1h-3v-1zM59,88h2v1h-2v-1zM57,88h1v1h-1v-1zM54,88h2v1h-2v-1zM49,88h1v1h-1v-1zM47,88h1v1h-1v-1zM42,88h4v1h-4v-1zM39,88h1v1h-1v-1zM35,88h1v1h-1v-1zM31,88h2v1h-2v-1zM23,88h2v1h-2v-1zM20,88h1v1h-1v-1zM16,88h3v1h-3v-1zM14,88h1v1h-1v-1zM12,88h1v1h-1v-1zM9,88h2v1h-2v-1zM6,88h1v1h-1v-1zM3,88h1v1h-1v-1zM1,88h1v1h-1v-1zM116,87h1v1h-1v-1zM112,87h2v1h-2v-1zM108,87h1v1h-1v-1zM105,87h2v1h-2v-1zM100,87h4v1h-4v-1zM98,87h1v1h-1v-1zM93,87h1v1h-1v-1zM90,87h2v1h-2v-1zM88,87h1v1h-1v-1zM85,87h1v1h-1v-1zM81,87h2v1h-2v-1zM76,87h4v1h-4v-1zM74,87h1v1h-1v-1zM70,87h1v1h-1v-1zM64,87h4v1h-4v-1zM57,87h3v1h-3v-1zM54,87h1v1h-1v-1zM52,87h1v1h-1v-1zM49,87h2v1h-2v-1zM46,87h1v1h-1v-1zM40,87h4v1h-4v-1zM37,87h1v1h-1v-1zM33,87h1v1h-1v-1zM31,87h1v1h-1v-1zM28,87h2v1h-2v-1zM25,87h2v1h-2v-1zM20,87h3v1h-3v-1zM16,87h1v1h-1v-1zM12,87h3v1h-3v-1zM8,87h1v1h-1v-1zM5,87h1v1h-1v-1zM3,87h1v1h-1v-1zM115,86h1v1h-1v-1zM106,86h7v1h-7v-1zM104,86h1v1h-1v-1zM99,86h1v1h-1v-1zM97,86h1v1h-1v-1zM94,86h2v1h-2v-1zM92,86h1v1h-1v-1zM88,86h2v1h-2v-1zM82,86h5v1h-5v-1zM75,86h1v1h-1v-1zM70,86h4v1h-4v-1zM63,86h3v1h-3v-1zM56,86h6v1h-6v-1zM51,86h2v1h-2v-1zM43,86h5v1h-5v-1zM40,86h1v1h-1v-1zM37,86h1v1h-1v-1zM29,86h7v1h-7v-1zM22,86h1v1h-1v-1zM13,86h6v1h-6v-1zM10,86h1v1h-1v-1zM3,86h6v1h-6v-1zM1,86h1v1h-1v-1zM115,85h1v1h-1v-1zM112,85h1v1h-1v-1zM108,85h1v1h-1v-1zM102,85h1v1h-1v-1zM100,85h1v1h-1v-1zM97,85h1v1h-1v-1zM95,85h1v1h-1v-1zM92,85h1v1h-1v-1zM88,85h1v1h-1v-1zM86,85h1v1h-1v-1zM79,85h4v1h-4v-1zM74,85h3v1h-3v-1zM70,85h3v1h-3v-1zM65,85h3v1h-3v-1zM60,85h4v1h-4v-1zM54,85h3v1h-3v-1zM49,85h3v1h-3v-1zM43,85h3v1h-3v-1zM41,85h1v1h-1v-1zM38,85h2v1h-2v-1zM34,85h2v1h-2v-1zM30,85h1v1h-1v-1zM28,85h1v1h-1v-1zM22,85h3v1h-3v-1zM19,85h2v1h-2v-1zM17,85h1v1h-1v-1zM15,85h1v1h-1v-1zM8,85h1v1h-1v-1zM3,85h2v1h-2v-1zM116,84h1v1h-1v-1zM112,84h3v1h-3v-1zM110,84h1v1h-1v-1zM108,84h1v1h-1v-1zM103,84h4v1h-4v-1zM98,84h3v1h-3v-1zM96,84h1v1h-1v-1zM90,84h1v1h-1v-1zM88,84h1v1h-1v-1zM86,84h1v1h-1v-1zM84,84h1v1h-1v-1zM81,84h2v1h-2v-1zM79,84h1v1h-1v-1zM73,84h1v1h-1v-1zM71,84h1v1h-1v-1zM66,84h2v1h-2v-1zM60,84h3v1h-3v-1zM58,84h1v1h-1v-1zM53,84h4v1h-4v-1zM49,84h1v1h-1v-1zM42,84h2v1h-2v-1zM39,84h2v1h-2v-1zM37,84h1v1h-1v-1zM34,84h1v1h-1v-1zM32,84h1v1h-1v-1zM29,84h2v1h-2v-1zM26,84h2v1h-2v-1zM23,84h1v1h-1v-1zM16,84h5v1h-5v-1zM14,84h1v1h-1v-1zM10,84h3v1h-3v-1zM8,84h1v1h-1v-1zM6,84h1v1h-1v-1zM4,84h1v1h-1v-1zM116,83h1v1h-1v-1zM112,83h1v1h-1v-1zM108,83h1v1h-1v-1zM105,83h1v1h-1v-1zM100,83h3v1h-3v-1zM97,83h1v1h-1v-1zM94,83h1v1h-1v-1zM90,83h1v1h-1v-1zM88,83h1v1h-1v-1zM86,83h1v1h-1v-1zM81,83h2v1h-2v-1zM78,83h2v1h-2v-1zM76,83h1v1h-1v-1zM74,83h1v1h-1v-1zM69,83h1v1h-1v-1zM66,83h2v1h-2v-1zM64,83h1v1h-1v-1zM62,83h1v1h-1v-1zM60,83h1v1h-1v-1zM56,83h1v1h-1v-1zM52,83h3v1h-3v-1zM42,83h2v1h-2v-1zM40,83h1v1h-1v-1zM36,83h3v1h-3v-1zM34,83h1v1h-1v-1zM28,83h3v1h-3v-1zM26,83h1v1h-1v-1zM15,83h2v1h-2v-1zM13,83h1v1h-1v-1zM10,83h1v1h-1v-1zM8,83h1v1h-1v-1zM4,83h1v1h-1v-1zM1,83h1v1h-1v-1zM114,82h2v1h-2v-1zM106,82h7v1h-7v-1zM103,82h2v1h-2v-1zM100,82h1v1h-1v-1zM96,82h2v1h-2v-1zM94,82h1v1h-1v-1zM91,82h2v1h-2v-1zM89,82h1v1h-1v-1zM82,82h5v1h-5v-1zM79,82h1v1h-1v-1zM77,82h1v1h-1v-1zM72,82h2v1h-2v-1zM70,82h1v1h-1v-1zM67,82h2v1h-2v-1zM64,82h2v1h-2v-1zM55,82h7v1h-7v-1zM51,82h1v1h-1v-1zM45,82h5v1h-5v-1zM43,82h1v1h-1v-1zM39,82h3v1h-3v-1zM30,82h6v1h-6v-1zM28,82h1v1h-1v-1zM25,82h1v1h-1v-1zM22,82h1v1h-1v-1zM20,82h1v1h-1v-1zM16,82h2v1h-2v-1zM12,82h3v1h-3v-1zM3,82h8v1h-8v-1zM114,81h2v1h-2v-1zM110,81h1v1h-1v-1zM106,81h3v1h-3v-1zM103,81h2v1h-2v-1zM100,81h1v1h-1v-1zM88,81h10v1h-10v-1zM83,81h2v1h-2v-1zM79,81h3v1h-3v-1zM76,81h2v1h-2v-1zM74,81h1v1h-1v-1zM72,81h1v1h-1v-1zM66,81h1v1h-1v-1zM63,81h1v1h-1v-1zM59,81h2v1h-2v-1zM54,81h4v1h-4v-1zM51,81h1v1h-1v-1zM49,81h1v1h-1v-1zM44,81h2v1h-2v-1zM40,81h2v1h-2v-1zM38,81h1v1h-1v-1zM36,81h1v1h-1v-1zM29,81h5v1h-5v-1zM26,81h1v1h-1v-1zM22,81h3v1h-3v-1zM20,81h1v1h-1v-1zM17,81h1v1h-1v-1zM13,81h1v1h-1v-1zM11,81h1v1h-1v-1zM7,81h2v1h-2v-1zM5,81h1v1h-1v-1zM2,81h2v1h-2v-1zM0,81h1v1h-1v-1zM115,80h1v1h-1v-1zM113,80h1v1h-1v-1zM111,80h1v1h-1v-1zM107,80h1v1h-1v-1zM101,80h3v1h-3v-1zM96,80h3v1h-3v-1zM92,80h1v1h-1v-1zM89,80h2v1h-2v-1zM85,80h2v1h-2v-1zM76,80h5v1h-5v-1zM73,80h2v1h-2v-1zM62,80h7v1h-7v-1zM60,80h1v1h-1v-1zM55,80h3v1h-3v-1zM52,80h1v1h-1v-1zM44,80h7v1h-7v-1zM41,80h2v1h-2v-1zM38,80h1v1h-1v-1zM35,80h2v1h-2v-1zM33,80h1v1h-1v-1zM30,80h1v1h-1v-1zM28,80h1v1h-1v-1zM24,80h3v1h-3v-1zM19,80h1v1h-1v-1zM16,80h1v1h-1v-1zM10,80h1v1h-1v-1zM5,80h2v1h-2v-1zM3,80h1v1h-1v-1zM1,80h1v1h-1v-1zM113,79h1v1h-1v-1zM108,79h4v1h-4v-1zM106,79h1v1h-1v-1zM103,79h1v1h-1v-1zM100,79h1v1h-1v-1zM97,79h2v1h-2v-1zM94,79h2v1h-2v-1zM88,79h2v1h-2v-1zM83,79h1v1h-1v-1zM81,79h1v1h-1v-1zM79,79h1v1h-1v-1zM76,79h2v1h-2v-1zM73,79h1v1h-1v-1zM69,79h1v1h-1v-1zM67,79h1v1h-1v-1zM64,79h1v1h-1v-1zM61,79h2v1h-2v-1zM52,79h2v1h-2v-1zM50,79h1v1h-1v-1zM45,79h1v1h-1v-1zM43,79h1v1h-1v-1zM40,79h2v1h-2v-1zM37,79h2v1h-2v-1zM28,79h4v1h-4v-1zM26,79h1v1h-1v-1zM21,79h1v1h-1v-1zM18,79h1v1h-1v-1zM16,79h1v1h-1v-1zM12,79h3v1h-3v-1zM7,79h2v1h-2v-1zM0,79h5v1h-5v-1zM112,78h2v1h-2v-1zM109,78h2v1h-2v-1zM106,78h1v1h-1v-1zM99,78h1v1h-1v-1zM94,78h3v1h-3v-1zM91,78h2v1h-2v-1zM88,78h1v1h-1v-1zM84,78h3v1h-3v-1zM82,78h1v1h-1v-1zM80,78h1v1h-1v-1zM73,78h1v1h-1v-1zM70,78h1v1h-1v-1zM67,78h1v1h-1v-1zM63,78h2v1h-2v-1zM61,78h1v1h-1v-1zM58,78h1v1h-1v-1zM55,78h1v1h-1v-1zM51,78h2v1h-2v-1zM46,78h4v1h-4v-1zM44,78h1v1h-1v-1zM39,78h1v1h-1v-1zM33,78h2v1h-2v-1zM27,78h1v1h-1v-1zM25,78h1v1h-1v-1zM22,78h2v1h-2v-1zM16,78h2v1h-2v-1zM13,78h2v1h-2v-1zM11,78h1v1h-1v-1zM9,78h1v1h-1v-1zM4,78h3v1h-3v-1zM0,78h2v1h-2v-1zM114,77h1v1h-1v-1zM112,77h1v1h-1v-1zM110,77h1v1h-1v-1zM107,77h2v1h-2v-1zM105,77h1v1h-1v-1zM102,77h1v1h-1v-1zM100,77h1v1h-1v-1zM95,77h4v1h-4v-1zM93,77h1v1h-1v-1zM91,77h1v1h-1v-1zM88,77h2v1h-2v-1zM83,77h2v1h-2v-1zM78,77h4v1h-4v-1zM75,77h1v1h-1v-1zM67,77h7v1h-7v-1zM64,77h2v1h-2v-1zM60,77h1v1h-1v-1zM58,77h1v1h-1v-1zM55,77h1v1h-1v-1zM53,77h1v1h-1v-1zM41,77h10v1h-10v-1zM39,77h1v1h-1v-1zM37,77h1v1h-1v-1zM32,77h2v1h-2v-1zM30,77h1v1h-1v-1zM28,77h1v1h-1v-1zM25,77h2v1h-2v-1zM21,77h3v1h-3v-1zM14,77h6v1h-6v-1zM10,77h3v1h-3v-1zM8,77h1v1h-1v-1zM3,77h3v1h-3v-1zM0,77h1v1h-1v-1zM115,76h2v1h-2v-1zM113,76h1v1h-1v-1zM110,76h1v1h-1v-1zM103,76h6v1h-6v-1zM100,76h1v1h-1v-1zM98,76h1v1h-1v-1zM96,76h1v1h-1v-1zM92,76h2v1h-2v-1zM90,76h1v1h-1v-1zM84,76h4v1h-4v-1zM82,76h1v1h-1v-1zM80,76h1v1h-1v-1zM75,76h3v1h-3v-1zM73,76h1v1h-1v-1zM69,76h1v1h-1v-1zM67,76h1v1h-1v-1zM62,76h2v1h-2v-1zM59,76h1v1h-1v-1zM56,76h1v1h-1v-1zM54,76h1v1h-1v-1zM49,76h2v1h-2v-1zM47,76h1v1h-1v-1zM41,76h3v1h-3v-1zM37,76h2v1h-2v-1zM28,76h5v1h-5v-1zM23,76h4v1h-4v-1zM20,76h1v1h-1v-1zM17,76h2v1h-2v-1zM12,76h4v1h-4v-1zM6,76h4v1h-4v-1zM3,76h2v1h-2v-1zM0,76h2v1h-2v-1zM115,75h2v1h-2v-1zM107,75h1v1h-1v-1zM105,75h1v1h-1v-1zM103,75h1v1h-1v-1zM100,75h2v1h-2v-1zM97,75h2v1h-2v-1zM93,75h2v1h-2v-1zM90,75h2v1h-2v-1zM88,75h1v1h-1v-1zM86,75h1v1h-1v-1zM84,75h1v1h-1v-1zM82,75h1v1h-1v-1zM79,75h1v1h-1v-1zM76,75h1v1h-1v-1zM73,75h2v1h-2v-1zM70,75h1v1h-1v-1zM67,75h1v1h-1v-1zM64,75h1v1h-1v-1zM62,75h1v1h-1v-1zM58,75h2v1h-2v-1zM55,75h1v1h-1v-1zM52,75h1v1h-1v-1zM49,75h1v1h-1v-1zM42,75h1v1h-1v-1zM40,75h1v1h-1v-1zM38,75h1v1h-1v-1zM34,75h1v1h-1v-1zM31,75h1v1h-1v-1zM28,75h2v1h-2v-1zM25,75h2v1h-2v-1zM13,75h8v1h-8v-1zM9,75h2v1h-2v-1zM7,75h1v1h-1v-1zM4,75h2v1h-2v-1zM0,75h1v1h-1v-1zM115,74h1v1h-1v-1zM111,74h1v1h-1v-1zM108,74h2v1h-2v-1zM106,74h1v1h-1v-1zM104,74h1v1h-1v-1zM99,74h1v1h-1v-1zM94,74h2v1h-2v-1zM92,74h1v1h-1v-1zM89,74h1v1h-1v-1zM87,74h1v1h-1v-1zM83,74h1v1h-1v-1zM79,74h1v1h-1v-1zM75,74h1v1h-1v-1zM70,74h4v1h-4v-1zM67,74h2v1h-2v-1zM64,74h1v1h-1v-1zM61,74h1v1h-1v-1zM58,74h1v1h-1v-1zM51,74h1v1h-1v-1zM43,74h7v1h-7v-1zM41,74h1v1h-1v-1zM39,74h1v1h-1v-1zM36,74h2v1h-2v-1zM33,74h2v1h-2v-1zM27,74h5v1h-5v-1zM22,74h4v1h-4v-1zM20,74h1v1h-1v-1zM16,74h1v1h-1v-1zM14,74h1v1h-1v-1zM9,74h3v1h-3v-1zM6,74h1v1h-1v-1zM1,74h1v1h-1v-1zM115,73h2v1h-2v-1zM113,73h1v1h-1v-1zM110,73h2v1h-2v-1zM107,73h2v1h-2v-1zM104,73h1v1h-1v-1zM98,73h1v1h-1v-1zM93,73h1v1h-1v-1zM91,73h1v1h-1v-1zM88,73h1v1h-1v-1zM83,73h2v1h-2v-1zM79,73h3v1h-3v-1zM77,73h1v1h-1v-1zM75,73h1v1h-1v-1zM70,73h4v1h-4v-1zM67,73h1v1h-1v-1zM64,73h1v1h-1v-1zM59,73h2v1h-2v-1zM54,73h1v1h-1v-1zM49,73h2v1h-2v-1zM46,73h1v1h-1v-1zM43,73h2v1h-2v-1zM40,73h2v1h-2v-1zM36,73h3v1h-3v-1zM32,73h2v1h-2v-1zM29,73h2v1h-2v-1zM25,73h2v1h-2v-1zM22,73h2v1h-2v-1zM17,73h2v1h-2v-1zM14,73h2v1h-2v-1zM7,73h1v1h-1v-1zM4,73h2v1h-2v-1zM1,73h2v1h-2v-1zM115,72h2v1h-2v-1zM108,72h4v1h-4v-1zM106,72h1v1h-1v-1zM101,72h4v1h-4v-1zM97,72h1v1h-1v-1zM94,72h1v1h-1v-1zM89,72h1v1h-1v-1zM85,72h3v1h-3v-1zM82,72h1v1h-1v-1zM77,72h3v1h-3v-1zM74,72h2v1h-2v-1zM72,72h1v1h-1v-1zM67,72h2v1h-2v-1zM59,72h2v1h-2v-1zM56,72h2v1h-2v-1zM53,72h2v1h-2v-1zM47,72h3v1h-3v-1zM41,72h4v1h-4v-1zM39,72h1v1h-1v-1zM37,72h1v1h-1v-1zM33,72h1v1h-1v-1zM28,72h2v1h-2v-1zM26,72h1v1h-1v-1zM22,72h3v1h-3v-1zM18,72h2v1h-2v-1zM15,72h2v1h-2v-1zM9,72h5v1h-5v-1zM6,72h2v1h-2v-1zM2,72h1v1h-1v-1zM115,71h2v1h-2v-1zM109,71h4v1h-4v-1zM103,71h1v1h-1v-1zM97,71h4v1h-4v-1zM95,71h1v1h-1v-1zM93,71h1v1h-1v-1zM90,71h2v1h-2v-1zM88,71h1v1h-1v-1zM83,71h3v1h-3v-1zM81,71h1v1h-1v-1zM76,71h4v1h-4v-1zM73,71h1v1h-1v-1zM71,71h1v1h-1v-1zM67,71h1v1h-1v-1zM64,71h2v1h-2v-1zM62,71h1v1h-1v-1zM58,71h2v1h-2v-1zM52,71h3v1h-3v-1zM49,71h2v1h-2v-1zM43,71h1v1h-1v-1zM40,71h1v1h-1v-1zM37,71h1v1h-1v-1zM34,71h1v1h-1v-1zM31,71h1v1h-1v-1zM26,71h4v1h-4v-1zM20,71h3v1h-3v-1zM18,71h1v1h-1v-1zM16,71h1v1h-1v-1zM13,71h2v1h-2v-1zM11,71h1v1h-1v-1zM8,71h2v1h-2v-1zM5,71h1v1h-1v-1zM3,71h1v1h-1v-1zM0,71h2v1h-2v-1zM113,70h3v1h-3v-1zM109,70h2v1h-2v-1zM105,70h2v1h-2v-1zM103,70h1v1h-1v-1zM96,70h2v1h-2v-1zM94,70h1v1h-1v-1zM92,70h1v1h-1v-1zM86,70h4v1h-4v-1zM82,70h1v1h-1v-1zM80,70h1v1h-1v-1zM75,70h1v1h-1v-1zM72,70h2v1h-2v-1zM69,70h2v1h-2v-1zM67,70h1v1h-1v-1zM64,70h1v1h-1v-1zM59,70h3v1h-3v-1zM55,70h1v1h-1v-1zM51,70h1v1h-1v-1zM49,70h1v1h-1v-1zM46,70h2v1h-2v-1zM43,70h2v1h-2v-1zM39,70h2v1h-2v-1zM37,70h1v1h-1v-1zM35,70h1v1h-1v-1zM33,70h1v1h-1v-1zM29,70h2v1h-2v-1zM25,70h1v1h-1v-1zM22,70h2v1h-2v-1zM15,70h4v1h-4v-1zM11,70h3v1h-3v-1zM6,70h3v1h-3v-1zM3,70h2v1h-2v-1zM0,70h1v1h-1v-1zM114,69h1v1h-1v-1zM103,69h9v1h-9v-1zM101,69h1v1h-1v-1zM96,69h3v1h-3v-1zM93,69h2v1h-2v-1zM91,69h1v1h-1v-1zM83,69h4v1h-4v-1zM81,69h1v1h-1v-1zM78,69h2v1h-2v-1zM75,69h1v1h-1v-1zM71,69h3v1h-3v-1zM65,69h1v1h-1v-1zM55,69h7v1h-7v-1zM53,69h1v1h-1v-1zM51,69h1v1h-1v-1zM48,69h2v1h-2v-1zM46,69h1v1h-1v-1zM41,69h3v1h-3v-1zM38,69h1v1h-1v-1zM36,69h1v1h-1v-1zM34,69h1v1h-1v-1zM32,69h1v1h-1v-1zM28,69h3v1h-3v-1zM24,69h2v1h-2v-1zM22,69h1v1h-1v-1zM15,69h1v1h-1v-1zM8,69h6v1h-6v-1zM3,69h3v1h-3v-1zM0,69h1v1h-1v-1zM116,68h1v1h-1v-1zM113,68h2v1h-2v-1zM110,68h2v1h-2v-1zM105,68h3v1h-3v-1zM101,68h3v1h-3v-1zM98,68h1v1h-1v-1zM89,68h5v1h-5v-1zM86,68h2v1h-2v-1zM84,68h1v1h-1v-1zM81,68h1v1h-1v-1zM78,68h2v1h-2v-1zM73,68h2v1h-2v-1zM71,68h1v1h-1v-1zM65,68h5v1h-5v-1zM61,68h1v1h-1v-1zM59,68h1v1h-1v-1zM55,68h3v1h-3v-1zM49,68h5v1h-5v-1zM45,68h1v1h-1v-1zM39,68h5v1h-5v-1zM37,68h1v1h-1v-1zM31,68h3v1h-3v-1zM28,68h2v1h-2v-1zM25,68h1v1h-1v-1zM17,68h2v1h-2v-1zM11,68h3v1h-3v-1zM9,68h1v1h-1v-1zM5,68h2v1h-2v-1zM2,68h2v1h-2v-1zM115,67h1v1h-1v-1zM111,67h1v1h-1v-1zM107,67h2v1h-2v-1zM100,67h4v1h-4v-1zM97,67h2v1h-2v-1zM93,67h3v1h-3v-1zM91,67h1v1h-1v-1zM88,67h1v1h-1v-1zM85,67h1v1h-1v-1zM81,67h1v1h-1v-1zM78,67h1v1h-1v-1zM75,67h2v1h-2v-1zM69,67h3v1h-3v-1zM64,67h1v1h-1v-1zM58,67h3v1h-3v-1zM50,67h7v1h-7v-1zM46,67h1v1h-1v-1zM37,67h4v1h-4v-1zM31,67h4v1h-4v-1zM28,67h1v1h-1v-1zM25,67h1v1h-1v-1zM20,67h1v1h-1v-1zM13,67h6v1h-6v-1zM8,67h3v1h-3v-1zM0,67h4v1h-4v-1zM110,66h3v1h-3v-1zM106,66h3v1h-3v-1zM104,66h1v1h-1v-1zM99,66h1v1h-1v-1zM96,66h1v1h-1v-1zM94,66h1v1h-1v-1zM91,66h1v1h-1v-1zM88,66h1v1h-1v-1zM83,66h3v1h-3v-1zM79,66h3v1h-3v-1zM77,66h1v1h-1v-1zM70,66h4v1h-4v-1zM67,66h2v1h-2v-1zM63,66h1v1h-1v-1zM61,66h1v1h-1v-1zM57,66h2v1h-2v-1zM46,66h4v1h-4v-1zM43,66h2v1h-2v-1zM36,66h1v1h-1v-1zM30,66h4v1h-4v-1zM28,66h1v1h-1v-1zM24,66h2v1h-2v-1zM19,66h4v1h-4v-1zM17,66h1v1h-1v-1zM14,66h2v1h-2v-1zM10,66h1v1h-1v-1zM6,66h3v1h-3v-1zM2,66h2v1h-2v-1zM0,66h1v1h-1v-1zM115,65h2v1h-2v-1zM112,65h1v1h-1v-1zM110,65h1v1h-1v-1zM108,65h1v1h-1v-1zM106,65h1v1h-1v-1zM100,65h5v1h-5v-1zM97,65h1v1h-1v-1zM93,65h3v1h-3v-1zM89,65h3v1h-3v-1zM87,65h1v1h-1v-1zM83,65h2v1h-2v-1zM81,65h1v1h-1v-1zM79,65h1v1h-1v-1zM76,65h1v1h-1v-1zM71,65h2v1h-2v-1zM66,65h4v1h-4v-1zM57,65h5v1h-5v-1zM48,65h4v1h-4v-1zM43,65h3v1h-3v-1zM41,65h1v1h-1v-1zM36,65h2v1h-2v-1zM32,65h3v1h-3v-1zM29,65h2v1h-2v-1zM27,65h1v1h-1v-1zM22,65h1v1h-1v-1zM16,65h1v1h-1v-1zM12,65h2v1h-2v-1zM9,65h1v1h-1v-1zM5,65h1v1h-1v-1zM0,65h4v1h-4v-1zM116,64h1v1h-1v-1zM109,64h3v1h-3v-1zM107,64h1v1h-1v-1zM100,64h5v1h-5v-1zM97,64h2v1h-2v-1zM89,64h3v1h-3v-1zM86,64h2v1h-2v-1zM82,64h2v1h-2v-1zM78,64h2v1h-2v-1zM72,64h4v1h-4v-1zM66,64h4v1h-4v-1zM64,64h1v1h-1v-1zM61,64h1v1h-1v-1zM55,64h3v1h-3v-1zM48,64h5v1h-5v-1zM46,64h1v1h-1v-1zM44,64h1v1h-1v-1zM40,64h3v1h-3v-1zM37,64h2v1h-2v-1zM33,64h1v1h-1v-1zM31,64h1v1h-1v-1zM28,64h1v1h-1v-1zM26,64h1v1h-1v-1zM24,64h1v1h-1v-1zM21,64h2v1h-2v-1zM19,64h1v1h-1v-1zM11,64h6v1h-6v-1zM4,64h5v1h-5v-1zM2,64h1v1h-1v-1zM116,63h1v1h-1v-1zM112,63h1v1h-1v-1zM107,63h1v1h-1v-1zM105,63h1v1h-1v-1zM103,63h1v1h-1v-1zM100,63h2v1h-2v-1zM98,63h1v1h-1v-1zM95,63h1v1h-1v-1zM91,63h1v1h-1v-1zM88,63h2v1h-2v-1zM85,63h1v1h-1v-1zM83,63h1v1h-1v-1zM79,63h1v1h-1v-1zM76,63h1v1h-1v-1zM74,63h1v1h-1v-1zM69,63h2v1h-2v-1zM67,63h1v1h-1v-1zM60,63h6v1h-6v-1zM55,63h3v1h-3v-1zM51,63h3v1h-3v-1zM49,63h1v1h-1v-1zM40,63h4v1h-4v-1zM37,63h1v1h-1v-1zM34,63h1v1h-1v-1zM28,63h1v1h-1v-1zM26,63h1v1h-1v-1zM20,63h3v1h-3v-1zM18,63h1v1h-1v-1zM13,63h1v1h-1v-1zM11,63h1v1h-1v-1zM8,63h2v1h-2v-1zM4,63h2v1h-2v-1zM0,63h3v1h-3v-1zM112,62h4v1h-4v-1zM110,62h1v1h-1v-1zM106,62h3v1h-3v-1zM104,62h1v1h-1v-1zM100,62h1v1h-1v-1zM96,62h2v1h-2v-1zM92,62h3v1h-3v-1zM88,62h1v1h-1v-1zM83,62h1v1h-1v-1zM80,62h2v1h-2v-1zM75,62h2v1h-2v-1zM73,62h1v1h-1v-1zM70,62h2v1h-2v-1zM68,62h1v1h-1v-1zM61,62h1v1h-1v-1zM59,62h1v1h-1v-1zM57,62h1v1h-1v-1zM55,62h1v1h-1v-1zM46,62h4v1h-4v-1zM44,62h1v1h-1v-1zM39,62h2v1h-2v-1zM37,62h1v1h-1v-1zM35,62h1v1h-1v-1zM33,62h1v1h-1v-1zM31,62h1v1h-1v-1zM27,62h1v1h-1v-1zM22,62h4v1h-4v-1zM19,62h1v1h-1v-1zM13,62h5v1h-5v-1zM9,62h1v1h-1v-1zM4,62h3v1h-3v-1zM0,62h1v1h-1v-1zM114,61h1v1h-1v-1zM110,61h2v1h-2v-1zM104,61h5v1h-5v-1zM101,61h2v1h-2v-1zM98,61h2v1h-2v-1zM96,61h1v1h-1v-1zM91,61h3v1h-3v-1zM83,61h3v1h-3v-1zM80,61h2v1h-2v-1zM77,61h1v1h-1v-1zM75,61h1v1h-1v-1zM73,61h1v1h-1v-1zM69,61h1v1h-1v-1zM64,61h2v1h-2v-1zM62,61h1v1h-1v-1zM58,61h3v1h-3v-1zM55,61h2v1h-2v-1zM53,61h1v1h-1v-1zM49,61h2v1h-2v-1zM47,61h1v1h-1v-1zM43,61h1v1h-1v-1zM40,61h2v1h-2v-1zM38,61h1v1h-1v-1zM32,61h3v1h-3v-1zM29,61h2v1h-2v-1zM25,61h1v1h-1v-1zM13,61h3v1h-3v-1zM10,61h2v1h-2v-1zM8,61h1v1h-1v-1zM3,61h2v1h-2v-1zM0,61h2v1h-2v-1zM115,60h1v1h-1v-1zM108,60h6v1h-6v-1zM101,60h1v1h-1v-1zM93,60h6v1h-6v-1zM82,60h6v1h-6v-1zM80,60h1v1h-1v-1zM76,60h1v1h-1v-1zM73,60h2v1h-2v-1zM70,60h1v1h-1v-1zM66,60h3v1h-3v-1zM62,60h1v1h-1v-1zM56,60h5v1h-5v-1zM53,60h2v1h-2v-1zM47,60h3v1h-3v-1zM42,60h4v1h-4v-1zM40,60h1v1h-1v-1zM36,60h2v1h-2v-1zM23,60h12v1h-12v-1zM18,60h4v1h-4v-1zM16,60h1v1h-1v-1zM10,60h5v1h-5v-1zM2,60h7v1h-7v-1zM116,59h1v1h-1v-1zM112,59h2v1h-2v-1zM108,59h1v1h-1v-1zM105,59h2v1h-2v-1zM103,59h1v1h-1v-1zM100,59h1v1h-1v-1zM97,59h2v1h-2v-1zM90,59h1v1h-1v-1zM88,59h1v1h-1v-1zM86,59h1v1h-1v-1zM82,59h1v1h-1v-1zM79,59h1v1h-1v-1zM76,59h1v1h-1v-1zM74,59h1v1h-1v-1zM64,59h4v1h-4v-1zM60,59h1v1h-1v-1zM52,59h5v1h-5v-1zM45,59h3v1h-3v-1zM42,59h2v1h-2v-1zM40,59h1v1h-1v-1zM37,59h2v1h-2v-1zM34,59h1v1h-1v-1zM28,59h3v1h-3v-1zM25,59h1v1h-1v-1zM20,59h1v1h-1v-1zM16,59h3v1h-3v-1zM12,59h1v1h-1v-1zM8,59h3v1h-3v-1zM2,59h3v1h-3v-1zM0,59h1v1h-1v-1zM114,58h2v1h-2v-1zM112,58h1v1h-1v-1zM110,58h1v1h-1v-1zM108,58h1v1h-1v-1zM106,58h1v1h-1v-1zM103,58h1v1h-1v-1zM100,58h1v1h-1v-1zM94,58h1v1h-1v-1zM91,58h2v1h-2v-1zM89,58h1v1h-1v-1zM86,58h2v1h-2v-1zM84,58h1v1h-1v-1zM81,58h2v1h-2v-1zM76,58h1v1h-1v-1zM72,58h2v1h-2v-1zM69,58h2v1h-2v-1zM67,58h1v1h-1v-1zM63,58h2v1h-2v-1zM60,58h2v1h-2v-1zM58,58h1v1h-1v-1zM55,58h2v1h-2v-1zM52,58h2v1h-2v-1zM48,58h2v1h-2v-1zM46,58h1v1h-1v-1zM43,58h1v1h-1v-1zM39,58h3v1h-3v-1zM36,58h1v1h-1v-1zM34,58h1v1h-1v-1zM32,58h1v1h-1v-1zM29,58h2v1h-2v-1zM25,58h1v1h-1v-1zM22,58h2v1h-2v-1zM18,58h2v1h-2v-1zM15,58h2v1h-2v-1zM12,58h1v1h-1v-1zM8,58h2v1h-2v-1zM6,58h1v1h-1v-1zM4,58h1v1h-1v-1zM116,57h1v1h-1v-1zM114,57h1v1h-1v-1zM112,57h1v1h-1v-1zM108,57h1v1h-1v-1zM104,57h1v1h-1v-1zM102,57h1v1h-1v-1zM98,57h2v1h-2v-1zM94,57h3v1h-3v-1zM90,57h1v1h-1v-1zM88,57h1v1h-1v-1zM86,57h1v1h-1v-1zM78,57h5v1h-5v-1zM74,57h2v1h-2v-1zM72,57h1v1h-1v-1zM70,57h1v1h-1v-1zM67,57h1v1h-1v-1zM63,57h3v1h-3v-1zM60,57h2v1h-2v-1zM56,57h1v1h-1v-1zM53,57h2v1h-2v-1zM47,57h2v1h-2v-1zM45,57h1v1h-1v-1zM38,57h2v1h-2v-1zM34,57h3v1h-3v-1zM30,57h1v1h-1v-1zM24,57h1v1h-1v-1zM17,57h1v1h-1v-1zM12,57h2v1h-2v-1zM8,57h2v1h-2v-1zM4,57h1v1h-1v-1zM115,56h1v1h-1v-1zM106,56h7v1h-7v-1zM102,56h2v1h-2v-1zM98,56h3v1h-3v-1zM96,56h1v1h-1v-1zM88,56h6v1h-6v-1zM81,56h6v1h-6v-1zM79,56h1v1h-1v-1zM76,56h1v1h-1v-1zM74,56h1v1h-1v-1zM71,56h1v1h-1v-1zM65,56h5v1h-5v-1zM54,56h8v1h-8v-1zM50,56h3v1h-3v-1zM46,56h3v1h-3v-1zM43,56h2v1h-2v-1zM39,56h2v1h-2v-1zM36,56h2v1h-2v-1zM30,56h5v1h-5v-1zM26,56h2v1h-2v-1zM22,56h2v1h-2v-1zM18,56h3v1h-3v-1zM15,56h1v1h-1v-1zM10,56h2v1h-2v-1zM4,56h5v1h-5v-1zM1,56h1v1h-1v-1zM115,55h1v1h-1v-1zM112,55h1v1h-1v-1zM109,55h1v1h-1v-1zM105,55h3v1h-3v-1zM100,55h2v1h-2v-1zM93,55h1v1h-1v-1zM88,55h4v1h-4v-1zM85,55h1v1h-1v-1zM82,55h1v1h-1v-1zM79,55h1v1h-1v-1zM76,55h1v1h-1v-1zM74,55h1v1h-1v-1zM69,55h2v1h-2v-1zM67,55h1v1h-1v-1zM60,55h6v1h-6v-1zM58,55h1v1h-1v-1zM55,55h2v1h-2v-1zM51,55h2v1h-2v-1zM45,55h1v1h-1v-1zM43,55h1v1h-1v-1zM40,55h2v1h-2v-1zM34,55h1v1h-1v-1zM30,55h2v1h-2v-1zM26,55h3v1h-3v-1zM21,55h2v1h-2v-1zM17,55h1v1h-1v-1zM15,55h1v1h-1v-1zM7,55h1v1h-1v-1zM5,55h1v1h-1v-1zM1,55h2v1h-2v-1zM113,54h3v1h-3v-1zM108,54h2v1h-2v-1zM106,54h1v1h-1v-1zM103,54h2v1h-2v-1zM100,54h1v1h-1v-1zM94,54h4v1h-4v-1zM92,54h1v1h-1v-1zM88,54h1v1h-1v-1zM84,54h3v1h-3v-1zM79,54h4v1h-4v-1zM75,54h2v1h-2v-1zM70,54h4v1h-4v-1zM59,54h3v1h-3v-1zM55,54h2v1h-2v-1zM46,54h4v1h-4v-1zM43,54h2v1h-2v-1zM35,54h5v1h-5v-1zM33,54h1v1h-1v-1zM31,54h1v1h-1v-1zM28,54h2v1h-2v-1zM25,54h1v1h-1v-1zM22,54h2v1h-2v-1zM18,54h1v1h-1v-1zM13,54h3v1h-3v-1zM10,54h1v1h-1v-1zM8,54h1v1h-1v-1zM5,54h2v1h-2v-1zM3,54h1v1h-1v-1zM0,54h1v1h-1v-1zM114,53h2v1h-2v-1zM110,53h1v1h-1v-1zM106,53h1v1h-1v-1zM103,53h1v1h-1v-1zM101,53h1v1h-1v-1zM98,53h1v1h-1v-1zM96,53h1v1h-1v-1zM92,53h3v1h-3v-1zM88,53h1v1h-1v-1zM85,53h2v1h-2v-1zM83,53h1v1h-1v-1zM81,53h1v1h-1v-1zM76,53h1v1h-1v-1zM71,53h4v1h-4v-1zM68,53h2v1h-2v-1zM65,53h2v1h-2v-1zM59,53h1v1h-1v-1zM57,53h1v1h-1v-1zM55,53h1v1h-1v-1zM50,53h4v1h-4v-1zM46,53h2v1h-2v-1zM43,53h2v1h-2v-1zM41,53h1v1h-1v-1zM39,53h1v1h-1v-1zM35,53h3v1h-3v-1zM29,53h4v1h-4v-1zM26,53h2v1h-2v-1zM23,53h2v1h-2v-1zM20,53h2v1h-2v-1zM18,53h1v1h-1v-1zM14,53h3v1h-3v-1zM9,53h4v1h-4v-1zM2,53h2v1h-2v-1zM115,52h2v1h-2v-1zM110,52h4v1h-4v-1zM108,52h1v1h-1v-1zM106,52h1v1h-1v-1zM102,52h2v1h-2v-1zM100,52h1v1h-1v-1zM97,52h1v1h-1v-1zM89,52h5v1h-5v-1zM83,52h2v1h-2v-1zM80,52h2v1h-2v-1zM78,52h1v1h-1v-1zM74,52h1v1h-1v-1zM70,52h2v1h-2v-1zM67,52h2v1h-2v-1zM62,52h1v1h-1v-1zM58,52h3v1h-3v-1zM55,52h1v1h-1v-1zM51,52h1v1h-1v-1zM48,52h1v1h-1v-1zM46,52h1v1h-1v-1zM44,52h1v1h-1v-1zM40,52h3v1h-3v-1zM30,52h5v1h-5v-1zM27,52h2v1h-2v-1zM24,52h2v1h-2v-1zM20,52h1v1h-1v-1zM16,52h2v1h-2v-1zM14,52h1v1h-1v-1zM10,52h3v1h-3v-1zM1,52h6v1h-6v-1zM115,51h2v1h-2v-1zM112,51h2v1h-2v-1zM107,51h2v1h-2v-1zM102,51h1v1h-1v-1zM100,51h1v1h-1v-1zM97,51h2v1h-2v-1zM95,51h1v1h-1v-1zM93,51h1v1h-1v-1zM88,51h4v1h-4v-1zM83,51h2v1h-2v-1zM79,51h1v1h-1v-1zM76,51h2v1h-2v-1zM67,51h1v1h-1v-1zM64,51h2v1h-2v-1zM61,51h2v1h-2v-1zM58,51h2v1h-2v-1zM56,51h1v1h-1v-1zM54,51h1v1h-1v-1zM52,51h1v1h-1v-1zM50,51h1v1h-1v-1zM46,51h2v1h-2v-1zM38,51h5v1h-5v-1zM34,51h2v1h-2v-1zM30,51h3v1h-3v-1zM28,51h1v1h-1v-1zM26,51h1v1h-1v-1zM16,51h7v1h-7v-1zM14,51h1v1h-1v-1zM11,51h1v1h-1v-1zM7,51h2v1h-2v-1zM2,51h3v1h-3v-1zM114,50h1v1h-1v-1zM111,50h1v1h-1v-1zM103,50h6v1h-6v-1zM100,50h2v1h-2v-1zM96,50h1v1h-1v-1zM94,50h1v1h-1v-1zM92,50h1v1h-1v-1zM81,50h5v1h-5v-1zM79,50h1v1h-1v-1zM75,50h1v1h-1v-1zM68,50h6v1h-6v-1zM63,50h2v1h-2v-1zM59,50h1v1h-1v-1zM57,50h1v1h-1v-1zM51,50h1v1h-1v-1zM48,50h2v1h-2v-1zM46,50h1v1h-1v-1zM43,50h1v1h-1v-1zM36,50h2v1h-2v-1zM32,50h3v1h-3v-1zM28,50h2v1h-2v-1zM25,50h1v1h-1v-1zM18,50h2v1h-2v-1zM14,50h2v1h-2v-1zM12,50h1v1h-1v-1zM9,50h1v1h-1v-1zM6,50h1v1h-1v-1zM3,50h2v1h-2v-1zM1,50h1v1h-1v-1zM114,49h1v1h-1v-1zM111,49h1v1h-1v-1zM107,49h1v1h-1v-1zM104,49h2v1h-2v-1zM102,49h1v1h-1v-1zM99,49h1v1h-1v-1zM95,49h2v1h-2v-1zM92,49h2v1h-2v-1zM86,49h1v1h-1v-1zM82,49h3v1h-3v-1zM77,49h3v1h-3v-1zM70,49h1v1h-1v-1zM67,49h1v1h-1v-1zM65,49h1v1h-1v-1zM61,49h1v1h-1v-1zM59,49h1v1h-1v-1zM56,49h1v1h-1v-1zM46,49h8v1h-8v-1zM44,49h1v1h-1v-1zM41,49h1v1h-1v-1zM38,49h1v1h-1v-1zM32,49h3v1h-3v-1zM25,49h6v1h-6v-1zM22,49h2v1h-2v-1zM15,49h3v1h-3v-1zM10,49h2v1h-2v-1zM7,49h2v1h-2v-1zM4,49h2v1h-2v-1zM0,49h3v1h-3v-1zM115,48h1v1h-1v-1zM110,48h3v1h-3v-1zM107,48h1v1h-1v-1zM103,48h3v1h-3v-1zM101,48h1v1h-1v-1zM98,48h2v1h-2v-1zM96,48h1v1h-1v-1zM94,48h1v1h-1v-1zM90,48h3v1h-3v-1zM88,48h1v1h-1v-1zM86,48h1v1h-1v-1zM82,48h3v1h-3v-1zM79,48h1v1h-1v-1zM71,48h4v1h-4v-1zM69,48h1v1h-1v-1zM64,48h4v1h-4v-1zM53,48h10v1h-10v-1zM49,48h3v1h-3v-1zM46,48h1v1h-1v-1zM38,48h7v1h-7v-1zM34,48h1v1h-1v-1zM32,48h1v1h-1v-1zM29,48h2v1h-2v-1zM26,48h2v1h-2v-1zM17,48h6v1h-6v-1zM15,48h1v1h-1v-1zM6,48h7v1h-7v-1zM0,48h3v1h-3v-1zM110,47h3v1h-3v-1zM105,47h3v1h-3v-1zM100,47h4v1h-4v-1zM97,47h2v1h-2v-1zM95,47h1v1h-1v-1zM93,47h1v1h-1v-1zM91,47h1v1h-1v-1zM88,47h2v1h-2v-1zM82,47h4v1h-4v-1zM79,47h1v1h-1v-1zM76,47h2v1h-2v-1zM64,47h4v1h-4v-1zM60,47h3v1h-3v-1zM58,47h1v1h-1v-1zM55,47h1v1h-1v-1zM52,47h1v1h-1v-1zM49,47h2v1h-2v-1zM43,47h1v1h-1v-1zM40,47h1v1h-1v-1zM37,47h1v1h-1v-1zM34,47h1v1h-1v-1zM30,47h1v1h-1v-1zM28,47h1v1h-1v-1zM24,47h2v1h-2v-1zM20,47h2v1h-2v-1zM13,47h2v1h-2v-1zM11,47h1v1h-1v-1zM4,47h2v1h-2v-1zM0,47h2v1h-2v-1zM115,46h1v1h-1v-1zM113,46h1v1h-1v-1zM110,46h1v1h-1v-1zM108,46h1v1h-1v-1zM106,46h1v1h-1v-1zM104,46h1v1h-1v-1zM99,46h2v1h-2v-1zM96,46h2v1h-2v-1zM94,46h1v1h-1v-1zM92,46h1v1h-1v-1zM85,46h3v1h-3v-1zM81,46h2v1h-2v-1zM76,46h1v1h-1v-1zM73,46h1v1h-1v-1zM68,46h4v1h-4v-1zM63,46h1v1h-1v-1zM61,46h1v1h-1v-1zM58,46h2v1h-2v-1zM56,46h1v1h-1v-1zM52,46h1v1h-1v-1zM48,46h1v1h-1v-1zM45,46h2v1h-2v-1zM43,46h1v1h-1v-1zM41,46h1v1h-1v-1zM39,46h1v1h-1v-1zM35,46h3v1h-3v-1zM27,46h3v1h-3v-1zM25,46h1v1h-1v-1zM22,46h2v1h-2v-1zM19,46h1v1h-1v-1zM10,46h6v1h-6v-1zM6,46h1v1h-1v-1zM3,46h2v1h-2v-1zM0,46h2v1h-2v-1zM111,45h4v1h-4v-1zM107,45h2v1h-2v-1zM104,45h1v1h-1v-1zM100,45h1v1h-1v-1zM97,45h1v1h-1v-1zM94,45h1v1h-1v-1zM92,45h1v1h-1v-1zM84,45h3v1h-3v-1zM80,45h1v1h-1v-1zM77,45h2v1h-2v-1zM75,45h1v1h-1v-1zM72,45h1v1h-1v-1zM63,45h1v1h-1v-1zM59,45h3v1h-3v-1zM55,45h3v1h-3v-1zM51,45h1v1h-1v-1zM49,45h1v1h-1v-1zM47,45h1v1h-1v-1zM44,45h1v1h-1v-1zM37,45h6v1h-6v-1zM35,45h1v1h-1v-1zM31,45h2v1h-2v-1zM24,45h4v1h-4v-1zM21,45h2v1h-2v-1zM17,45h2v1h-2v-1zM14,45h2v1h-2v-1zM10,45h3v1h-3v-1zM8,45h1v1h-1v-1zM4,45h2v1h-2v-1zM1,45h1v1h-1v-1zM115,44h2v1h-2v-1zM110,44h1v1h-1v-1zM108,44h1v1h-1v-1zM103,44h3v1h-3v-1zM100,44h2v1h-2v-1zM96,44h3v1h-3v-1zM94,44h1v1h-1v-1zM90,44h1v1h-1v-1zM88,44h1v1h-1v-1zM81,44h5v1h-5v-1zM74,44h6v1h-6v-1zM66,44h4v1h-4v-1zM59,44h4v1h-4v-1zM55,44h3v1h-3v-1zM48,44h5v1h-5v-1zM46,44h1v1h-1v-1zM42,44h1v1h-1v-1zM40,44h1v1h-1v-1zM38,44h1v1h-1v-1zM36,44h1v1h-1v-1zM34,44h1v1h-1v-1zM32,44h1v1h-1v-1zM29,44h1v1h-1v-1zM25,44h2v1h-2v-1zM21,44h1v1h-1v-1zM18,44h1v1h-1v-1zM11,44h1v1h-1v-1zM9,44h1v1h-1v-1zM6,44h2v1h-2v-1zM3,44h1v1h-1v-1zM0,44h2v1h-2v-1zM115,43h2v1h-2v-1zM110,43h3v1h-3v-1zM107,43h2v1h-2v-1zM105,43h1v1h-1v-1zM103,43h1v1h-1v-1zM100,43h1v1h-1v-1zM97,43h1v1h-1v-1zM91,43h1v1h-1v-1zM88,43h1v1h-1v-1zM84,43h2v1h-2v-1zM79,43h1v1h-1v-1zM76,43h1v1h-1v-1zM73,43h1v1h-1v-1zM71,43h1v1h-1v-1zM67,43h1v1h-1v-1zM64,43h2v1h-2v-1zM61,43h2v1h-2v-1zM58,43h2v1h-2v-1zM56,43h1v1h-1v-1zM54,43h1v1h-1v-1zM52,43h1v1h-1v-1zM49,43h1v1h-1v-1zM45,43h2v1h-2v-1zM42,43h2v1h-2v-1zM34,43h1v1h-1v-1zM32,43h1v1h-1v-1zM27,43h2v1h-2v-1zM25,43h1v1h-1v-1zM20,43h1v1h-1v-1zM13,43h4v1h-4v-1zM9,43h3v1h-3v-1zM7,43h1v1h-1v-1zM5,43h1v1h-1v-1zM1,43h1v1h-1v-1zM115,42h1v1h-1v-1zM105,42h5v1h-5v-1zM99,42h1v1h-1v-1zM97,42h1v1h-1v-1zM92,42h4v1h-4v-1zM86,42h1v1h-1v-1zM84,42h1v1h-1v-1zM79,42h4v1h-4v-1zM75,42h2v1h-2v-1zM72,42h2v1h-2v-1zM70,42h1v1h-1v-1zM68,42h1v1h-1v-1zM63,42h2v1h-2v-1zM59,42h3v1h-3v-1zM57,42h1v1h-1v-1zM52,42h1v1h-1v-1zM49,42h1v1h-1v-1zM46,42h1v1h-1v-1zM43,42h2v1h-2v-1zM39,42h3v1h-3v-1zM37,42h1v1h-1v-1zM35,42h1v1h-1v-1zM33,42h1v1h-1v-1zM29,42h3v1h-3v-1zM22,42h3v1h-3v-1zM19,42h1v1h-1v-1zM11,42h6v1h-6v-1zM6,42h2v1h-2v-1zM2,42h1v1h-1v-1zM115,41h1v1h-1v-1zM112,41h1v1h-1v-1zM109,41h1v1h-1v-1zM107,41h1v1h-1v-1zM101,41h2v1h-2v-1zM97,41h2v1h-2v-1zM94,41h1v1h-1v-1zM88,41h4v1h-4v-1zM85,41h2v1h-2v-1zM82,41h2v1h-2v-1zM79,41h2v1h-2v-1zM72,41h1v1h-1v-1zM68,41h1v1h-1v-1zM66,41h1v1h-1v-1zM61,41h1v1h-1v-1zM58,41h1v1h-1v-1zM49,41h1v1h-1v-1zM46,41h2v1h-2v-1zM41,41h3v1h-3v-1zM34,41h5v1h-5v-1zM32,41h1v1h-1v-1zM28,41h3v1h-3v-1zM26,41h1v1h-1v-1zM24,41h1v1h-1v-1zM22,41h1v1h-1v-1zM20,41h1v1h-1v-1zM15,41h3v1h-3v-1zM13,41h1v1h-1v-1zM8,41h1v1h-1v-1zM5,41h1v1h-1v-1zM2,41h1v1h-1v-1zM113,40h2v1h-2v-1zM110,40h2v1h-2v-1zM108,40h1v1h-1v-1zM105,40h1v1h-1v-1zM102,40h2v1h-2v-1zM99,40h1v1h-1v-1zM95,40h3v1h-3v-1zM88,40h3v1h-3v-1zM83,40h2v1h-2v-1zM76,40h1v1h-1v-1zM74,40h1v1h-1v-1zM69,40h1v1h-1v-1zM64,40h2v1h-2v-1zM58,40h4v1h-4v-1zM51,40h6v1h-6v-1zM49,40h1v1h-1v-1zM43,40h2v1h-2v-1zM37,40h1v1h-1v-1zM32,40h1v1h-1v-1zM28,40h1v1h-1v-1zM24,40h3v1h-3v-1zM22,40h1v1h-1v-1zM13,40h3v1h-3v-1zM9,40h2v1h-2v-1zM6,40h2v1h-2v-1zM4,40h1v1h-1v-1zM0,40h2v1h-2v-1zM115,39h2v1h-2v-1zM112,39h1v1h-1v-1zM110,39h1v1h-1v-1zM107,39h1v1h-1v-1zM105,39h1v1h-1v-1zM100,39h4v1h-4v-1zM97,39h1v1h-1v-1zM88,39h4v1h-4v-1zM83,39h3v1h-3v-1zM78,39h1v1h-1v-1zM75,39h2v1h-2v-1zM64,39h1v1h-1v-1zM61,39h1v1h-1v-1zM58,39h2v1h-2v-1zM55,39h2v1h-2v-1zM50,39h4v1h-4v-1zM45,39h2v1h-2v-1zM40,39h4v1h-4v-1zM37,39h1v1h-1v-1zM34,39h1v1h-1v-1zM30,39h3v1h-3v-1zM28,39h1v1h-1v-1zM21,39h1v1h-1v-1zM16,39h2v1h-2v-1zM13,39h2v1h-2v-1zM11,39h1v1h-1v-1zM7,39h2v1h-2v-1zM4,39h1v1h-1v-1zM0,39h2v1h-2v-1zM114,38h2v1h-2v-1zM112,38h1v1h-1v-1zM108,38h2v1h-2v-1zM106,38h1v1h-1v-1zM103,38h1v1h-1v-1zM97,38h1v1h-1v-1zM92,38h4v1h-4v-1zM87,38h2v1h-2v-1zM85,38h1v1h-1v-1zM79,38h3v1h-3v-1zM73,38h1v1h-1v-1zM67,38h4v1h-4v-1zM63,38h1v1h-1v-1zM61,38h1v1h-1v-1zM57,38h2v1h-2v-1zM55,38h1v1h-1v-1zM47,38h3v1h-3v-1zM39,38h2v1h-2v-1zM36,38h2v1h-2v-1zM33,38h1v1h-1v-1zM29,38h1v1h-1v-1zM27,38h1v1h-1v-1zM22,38h4v1h-4v-1zM17,38h1v1h-1v-1zM11,38h2v1h-2v-1zM6,38h2v1h-2v-1zM4,38h1v1h-1v-1zM2,38h1v1h-1v-1zM112,37h4v1h-4v-1zM110,37h1v1h-1v-1zM108,37h1v1h-1v-1zM104,37h1v1h-1v-1zM102,37h1v1h-1v-1zM94,37h3v1h-3v-1zM92,37h1v1h-1v-1zM80,37h6v1h-6v-1zM76,37h3v1h-3v-1zM73,37h1v1h-1v-1zM68,37h2v1h-2v-1zM64,37h2v1h-2v-1zM58,37h3v1h-3v-1zM56,37h1v1h-1v-1zM52,37h3v1h-3v-1zM48,37h3v1h-3v-1zM46,37h1v1h-1v-1zM44,37h1v1h-1v-1zM42,37h1v1h-1v-1zM39,37h2v1h-2v-1zM36,37h1v1h-1v-1zM32,37h1v1h-1v-1zM23,37h3v1h-3v-1zM20,37h1v1h-1v-1zM18,37h1v1h-1v-1zM16,37h1v1h-1v-1zM14,37h1v1h-1v-1zM10,37h1v1h-1v-1zM8,37h1v1h-1v-1zM5,37h1v1h-1v-1zM2,37h2v1h-2v-1zM0,37h1v1h-1v-1zM116,36h1v1h-1v-1zM113,36h1v1h-1v-1zM110,36h2v1h-2v-1zM106,36h1v1h-1v-1zM98,36h1v1h-1v-1zM95,36h2v1h-2v-1zM91,36h2v1h-2v-1zM83,36h3v1h-3v-1zM78,36h1v1h-1v-1zM76,36h1v1h-1v-1zM72,36h2v1h-2v-1zM70,36h1v1h-1v-1zM65,36h2v1h-2v-1zM63,36h1v1h-1v-1zM58,36h4v1h-4v-1zM55,36h2v1h-2v-1zM51,36h3v1h-3v-1zM45,36h5v1h-5v-1zM40,36h2v1h-2v-1zM38,36h1v1h-1v-1zM34,36h3v1h-3v-1zM31,36h2v1h-2v-1zM27,36h3v1h-3v-1zM25,36h1v1h-1v-1zM19,36h2v1h-2v-1zM14,36h2v1h-2v-1zM12,36h1v1h-1v-1zM10,36h1v1h-1v-1zM3,36h5v1h-5v-1zM0,36h1v1h-1v-1zM116,35h1v1h-1v-1zM112,35h2v1h-2v-1zM107,35h3v1h-3v-1zM105,35h1v1h-1v-1zM102,35h2v1h-2v-1zM100,35h1v1h-1v-1zM98,35h1v1h-1v-1zM90,35h2v1h-2v-1zM88,35h1v1h-1v-1zM83,35h3v1h-3v-1zM79,35h1v1h-1v-1zM76,35h1v1h-1v-1zM73,35h2v1h-2v-1zM66,35h2v1h-2v-1zM64,35h1v1h-1v-1zM52,35h9v1h-9v-1zM50,35h1v1h-1v-1zM45,35h3v1h-3v-1zM43,35h1v1h-1v-1zM40,35h1v1h-1v-1zM34,35h2v1h-2v-1zM28,35h4v1h-4v-1zM25,35h1v1h-1v-1zM22,35h2v1h-2v-1zM15,35h2v1h-2v-1zM13,35h1v1h-1v-1zM7,35h4v1h-4v-1zM3,35h3v1h-3v-1zM0,35h1v1h-1v-1zM114,34h2v1h-2v-1zM108,34h5v1h-5v-1zM106,34h1v1h-1v-1zM103,34h1v1h-1v-1zM99,34h2v1h-2v-1zM97,34h1v1h-1v-1zM92,34h3v1h-3v-1zM89,34h1v1h-1v-1zM79,34h8v1h-8v-1zM75,34h1v1h-1v-1zM68,34h5v1h-5v-1zM64,34h2v1h-2v-1zM56,34h6v1h-6v-1zM51,34h1v1h-1v-1zM48,34h2v1h-2v-1zM46,34h1v1h-1v-1zM44,34h1v1h-1v-1zM39,34h1v1h-1v-1zM37,34h1v1h-1v-1zM29,34h6v1h-6v-1zM24,34h2v1h-2v-1zM22,34h1v1h-1v-1zM17,34h3v1h-3v-1zM3,34h13v1h-13v-1zM0,34h2v1h-2v-1zM116,33h1v1h-1v-1zM114,33h1v1h-1v-1zM112,33h1v1h-1v-1zM108,33h1v1h-1v-1zM104,33h1v1h-1v-1zM101,33h1v1h-1v-1zM97,33h3v1h-3v-1zM91,33h5v1h-5v-1zM88,33h1v1h-1v-1zM86,33h1v1h-1v-1zM82,33h1v1h-1v-1zM77,33h3v1h-3v-1zM75,33h1v1h-1v-1zM71,33h3v1h-3v-1zM69,33h1v1h-1v-1zM67,33h1v1h-1v-1zM62,33h2v1h-2v-1zM60,33h1v1h-1v-1zM54,33h3v1h-3v-1zM51,33h1v1h-1v-1zM47,33h1v1h-1v-1zM41,33h2v1h-2v-1zM34,33h1v1h-1v-1zM30,33h1v1h-1v-1zM25,33h4v1h-4v-1zM23,33h1v1h-1v-1zM18,33h3v1h-3v-1zM8,33h8v1h-8v-1zM4,33h1v1h-1v-1zM2,33h1v1h-1v-1zM115,32h2v1h-2v-1zM112,32h2v1h-2v-1zM110,32h1v1h-1v-1zM107,32h2v1h-2v-1zM101,32h2v1h-2v-1zM96,32h1v1h-1v-1zM90,32h2v1h-2v-1zM88,32h1v1h-1v-1zM86,32h1v1h-1v-1zM84,32h1v1h-1v-1zM80,32h3v1h-3v-1zM78,32h1v1h-1v-1zM73,32h4v1h-4v-1zM71,32h1v1h-1v-1zM67,32h2v1h-2v-1zM64,32h1v1h-1v-1zM60,32h3v1h-3v-1zM58,32h1v1h-1v-1zM55,32h2v1h-2v-1zM50,32h4v1h-4v-1zM48,32h1v1h-1v-1zM46,32h1v1h-1v-1zM42,32h3v1h-3v-1zM38,32h3v1h-3v-1zM36,32h1v1h-1v-1zM34,32h1v1h-1v-1zM32,32h1v1h-1v-1zM30,32h1v1h-1v-1zM27,32h1v1h-1v-1zM24,32h2v1h-2v-1zM22,32h1v1h-1v-1zM13,32h3v1h-3v-1zM11,32h1v1h-1v-1zM8,32h1v1h-1v-1zM6,32h1v1h-1v-1zM4,32h1v1h-1v-1zM2,32h1v1h-1v-1zM115,31h1v1h-1v-1zM112,31h2v1h-2v-1zM107,31h2v1h-2v-1zM105,31h1v1h-1v-1zM103,31h1v1h-1v-1zM100,31h2v1h-2v-1zM97,31h2v1h-2v-1zM88,31h4v1h-4v-1zM86,31h1v1h-1v-1zM81,31h2v1h-2v-1zM76,31h4v1h-4v-1zM73,31h1v1h-1v-1zM69,31h2v1h-2v-1zM64,31h4v1h-4v-1zM60,31h3v1h-3v-1zM55,31h2v1h-2v-1zM52,31h1v1h-1v-1zM49,31h1v1h-1v-1zM47,31h1v1h-1v-1zM42,31h2v1h-2v-1zM38,31h3v1h-3v-1zM34,31h1v1h-1v-1zM30,31h1v1h-1v-1zM28,31h1v1h-1v-1zM25,31h2v1h-2v-1zM19,31h3v1h-3v-1zM17,31h1v1h-1v-1zM14,31h1v1h-1v-1zM11,31h2v1h-2v-1zM8,31h1v1h-1v-1zM2,31h3v1h-3v-1zM0,31h1v1h-1v-1zM115,30h1v1h-1v-1zM106,30h8v1h-8v-1zM104,30h1v1h-1v-1zM97,30h1v1h-1v-1zM94,30h1v1h-1v-1zM92,30h1v1h-1v-1zM81,30h8v1h-8v-1zM79,30h1v1h-1v-1zM73,30h1v1h-1v-1zM70,30h2v1h-2v-1zM68,30h1v1h-1v-1zM65,30h1v1h-1v-1zM63,30h1v1h-1v-1zM55,30h7v1h-7v-1zM51,30h1v1h-1v-1zM48,30h2v1h-2v-1zM46,30h1v1h-1v-1zM44,30h1v1h-1v-1zM37,30h1v1h-1v-1zM28,30h7v1h-7v-1zM25,30h1v1h-1v-1zM22,30h2v1h-2v-1zM20,30h1v1h-1v-1zM16,30h1v1h-1v-1zM3,30h6v1h-6v-1zM1,30h1v1h-1v-1zM115,29h1v1h-1v-1zM111,29h2v1h-2v-1zM108,29h2v1h-2v-1zM101,29h2v1h-2v-1zM94,29h4v1h-4v-1zM90,29h3v1h-3v-1zM88,29h1v1h-1v-1zM86,29h1v1h-1v-1zM84,29h1v1h-1v-1zM80,29h3v1h-3v-1zM76,29h3v1h-3v-1zM72,29h1v1h-1v-1zM68,29h1v1h-1v-1zM64,29h3v1h-3v-1zM61,29h1v1h-1v-1zM54,29h5v1h-5v-1zM48,29h1v1h-1v-1zM46,29h1v1h-1v-1zM42,29h3v1h-3v-1zM39,29h2v1h-2v-1zM37,29h1v1h-1v-1zM32,29h2v1h-2v-1zM28,29h2v1h-2v-1zM25,29h1v1h-1v-1zM22,29h2v1h-2v-1zM17,29h3v1h-3v-1zM13,29h1v1h-1v-1zM11,29h1v1h-1v-1zM7,29h1v1h-1v-1zM4,29h2v1h-2v-1zM1,29h2v1h-2v-1zM114,28h2v1h-2v-1zM107,28h5v1h-5v-1zM104,28h2v1h-2v-1zM101,28h2v1h-2v-1zM99,28h1v1h-1v-1zM95,28h1v1h-1v-1zM93,28h1v1h-1v-1zM90,28h2v1h-2v-1zM88,28h1v1h-1v-1zM84,28h1v1h-1v-1zM81,28h1v1h-1v-1zM73,28h1v1h-1v-1zM66,28h2v1h-2v-1zM64,28h1v1h-1v-1zM60,28h2v1h-2v-1zM58,28h1v1h-1v-1zM54,28h1v1h-1v-1zM52,28h1v1h-1v-1zM49,28h2v1h-2v-1zM39,28h3v1h-3v-1zM37,28h1v1h-1v-1zM30,28h4v1h-4v-1zM24,28h3v1h-3v-1zM21,28h1v1h-1v-1zM17,28h3v1h-3v-1zM12,28h4v1h-4v-1zM6,28h5v1h-5v-1zM0,28h4v1h-4v-1zM115,27h1v1h-1v-1zM107,27h3v1h-3v-1zM102,27h2v1h-2v-1zM99,27h2v1h-2v-1zM97,27h1v1h-1v-1zM93,27h1v1h-1v-1zM91,27h1v1h-1v-1zM88,27h2v1h-2v-1zM85,27h1v1h-1v-1zM81,27h1v1h-1v-1zM79,27h1v1h-1v-1zM75,27h3v1h-3v-1zM73,27h1v1h-1v-1zM67,27h1v1h-1v-1zM63,27h2v1h-2v-1zM56,27h2v1h-2v-1zM54,27h1v1h-1v-1zM52,27h1v1h-1v-1zM45,27h1v1h-1v-1zM43,27h1v1h-1v-1zM40,27h1v1h-1v-1zM38,27h1v1h-1v-1zM34,27h1v1h-1v-1zM28,27h2v1h-2v-1zM20,27h3v1h-3v-1zM14,27h4v1h-4v-1zM12,27h1v1h-1v-1zM10,27h1v1h-1v-1zM4,27h1v1h-1v-1zM1,27h1v1h-1v-1zM112,26h4v1h-4v-1zM109,26h2v1h-2v-1zM106,26h2v1h-2v-1zM104,26h1v1h-1v-1zM101,26h1v1h-1v-1zM97,26h1v1h-1v-1zM94,26h2v1h-2v-1zM91,26h1v1h-1v-1zM87,26h1v1h-1v-1zM83,26h3v1h-3v-1zM81,26h1v1h-1v-1zM79,26h1v1h-1v-1zM68,26h6v1h-6v-1zM58,26h4v1h-4v-1zM55,26h2v1h-2v-1zM53,26h1v1h-1v-1zM51,26h1v1h-1v-1zM49,26h1v1h-1v-1zM46,26h1v1h-1v-1zM43,26h1v1h-1v-1zM37,26h1v1h-1v-1zM34,26h1v1h-1v-1zM31,26h2v1h-2v-1zM22,26h4v1h-4v-1zM15,26h4v1h-4v-1zM12,26h2v1h-2v-1zM8,26h3v1h-3v-1zM3,26h4v1h-4v-1zM0,26h2v1h-2v-1zM115,25h1v1h-1v-1zM109,25h2v1h-2v-1zM105,25h2v1h-2v-1zM101,25h3v1h-3v-1zM96,25h3v1h-3v-1zM91,25h3v1h-3v-1zM85,25h2v1h-2v-1zM82,25h2v1h-2v-1zM77,25h2v1h-2v-1zM75,25h1v1h-1v-1zM68,25h1v1h-1v-1zM56,25h5v1h-5v-1zM52,25h1v1h-1v-1zM50,25h1v1h-1v-1zM48,25h1v1h-1v-1zM38,25h9v1h-9v-1zM34,25h3v1h-3v-1zM30,25h2v1h-2v-1zM26,25h1v1h-1v-1zM22,25h2v1h-2v-1zM16,25h1v1h-1v-1zM13,25h1v1h-1v-1zM7,25h2v1h-2v-1zM3,25h1v1h-1v-1zM1,25h1v1h-1v-1zM113,24h3v1h-3v-1zM107,24h4v1h-4v-1zM103,24h3v1h-3v-1zM101,24h1v1h-1v-1zM99,24h1v1h-1v-1zM96,24h2v1h-2v-1zM94,24h1v1h-1v-1zM90,24h2v1h-2v-1zM88,24h1v1h-1v-1zM86,24h1v1h-1v-1zM84,24h1v1h-1v-1zM80,24h2v1h-2v-1zM77,24h1v1h-1v-1zM74,24h1v1h-1v-1zM72,24h1v1h-1v-1zM69,24h2v1h-2v-1zM67,24h1v1h-1v-1zM64,24h1v1h-1v-1zM59,24h1v1h-1v-1zM56,24h2v1h-2v-1zM53,24h2v1h-2v-1zM49,24h3v1h-3v-1zM46,24h1v1h-1v-1zM42,24h1v1h-1v-1zM38,24h1v1h-1v-1zM34,24h2v1h-2v-1zM32,24h1v1h-1v-1zM29,24h1v1h-1v-1zM25,24h2v1h-2v-1zM23,24h1v1h-1v-1zM16,24h1v1h-1v-1zM14,24h1v1h-1v-1zM9,24h1v1h-1v-1zM6,24h1v1h-1v-1zM2,24h1v1h-1v-1zM0,24h1v1h-1v-1zM115,23h1v1h-1v-1zM112,23h1v1h-1v-1zM108,23h2v1h-2v-1zM105,23h2v1h-2v-1zM103,23h1v1h-1v-1zM100,23h1v1h-1v-1zM98,23h1v1h-1v-1zM93,23h1v1h-1v-1zM88,23h2v1h-2v-1zM86,23h1v1h-1v-1zM81,23h2v1h-2v-1zM78,23h2v1h-2v-1zM76,23h1v1h-1v-1zM74,23h1v1h-1v-1zM67,23h1v1h-1v-1zM64,23h1v1h-1v-1zM57,23h2v1h-2v-1zM52,23h3v1h-3v-1zM45,23h2v1h-2v-1zM42,23h2v1h-2v-1zM40,23h1v1h-1v-1zM37,23h1v1h-1v-1zM28,23h4v1h-4v-1zM26,23h1v1h-1v-1zM23,23h1v1h-1v-1zM21,23h1v1h-1v-1zM18,23h2v1h-2v-1zM11,23h1v1h-1v-1zM9,23h1v1h-1v-1zM4,23h2v1h-2v-1zM2,23h1v1h-1v-1zM111,22h2v1h-2v-1zM106,22h1v1h-1v-1zM99,22h1v1h-1v-1zM97,22h1v1h-1v-1zM94,22h2v1h-2v-1zM91,22h2v1h-2v-1zM87,22h1v1h-1v-1zM83,22h3v1h-3v-1zM75,22h3v1h-3v-1zM73,22h1v1h-1v-1zM67,22h5v1h-5v-1zM63,22h1v1h-1v-1zM60,22h2v1h-2v-1zM58,22h1v1h-1v-1zM51,22h1v1h-1v-1zM46,22h4v1h-4v-1zM44,22h1v1h-1v-1zM39,22h2v1h-2v-1zM37,22h1v1h-1v-1zM34,22h1v1h-1v-1zM32,22h1v1h-1v-1zM30,22h1v1h-1v-1zM27,22h1v1h-1v-1zM24,22h2v1h-2v-1zM22,22h1v1h-1v-1zM19,22h1v1h-1v-1zM15,22h2v1h-2v-1zM12,22h2v1h-2v-1zM10,22h1v1h-1v-1zM6,22h3v1h-3v-1zM3,22h1v1h-1v-1zM0,22h2v1h-2v-1zM109,21h5v1h-5v-1zM107,21h1v1h-1v-1zM105,21h1v1h-1v-1zM99,21h1v1h-1v-1zM96,21h2v1h-2v-1zM91,21h3v1h-3v-1zM89,21h1v1h-1v-1zM87,21h1v1h-1v-1zM79,21h2v1h-2v-1zM73,21h2v1h-2v-1zM67,21h3v1h-3v-1zM60,21h2v1h-2v-1zM56,21h2v1h-2v-1zM53,21h2v1h-2v-1zM50,21h1v1h-1v-1zM43,21h4v1h-4v-1zM34,21h5v1h-5v-1zM31,21h1v1h-1v-1zM25,21h2v1h-2v-1zM16,21h5v1h-5v-1zM14,21h1v1h-1v-1zM10,21h1v1h-1v-1zM7,21h2v1h-2v-1zM4,21h1v1h-1v-1zM1,21h2v1h-2v-1zM113,20h3v1h-3v-1zM101,20h8v1h-8v-1zM97,20h2v1h-2v-1zM95,20h1v1h-1v-1zM93,20h1v1h-1v-1zM86,20h6v1h-6v-1zM83,20h2v1h-2v-1zM81,20h1v1h-1v-1zM78,20h2v1h-2v-1zM73,20h3v1h-3v-1zM70,20h2v1h-2v-1zM66,20h1v1h-1v-1zM64,20h1v1h-1v-1zM60,20h3v1h-3v-1zM58,20h1v1h-1v-1zM56,20h1v1h-1v-1zM51,20h1v1h-1v-1zM47,20h3v1h-3v-1zM45,20h1v1h-1v-1zM41,20h3v1h-3v-1zM38,20h2v1h-2v-1zM35,20h1v1h-1v-1zM26,20h7v1h-7v-1zM24,20h1v1h-1v-1zM22,20h1v1h-1v-1zM19,20h2v1h-2v-1zM13,20h3v1h-3v-1zM9,20h3v1h-3v-1zM5,20h3v1h-3v-1zM3,20h1v1h-1v-1zM0,20h2v1h-2v-1zM116,19h1v1h-1v-1zM111,19h2v1h-2v-1zM108,19h1v1h-1v-1zM106,19h1v1h-1v-1zM102,19h2v1h-2v-1zM100,19h1v1h-1v-1zM98,19h1v1h-1v-1zM93,19h2v1h-2v-1zM90,19h1v1h-1v-1zM86,19h3v1h-3v-1zM81,19h1v1h-1v-1zM78,19h1v1h-1v-1zM76,19h1v1h-1v-1zM74,19h1v1h-1v-1zM66,19h2v1h-2v-1zM64,19h1v1h-1v-1zM61,19h1v1h-1v-1zM57,19h2v1h-2v-1zM55,19h1v1h-1v-1zM52,19h1v1h-1v-1zM49,19h2v1h-2v-1zM46,19h1v1h-1v-1zM43,19h1v1h-1v-1zM40,19h1v1h-1v-1zM37,19h1v1h-1v-1zM33,19h2v1h-2v-1zM28,19h4v1h-4v-1zM21,19h2v1h-2v-1zM19,19h1v1h-1v-1zM17,19h1v1h-1v-1zM9,19h6v1h-6v-1zM7,19h1v1h-1v-1zM2,19h3v1h-3v-1zM112,18h4v1h-4v-1zM106,18h4v1h-4v-1zM104,18h1v1h-1v-1zM99,18h1v1h-1v-1zM97,18h1v1h-1v-1zM94,18h1v1h-1v-1zM91,18h2v1h-2v-1zM83,18h3v1h-3v-1zM79,18h3v1h-3v-1zM77,18h1v1h-1v-1zM75,18h1v1h-1v-1zM73,18h1v1h-1v-1zM69,18h2v1h-2v-1zM63,18h1v1h-1v-1zM61,18h1v1h-1v-1zM58,18h1v1h-1v-1zM55,18h2v1h-2v-1zM49,18h1v1h-1v-1zM46,18h2v1h-2v-1zM44,18h1v1h-1v-1zM39,18h1v1h-1v-1zM35,18h3v1h-3v-1zM32,18h1v1h-1v-1zM27,18h2v1h-2v-1zM24,18h2v1h-2v-1zM22,18h1v1h-1v-1zM14,18h5v1h-5v-1zM11,18h2v1h-2v-1zM4,18h3v1h-3v-1zM2,18h1v1h-1v-1zM115,17h1v1h-1v-1zM111,17h1v1h-1v-1zM108,17h2v1h-2v-1zM105,17h2v1h-2v-1zM102,17h2v1h-2v-1zM99,17h1v1h-1v-1zM95,17h2v1h-2v-1zM90,17h3v1h-3v-1zM88,17h1v1h-1v-1zM86,17h1v1h-1v-1zM81,17h1v1h-1v-1zM75,17h4v1h-4v-1zM72,17h2v1h-2v-1zM70,17h1v1h-1v-1zM68,17h1v1h-1v-1zM66,17h1v1h-1v-1zM59,17h2v1h-2v-1zM56,17h1v1h-1v-1zM54,17h1v1h-1v-1zM48,17h3v1h-3v-1zM45,17h1v1h-1v-1zM42,17h2v1h-2v-1zM39,17h2v1h-2v-1zM34,17h1v1h-1v-1zM32,17h1v1h-1v-1zM30,17h1v1h-1v-1zM27,17h1v1h-1v-1zM23,17h3v1h-3v-1zM18,17h3v1h-3v-1zM16,17h1v1h-1v-1zM14,17h1v1h-1v-1zM11,17h1v1h-1v-1zM7,17h3v1h-3v-1zM4,17h1v1h-1v-1zM0,17h1v1h-1v-1zM113,16h3v1h-3v-1zM107,16h5v1h-5v-1zM105,16h1v1h-1v-1zM103,16h1v1h-1v-1zM100,16h2v1h-2v-1zM98,16h1v1h-1v-1zM95,16h2v1h-2v-1zM91,16h1v1h-1v-1zM89,16h1v1h-1v-1zM86,16h1v1h-1v-1zM83,16h2v1h-2v-1zM81,16h1v1h-1v-1zM78,16h2v1h-2v-1zM74,16h3v1h-3v-1zM71,16h1v1h-1v-1zM65,16h5v1h-5v-1zM61,16h1v1h-1v-1zM59,16h1v1h-1v-1zM57,16h1v1h-1v-1zM55,16h1v1h-1v-1zM53,16h1v1h-1v-1zM51,16h1v1h-1v-1zM49,16h1v1h-1v-1zM46,16h2v1h-2v-1zM41,16h4v1h-4v-1zM36,16h3v1h-3v-1zM29,16h6v1h-6v-1zM24,16h2v1h-2v-1zM22,16h1v1h-1v-1zM20,16h1v1h-1v-1zM18,16h1v1h-1v-1zM16,16h1v1h-1v-1zM9,16h1v1h-1v-1zM6,16h2v1h-2v-1zM3,16h1v1h-1v-1zM0,16h1v1h-1v-1zM115,15h1v1h-1v-1zM108,15h2v1h-2v-1zM105,15h1v1h-1v-1zM100,15h4v1h-4v-1zM97,15h2v1h-2v-1zM93,15h1v1h-1v-1zM88,15h1v1h-1v-1zM85,15h2v1h-2v-1zM81,15h3v1h-3v-1zM73,15h7v1h-7v-1zM69,15h3v1h-3v-1zM67,15h1v1h-1v-1zM64,15h2v1h-2v-1zM61,15h2v1h-2v-1zM57,15h3v1h-3v-1zM55,15h1v1h-1v-1zM52,15h1v1h-1v-1zM49,15h1v1h-1v-1zM45,15h1v1h-1v-1zM42,15h2v1h-2v-1zM40,15h1v1h-1v-1zM37,15h1v1h-1v-1zM34,15h1v1h-1v-1zM31,15h1v1h-1v-1zM28,15h2v1h-2v-1zM21,15h1v1h-1v-1zM18,15h2v1h-2v-1zM15,15h2v1h-2v-1zM10,15h2v1h-2v-1zM7,15h1v1h-1v-1zM3,15h3v1h-3v-1zM114,14h2v1h-2v-1zM110,14h3v1h-3v-1zM106,14h2v1h-2v-1zM103,14h2v1h-2v-1zM99,14h1v1h-1v-1zM94,14h3v1h-3v-1zM91,14h2v1h-2v-1zM87,14h2v1h-2v-1zM84,14h1v1h-1v-1zM82,14h1v1h-1v-1zM80,14h1v1h-1v-1zM77,14h1v1h-1v-1zM72,14h1v1h-1v-1zM70,14h1v1h-1v-1zM68,14h1v1h-1v-1zM63,14h1v1h-1v-1zM60,14h1v1h-1v-1zM58,14h1v1h-1v-1zM56,14h1v1h-1v-1zM49,14h1v1h-1v-1zM46,14h2v1h-2v-1zM44,14h1v1h-1v-1zM39,14h2v1h-2v-1zM37,14h1v1h-1v-1zM34,14h1v1h-1v-1zM32,14h1v1h-1v-1zM28,14h1v1h-1v-1zM25,14h1v1h-1v-1zM22,14h1v1h-1v-1zM13,14h6v1h-6v-1zM9,14h1v1h-1v-1zM6,14h1v1h-1v-1zM1,14h2v1h-2v-1zM114,13h2v1h-2v-1zM111,13h2v1h-2v-1zM107,13h3v1h-3v-1zM100,13h4v1h-4v-1zM94,13h3v1h-3v-1zM91,13h2v1h-2v-1zM87,13h3v1h-3v-1zM83,13h2v1h-2v-1zM79,13h2v1h-2v-1zM77,13h1v1h-1v-1zM75,13h1v1h-1v-1zM72,13h1v1h-1v-1zM65,13h3v1h-3v-1zM60,13h1v1h-1v-1zM56,13h3v1h-3v-1zM52,13h1v1h-1v-1zM50,13h1v1h-1v-1zM46,13h2v1h-2v-1zM42,13h3v1h-3v-1zM35,13h2v1h-2v-1zM32,13h2v1h-2v-1zM29,13h2v1h-2v-1zM24,13h4v1h-4v-1zM19,13h1v1h-1v-1zM12,13h2v1h-2v-1zM8,13h3v1h-3v-1zM4,13h2v1h-2v-1zM2,13h1v1h-1v-1zM0,13h1v1h-1v-1zM115,12h1v1h-1v-1zM112,12h1v1h-1v-1zM105,12h4v1h-4v-1zM103,12h1v1h-1v-1zM100,12h1v1h-1v-1zM98,12h1v1h-1v-1zM94,12h2v1h-2v-1zM92,12h1v1h-1v-1zM89,12h2v1h-2v-1zM86,12h1v1h-1v-1zM83,12h1v1h-1v-1zM81,12h1v1h-1v-1zM76,12h3v1h-3v-1zM72,12h3v1h-3v-1zM68,12h3v1h-3v-1zM65,12h2v1h-2v-1zM62,12h2v1h-2v-1zM60,12h1v1h-1v-1zM54,12h4v1h-4v-1zM52,12h1v1h-1v-1zM47,12h4v1h-4v-1zM43,12h1v1h-1v-1zM41,12h1v1h-1v-1zM39,12h1v1h-1v-1zM33,12h1v1h-1v-1zM28,12h3v1h-3v-1zM25,12h1v1h-1v-1zM21,12h1v1h-1v-1zM17,12h2v1h-2v-1zM15,12h1v1h-1v-1zM12,12h1v1h-1v-1zM8,12h1v1h-1v-1zM6,12h1v1h-1v-1zM1,12h1v1h-1v-1zM112,11h1v1h-1v-1zM107,11h2v1h-2v-1zM102,11h2v1h-2v-1zM100,11h1v1h-1v-1zM98,11h1v1h-1v-1zM93,11h2v1h-2v-1zM91,11h1v1h-1v-1zM88,11h1v1h-1v-1zM86,11h1v1h-1v-1zM81,11h2v1h-2v-1zM76,11h4v1h-4v-1zM73,11h1v1h-1v-1zM69,11h2v1h-2v-1zM66,11h2v1h-2v-1zM63,11h2v1h-2v-1zM61,11h1v1h-1v-1zM57,11h2v1h-2v-1zM55,11h1v1h-1v-1zM52,11h2v1h-2v-1zM49,11h2v1h-2v-1zM45,11h3v1h-3v-1zM40,11h4v1h-4v-1zM37,11h2v1h-2v-1zM33,11h2v1h-2v-1zM31,11h1v1h-1v-1zM28,11h2v1h-2v-1zM20,11h1v1h-1v-1zM17,11h1v1h-1v-1zM12,11h2v1h-2v-1zM10,11h1v1h-1v-1zM5,11h1v1h-1v-1zM2,11h1v1h-1v-1zM112,10h4v1h-4v-1zM109,10h2v1h-2v-1zM106,10h1v1h-1v-1zM103,10h1v1h-1v-1zM99,10h2v1h-2v-1zM97,10h1v1h-1v-1zM94,10h1v1h-1v-1zM92,10h1v1h-1v-1zM87,10h1v1h-1v-1zM83,10h3v1h-3v-1zM75,10h2v1h-2v-1zM73,10h1v1h-1v-1zM70,10h1v1h-1v-1zM67,10h1v1h-1v-1zM65,10h1v1h-1v-1zM63,10h1v1h-1v-1zM58,10h4v1h-4v-1zM55,10h2v1h-2v-1zM52,10h1v1h-1v-1zM49,10h1v1h-1v-1zM46,10h2v1h-2v-1zM44,10h1v1h-1v-1zM39,10h1v1h-1v-1zM34,10h3v1h-3v-1zM32,10h1v1h-1v-1zM28,10h3v1h-3v-1zM24,10h2v1h-2v-1zM22,10h1v1h-1v-1zM20,10h1v1h-1v-1zM17,10h2v1h-2v-1zM14,10h2v1h-2v-1zM5,10h8v1h-8v-1zM1,10h1v1h-1v-1zM116,9h1v1h-1v-1zM109,9h3v1h-3v-1zM103,9h5v1h-5v-1zM99,9h1v1h-1v-1zM89,9h6v1h-6v-1zM87,9h1v1h-1v-1zM84,9h1v1h-1v-1zM80,9h2v1h-2v-1zM75,9h4v1h-4v-1zM66,9h6v1h-6v-1zM61,9h2v1h-2v-1zM56,9h1v1h-1v-1zM54,9h1v1h-1v-1zM47,9h4v1h-4v-1zM41,9h3v1h-3v-1zM35,9h1v1h-1v-1zM33,9h1v1h-1v-1zM31,9h1v1h-1v-1zM25,9h4v1h-4v-1zM22,9h1v1h-1v-1zM18,9h1v1h-1v-1zM15,9h2v1h-2v-1zM11,9h2v1h-2v-1zM7,9h3v1h-3v-1zM4,9h2v1h-2v-1zM1,9h2v1h-2v-1zM113,8h4v1h-4v-1zM111,8h1v1h-1v-1zM107,8h2v1h-2v-1zM103,8h2v1h-2v-1zM100,8h1v1h-1v-1zM95,8h4v1h-4v-1zM93,8h1v1h-1v-1zM79,8h13v1h-13v-1zM76,8h1v1h-1v-1zM71,8h4v1h-4v-1zM69,8h1v1h-1v-1zM67,8h1v1h-1v-1zM64,8h1v1h-1v-1zM55,8h7v1h-7v-1zM50,8h2v1h-2v-1zM46,8h2v1h-2v-1zM44,8h1v1h-1v-1zM28,8h12v1h-12v-1zM26,8h1v1h-1v-1zM24,8h1v1h-1v-1zM22,8h1v1h-1v-1zM18,8h3v1h-3v-1zM13,8h1v1h-1v-1zM9,8h1v1h-1v-1zM4,8h3v1h-3v-1zM0,8h2v1h-2v-1zM106,7h1v1h-1v-1zM103,7h1v1h-1v-1zM100,7h2v1h-2v-1zM93,7h1v1h-1v-1zM90,7h2v1h-2v-1zM86,7h3v1h-3v-1zM81,7h2v1h-2v-1zM76,7h4v1h-4v-1zM73,7h2v1h-2v-1zM69,7h2v1h-2v-1zM64,7h4v1h-4v-1zM62,7h1v1h-1v-1zM60,7h1v1h-1v-1zM55,7h2v1h-2v-1zM52,7h2v1h-2v-1zM50,7h1v1h-1v-1zM46,7h1v1h-1v-1zM42,7h1v1h-1v-1zM40,7h1v1h-1v-1zM37,7h1v1h-1v-1zM34,7h1v1h-1v-1zM29,7h2v1h-2v-1zM26,7h1v1h-1v-1zM21,7h1v1h-1v-1zM15,7h1v1h-1v-1zM9,7h2v1h-2v-1zM110,6h7v1h-7v-1zM108,6h1v1h-1v-1zM106,6h1v1h-1v-1zM104,6h1v1h-1v-1zM102,6h1v1h-1v-1zM100,6h1v1h-1v-1zM98,6h1v1h-1v-1zM96,6h1v1h-1v-1zM94,6h1v1h-1v-1zM92,6h1v1h-1v-1zM90,6h1v1h-1v-1zM88,6h1v1h-1v-1zM86,6h1v1h-1v-1zM84,6h1v1h-1v-1zM82,6h1v1h-1v-1zM80,6h1v1h-1v-1zM78,6h1v1h-1v-1zM76,6h1v1h-1v-1zM74,6h1v1h-1v-1zM72,6h1v1h-1v-1zM70,6h1v1h-1v-1zM68,6h1v1h-1v-1zM66,6h1v1h-1v-1zM64,6h1v1h-1v-1zM62,6h1v1h-1v-1zM60,6h1v1h-1v-1zM58,6h1v1h-1v-1zM56,6h1v1h-1v-1zM54,6h1v1h-1v-1zM52,6h1v1h-1v-1zM50,6h1v1h-1v-1zM48,6h1v1h-1v-1zM46,6h1v1h-1v-1zM44,6h1v1h-1v-1zM42,6h1v1h-1v-1zM40,6h1v1h-1v-1zM38,6h1v1h-1v-1zM36,6h1v1h-1v-1zM34,6h1v1h-1v-1zM32,6h1v1h-1v-1zM30,6h1v1h-1v-1zM28,6h1v1h-1v-1zM26,6h1v1h-1v-1zM24,6h1v1h-1v-1zM22,6h1v1h-1v-1zM20,6h1v1h-1v-1zM18,6h1v1h-1v-1zM16,6h1v1h-1v-1zM14,6h1v1h-1v-1zM12,6h1v1h-1v-1zM10,6h1v1h-1v-1zM8,6h1v1h-1v-1zM0,6h7v1h-7v-1zM116,5h1v1h-1v-1zM110,5h1v1h-1v-1zM105,5h3v1h-3v-1zM100,5h4v1h-4v-1zM98,5h1v1h-1v-1zM92,5h2v1h-2v-1zM86,5h5v1h-5v-1zM82,5h1v1h-1v-1zM80,5h1v1h-1v-1zM77,5h2v1h-2v-1zM74,5h2v1h-2v-1zM69,5h1v1h-1v-1zM65,5h3v1h-3v-1zM62,5h1v1h-1v-1zM60,5h1v1h-1v-1zM56,5h1v1h-1v-1zM50,5h5v1h-5v-1zM47,5h2v1h-2v-1zM45,5h1v1h-1v-1zM42,5h1v1h-1v-1zM37,5h3v1h-3v-1zM34,5h1v1h-1v-1zM29,5h2v1h-2v-1zM26,5h1v1h-1v-1zM24,5h1v1h-1v-1zM21,5h1v1h-1v-1zM18,5h2v1h-2v-1zM12,5h5v1h-5v-1zM8,5h3v1h-3v-1zM6,5h1v1h-1v-1zM0,5h1v1h-1v-1zM116,4h1v1h-1v-1zM112,4h3v1h-3v-1zM110,4h1v1h-1v-1zM106,4h1v1h-1v-1zM104,4h1v1h-1v-1zM100,4h2v1h-2v-1zM96,4h3v1h-3v-1zM93,4h1v1h-1v-1zM90,4h1v1h-1v-1zM80,4h8v1h-8v-1zM77,4h2v1h-2v-1zM75,4h1v1h-1v-1zM73,4h1v1h-1v-1zM68,4h1v1h-1v-1zM64,4h1v1h-1v-1zM54,4h7v1h-7v-1zM50,4h1v1h-1v-1zM48,4h1v1h-1v-1zM45,4h2v1h-2v-1zM41,4h1v1h-1v-1zM38,4h1v1h-1v-1zM36,4h1v1h-1v-1zM29,4h6v1h-6v-1zM25,4h3v1h-3v-1zM22,4h1v1h-1v-1zM20,4h1v1h-1v-1zM16,4h1v1h-1v-1zM13,4h1v1h-1v-1zM6,4h1v1h-1v-1zM2,4h3v1h-3v-1zM0,4h1v1h-1v-1zM116,3h1v1h-1v-1zM112,3h3v1h-3v-1zM110,3h1v1h-1v-1zM105,3h1v1h-1v-1zM102,3h2v1h-2v-1zM96,3h5v1h-5v-1zM90,3h3v1h-3v-1zM87,3h1v1h-1v-1zM85,3h1v1h-1v-1zM83,3h1v1h-1v-1zM81,3h1v1h-1v-1zM77,3h2v1h-2v-1zM73,3h1v1h-1v-1zM70,3h1v1h-1v-1zM63,3h3v1h-3v-1zM61,3h1v1h-1v-1zM58,3h1v1h-1v-1zM55,3h1v1h-1v-1zM50,3h2v1h-2v-1zM46,3h3v1h-3v-1zM44,3h1v1h-1v-1zM39,3h2v1h-2v-1zM35,3h1v1h-1v-1zM32,3h2v1h-2v-1zM29,3h1v1h-1v-1zM27,3h1v1h-1v-1zM19,3h3v1h-3v-1zM15,3h2v1h-2v-1zM8,3h3v1h-3v-1zM6,3h1v1h-1v-1zM2,3h3v1h-3v-1zM0,3h1v1h-1v-1zM116,2h1v1h-1v-1zM112,2h3v1h-3v-1zM110,2h1v1h-1v-1zM106,2h3v1h-3v-1zM100,2h4v1h-4v-1zM94,2h1v1h-1v-1zM90,2h1v1h-1v-1zM88,2h1v1h-1v-1zM85,2h1v1h-1v-1zM81,2h2v1h-2v-1zM76,2h3v1h-3v-1zM73,2h1v1h-1v-1zM69,2h2v1h-2v-1zM66,2h1v1h-1v-1zM64,2h1v1h-1v-1zM62,2h1v1h-1v-1zM58,2h1v1h-1v-1zM54,2h2v1h-2v-1zM49,2h4v1h-4v-1zM46,2h1v1h-1v-1zM43,2h2v1h-2v-1zM40,2h1v1h-1v-1zM37,2h2v1h-2v-1zM31,2h1v1h-1v-1zM27,2h2v1h-2v-1zM25,2h1v1h-1v-1zM22,2h1v1h-1v-1zM19,2h1v1h-1v-1zM16,2h2v1h-2v-1zM14,2h1v1h-1v-1zM8,2h3v1h-3v-1zM6,2h1v1h-1v-1zM2,2h3v1h-3v-1zM0,2h1v1h-1v-1zM116,1h1v1h-1v-1zM110,1h1v1h-1v-1zM108,1h1v1h-1v-1zM101,1h5v1h-5v-1zM98,1h1v1h-1v-1zM96,1h1v1h-1v-1zM93,1h1v1h-1v-1zM90,1h1v1h-1v-1zM88,1h1v1h-1v-1zM86,1h1v1h-1v-1zM81,1h1v1h-1v-1zM76,1h3v1h-3v-1zM74,1h1v1h-1v-1zM71,1h2v1h-2v-1zM69,1h1v1h-1v-1zM65,1h2v1h-2v-1zM62,1h2v1h-2v-1zM59,1h1v1h-1v-1zM56,1h2v1h-2v-1zM49,1h6v1h-6v-1zM40,1h6v1h-6v-1zM38,1h1v1h-1v-1zM32,1h1v1h-1v-1zM26,1h5v1h-5v-1zM23,1h2v1h-2v-1zM19,1h1v1h-1v-1zM16,1h2v1h-2v-1zM14,1h1v1h-1v-1zM10,1h2v1h-2v-1zM8,1h1v1h-1v-1zM6,1h1v1h-1v-1zM0,1h1v1h-1v-1zM110,0h7v1h-7v-1zM106,0h1v1h-1v-1zM100,0h3v1h-3v-1zM98,0h1v1h-1v-1zM91,0h2v1h-2v-1zM87,0h3v1h-3v-1zM84,0h2v1h-2v-1zM81,0h2v1h-2v-1zM78,0h1v1h-1v-1zM76,0h1v1h-1v-1zM74,0h1v1h-1v-1zM69,0h4v1h-4v-1zM64,0h2v1h-2v-1zM59,0h3v1h-3v-1zM55,0h3v1h-3v-1zM53,0h1v1h-1v-1zM51,0h1v1h-1v-1zM48,0h2v1h-2v-1zM45,0h2v1h-2v-1zM41,0h3v1h-3v-1zM35,0h1v1h-1v-1zM33,0h1v1h-1v-1zM30,0h2v1h-2v-1zM24,0h5v1h-5v-1zM21,0h1v1h-1v-1zM19,0h1v1h-1v-1zM16,0h2v1h-2v-1zM13,0h1v1h-1v-1zM8,0h2v1h-2v-1zM0,0h7v1h-7v-1z"></path></svg>
<br><small><i>QR code for the data URL of "<a href="https://example.com">example.com</a>"<br>The content uses 1,290 of the maximum 2,953 bytes of information encodable in a binary QR code</i></small>
</center>
</div>
</div>
<p>You'll notice that the example.com QR code doesn't scan with your camera's built-in QR parser. Encoding a data URL into a QR code isn't against
the QR standard (which allows arbitrary data, deferring to scanners for deciding what to do with the data) so this means the parser itself
is refusing to process the data URL.</p>
<h3>Dynamic content</h3>
<p>One of the downsides of data URLs is they're static, whatever resources are embedded in them are there forever.
New content requires either JavaScript and an internet connection or to create a new data URL.</p>
<p>This constraint is similar to physical media formats like cartridges, records, and disks.
Creators of these physical media formats had to get everything right before they
were distributed to users, you can't patch or update the media after!</p>
<div class="row">
<div class="col-6">
<p>If we carry on using QR codes as a means of distributing local web content we can use either screens
to update QR codes automatically (after considering whether the information can be displayed directly to the screen) or using stickers or labels which are cheap to print if content needs to be updated
on a semi-regular basis in a centralized location.</p>
</div>
<div class="col-6">
<div>
<center>
<div id="qrcode" style="margin-bottom: 1em;"></div><br>
<small><i>Encodes the above text area as a data URL QR code</i></small>
</center>
</div>
</div>
</div>
<h3>Size constraints</h3>
<p>Websites can be any size, and frequently are on the order of megabytes (!) in terms of total content size.
Data URLs encoded into QR codes can't be any length as they are limited in size in two ways.</p>
<p>The maximum amount of data a QR code can encode depends on multiple variables.
QR codes can be different "versions" (i.e. "sizes"), have different error correction formats (L, M, Q, and H),
and be a different "type" (Numeric, Alphanumeric, Binary, and Kanji).</p>
<p>Since we need more than alphanumerics to encode base64 data and the <code>:</code> character we'll need to use the "Binary" type.
Optimizing for total amount of data with low error correction and version 40 we can fit a
maximum of 2,953 characters into a QR code.</p>
<p>URLs have no maximum size according to standards,
however in practice many browsers will limit URLs to a <a href="https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers">maximum of 2,000 characters</a>,
so to be on the safe side we'll be constrained to 2,000 characters in a data URL.</p>
<p>Base64 generally increases the size of a string by ~1.3x, so dividing 2,000 by ~1.3 we get ~1,538 bytes of data encodable into our data URLs.
Quite a bit smaller than multi-megabytes websites of today.</p>
<h3>Use-cases for data URLs</h3>
<p>So given all of the above constraints, what niche would data URLs fill for real-life usage?</p>
<ul>
<li>Small amounts of static data that doesn't need to update frequently</li>
<li>Users are likely to have mobile phones when encountering the data URL</li>
<li>Users are unlikely to have network connectivity OR the distributor of information wants to minimize spend/operations by not running a website</li>
<li>Users may want to access information after opening the data URL</li>
<li>Provide additional information mixed with information your phone still has access to (think GPS, accelerometer, contacts, pictures)</li>
</ul>
<p>Using the above constraints I can think of a few cases:</p>
<ul>
<li>Maps for remote locations or trails. Phones typically have GPS signal even without internet connectivity. QR codes could be placed at trailhead signs.</li>
<li>Providing a decent initial web "landing page" for a QR code in areas where internet connectivity is spotty or unavailable so would provide a negative experience after scanning the QR code.
For example advertisements on trains, subways, or airplanes. These data URL
"landing pages" could automatically upgrade to the real-deal once internet connectivity is restored.</li>
<li>Restaurant food and beverage menus are frequently encoded into a QR code. This requires serving a PDF or webpage from an actual website
so costs money to maintain. Instead restaurant owners could encode their menu into a data URL for a zero-cost solution.</li>
</ul>
<p>I'm sure there are many more example, <a href="mailto:sethmichaellarson@gmail.com">send me any interesting ones you think of yourself</a>.</p>
<h2>Data URLs are dead, long live data URLs</h2>
<p>So what's the biggest barrier to the local web being possible? <strong>Data URLs are dead.</strong></p>
<p>Data URLs were essentially <a href="https://blog.mozilla.org/security/2017/11/27/blocking-top-level-navigations-data-urls-firefox-59/">blocked from use as top-level domains</a> (and thus in QR codes)
by all major browsers in 2017 citing phishing, being confusing for users, and interacting strange ways with other standards (for example, should a <code>data:</code> URL be considered "secure" or "insecure"?)
According to caniuse.com, the <a href="https://caniuse.com/mdn-html_elements_base_href_forbid_data_javascript_urls">base href can't be <code>data:</code> for 92.75% of global browser users</a>.</p>
<p>This ends our hypothetical local web journey, hope you had fun! 🥲</p>
<p>QR codes generated using the <a href="https://github.com/datalog/qrcode-svg/blob/master/LICENSE">MIT-licensed</a> '<a href="https://github.com/datalog/qrcode-svg">qrcode-svg</a>' project.
Copyright (c) 2020 datalog.</p>
<script>
/** https://github.com/datalog/qrcode-svg under MIT license */
'use strict';function QRCode(r){var n,t,o,e,a=[],f=[],i=Math.max,u=Math.min,h=Math.abs,v=Math.ceil,c=/^[0-9]*$/,s=/^[A-Z0-9 $%*+.\/:-]*$/,l="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:",g=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],d=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],m={L:[0,1],M:[1,0],Q:[2,3],H:[3,2]},p=function(r,n){for(var t=0,o=8;o--;)t=t<<1^285*(t>>>7)^(n>>>o&1)*r;return t},C=function(r,n){for(var t=[],o=r.length,e=o;e;)for(var a=r[o-e--]^t.shift(),f=n.length;f--;)t[f]^=p(n[f],a);return t},w=function(r){for(var n=[function(){return 0==(t+o)%2},function(){return 0==t%2},function(){return 0==o%3},function(){return 0==(t+o)%3},function(){return 0==((t/2|0)+(o/3|0))%2},function(){return 0==t*o%2+t*o%3},function(){return 0==(t*o%2+t*o%3)%2},function(){return 0==((t+o)%2+t*o%3)%2}][r],t=e;t--;)for(var o=e;o--;)f[t][o]||(a[t][o]^=n())},b=function(){for(var r=function(r,n){n[6]||(r+=e),n.shift(),n.push(r)},n=function(n,o,a){return n&&(r(o,a),o=0),r(o+=e,a),t(a)},t=function(r){var n=r[5],t=n>0&&r[4]==n&&r[3]==3*n&&r[2]==n&&r[1]==n;return(t&&r[6]>=4*n&&r[0]>=n?1:0)+(t&&r[0]>=4*n&&r[6]>=n?1:0)},o=0,f=e*e,i=0,u=e;u--;){for(var c=[0,0,0,0,0,0,0],s=[0,0,0,0,0,0,0],l=!1,g=!1,d=0,m=0,p=e;p--;){a[u][p]==l?5==++d?o+=3:d>5&&o++:(r(d,c),o+=40*t(c),d=1,l=a[u][p]),a[p][u]==g?5==++m?o+=3:m>5&&o++:(r(m,s),o+=40*t(s),m=1,g=a[p][u]);var C=a[u][p];C&&i++,p&&u&&C==a[u][p-1]&&C==a[u-1][p]&&C==a[u-1][p-1]&&(o+=3)}o+=40*n(l,d,c)+40*n(g,m,s)}return o+=10*(v(h(20*i-10*f)/f)-1)},A=function(r,n,t){for(;n--;)t.push(r>>>n&1)},M=function(r,n){return r.numBitsCharCount[(n+7)/17|0]},B=function(r,n){return 0!=(r>>>n&1)},x=function(r,n){for(var t=0,o=r.length;o--;){var e=r[o],a=M(e,n);if(1<<a<=e.numChars)return 1/0;t+=4+a+e.bitData.length}return t},D=function(r){if(r<1||r>40)throw"Version number out of range";var n=(16*r+128)*r+64;if(r>=2){var t=r/7|2;n-=(25*t-10)*t-55,r>=7&&(n-=36)}return n},I=function(r,n){for(var t=2;-2<=t;t--)for(var o=2;-2<=o;o--)E(r+o,n+t,1!=i(h(o),h(t)))},H=function(r,n){for(var t=4;-4<=t;t--)for(var o=4;-4<=o;o--){var a=i(h(o),h(t)),f=r+o,u=n+t;0<=f&&f<e&&0<=u&&u<e&&E(f,u,2!=a&&4!=a)}},$=function(r){for(var n=t[1]<<3|r,o=n,a=10;a--;)o=o<<1^1335*(o>>>9);var f=21522^(n<<10|o);if(f>>>15!=0)throw"Assertion error";for(a=0;a<=5;a++)E(8,a,B(f,a));E(8,7,B(f,6)),E(8,8,B(f,7)),E(7,8,B(f,8));for(a=9;a<15;a++)E(14-a,8,B(f,a));for(a=0;a<8;a++)E(e-1-a,8,B(f,a));for(a=8;a<15;a++)E(8,e-15+a,B(f,a));E(8,e-8,1)},O=function(){for(var r=e;r--;)E(6,r,0==r%2),E(r,6,0==r%2);for(var t=function(){var r=[];if(n>1)for(var t=2+(n/7|0),o=32==n?26:2*v((e-13)/(2*t-2));t--;)r[t]=t*o+6;return r}(),o=r=t.length;o--;)for(var a=r;a--;)0==a&&0==o||0==a&&o==r-1||a==r-1&&0==o||I(t[a],t[o]);H(3,3),H(e-4,3),H(3,e-4),$(0),function(){if(!(7>n)){for(var r=n,t=12;t--;)r=r<<1^7973*(r>>>11);var o=n<<12|r;if(t=18,o>>>18!=0)throw"Assertion error";for(;t--;){var a=e-11+t%3,f=t/3|0,i=B(o,t);E(a,f,i),E(f,a,i)}}}()},Q=function(r){if(r.length!=V(n,t))throw"Invalid argument";for(var o=d[t[0]][n],e=g[t[0]][n],a=D(n)/8|0,f=o-a%o,i=a/o|0,u=[],h=function(r){var n=1,t=[];t[r-1]=1;for(var o=0;o<r;o++){for(var e=0;e<r;e++)t[e]=p(t[e],n)^t[e+1];n=p(n,2)}return t}(e),v=0,c=0;v<o;v++){var s=r.slice(c,c+i-e+(v<f?0:1));c+=s.length;var l=C(s,h);v<f&&s.push(0),u.push(s.concat(l))}var m=[];for(v=0;v<u[0].length;v++)for(var w=0;w<u.length;w++)(v!=i-e||w>=f)&&m.push(u[w][v]);return m},S=function(r){for(var n=[],t=(r=encodeURI(r),0);t<r.length;t++)"%"!=r.charAt(t)?n.push(r.charCodeAt(t)):(n.push(parseInt(r.substr(t+1,2),16)),t+=2);return n},V=function(r,n){return(D(r)/8|0)-g[n[0]][r]*d[n[0]][r]},E=function(r,n,t){a[n][r]=t?1:0,f[n][r]=1},R=function(r){for(var n=[],t=0,o=r;t<o.length;t++){var e=o[t];A(e,8,n)}return{modeBits:4,numBitsCharCount:[8,16,16],numChars:r.length,bitData:n}},Z=function(r){if(!c.test(r))throw"String contains non-numeric characters";for(var n=[],t=0;t<r.length;){var o=u(r.length-t,3);A(parseInt(r.substr(t,o),10),3*o+1,n),t+=o}return{modeBits:1,numBitsCharCount:[10,12,14],numChars:r.length,bitData:n}},z=function(r){if(!s.test(r))throw"String contains unencodable characters in alphanumeric mode";var n,t=[];for(n=0;n+2<=r.length;n+=2){var o=45*l.indexOf(r.charAt(n));o+=l.indexOf(r.charAt(n+1)),A(o,11,t)}return n<r.length&&A(l.indexOf(r.charAt(n)),6,t),{modeBits:2,numBitsCharCount:[9,11,13],numChars:r.length,bitData:t}},L=function(r,n,t,o){var e=function(r){return""==r?[]:c.test(r)?[Z(r)]:s.test(r)?[z(r)]:[R(S(r))]}(r);return U(e,n,t,o)},N=function(r,i,u,h){t=i,o=h;for(var v=e=4*(n=r)+17;v--;)a[v]=[],f[v]=[];if(O(),function(r){for(var n=0,t=1,o=e-1,i=o;i>0;i-=2){6==i&&--i;for(var u=0>(t=-t)?o:0,h=0;h<e;++h){for(var v=i;v>i-2;--v)f[u][v]||(a[u][v]=B(r[n>>>3],7-(7&n)),++n);u+=t}}}(Q(u)),0>o){var c=1e9;for(v=8;v--;){w(v),$(v);var s=b();c>s&&(c=s,o=v),w(v)}}w(o),$(o),f=[]},U=function(r,n,t,o,e,a){if(void 0===e&&(e=1),void 0===a&&(a=40),void 0===o&&(o=-1),void 0===t&&(t=!0),!(1<=e&&e<=a&&a<=40)||o<-1||o>7)throw"Invalid value";for(var f=[],i=236,h=[],v=e;;){var c=x(r,v);if(c<=8*V(v,n))break;if(v>=a)throw"Data too long";v++}if(t)for(var s=(l=[m.H,m.Q,m.M]).length;s--;)c<=8*V(v,l[s])&&(n=l[s]);for(var l=0;l<r.length;l++){var g=r[l];A(g.modeBits,4,f),A(g.numChars,M(g,v),f);for(var d=0,p=g.bitData;d<p.length;d++)f.push(p[d])}if(f.length!=c)throw"Assertion error";var C=8*V(v,n);if(f.length>C)throw"Assertion error";if(A(0,u(4,C-f.length),f),A(0,(8-f.length%8)%8,f),f.length%8!=0)throw"Assertion error";for(;f.length<C;)A(i,8,f),i^=253;for(s=f.length;s--;)h[s>>>3]|=f[s]<<7-(7&s);return N(v,n,h,o)};return function(){function n(r){return/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(r)}function t(r,n){for(var t in r=document.createElementNS(s,r),n||{})r.setAttribute(t,n[t]);return r}var o,f,i,u,v,c,s="http://www.w3.org/2000/svg",l="",g="string"==typeof r?{msg:r}:r||{},d=g.pal||["#000"],p=h(g.dim)||256,C=[1,0,0,1,c=(c=h(g.pad))>-1?c:4,c],w=n(w=d[0])?w:"#000",b=n(b=d[1])?b:0,A=g.vrb?0:1;for(L(g.msg||"",m[g.ecl]||m.M,0==g.ecb?0:1,g.mtx),v=e+2*c,i=e;i--;)for(u=0,f=e;f--;)a[i][f]&&(A?(u++,a[i][f-1]||(l+="M"+f+","+i+"h"+u+"v1h-"+u+"v-1z",u=0)):l+="M"+f+","+i+"h1v1h-1v-1z");return o=t("svg",{viewBox:[0,0,v,v].join(" "),width:p,height:p,fill:w,"shape-rendering":"crispEdges",xmlns:s,version:"1.1"}),b&&o.appendChild(t("path",{fill:b,d:"M0,0V"+v+"H"+v+"V0H0Z"})),o.appendChild(t("path",{transform:"matrix("+C+")",d:l})),o}()}
async function setClipboard() {
const text = document.getElementById("dataurl-content").value;
await navigator.clipboard.writeText(text);
}
document.getElementById("copy-dataurl").addEventListener("click", setClipboard);
function makeQrCode(data) {
return new QRCode({
msg: data,
ecl: 'L'
});
}
function computeDataUrlFromContent() {
var content = document.getElementById("webcontent").value;
var dataUrl = 'data:text/html;base64,' + btoa(content.replace(/\>\s+\</g, '><'));
document.getElementById("dataurl-content").value = dataUrl;
var qrcode = makeQrCode(dataUrl);
qrcode.setAttribute('id', 'qrcode');
document.getElementById("qrcode").replaceWith(qrcode);
};
document.getElementById("webcontent").addEventListener("input", (event) => {
computeDataUrlFromContent();
}, false);
computeDataUrlFromContent();
</script>
<blockquote>
<p>
<strong>Thanks for reading!</strong> ♡ Did you find this article helpful and want more content like it?
<nobr>Get notified of new posts</nobr> by subscribing to the <a href="/feed">RSS feed</a> or the <a href="https://buttondown.email/sethmlarson">email newsletter</a>.
<form
action="https://buttondown.email/api/emails/embed-subscribe/sethmlarson"
method="post"
target="popupwindow"
onsubmit="window.open('https://buttondown.email/sethmlarson', 'popupwindow')"
>
<center>
<input type="email" name="email" id="bd-email" placeholder="Email address here" style="max-width: 100%; width: 16em; margin-bottom: 0.5em;" required/><br>
<input type="submit" value="Subscribe" style="max-width: 100%; width: 16em;"/>
</center>
</form>
</p>
</blockquote>
<div>
<center>
<p xmlns:cc="http://creativecommons.org/ns#" >This work is licensed under <nobr><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-SA 4.0</a> <a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></nobr></p>
</center>
</div>
<script>
fetch("https://webmention.io/api/count?target=https://sethmlarson.dev/")
.then(response => response.json()).then(responseJson => {
if (responseJson.count) {
var webmentionsElement = document.getElementById("webmentions");
webmentionsElement.classList.add("webmentions-fade-in");
webmentionsElement.innerHTML = "❤ × " + String(responseJson.count);
};
});
</script>
</div>
<script data-goatcounter="https://sethmlarson-dev.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
</body>
</html>Challenges while building SBOM infrastructure for CPythonhttp://sethmlarson.dev/security-developer-in-residence-weekly-report-29?date=2024-02-142024-02-14T00:00:00Z2024-02-14T00:00:00ZSeth Michael Larson<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Challenges while building SBOM infrastructure for CPython</title>
<meta name="description" content="Python, open source, and the internet">
<meta name="keywords" content="python pypi open source maintainer urllib3 requests http networking security oss">
<meta name="author" content="Seth Michael Larson">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no"/>
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed"/>
<link rel="alternate" type="application/atom+xml" title="Atom Feed" href="/feed"/>
<link rel="icon" href="/static/favicon.ico">
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="/static/style.css">
<link rel="webmention" href="https://webmention.io/sethmlarson.dev/webmention" />
<meta property="og:site_name" content="Seth Michael Larson"/>
<meta property="og:author" content="Seth Michael Larson"/>
<meta property="og:type" content="article"/>
<meta property="og:title" content="Challenges while building SBOM infrastructure for CPython"/>
<meta property="og:description" content="
This critical role would not be possible without funding from the OpenSSF Alpha-Omega project. Massive thank-you to Alpha-Omega for investing in the security of the Python ecosystem!
In case y..."/>
<meta property="og:image" content="https://github.com/sethmlarson.png"/>
<meta name="twitter:card" content="summary"/>
<meta name="twitter:site" content="@sethmlarson"/>
<meta name="twitter:creator" content="@sethmlarson"/>
<meta name="twitter:title" content="Challenges while building SBOM infrastructure for CPython"/>
<meta name="twitter:description" content="
This critical role would not be possible without funding from the OpenSSF Alpha-Omega project. Massive thank-you to Alpha-Omega for investing in the security of the Python ecosystem!
In case y..."/>
<meta name="twitter:image" content="https://github.com/sethmlarson.png"/>
</head>
<body>
<div class="header">
<div class="container">
<div class="row">
<a href="/">About</a> •
<a href="/blog">Blog</a> •
<a href="https://buttondown.email/sethmlarson">Newsletter</a> •
<a href="/links">Links</a>
</div>
<div class="row">
<h1>Challenges while building SBOM infrastructure for CPython</h1>
<p><nobr>Published 2024-02-14</nobr> <nobr>by Seth Larson</nobr><br>
Reading time: minutes <a href="https://webmention.io/api/mentions.html?target=https://sethmlarson.dev/"><span id="webmentions"></span></a></p>
</div>
</div>
</div>
<div class="container">
<blockquote>
<center>This critical role would not be possible without funding from the OpenSSF <a href="https://alpha-omega.dev">Alpha-Omega project</a>. Massive thank-you to Alpha-Omega for investing in the security of the Python ecosystem!</center>
</blockquote>
<p>In case you missed it, recently I announced support for <a href="https://pyfound.blogspot.com/2024/02/software-bill-of-materials-now-available-for-cpython.html">Software Bill-of-Materials
for the CPython project</a>
on the Python Software Foundation blog.</p>
<p>Part of the project is intended to document the challenges that the project faced to
start publishing first-party SBOM documents alongside release artifacts. Yesterday I gave
a presentation to the <a href="https://github.com/ossf/sbom-everywhere">OpenSSF SBOM Everywhere SIG</a>,
the <a href="https://docs.google.com/presentation/d/15BbzIpQUIQv56vpwFNAEl4y8PAALVFnR5S_YpKxxkck">slides</a>
are available in Google Drive, but I'll be summarizing the discussion here:</p>
<h2>List of challenges so far for CPython SBOMs</h2>
<p><strong>Building for sustainability</strong>. There are no guarantees that my role will be around forever.
There's a non-zero chance that CPython core developers will need to maintain SBOM infrastructure at some point in the future. This means it needs to have buy-in,
be as low-effort to maintain as possible, fit into existing workflows, and be well documented.</p>
<p>This challenge sparked a bunch of conversation in the group about getting buy-in from technical leadership of open source projects.
My thoughts being the following:</p>
<ul>
<li>There isn't a one-size-fits-all approach for projects. Every proposal needs to be fit for that project.</li>
<li>Having engagements be driven by community members.
There's already a relationship of trust that the work will be done right by the community and that the individual won't leave as soon as the project is complete.
I applaud Alpha-Omega's approach here of supporting communities to do security work for the ecosystems they care about.</li>
<li>Being public and honest about all aspects of the work, especially the not-so-fun truths (like additional maintenance, complexity, etc).
I created a <a href="https://discuss.python.org/t/create-and-distribute-software-bill-of-materials-sbom-for-python-artifacts/39293">public discussion of the SBOM project for CPython</a>
and enumerate its impact specifically on developers updating dependencies and how having accurate SBOMs may increase the amount of reports from users we get to patch dependencies.</li>
<li>Show value for the maintainers of the project. SBOM itself may not have tons of value specifically for maintainers, but as an avenue
for scanners to discover VEX statements and thus reduce the amount of reports we receive to pointlessly patch dependencies is a valuable capability.</li>
</ul>
<p><strong>Recursive dependency bundling</strong>: CPython bundles pip in the <code>ensurepip</code> module. pip bundles 18
dependencies. There are even more projects bundled in older CPython versions which was the primary reason
I stopped backporting beyond 3.12. This requires a customized tool to handle the job. pip and its dependencies
being a part of the Python package ecosystem helps a lot, this means we can automatically do lookups for metadata on PyPI,
drastically reducing maintainer effort to keep the SBOM updated.</p>
<p><strong>Software IDs and metadata of C projects</strong>: Many of CPython dependencies are C projects (libexpat, mpdecimal, HACL*, etc)
and those projects aren't a part of a packaging ecosystem, they're tarballs you download and install by pasting into a directory.
This means there aren't any standards for what a version number or name should be. The unfortunate part of this
is it means the SBOM has to be updated manually when these projects are updated by core developers.</p>
<p>CPEs also don't exist universally for the projects, CPEs being the primary software vulnerability identifier used for C projects.
OSV and PURL don't work for projects outside of packaging ecosystems.</p>
<h2>Other items</h2>
<ul>
<li>Created a presentation and presented to the OpenSSF SBOM Everywhere group on CPython SBOM project.</li>
<li>More SBOM stuff:
<ul>
<li><a href="https://github.com/python/cpython/pull/115360">Moved pip SBOM discovery</a> from the CPython tooling to the CPython release tools.</li>
<li><a href="https://github.com/python/release-tools/pull/95">Make SBOM formatting reproducible</a></li>
<li><a href="https://github.com/python/release-tools/pull/93">Add test suite to CPython release tooling</a></li>
<li><a href="https://github.com/python/release-tools/pull/92">Fixed minor issue to remove whitespace from SBOM tool version</a></li>
</ul></li>
<li>Updated and backported <a href="https://github.com/python/cpython/issues/115399">libexpat to 2.6.0</a></li>
<li><a href="http://www.kroah.com/log/blog/2024/02/13/linux-is-a-cna/">Linux announced as a CVE Numbering Authority</a> and referenced my work on the <a href="https://openssf.org/blog/2023/11/27/openssf-introduces-guide-to-becoming-a-cve-numbering-authority-as-an-open-source-project/">OpenSSF guide to becoming a CNA</a>.</li>
<li>Attended the Python Software Foundation February board meeting</li>
<li>Triaged reports to the Python Security Response Team</li>
</ul>
<p>That's all for this week! 👋 If you're interested in more you can read <a href="https://sethmlarson.dev/security-developer-in-residence-weekly-report-30">next week's report</a> or <a href="https://sethmlarson.dev/security-developer-in-residence-weekly-report-28">last week's report</a>.</p>
<blockquote>
<p>
<strong>Thanks for reading!</strong> ♡ Did you find this article helpful and want more content like it?
<nobr>Get notified of new posts</nobr> by subscribing to the <a href="/feed">RSS feed</a> or the <a href="https://buttondown.email/sethmlarson">email newsletter</a>.
<form
action="https://buttondown.email/api/emails/embed-subscribe/sethmlarson"
method="post"
target="popupwindow"
onsubmit="window.open('https://buttondown.email/sethmlarson', 'popupwindow')"
>
<center>
<input type="email" name="email" id="bd-email" placeholder="Email address here" style="max-width: 100%; width: 16em; margin-bottom: 0.5em;" required/><br>
<input type="submit" value="Subscribe" style="max-width: 100%; width: 16em;"/>
</center>
</form>
</p>
</blockquote>
<div>
<center>
<p xmlns:cc="http://creativecommons.org/ns#" >This work is licensed under <nobr><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC BY-SA 4.0</a> <a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1" target="_blank" rel="license noopener noreferrer" style="display:inline-block;"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1"><img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg?ref=chooser-v1"></a></nobr></p>
</center>
</div>
<script>
fetch("https://webmention.io/api/count?target=https://sethmlarson.dev/")
.then(response => response.json()).then(responseJson => {
if (responseJson.count) {
var webmentionsElement = document.getElementById("webmentions");
webmentionsElement.classList.add("webmentions-fade-in");
webmentionsElement.innerHTML = "❤ × " + String(responseJson.count);
};
});
</script>
</div>
<script data-goatcounter="https://sethmlarson-dev.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
</body>
</html>