125 |
126 |
167 |
168 |
169 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/SETUP.md:
--------------------------------------------------------------------------------
1 | # GetPost Setup Guide
2 |
3 | Deploy your own GetPost instance for free on Cloudflare Workers.
4 |
5 | ## Quick Start (Try First!)
6 |
7 | Because I love you, I've included credentials allowing anyone to deploy to the shared staging environment. Try this first to see how it works:
8 |
9 | ```bash
10 | git clone https://github.com/getpost-loves-you/getpost
11 | cd getpost
12 | ./deploy.sh staging
13 | ./test.sh staging
14 | ```
15 |
16 | Your changes will appear at https://staging.getpost.workers.dev - perfect for testing modifications before setting up your own instance!
17 |
18 | ## Prerequisites
19 |
20 | - **Tools:** `curl`, `python3`, and a Linux-like environment (macOS, Linux, WSL, or Termux)
21 | - **Account:** Free Cloudflare account ([workers.dev](https://workers.dev))
22 | - **No complex toolchains:** We deliberately avoid Wrangler, NPM, or Rust to keep things simple
23 |
24 | ## Step 1: Cloudflare Account Setup
25 |
26 | ### Create Worker Environment
27 | 1. **Sign up** at [workers.dev](https://workers.dev) (free tier gives you 100k reads/day, 1k uploads/day)
28 | 2. **Create KV Namespace:**
29 | - Go to Workers → KV
30 | - Click "Create Namespace"
31 | - Name it something descriptive (or just "NAMESPACE")
32 | - Note the namespace ID
33 |
34 | 3. **Create Worker:**
35 | - Go to Workers → Overview
36 | - Click "Create a Service"
37 | - Choose any name (you can change it later)
38 | - Select "HTTP handler"
39 | - Click "Create service"
40 |
41 | 4. **Configure KV Binding:**
42 | - In your worker, go to Settings → Variables
43 | - Under "KV Namespace Bindings", click "Add binding"
44 | - Variable name: `NAMESPACE`
45 | - KV namespace: Select the one you created
46 | - Click "Save"
47 |
48 | ### Get API Credentials
49 | 1. **Generate API Token:**
50 | - Go to [dash.cloudflare.com/profile/api-tokens](https://dash.cloudflare.com/profile/api-tokens)
51 | - Click "Create Token"
52 | - Use "Edit Cloudflare Workers" template, or create custom with:
53 | - Zone:Zone:Read (if using custom domain)
54 | - Account:Cloudflare Workers:Edit
55 | - Account:Account Settings:Read
56 |
57 | 2. **Find Account ID:**
58 | - Go to Workers dashboard
59 | - Account ID is shown in the right sidebar
60 | - Or copy from the URL: `dash.cloudflare.com/ACCOUNT_ID/workers`
61 |
62 | ## Step 2: Local Configuration
63 |
64 | ### Create Deployment Config
65 | ```bash
66 | # Copy the staging template
67 | cp .staging .mydomain
68 |
69 | # Edit with your credentials
70 | nano .mydomain # or vim, code, etc.
71 | ```
72 |
73 | ### Configure Your `.mydomain` File
74 | ```bash
75 | # Required: Your Cloudflare credentials
76 | CF_ACCOUNT_ID="your-account-id-here"
77 | CF_API_TOKEN="your-api-token-here"
78 | SCRIPT_NAME="your-worker-name"
79 | DEPLOY_URL="https://your-worker-name.your-subdomain.workers.dev"
80 |
81 | # Optional: Test hashes (generated automatically on first run)
82 | # rendered_good="hash-will-be-generated"
83 | # upload_good="hash-will-be-generated"
84 | # image_good="hash-will-be-generated"
85 | ```
86 |
87 | **Where to find these values:**
88 | - `CF_ACCOUNT_ID`: From Cloudflare dashboard sidebar or URL
89 | - `CF_API_TOKEN`: The token you just created
90 | - `SCRIPT_NAME`: Your worker name (from step 1)
91 | - `DEPLOY_URL`: Your worker's URL (usually `https://SCRIPT_NAME.YOUR_SUBDOMAIN.workers.dev`)
92 |
93 | ## Step 3: Deploy & Test
94 |
95 | ### Deploy Your Instance
96 | ```bash
97 | ./deploy.sh mydomain
98 | ```
99 |
100 | This script:
101 | 1. Runs `autoinsert.py` to embed assets from `deps/` into `worker.js`
102 | 2. Creates `worker.packed.js` with all dependencies included
103 | 3. Uploads to Cloudflare using your credentials
104 |
105 | ### Verify It Works
106 | ```bash
107 | ./test.sh mydomain
108 | ```
109 |
110 | Expected output:
111 | ```
112 | Running tests against: https://your-domain.workers.dev
113 | ==================================
114 | TEST RESULTS:
115 | ==================================
116 | IMAGE: ✅ PASS
117 | RENDERED: ✅ PASS
118 | UPLOAD: ✅ PASS
119 |
120 | 🎉 ALL TESTS PASSED!
121 | ```
122 |
123 | If tests fail on first run, that's normal! The script will generate baseline hashes for your content.
124 |
125 | ## Step 4: Customization (Optional)
126 |
127 | ### Custom Domain
128 | If you want to use your own domain instead of `*.workers.dev`:
129 |
130 | 1. **Add domain to Cloudflare** (Websites → Add a Site)
131 | 2. **Update .mydomain" (Add API key, ACCOUNT_ID, Deploy URL, script name)
132 | 3. **Deploy with route:** `./deploy.sh mydomain`
133 |
134 | ### Modify the Code
135 | GetPost is designed to be hackable! Try editing:
136 |
137 | - **`deps/getpost.css`** - Change colors, fonts, layout
138 | - **`deps/upload.html`** - Modify the upload page content
139 | - **`worker.js`** - Add features, change behavior
140 | - **`deps/getpost.html`** - Customize the content display template
141 |
142 | After changes, redeploy and test:
143 | ```bash
144 | ./deploy.sh mydomain
145 | ./test.sh mydomain
146 | ```
147 |
148 | ## How It Works
149 |
150 | ### Build Process
151 | To keep the main `worker.js` file manageable, we use a simple build system:
152 |
153 | 1. **`autoinsert.py`** scans `worker.js` for `AUTOINSERT_` markers
154 | 2. **Embeds files** from `deps/` directory using naming convention:
155 | - `AUTOINSERT_GETPOST__CSS` → `deps/getpost.css`
156 | - `AUTOINSERT_UPLOAD__HTML` → `deps/upload.html`
157 | 3. **Creates `worker.packed.js`** with all dependencies bundled
158 | 4. **`deploy.sh`** uploads the packed file to Cloudflare
159 |
160 | ### Testing System
161 | - **Hash-based validation:** Each test generates a hash of the response
162 | - **Baseline comparison:** Compares against known-good hashes in your config file
163 | - **Content filtering:** Removes dynamic content (ULIDs, timestamps) before hashing
164 | - **Automatic updates:** Generates new baselines when content changes
165 |
166 | ## Troubleshooting
167 |
168 | ### Common Issues
169 |
170 | **"Authentication error" during deploy:**
171 | - Check your `CF_API_TOKEN` has correct permissions
172 | - Verify `CF_ACCOUNT_ID` matches your account
173 | - Make sure the API token isn't expired
174 |
175 | **"Namespace binding not found":**
176 | - Ensure you created the KV namespace binding in worker settings
177 | - Variable name must be exactly `NAMESPACE`
178 | - The namespace itself can have any name
179 |
180 | **Tests fail with hash mismatches:**
181 | - This is normal after content changes
182 | - Run `./generate_test_hashes.sh mydomain` to update baselines
183 | - Or manually update the hash values in your `.mydomain` file
184 |
185 | **Deploy succeeds but site doesn't work:**
186 | - Check the worker logs in Cloudflare dashboard
187 | - Verify KV namespace is properly bound
188 | - Try the `/headers` endpoint to debug
189 |
190 | ### Getting Help
191 |
192 | - **Check logs:** Cloudflare dashboard → Workers → your-worker → Logs
193 | - **Debug endpoints:**
194 | - `https://your-domain.com/headers` - Shows request details
195 | - `https://your-domain.com/echo` - Echoes request body
196 | - **Test staging:** Compare behavior with https://staging.getpost.workers.dev
197 |
198 | ## Philosophy
199 |
200 | Be excellent to one another! This shared staging environment exists because I trust the community. Please:
201 |
202 | - 🧪 **Test responsibly** - Don't abuse the shared staging credentials
203 | - 🔧 **Experiment freely** - That's what it's for!
204 | - 🤝 **Share improvements** - Submit PRs for features you build
205 | - 🌍 **Deploy your own** - Set up your instance for real usage
206 |
207 | The goal is to make self-hosting so easy that everyone can have their own GetPost instance. No complex toolchains, no vendor lock-in, just simple tools and good documentation.
208 |
209 | ---
210 |
211 | *Need help? Open an issue or check out the main [README.md](README.md) for more context.*
212 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GetPost v1.2
2 |
3 | **Libre linking for poems and memes**
4 | 🚀 **Run your own instance for free on any domain**🚀
5 |
6 | GetPost is a simple, secure [imagebin](https://en.wikipedia.org/wiki/Image_hosting_service) and [pastebin](https://www.urbandictionary.com/define.php?term=Pastebin) built on Cloudflare Workers.
7 | Share text, images, and files up to 10MB with no accounts, no tracking, and global distribution.
8 |
9 |
10 | ```bash
11 | # Try it now
12 | curl --data-binary @myfile.txt https://public.getpost.workers.dev
13 |
14 | # Deploy your own in minutes
15 | git clone https://github.com/getpost-loves-you/getpost
16 | cp .staging .mydomain
17 |
18 | ./deploy.sh mydomain
19 | ```
20 |
21 | ## Why GetPost?
22 |
23 | **For Users:**
24 | - 📝 **Instant sharing** - Text, markdown, images, most other filetypes
25 | - 🔗 **Clean URLs** - Short, shareable links with delete keys
26 | - ⚡ **Fast worldwide** - Sub-100ms response times via Cloudflare edge
27 | - 🛡️ **Privacy-focused** - No tracking, no ads, no accounts required
28 |
29 | **For Self-Hosters:**
30 | - 💰 **Free forever** - Cloudflare's generous free tier (100k reads, 1k uploads daily)
31 | - 🔧 **Zero maintenance** - No servers, no updates, no downtime
32 | - 🌍 **Global by default** - Your content is distributed worldwide automatically
33 | - 🎨 **Hackable** - Minimal, suckless codebase that is easy to customize
34 |
35 | ## Quick Start
36 |
37 | ### Web Upload
38 | Visit your GetPost instance and drag & drop files. Markdown is rendered automatically via [marked](https://github.com/markedjs/marked).
39 |
40 | ### Command Line
41 | ```bash
42 | # Basic upload
43 | curl --data-binary @file.txt https://your-domain.com
44 |
45 | # From clipboard (macOS)
46 | pbpaste | curl --data-binary @- https://your-domain.com
47 |
48 | # Custom expiration
49 | curl -H "X-TTL: 3600" --data-binary @file.txt https://your-domain.com
50 | ```
51 |
52 | ### One-Liner Script
53 | Save as `/usr/local/bin/pastebin`:
54 | ```bash
55 | #!/bin/bash
56 | curl --data-binary @${1:--} https://your-domain.com
57 | ```
58 |
59 | Usage: `pastebin file.txt` or `echo "hello" | pastebin`
60 |
61 | ## Deploy Your Own
62 |
63 | GetPost runs on **Cloudflare Workers** - zero servers, global distribution, generous free tier (100k reads, 1k uploads daily).
64 |
65 | ```bash
66 | git clone https://github.com/getpost-loves-you/getpost
67 | cd getpost
68 | # Follow SETUP.md for detailed instructions
69 | ./deploy.sh mydomain
70 | ```
71 |
72 | **Why Self-Host?**
73 | - 💰 **Free forever** - No hosting costs on Cloudflare's free tier
74 | - 🌍 **Your domain** - Custom branding and control
75 | - 🔧 **Zero maintenance** - No servers, no updates, no downtime
76 | - 🛡️ **Privacy** - Your data stays in your KV namespace
77 |
78 | 📄 **[Full Setup Guide →](SETUP.md)**
79 |
80 | ## Features
81 |
82 | - **📝 Text & Markdown** - Server-side rendering with clean typography
83 | - **🖼️ Images** - PNG, JPEG, GIF with instant preview
84 | - **📄 Documents** - PDFs, videos, any file type up to 10MB
85 | - **🔗 Raw Access** - Append `&raw` for direct file download
86 | - **⏰ Configurable TTL** - Default 1 year, customizable via X-TTL header
87 | - **🗑️ Delete Keys** - Every upload gets a unique deletion URL
88 | - **🌐 CORS Support** - Add `?cors=1` for cross-origin requests
89 | - **🔍 Debug Tools** - `/headers`, `/echo` endpoints for troubleshooting
90 |
91 | ## Architecture
92 |
93 | **Built on Cloudflare Workers** - a globally distributed edge computing platform.
94 |
95 | ```
96 | User → Cloudflare Edge → Worker → KV Storage
97 | ```
98 |
99 | - **Workers:** JavaScript runtime at 200+ locations worldwide
100 | - **KV Storage:** Eventually-consistent key-value store, AES-256 encrypted
101 | - **ULIDs:** Lexicographically sortable identifiers for posts and delete keys
102 | - **Zero dependencies:** Self-contained, no external services
103 |
104 | ### Why Cloudflare Workers?
105 |
106 | From Cloudflare's documentation:
107 |
108 | > Workers KV supports exceptionally high read volumes with low-latency, making it possible to build highly dynamic APIs and websites which respond as quickly as a cached static file would.
109 |
110 | Perfect for a pastebin! Popular content gets cached globally, while the free tier offers:
111 | - 100,000 reads per day
112 | - 1,000 writes per day
113 | - Sub-100ms cold start times
114 | - 128MB memory per request
115 |
116 | ## Security Model
117 |
118 | GetPost prioritizes **simplicity over complexity** in its security approach:
119 |
120 | **What's Protected:**
121 | - 🔐 **Access control** - 80 bits of entropy in ULIDs (stronger than most passwords)
122 | - 🔒 **Data at rest** - AES-256 encryption by Cloudflare
123 | - 🌐 **Data in transit** - TLS encryption for all requests
124 | - 🚫 **No tracking** - No cookies, analytics, or third-party scripts
125 |
126 | **What's Not Protected:**
127 | - Content is theoretically accessible to Cloudflare employees, [with some difficulty](https://developers.cloudflare.com/kv/reference/data-security/)
128 | - No client-side encryption (by design, for simplicity)
129 | - Your computer.
130 |
131 | **Privacy Philosophy:**
132 | We choose transparent simplicity over false security promises. For most use cases, ULID-based access control and Cloudflare's infrastructure security are sufficient.
133 |
134 | ## Development
135 |
136 | ### Hacking
137 |
138 | It's free and easy to get started with your own GetPost instance, either on a domain you already own, or a free "*.workers.dev" subdomain.
139 |
140 | Because I love you, I have included a set of credentials allowing anyone to deploy to "https://staging.getpost.workers.dev" - as well as a set of end-to-end tests, and lots of source code comments. Also spared interested parties from painful toolchain misadventures!
141 |
142 | GetPost doesn't require the use of Cloudflare's Wrangler tool, the Node Package Manager, or a Rust buildchain. It does require `curl`, `python3`, and a Linux-like environment (termux or WSL should work).
143 |
144 | ### Build Process
145 |
146 | To keep the main worker.js file manageable, a simple well-documented Python script - `autoinsert.py` - loads files from the `deps` folder into `worker.js` to make `worker.packed.js`.
147 |
148 | The `deploy.sh` script calls autoinsert.py to assemble the packed worker, loads credentials from a file in the local directory, and uploads the `worker.packed.js` file to Cloudflare.
149 |
150 | You can get started by cloning this repository, making a small edit to `worker.js` or one of the resources in `deps` - and running `./deploy.sh staging`.
151 |
152 | This loads the credentials from the `.staging` file, assembles your changes, and uploads the file.
153 |
154 | Your script will then start running on "https://staging.getpost.workers.dev" - and you can verify it works as expected by running `./test.sh staging`
155 |
156 | This loads other values from the `.staging` file, makes a series of requests to the staging URL, and prints "ALL TESTS PASSED" if the responses to the inputs are all as expected.
157 |
158 | Be excellent to one another, and follow the instructions in SETUP.md to create your own account with your own credentials, if you intend to do any real work - after all, other folks may also avail themselves of the staging deploy API key!
159 |
160 | ### Project Structure
161 | ```
162 | getpost/
163 | ├── worker.js # Main Cloudflare Worker code
164 | ├── autoinsert.py # Build script (embeds deps/ into worker)
165 | ├── deploy.sh # Deployment automation
166 | ├── test.sh # End-to-end testing
167 | ├── SETUP.md # Detailed deployment guide
168 | ├── deps/ # Static assets
169 | │ ├── getpost.css # Styling
170 | │ ├── getpost.html # Content template
171 | │ ├── upload.html # Upload page
172 | │ └── marked.min.js # Markdown parser
173 | └── .staging # Shared staging credentials
174 | ```
175 |
176 | ### Testing
177 | ```bash
178 | # Test against staging (using shared credentials)
179 | ./test.sh staging
180 |
181 | # Test your own deployment
182 | ./test.sh mydomain
183 |
184 | # Generate new baseline hashes after changes
185 | ./generate_test_hashes.sh staging
186 | ```
187 |
188 | ### Customization Ideas
189 | - **Custom CSS themes** - Edit `deps/getpost.css`
190 | - **File type support** - Extend `generateHtmlBasedOnType()`
191 | - **Rate limiting** - Add IP-based restrictions
192 | - **Analytics** - Track usage stats (respect privacy!)
193 | - **Content filtering** - Add moderation hooks
194 |
195 | ## API Reference
196 |
197 | ### Upload
198 | ```bash
199 | POST /post
200 | Content-Type: application/octet-stream
201 | X-TTL: 3600 # Optional: expiry in seconds
202 |
203 | # Response includes share link and delete key
204 | ```
205 |
206 | ### Retrieve
207 | ```bash
208 | GET /post?key=ULID # Rendered HTML view
209 | GET /post?key=ULID&raw # Original file
210 | GET /post?key=ULID&cors=1 # With CORS headers
211 | ```
212 |
213 | ### Delete
214 | ```bash
215 | GET /post?key=ULID&del=DELETE_KEY
216 | ```
217 |
218 | ### Debug
219 | ```bash
220 | GET /headers # Request headers and metadata
221 | GET /echo # Echo request body
222 | ```
223 |
224 | ## Community
225 |
226 | **Philosophy:** CC0. No Rights Reserved. Fork it, hack it, improve it, deploy it everywhere.
227 |
228 | - 📄 [Source Code](https://github.com/getpost-loves-you/getpost)
229 | - 🚀 [Setup Guide](SETUP.md)
230 | - 🐛 [Report Issues](https://github.com/getpost-loves-you/getpost/issues)
231 |
232 | ### Contributing
233 | 1. Test changes with `./test.sh staging`
234 | 2. Update `RELEASE_NOTES.md` and `README.md`
235 | 3. Follow [SemVer](https://semver.org/) for version numbers
236 | 4. Submit PRs with clear descriptions
237 |
238 | ### Inspiration
239 | GetPost revives the spirit of personal file servers from the pre-GitHub era, when sharing a file meant SCPing it to your homepage. We've made that experience:
240 | - Globally distributed (via Cloudflare's edge network)
241 | - Zero maintenance (no servers to patch)
242 | - Free forever (generous cloud free tiers)
243 | - Instantly deployable (minutes, not hours)
244 |
245 | ## Advanced Topics
246 |
247 | ### ULID Format
248 | Posts use [ULIDs](https://github.com/ulid/spec) instead of UUIDs:
249 | - **Lexicographically sortable** (chronological ordering)
250 | - **26 characters** vs UUID's 36 (shorter URLs)
251 | - **Crockford base32** (avoids visual ambiguity: 0/O, 1/I/L)
252 |
253 | ### Content Type Detection
254 | GetPost examines file headers to determine MIME types:
255 | - **Magic bytes** for binary formats (PNG, PDF, etc.)
256 | - **UTF-8 validation** for text content
257 | - **Markdown rendering** for text files
258 | - **Raw passthrough** for unknown types
259 |
260 | ### Performance Characteristics
261 | - **Cold start:** ~50ms (Cloudflare Workers)
262 | - **Warm requests:** ~10ms globally
263 | - **KV read latency:** ~10ms from cache, ~100ms from origin
264 | - **Global propagation:** ~60 seconds for KV writes
265 |
266 | ---
267 |
268 | *"Because I love you, I included credentials for anyone to deploy to staging.getpost.workers.dev. Be excellent to one another!"*
269 |
--------------------------------------------------------------------------------
/worker.js:
--------------------------------------------------------------------------------
1 | // Copyleft 2021: AKA Infra
2 | // Formally: PUBLIC DOMAIN / CC0
3 | // Informally: "an ye harm none, do what ye will"
4 |
5 | // declaration parsed by autoinsert.py; inserts the literal contents of deps/marked.min.js
6 | import 'marked' // prettier-ignore
7 |
8 | const ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
9 |
10 | const DEFAULT_MIME_TEXT = "text/raw; charset=UTF-8";
11 | const DEFAULT_MIME_HTML = "text/html; charset=UTF-8";
12 | const favicon_gzip =
13 | "H4sIAO9PM2AAA+2UMQrCQBBF36wbNZUBiUKa2MXOI9il9Rh6DMHKyjOls/UKVpYqFimEOBpE4yYXkLzls7Pzh+FXC6InCHix8mCk91T1bE1UQr80hQ9fdZIk+L6PMQZrLWmaIiJEUUQYhrS0tPwx3crLOIXj9vCaJ5o3//Y6VUNwqVvg5nl/cA2JbZ1bbs7ncFrCfgNbDbArVGdY5DBTxTfVFQYXKFTrA2RDOI7hHsMDH7d8sX4FAAA=";
14 |
15 | // This is non-standard, but very convenient and relatively simple:
16 | // specific interpolated strings - those wrapped in single-backticks (`) - and prefaced by AUTOINSERT_
17 | // are found by a regular-expression search autoinsert.py and converted into corresponding filenames
18 | //
19 | // For example, AUTOINSERT_NOTPACMAN__SVG is replaced with the contents of notpacman.svg, in the deps directory
20 | //
21 | // This keeps the worker.js script simple, without requiring much build tooling!
22 |
23 | const notpacman_svg = `AUTOINSERT_NOTPACMAN__SVG`; // eslint-disable-line
24 | const getpost_css = `AUTOINSERT_GETPOST__CSS`; // eslint-disable-line
25 |
26 | const ENCODING_LEN = ENCODING.length;
27 | const TIME_LEN = 10;
28 | const RANDOM_LEN = 16;
29 |
30 | addEventListener("fetch", (fetch_event) => {
31 | // configure primary entrypoint
32 | fetch_event.respondWith(HANDLER(fetch_event));
33 | });
34 |
35 | // main entrypoint for all requests
36 | async function HANDLER(fetch_event) {
37 | const now = Date.now();
38 | request = fetch_event.request;
39 | let headers = [...request.headers];
40 | for (const key in request.cf) {
41 | headers = headers.concat([
42 | ["cf-" + key, request.cf[key]]
43 | ]);
44 | }
45 | // massage headers and cloudflare metadata into "requestHeadersAndFriends" - an object containing helpful metadata for a given request
46 | const requestHeadersAndFriends = {};
47 | for (const header_index in headers) {
48 | requestHeadersAndFriends[headers[header_index][0].toLowerCase()] =
49 | headers[header_index][1];
50 | }
51 | const url = new URL(request.url);
52 |
53 | // Handle CORS preflight requests
54 | if (request.method === "OPTIONS") {
55 | return handleCorsPreflightRequest(url);
56 | }
57 |
58 | // Clone the request to avoid "body already used" errors in error handling
59 | let requestBodyForDebug = null;
60 | try {
61 | if (request.body) {
62 | const clonedRequest = request.clone();
63 | requestBodyForDebug = await clonedRequest.arrayBuffer();
64 | }
65 | } catch (e) {
66 | // If cloning fails, we'll just not have debug info
67 | requestBodyForDebug = new ArrayBuffer(0);
68 | }
69 |
70 | // wrap main handler in a try/catch exception logging & reporting block, for easy debug
71 | try {
72 | url.protocol = "https:";
73 |
74 | if (url.pathname === "/post" || url.pathname === "/") {
75 | if (request.method === "POST") {
76 | // Accept any reasonable content for uploads
77 | let blob = await request.arrayBuffer();
78 | blob = await new Blob([blob]).arrayBuffer();
79 |
80 | // Generate keys
81 | const storeKey = ulid(now);
82 | const editKey = ulid(now);
83 | const deleteKey = ulid(now);
84 |
85 | // Handle TTL
86 | let xTtlSeconds = requestHeadersAndFriends["x-ttl"];
87 | if (xTtlSeconds === undefined) {
88 | xTtlSeconds = 24 * 60 * 60 * 30 * 12; // 1 year
89 | } else {
90 | xTtlSeconds = parseInt(xTtlSeconds, 10);
91 | }
92 |
93 | const expiryTime = new Date(xTtlSeconds * 1000 + now).toISOString();
94 |
95 | // Store the content
96 | await NAMESPACE.put(storeKey, blob, {
97 | expirationTtl: xTtlSeconds,
98 | metadata: {
99 | edit: editKey,
100 | del: deleteKey,
101 | expiry: expiryTime
102 | }
103 | });
104 |
105 | // Prepare response data
106 | const responseData = {
107 | message: `GetPost stored ${blob.byteLength} bytes!`,
108 | size: blob.byteLength,
109 | key: storeKey,
110 | share_url: `${url.href}?key=${storeKey}`,
111 | raw_url: `${url.href}?key=${storeKey}&raw`,
112 | delete_url: `${url.href}?key=${storeKey}&del=${deleteKey}`,
113 | expires_at: expiryTime
114 | };
115 |
116 | // Content negotiation based on Accept header with user-agent fallback
117 | const acceptHeader = requestHeadersAndFriends["accept"] || "";
118 | const userAgent = requestHeadersAndFriends["user-agent"] || "";
119 |
120 | // Check for CLI tools as fallback when Accept header is generic
121 | const isCLITool = userAgent.startsWith("curl/") ||
122 | userAgent.toLowerCase().includes("wget") ||
123 | userAgent.toLowerCase().includes("python") ||
124 | userAgent.toLowerCase().includes("node") ||
125 | userAgent.toLowerCase().includes("go-http-client");
126 |
127 | if (acceptHeader.includes("application/json")) {
128 | // JSON response for API clients
129 | return buildResponse(JSON.stringify(responseData, null, 2), "application/json", {}, 200, url);
130 | } else if (acceptHeader.includes("text/plain") && !acceptHeader.includes("text/html")) {
131 | // Plain text response explicitly requested
132 | const textResp = `${responseData.message}
133 |
134 | share link: ${responseData.share_url}
135 | raw link: ${responseData.raw_url}
136 | delete link: ${responseData.delete_url}
137 | expires at: ${responseData.expires_at}`;
138 | return buildResponse(textResp, DEFAULT_MIME_TEXT, {}, 200, url);
139 | } else if (isCLITool && !acceptHeader.includes("text/html")) {
140 | // Fallback: CLI tools get plain text when Accept header is generic (*/* or missing)
141 | const textResp = `${responseData.message}
142 |
143 | share link: ${responseData.share_url}
144 | raw link: ${responseData.raw_url}
145 | delete link: ${responseData.delete_url}
146 | expires at: ${responseData.expires_at}`;
147 | return buildResponse(textResp, DEFAULT_MIME_TEXT, {}, 200, url);
148 | } else {
149 | // HTML response for browsers (with markdown parsing)
150 | const htmlResp = marked(`${responseData.message}
151 |
152 | **Share link:** ${responseData.share_url}
153 | **Raw link:** ${responseData.raw_url}
154 | **Delete link:** ${responseData.delete_url}
155 | **Expires at:** ${responseData.expires_at}`);
156 | return buildResponse(htmlResp, DEFAULT_MIME_HTML, {}, 200, url);
157 | }
158 | } else if (request.method === "GET") {
159 | const del = url.searchParams.get("del");
160 | const key = url.searchParams.get("key");
161 | const raw = url.searchParams.has("raw");
162 | const customContentType = url.searchParams.get("content_type");
163 |
164 | // if no key parameter provided, return the upload prompt so user can upload
165 | if (!url.searchParams.has("key")) {
166 | const upload = `AUTOINSERT_UPLOAD__HTML`; // eslint-disable-line
167 | return buildResponse(upload, DEFAULT_MIME_HTML, {}, 200, url);
168 | }
169 | // ULID is len26
170 | if (key.length === 26 || key.length === 91) {
171 | let {
172 | contentFromKeyAsArrayBuffer,
173 | metadata
174 | } =
175 | await NAMESPACE.getWithMetadata(key, "arrayBuffer");
176 | // if either key dne, or old format
177 | if (metadata === null) {
178 | // check to see if old (pre-metadata)
179 | contentFromKeyAsArrayBuffer = await NAMESPACE.get(
180 | key,
181 | "arrayBuffer",
182 | );
183 | if (contentFromKeyAsArrayBuffer !== null) {
184 | contentFromKeyAsArrayBuffer = contentFromKeyAsArrayBuffer.slice(
185 | 0,
186 | -26,
187 | );
188 | } else {
189 | return buildResponse(
190 | "Sorry, invalid key!",
191 | DEFAULT_MIME_TEXT, {},
192 | 404,
193 | url,
194 | );
195 | }
196 | } else {
197 | // this second get should not be required... it appears getWithMetadata doesn't support returning arrayBuffers!?
198 | contentFromKeyAsArrayBuffer = await NAMESPACE.get(
199 | key,
200 | "arrayBuffer",
201 | );
202 | }
203 | // if both key and delete key...
204 | if (url.searchParams.has("del") && del.length == 26) {
205 | if (del === metadata.del) {
206 | const deleted_target_key = await NAMESPACE.delete(key);
207 | return buildResponse(
208 | `OK, sent command to delete ${key} using ${del} - please wait 3min for full delete.`,
209 | DEFAULT_MIME_TEXT, {},
210 | 200,
211 | url,
212 | );
213 | } else {
214 | return buildResponse(
215 | "Sorry, invalid del key!",
216 | DEFAULT_MIME_TEXT, {},
217 | 404,
218 | url,
219 | );
220 | }
221 | }
222 | const [generatedBodyHtml, type] = generateHtmlBasedOnType(
223 | contentFromKeyAsArrayBuffer,
224 | url,
225 | metadata
226 | );
227 | if (raw) {
228 | // Check if custom content type is provided and validate it
229 | let responseContentType = type;
230 | if (customContentType) {
231 | if (isValidContentType(customContentType)) {
232 | responseContentType = customContentType;
233 | } else {
234 | return buildResponse(
235 | "Sorry, invalid content_type parameter!",
236 | DEFAULT_MIME_TEXT, {},
237 | 400,
238 | url,
239 | );
240 | }
241 | }
242 |
243 | // if requested as raw, return the original resp object with detected or custom MIME type
244 | return buildResponse(
245 | contentFromKeyAsArrayBuffer,
246 | responseContentType, {},
247 | 200,
248 | url,
249 | );
250 | }
251 | // otherwise, return the wrapped body with the text/html mimetype
252 | else {
253 | return buildResponse(
254 | generatedBodyHtml,
255 | DEFAULT_MIME_HTML, {},
256 | 200,
257 | url,
258 | );
259 | }
260 | } else {
261 | return buildResponse(
262 | "Sorry, invalid key!",
263 | DEFAULT_MIME_TEXT, {},
264 | 404,
265 | url,
266 | );
267 | }
268 | }
269 | } else if (url.pathname === "/headers") {
270 | // helpful debug endpoint - return the headersAndFriends object, as a nicely formatted string
271 | requestHeadersAndFriends.url = url.toString();
272 | requestHeadersAndFriends.method = request.method;
273 | // first 20 bytes (hex-encoded) of the request
274 | if (requestBodyForDebug && requestBodyForDebug.byteLength > 0) {
275 | requestHeadersAndFriends.startBodyHex = hex(
276 | requestBodyForDebug.slice(0, 20),
277 | );
278 | } else {
279 | requestHeadersAndFriends.startBodyHex = "";
280 | }
281 | return buildResponse(
282 | JSON.stringify(requestHeadersAndFriends, null, 2) + "\n",
283 | "application/json", {},
284 | 200,
285 | url,
286 | );
287 | } else if (url.pathname === "/echo") {
288 | // helpful debug endpoint - return the request body
289 | return buildResponse(
290 | await request.arrayBuffer(),
291 | "application/octet-stream", {},
292 | 200,
293 | url,
294 | );
295 | } else if (url.pathname === "/raise_exception") {
296 | // trigger an exception
297 | this_method_does_not_exist();
298 | } else if (url.pathname === "/getpost.css") {
299 | // return static css content
300 | return buildResponse(getpost_css, "text/css", {}, 200, url);
301 | } else if (url.pathname === "/favicon.ico") {
302 | // returning binary requires UTF-16 JS strings to be converted to ie) UTF-8 bytes
303 | return buildResponse(
304 | str2ab(atob(favicon_gzip)),
305 | "image/x-icon", {
306 | "Content-Encoding": "gzip"
307 | },
308 | 200,
309 | url,
310 | );
311 | } else {
312 | return buildResponse(
313 | `You probably want ${url.host}/post, not ${url.pathname}!`,
314 | DEFAULT_MIME_HTML, {},
315 | 404,
316 | url,
317 | );
318 | }
319 | } catch (err) {
320 | // very helpful traceback functionality, such that users can report errors
321 | requestHeadersAndFriends.url = url.toString();
322 | requestHeadersAndFriends.method = request.method;
323 | requestHeadersAndFriends.traceback = err.stack.split("\n");
324 | // include the first 20 bytes, as 40 hex characters - use pre-cloned body
325 | if (requestBodyForDebug && requestBodyForDebug.byteLength > 0) {
326 | requestHeadersAndFriends.startBodyHex = hex(
327 | requestBodyForDebug.slice(0, 20),
328 | );
329 | } else {
330 | requestHeadersAndFriends.startBodyHex = "";
331 | }
332 | return new Response(JSON.stringify(requestHeadersAndFriends, null, 2), {
333 | status: 500,
334 | statusText: "caught exception in worker",
335 | headers: addCorsHeaders({}, url),
336 | });
337 | }
338 | }
339 |
340 | // Validate content type parameter
341 | function isValidContentType(contentType) {
342 | // Basic validation for content type format
343 | // Allow common patterns like "text/html", "application/json", etc.
344 | const contentTypeRegex = /^[a-zA-Z][a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_]*\/[a-zA-Z0-9][a-zA-Z0-9!#$&\-\^_.+]*(?:\s*;\s*[a-zA-Z0-9!#$&\-\^_]+=[a-zA-Z0-9!#$&\-\^_.+]*)*$/;
345 |
346 | if (!contentTypeRegex.test(contentType)) {
347 | return false;
348 | }
349 |
350 | // Additional length check for security
351 | if (contentType.length > 200) {
352 | return false;
353 | }
354 |
355 | return true;
356 | }
357 |
358 | // Handle CORS preflight requests
359 | function handleCorsPreflightRequest(url) {
360 | const corsHeaders = {
361 | "Access-Control-Allow-Origin": "*",
362 | "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
363 | "Access-Control-Allow-Headers": "Content-Type, X-TTL",
364 | "Access-Control-Max-Age": "86400", // 24 hours
365 | };
366 |
367 | return new Response(null, {
368 | status: 204,
369 | headers: corsHeaders,
370 | });
371 | }
372 |
373 | // Add CORS headers if cors=1 parameter is present
374 | function addCorsHeaders(headers, url) {
375 | if (url && url.searchParams.has("cors")) {
376 | headers["Access-Control-Allow-Origin"] = "*";
377 | headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS";
378 | headers["Access-Control-Allow-Headers"] = "Content-Type, X-TTL";
379 | }
380 | return headers;
381 | }
382 |
383 | // returns a single byte from the Cloudflare worker's (cryptographically secure) RNG
384 | function prng() {
385 | const buffer = new Uint8Array(8);
386 | crypto.getRandomValues(buffer);
387 | return buffer[0] / 0xff;
388 | }
389 |
390 | // get a random character from the set of encodings
391 | function randomChar() {
392 | let rand = Math.floor(prng() * ENCODING_LEN);
393 | if (rand === ENCODING_LEN) {
394 | rand = ENCODING_LEN - 1;
395 | }
396 | return ENCODING.charAt(rand);
397 | }
398 |
399 | // shove time (or any integer) into "len" base32 characters
400 | function encodeTime(now, len) {
401 | let mod;
402 | let str = "";
403 | for (; len > 0; len--) {
404 | mod = now % ENCODING_LEN;
405 | str = ENCODING.charAt(mod) + str;
406 | now = (now - mod) / ENCODING_LEN;
407 | }
408 | return str;
409 | }
410 |
411 | // get "len" random base32 characters
412 | function encodeRandom(len) {
413 | let str = "";
414 | for (; len > 0; len--) {
415 | str = randomChar() + str;
416 | }
417 | return str;
418 | }
419 |
420 | // return a ULID from an optional time, comprised of TIME_LEN characters of timestamp and RANDOM_LEN characters of entropy
421 | function ulid(seedTime) {
422 | // if no seedTime is provided, use the current time
423 | if (isNaN(seedTime)) {
424 | seedTime = Date.now();
425 | }
426 | return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN);
427 | }
428 |
429 | // helper to turn a string into an array buffer
430 | function str2ab(str) {
431 | const buf = new ArrayBuffer(str.length);
432 | const bufView = new Uint8Array(buf);
433 | for (let i = 0, strLen = str.length; i < strLen; i++) {
434 | bufView[i] = str.charCodeAt(i) & 0xff;
435 | }
436 | return buf;
437 | }
438 |
439 | // Uint8Array -> hex string
440 | function hex(uint8arr_or_arraybuffer) {
441 | const uint8arr = new Uint8Array(uint8arr_or_arraybuffer);
442 | if (!uint8arr) {
443 | return "";
444 | }
445 | let hexStr = "";
446 | for (let i = 0; i < uint8arr.length; i++) {
447 | let hex = (uint8arr[i] & 0xff).toString(16);
448 | hex = hex.length === 1 ? "0" + hex : hex;
449 | hexStr += hex;
450 | }
451 | return hexStr;
452 | }
453 |
454 | // content (and optional url) to wrapper html and detected type
455 | function generateHtmlBasedOnType(content, url = "", metadata = null) {
456 | let expiryTime = "Unknown";
457 | if (metadata) {
458 | if (metadata.permanent) {
459 | expiryTime = "Never (permanent)";
460 | } else if (metadata.expiry) {
461 | expiryTime = metadata.expiry.split('T')[0];
462 | }
463 | }
464 | if (content === null || content === undefined) {
465 | return ["CONTENT NOT FOUND", DEFAULT_MIME_TEXT];
466 | }
467 | const contentAsUint8Array = new Uint8Array(content);
468 | const contentAsString = new TextDecoder("utf-8").decode(contentAsUint8Array);
469 | // checks to see if characters are all plausibly utf-8 / printable
470 | const contentIsPrintable = /^[\x00-\x7F]*$/m.test(contentAsString);
471 | const header = hex(contentAsUint8Array.slice(0, 4));
472 | let injectorScript, type;
473 | // matches the first four bytes of the uploaded file
474 | switch (header) {
475 | // echo -n 'ftypmp42' | xxd
476 | // 00000000: 6674 7970 6d70 3432 ftypmp42
477 | case "00000018":
478 | case "0000001c":
479 | if (hex(contentAsUint8Array.slice(4, 12)) == "667479706d703432") {
480 | type = "video/mp4";
481 | break;
482 | }
483 | case "25504446":
484 | type = "application/pdf";
485 | break;
486 | case "89504e47":
487 | type = "image/png";
488 | break;
489 | case "47494638":
490 | type = "image/gif";
491 | break;
492 | case "49443304":
493 | type = "audio/mp3";
494 | break;
495 | case "504b0304":
496 | type = "application/zip";
497 | break;
498 | case "ffd8ffe0":
499 | case "ffd8ffe1":
500 | case "ffd8ffe2":
501 | case "ffd8ffe3":
502 | case "ffd8ffe8":
503 | type = "image/jpeg";
504 | break;
505 | default:
506 | if (contentIsPrintable === true) {
507 | type = DEFAULT_MIME_TEXT;
508 | } else {
509 | type = "application/octet-stream";
510 | }
511 | break;
512 | }
513 | switch (type) {
514 | case "image/png":
515 | case "image/gif":
516 | case "image/jpeg":
517 | break;
518 | case "audio/mp3":
519 | case "video/mp4":
520 | case "application/pdf":
521 | case "application/zip":
522 | case "application/octet-stream":
523 | injectorScript = "window.location.assign(window.location.href+'&raw')";
524 | break;
525 | case DEFAULT_MIME_TEXT:
526 | default:
527 | injectorScript = "";
528 | break;
529 | }
530 | const TITLE = `GetPost: ${type}`;
531 | let contentAsHtmlFromMarked = "";
532 | let imageUrl = "";
533 | let description = "";
534 | // future use
535 | const encodedPayload = "";
536 | // strip non-url characters from description
537 | if (type === DEFAULT_MIME_TEXT) {
538 | contentAsHtmlFromMarked = marked(new TextDecoder("utf-8").decode(content));
539 | // use the first 140 characters that aren't special, as the description!
540 | description = new TextDecoder("utf-8")
541 | .decode(new Uint8Array(content.slice(0, 140)))
542 | .replace(/[^0-9a-z\\\ \.\:\?]/gi, "");
543 | } else {
544 | description = "GetPost: " + type;
545 | }
546 | if (type.startsWith("image/")) {
547 | imageUrl = url.toString() + "&raw";
548 | injectorScript = "";
549 | }
550 | const contentAsWrappedHtml = `AUTOINSERT_GETPOST__HTML`; // eslint-disable-line
551 | return [contentAsWrappedHtml, type];
552 | }
553 |
554 | function buildResponse(
555 | blob,
556 | type = DEFAULT_MIME_HTML,
557 | headers = {},
558 | statuscode = 200,
559 | url = null
560 | ) {
561 | const headersObj = Object.assign(headers, {
562 | "content-type": type
563 | });
564 |
565 | // Add CORS headers if cors parameter is present
566 | if (url) {
567 | addCorsHeaders(headersObj, url);
568 | }
569 |
570 | if (statuscode !== 200) {
571 | return new Response(blob, {
572 | status: statuscode,
573 | statusText: blob,
574 | headers: headersObj,
575 | });
576 | }
577 | return new Response(blob, {
578 | status: statuscode,
579 | headers: headersObj
580 | });
581 | }
--------------------------------------------------------------------------------
/deps/ubuntu_mono_woff2.base64:
--------------------------------------------------------------------------------
1 | d09GMgABAAAAAGqAABAAAAAA2BgAAGogAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHIsgBmAWi2AAgXgIhAQJjCMRCAqC7AiCxhALhAwAATYCJAOEDAQgBYMMB4hODIMKGwDCN9Bt2xWNSm9WFYBz7W9nZCCPQ0KOUgPusMcBXKndsv///7ykIkclddJ2m9k9ODyJHB7K5JKoCTVErdSWSPWOuo5ae1n1raN+4e2vL4toU+87ouBAoTJRs4i1GsfUnFPd7YD0iZiFG4d9Cpc+UeDOPxRkpJMblW668fDd9WAld6wSyXjwunVhqwG3ijFIhmhMDnRLkKXZjDfkLP4X7a9P/bFk+Oeud6e3hdUuN0+ZX1kFsnJxW+IDW0PRvsApVDB+lJnIFgWL0IKTzhFLhZA33HAMS3g7nfwMhOEzHm5uMnfN5AxsG/mTnLxWrVWZWT2zgOTuTr0mlK9WPsuVD8DCAFsWClAyhkd1M0DbjGmjZB8pUYKKmCBwKKESFli4NnJGbrqftUoX6XRR4dLV//r1t/djEeX+r20nYkBJhEwsvE4VC5XaT/Z3oqGiPPxz+Lvvr1kBBbZ5Y9oJZC3xCZQXUFY8NratrcXPJ3NW/2RZtiRblmzLTtjppIEzCN2zs9CzcU16ASkfkqWBpV6i3v7AVwA8Ap3pcNvDcQa3mSaa4iUmRGcGhFqu86mzbwZkDMgWAomxAAEjCRBRkiWCEUnObLR3M6sN4PS4y/x7/W553eV5U3ChKEN0dSn6qit/qC9QlPvWT/dpnV7nuO3ep6Wd5BkZfYQmgDt8cTCJFnW81+8if2sBsRRArAzMs+TJvPG/usove+gQfSDffzMHsxtEnWV5AQeUyIvSULxdANChKcoU5XdwLtUVTYqeuEy9VlxsXn88iOOAOAzDMAwPDxd35mVxcaMu+D4BAv4HxqlCagPEk/j/m7O/D/WXe2WHOrWVBy+RZEiGk+H8YbH6HbayNa1T1ei0Uua1e3Nr8rp9WYVzlxrr2M340AjnrzXfq+0XpuMB2PL4jq+sMYmNPuQgbBDvEt59r/DySICCQIKMtv8+slr7ftT9/ypJk8ZO4hW7pn3yxWFnY56YdtjYdiaOdKW7K7gV7ojn8Od5n2WW7SQ6PQWA7oNl2HgGVpiK+ls3TYo6f5+q9kAQJIAP/ILWWSUSFEERbnQT5DQ5tTNb2nFdZpjGGcZM4060UdKVcrlsUTI6bj2ZPu36ZHlyuHByOGmMpRxrAf0+G6Juy+UCEu3ucKaITlgD44hSkedEEwCo8eo9YP9/XzVr73sgxA9qZAMTqY102BhreTaGpgqxfP/eB/z/78MD8B8UgE9iBgQtrQjJPhQ4AaIcABKzJqmZPdyUsoTxONDaY5GUxmPKUTNOGqdUbcipSrGqtqxSG3JdbFluUS48X2uZna2fF+CpESqEQgO1TMWpcC91yMZt+QDiZDIyQkVGAmkCBUfu6qQ5/qkOlHc+0LPo8dE6JpRMgIoF4hJ22c/6NkgI2AYlWAcVAeeV73rnf8NZ94i1Tm+PoUazDLFfQn9kcyK+jI2KCK9CG3WDAZuA8T/EnPZYUWPajY/kJe4sB8ctbs3Q/z0OAqKOhJz3/ObKYgh2uXJ8EYSz4ZlSCgnjA0AwygC+VPTUUEganvfk2ACANW13ApDP2s0A4pxHJCxzihy9XkRc9s06UQm5nw6emKQ83EJpWQlkmur9Ow/eC5D2N7FRNrYYMie16ENj+VZ1SSVk7QwIyO2IeHxhIFJKkY0x7W7MUeiYO7Yo7CZ9h8uUV+Z/8csUrPse2nX4U6mCGHoU8cMPRA4VBJ8sdAJfrN9odXqD0WS2mH63shYNniNA6jrU8aEe7DUst8iIQlEXelW1MOvPBoVj8KriBEQRMR/fFLUw1jtDF4eGCxHZsq6/CCKFKAlM7FyyFChUqUEbBQOHgISChiFTlmw5ckWv3x8MEa0tqROb5yTeOKkPTuaTs/LCWfthNnU5cqKgpAJhEC0dPQMjE/P5FqYqFiFn85yNecvCfA5efpqNixMlCNExWNPavJoF/cc78wXy0qwjCkoQRs/A9NGZJo+KQyxMDD0Lp/d++Cq/zMZGCUIM1rQ2RubjJOAbrxhtc1GBMIiRiTm0qJFhaUTfYVYavH8iSyqi45GK8NpzWqDNhEHMmjgliNloqOUZNc+TR5GAr0K9wRg+m7m84zfnwRd0om5AcAzf4Su2vgGo6UXMl8ntAmQEghXkH1s4adVCNCDBz8L+wI3Q4glb+gE5OzcGAtV0GxC0eWPSghsQ918d7QmLFkv9pYn5dIZ4JkuCLZnDheBB5gugdgidP0QwxRJYKVyZFfy9RuwMfzAEAAWGwcE3AfkhUbBNw78YRCwOiUclEDFJZOxWcB8qnkagEzO2SXqzyGwKh5rLo719eGyCJwiZIpaYU/JO4fGSPaF8F/xVKahSizRiraSu3iCd8YhJZla07FX534Zula3aTmOv7bCPun9OemeDi7Grm8nd3ON+Wv96edv42Pra+dnff4c/JrOjxWnW87a5tFNut3b/xbAenGde8BK9S7LvLn51Sd8gGRsZxThU46NtuglfY5g4zHOFZVJsHJNxFeJB4kMlIIQhgr3FcF+SkMInI0egQBrluaBCSU2DSouWbuvRP2fAYMS8TVifMbNgs+Kw4bLjceBzEozrDNxEeXiJ8/GTTuD0gmRC5MIURXaU8k6MSpymhCStFN1O09/KMJTdOcYbeaYKiiyVlFlV2FTZq911zmsNTS4t7to6PLvLOxnga9AQ/z0sODNiVMiYsHERE6JNmhK7pyVGM2YlzUmZl7YgM4unsiRrWc6K/Kye0pqCdUUbSjaV29rbKhd21Nq1p25fowOHWo605/jkTnQ7dWbAucEu/r409B9XRkbXyo3Rbt0Zc2/cA+eR9yR4Fr1I83rAm9y7D8Wnur+0mW+9H7+GP7P/15uyONgnifPwZcbHt58ZAE36vxN2GB3zjGt1TOf1p4bbIk7jHFZxCbv4APgM8O2wqybU5IefOQqlta293ug1DxCwhOVr7z5O5mv++/gbkNlV//pud5flw/SnmTreq+DHcEUHHp6wN/VujD9IvKuhpIkFHfWL/9XeqMpkhcYqUmyciSrJK7WO3Yl8dgzvAYE7ljquRfOt2UsvNR28Y5cCXK1xhLlZUuEp1kWO1/LdCzSYl5RmhNsw3Uwk9Qdglkxke6Nt0PAMPJyTADkJL0bd2SQlcm2w0Qcn8ZC55yRm10yD/Lv4GsgXLmt3vzKju512a3VleWlxYX5udiZRsYyuS/FGw0G/53Z3Ou2WaTTq5VKxoKl5SYzzsU02Ggm/B2zdHmukMLGcGpZKDZydnTZjdLinUzcR71ZJ3KoxdrsKnwtxbaMRMSrmsMP8IXhofjxcIacfauQTttYyO3wapt78h9RStdRIxIE4DIsV1k5nMVWYXbooeT7LlY0j3azYt1eiHO7tdkPh7ov2yRNJ45MFu/IIi5reFfUAJ1CT1+wiv67cgFbVPBUHYZjmqyBpHkAVSVXHd8LdMHxMxdTNfHdyGHq2uX+AA7dhyHcPTp37Ks8/oCNNuoqxq738K0JTDWnqbUJRE+MDC+3Gf0IYleuHkef/I27xv39zaQcVpfGIt6e7iE47XBOoIwuQmwvDMGY/ngjovT2Y3myZOfAhwZcgbm2m5FnrjptjJ/SON4OqicVwmPYp+3ju89lperPH+0kqNSDqfmoBJ79he/1M38ANc4zjPpvtGhJxs084ntOquO3W0tjZmne6IGwlO2/FJ+k4RjFdMO//yZ2OKZ6vcmM6LglsP1bCqTikhKt8ULB1SBMirncD7txVcYIHX90Jd0EaQo1OSrVdv6FyMxjRRRsMiNsRN0FIIiXmUjTDdIRm8TBd/bHmMKIayGuxkoUYWS+s1mvceH0/HSn/EPOEZzF6iKrtSAVHU71UztWsDw26+qMTD30UuG35dTl7P/vV1PbgIExDOWh7bJBAebQmSqPlvI/B2iVKqfIX73A1jFvX36AtQxMNEiJ7/ZBP/GKuDWVp9n7wlfLPl3t1qUcwPA3rwSo3OMQUM05i1fDCfjb5oM7r4EJrzYx0foKs7BraVbrPXjjUyJNUp6RJvVlqJojFbB9gTqOT5zVc6OSkFpMQzl1zBC1DAtep+47etd4eSzCxmDjkh3mSu8muMS+EyJ9UNnuAooZzAzfTMQ8FbWu3zWvBy/FdPQoL7PFuND1VeBAVyD5sFYK1nTVz4zAA/1DNFh6LUt1WpzNceE6XKD7omI5X0yy36cN6Fk6SVx/nMGL4CCyK1ymYV9lPe3EY0T6MbDIq4yPj0gekpMPHy7k285+SMZY9NTwueeUzr3ngWcfT6GuvfoDwRrsPKnkMg7zV3bRR6iCHS2vGEkjrHUtQoIJDf913CoVJ9qVBqAy9GKTofbX9pSmfJr6Plx3TgqyyGouhz0k14U0GXVbXXluKaXuL0DyWjMBKsochnpi49pM2GyjjKePTntZK7jSrBGMD+oSE7b5zoYx7CB8AejK9ebwDOfcOBq2TIwiRUTxBkx5gA59Ex/RGU9VbLwwbRQ9vtEshGksRzXx8sHWwBdfWwwxRRJVttl6dFJ27Og8x3JqNfaDH9s1bL4SoKoheqs+euQMdq7MnSux3o5gR+mqF8JOHuaoq7x1HXgi0uaPejeDlM5VLjGaO5A2jSfREWPzFWdExpuH3j7L+snNIiJ6xYKKS2xJeAJ5aCYMSSaIbR/N1QZzzBd2fXM75EAKFqI/Hm58jMYqcKxhqHNB5Fm6AALMDoAqIOLBorOqS4Qxm0VmyJTLJEUKd4FiiPzFHgmbLse34JOxzN8oOtZSGzIg2AH0DHCrDIeiCw6yMArnbyWgn8THAWMPgee2t7jSmdOeNIYwqNQYJI7jO9DyMYGkLZJPb869vylVAMSB7AQYRMIQ2tbmIPFb9lIElIG4Nq4Aqrd6cbMBKBov7UamOUFvC7Fi/X0vq6w1frgPj1h++Rd6iXLzKzx+PKTBpU+cDIO4Q64Pq8rt4Dbxj+1tGyGxrcdePacjN3epPOocgkqW9330reDoX9ljJyZzj+QooBqhJ0QrVi/UGBPIid52ZHRZIF1TFYEFVrtFtYgQECMhQjUhUnRqWgIXJbOXR2KfHD5lOH+Geq+LfZDmFEEpQXlFEo3XswlRp3b+wLF4qRj/p9luapDRBllGqnLl1a57lVB71TeX+vRpcyHYlGWyOrNVRo8GUKjewxq1Y2dOdv/sSeYx4aKLmC4gsiMnd+3CvWmvdmqhFMo0LXW856lP38rOVF52MNCpfFaXxNLNWTO0hG+nf8yjJ4e5pkRf/WUztwxQOZ59GKQOW9ZEB4b7VifrsgVNFnXP92tRMOlGa68qJGnvpUNxrPEzO6Gc3s1kmQy27ik0EuGFYEz3o6WH7+4FjJFVEdZvA3aLbrlm5g7XjAcDYu7Nzh2LNQ+LPy4spNyseg72VsTuZz685Re30J9LOzzNTFTJkUy7Uw2HQppliijsbNRnSzMx1a6qdguMK90Bevs7CZuOZqOKrppBzIbBbQqnQvVHbllNJNwnWMSZu09IF1hVidEZDjj/hiaj0DU/Yc5cophpbatnxfKab+A8WduqAXrs17zlszS3obJ55pTc0YVl7QyN/TsW8RbuqhfmP0FBVRD1ZRS06q6P7nDGDspWTYGphkzI9nu8rlJEhS9wDMrx9SckiyW/wpouPIMcr0amyOJYz2JTGFEqYIYlsyTYPI5PBcEVJ2+jwczfIQyZlf5LBSdONdbAmcjX+E7OmWo5P6zp9/8viWHSWa8Lit8qq4InlH8CevARUlGrzY9R+qntYIw5TejgVun8tB3MhAmYiYo+opYYCvy1W7gfE15u9/VzPb0C3oagenotaqXeSU5FjLEmUU/UUjGK468AQ2rMCASSYoJkJ4SOB4u0z7Vh+feI1YBozyFT7nJsiyalOXDcJaVx9h5i5/VGQKuNoEy0NOAQjAHsVBM4NqVWnZoMAqhflPggt5UinJimSSlGTdMRy+QvCp0SCwXasuS4ZsuwqwvHZLJMNAky7t2rQn9iOjDJNu5lrKtbVkkdjqNs04a2ErItLmmC3rafKDJDC6zYys557xRwQneXGWoTb3TFC3vQNfyQj0kHzKnbrGY01T6A/7ec3lmHHPwWq9y10Kqhe02Ny3hV5KIz4V0dIISPSrfHQCsWotuFbT1sg53uFTy5Uy78wa7ZW+15tEgUjOqJyGIwAZhrxAND6erO8Lky/7ZMckgKDC46VegS3bxIbKSNAvqqDxPjsc55kyMANOTKSnIEiU75/jRVW2H+SK/B/myayCwcWJ2/JjBUYDi2QFdLHGXpED0uaVH3XG0lwfIz+Fnkbc7+wc/8yDKbckt+2e7mUvbZvSqjfHAj9bFzx98/G1EEwUNKLwbZtgJ3L43ZDkTo3TLx3XOR1kcBn9Jk6OmcCg6IQkhLGq5FGBqFDKbqHfgXLeV8l0+2+sQsNer0rvPGkxem8ZjPCOBcQ1zEYtsAxEpuvLlTraVWAYQZzwjS1dgtSMUzb+xVSZH1zNqR0ZZBB1d6YbCpDNcjOGKiUp/1YUw/XIZy5tZzLl6e7jwIe8RKl1ik9aVjice3+Bj7FrLbb5o8nbpVXDxy8TYph1rqLq42Nta+Vn/hCENjeZqzIZJ28dLWfHdd7+BYRJBgKJ8a6gIFocEDj+2JDrloJ8Rr0C5pY8uMeCPuFATgaJaZnxhAmM/y0wU3ZgVCSgJ7Vo9duYd0FYfdJV0+PcqDfatzVSWd+MIHM9PcXdDY2erjbVEWzYDCNE7mF/GHE2OKQUVJQSRbEkhHJQfVmrPwiBh33vuVElC5Ae8HXipOBMFdB/uOTVd+QJx6e7xDiMFcPGUkLTg1HU11hSyk8uiCn7fz9EP+33/DjSUER0iGYfln1pzSoq6dK9vDNMBI4UORfRwtWV/qWDCT2Wd68ShspYUTI91X16b9tl+U4NnUY8pkzypZurVqlNXPB1fIFI65bh7VrPfbIAHQcb7yp5NlMrzP6XY2uOTY2hYsjQjuqms6f7D01ZfXECdX6Tt7wRzkJBX2pO72wzcsPjzOP5lawzMAIxKZGE+GWamKvbl+3RyE1FM/Hjay7XjvICIKARdIJFX00x5/7gDLQXnVDKpMhO47ehBWILOEdeZEbtRH47hPtrHr3au/EaT7B0Sepp7Rb13vPz4j6L/cMS0fghLwLKov3eiK5LP20oMdZQRL+KliVsyPXDI/cQHWe1agWKiWd5xcCsHaD/UeYztRjJZmJb++MHhdA9vZr/fxqmcndubPAsKfPDjL09hDThUoUKrKsvGnFVcQwH+nWhxjfSJrzV8VWUeHPD4lXPi92ZSCAU+ceSb86fb8HdPQQQkyTMG45Tq4E81Wi9oXMOTUnWpFZP34dLQlZlvVgyS7mEEDWTWCbO+Btb3Ey9pXye8hLMyHGKwYB2k7hloO7O/V20bMbtycOzVYw3e9bTGB875eeqnZvUTmjEGCfRe2F1REzhqSsrAi3Q0/bXo9Rwxt4mVgm/UyaW1XW/HIU+BoM4o9OwdygafMdDIvy8nC9BqQZAkqSyH419o2XaUylksP8v2B7kAVyfM03krmdgaErr/MvZW+/QGVZZ/5at+YmWpcKJ2UOtpwTyh1zJzH8sWXc7C0tfsj353UMdV3WQOfyeCyiNrTJBJSvw6OFC6N8h0ZTNVT9CsHbr1yomjTmtRbsq87nWb1BGDioIjS428SVoFc0ZOX2eA68bm+LJ2NcrNlP9cdqu4grLoUP7SdvsM8NKYIX4zVvV+ndXABOCsrllC2fyjviunUNZNskL594f81/woB8zocGgfTjXXiRyF+nvsOnlODkI/rlnYfuJsw270jjZ4R2VhWnuZryPvTdysOrJhLm9vtlR0R9rukkTShV8AiqYj3AT+8TRFLb8g0QUC+lkt1U3Vw7sCvLbsu3/RlngzIMA+v/v4Y5NKl5qYXyUM4wJtmHTbE95O3E/VKIwsUf4pt5PhZZYtKk3UqQW3iqMdB40yu4GA129rlTwp+u66IfrzFAD48GjTIP+mx+GQM9S6SUcgtDYOFrRF9uyc5gZxZNrspmO3nHSEZXf4YJ0x5yKMisLabertu4t5JgHf20d/uuBDoc0LxdlutO4fg+gHOMyWLZcZplf00uKS3jisuWFiVjt0JPK+c6CWWA2o6kmoyaD8LjVfFsf8tj9obrLA+qV82hiQYGnDH45ycfHl4SwMu249xR/6w5svKY2siSC1QcpeVC77yAw6gkwB590vfJtotktj//zkyKCK2TDM5XaYE/+XKkmqYcZXL6cMw0nyAej8ey+mrRrRl15YWB2WKlzsK8oMgdwXxhXhyKAn7GeVqD9VG+wswcSpV8n67gon6GFMZrMZIDg+WWXt72tMMvuygbgk7SJjJ77rgtzbWW7x60hVte2IVnpXqzyjWThOdZaCqTVCq8pZ5uuzrc1gKfE/SVtObt/L1bXsMtY7f9QfHwUdTByVsqdRSfd4Ctx9mZPah38bdfRFMJsMGj2rDXaNDkixdqI9MMhAbtilh78L/IsAMGkI8uPUg8qvqwejG4yaaZa2tRdM1648XzetfyC8Oulm76shIfz1xb0UG7XKW5dC+iq/yBdZRN3CYCapXm4h9VuJ2ko6NV5M8nP4fOrTXGdWtae780QIvlPFQs+QooR8ybsdRfhrBlsea0VFgLLxpgyrvzg1fpbOm8t7qIWU/pdxzvH3u5ObctojBQhUGxWURlEscB1F4EllB9MuLeFt2RT95R1zLR7y/DFcMw7+YYq+FUepwQKhduuXpVVNcsKsurRRzUPhPD05rRKEme0X6ZUrya9wrVLe6mcM5wacZ0iVqSbqRxN2WJayhTGIwpFOo4BmMc+2qfRBxY3iIsZbXwu/nlpcKWOTitmb6+bPTNqTQ6K211UUI9fYMZKmU0UHAqTYKVvrpYV88YKZ1fDEt3PnFyoPuOoUiV3WGHNxvb5nE05hQjdKJpXEUCXIU0GN+ERnTwcEEf122m/vh8ISTaaksNrDKVj1gJQpx+WxJ+bx7YUAhemG1RJyuV6mTLLFLuRMoKs6SeQOiSSLoIhHoX0xLp8EHtvkCbkbj/XqhFkL0TeY1B2hB9QBbe5VMm0PlmeKV8TmaJeIdWTAZk8rzEBQwjL6RrUQGNzEgtY0ij8zV8LfsSVQeEVK7UUQ8GgxbHF85YEvmigIY69zNEN4qY1yfB8y2uCGWEyyLAi7FTp2UbPUfLIvFjpe7ENPJgpbP87+amipEK+9GplYXxVMEesv+Tx1FrI0udBZ1HM+lrNy2JCzMoDFYm+PcbJlii14cacqs36a1QkYdsK5CAzLdVwVaef7o/L9ha9c4AiAtINluUJUgpEWw6lHhoM7j5cOLhTZxFyZiQBzVj313G8S/SuE4erfSRgfeRMZMznDwM08XTm5msZjqjmcVsRvb0pqGq8h1spYb8P4n8kUz+TCY99uWsLOzzFEzuW7lycl+Bp7BPt0IZ5KLo7rJYdym6IJfS+I/DT6Zn7LyYOVHcatAKtu/Z/J+ugpuw4Qows0u15VV9dD2CBtb6BPkKKcaTk7akdT0VEym+F9148nbvyrSuuq/npwKe7Mx5N6NTEuLCWceHjjJxOhr+yYRahvKZUHQo5leyEwgLNRAGXexQha7ipyFVxyfrPemUGILfcmgBAvxswH1g3/aPmphU6ijcktqVpE9anboahy3cFmFQWsQp+HMlhxtn+NQXuQUkg8dJiSI+6vk2FgF+TsAp+Tb4Yzxr3PQCtNntZ/FJ9DIShOA/MHFo7K7wzy55tyunNdQG8VOadKxOKkna3zAbCEtk7MMYuCwc+KeRo5g4vmvgCGDeGogJCoHqex9w6HWLd+Biyy6t8AH5q9WLDC1EcWKn4Q9DddwCSZ+vnXtqbXJB3vgoM/2UiBauttU5ZWNZq37qKSIFSDsRSQkPt/AmyGMrkXuO/8FknLpyE622xRgR1SLtQzhsV3clleZZvhYpiAJ1iLTBUfaJysN7j+yDSJV3ZuKKG1YC4Ub6PoyOx8KB941cxYSJM88dAIqWB6KhIVDDhlccet2i7bjY0u3IWb9i2vD61g3G1g14fbHkco+xx9ddz5NPs6jbu6P80B9eohOG/WzeTxlt9vWyG2a0SKmhuP4l0ktJ1cQyGuXB8wdDfV7xHypNN+OG7pHZB64TTWE5efnWgL/L45VJavZ8gYlQ7YwnTFFkJIep+Nv8E6ySpEKNfjKzwziRs1CTkyZWZI6vKbzcj7XiobSA0PUf28YEiKQJZxdx1r1ir3MitYIe+brw9bSkCdSksPXSdYIepPYtqzR8IyHjIj4rrO+/QR9ERWX1v5n/jm/zIKUpiI0wKf7edChPojfFZFfnDHD/QrYxGF1HtrIZXZ0umkOnJZGqq2mUNNVTMjm/omGQxE5GS1TZPF0yr96Rwq812HIE4VwLBiTotNwogYYl0RLdag0552cCLYT2C31wMDxdWGsyTWDGxL3KfBUXM4FpMgtrdYY2ssRA/kbK1rbkV+fBps03uIvcYOCJJ+CTIQYY4S7KA2GnXxpeMmRT5HYWz4FVR7qFGhu7zpocUqu3uYXhLLW1xUHWex6xeRq2REvKVkfi3SKthiOkfa5aP6XQXmQHPgH+9nw/hbI4D+vABLBO/f0nauGA3F4x2vokGYiJsTFlQILktVATp7Olm24XyhOnzNUZvxmNemdMnjZntjpDY9bH8fj2IjtWk1Az/5pn0ABWFNm5wLeIPKUVMx8Z6teX6jum2WuGV9cYTRYp0U2C5E6nV7tXs2+ql9l/DXQVvCcAtHydzLRHt0dUh0/a98pc5OSbYsoUk2SltMRhc1EyNdzBqFcnp/IUoTYeNYF6h6PtUqfYuKGKVC6EjPAU9gZtqwE0tDY0CGXU/gfj8mflKjulgGwQeSomVSY+thdgNm6YhgfJb3Z/05sTow1NLmpYg7+RTKRyWYpO0s4+1ltyE61tN+H2LhyfisxZ7ljQ9N/n13dsV0enhzy2cPWcxHeZNCM4PSCV4AN+cBT8O76tAlle7rlPJqxtfR3O6erO5XFyoqDjn6rjtTI5ra4F3zNU0j+DaxvvcpP8emBLSPpoA0Ek0YolZDZ0//K814MzRbbi9AnMZVdpM4i6KCv13pVCcAvXzt0CAl+DVRbGV5wjbIl9tgz+/0kq9eT/cNls+5IwnOOrhWEaX3iCs4i/SNCBfifsEiziLDyeXstuD+2LOQJkTaBnRR3etsDu6ND2WGcFL4Cu8e/3sqdCfYZETd/zU70cAf1Bq2Hzmy35ytF/rm+h6ZhGnjE5xDCPps8CkjK2haasZbvrXrS+yNoAyKxZ/SxH8R+PYsYWHOcUZFMdpmXCVIkTXEZNcXE9nsPRE55YTwi/J9fZplt+O68E50e8Mv1mnWqtVVDABtWcI6+16x6s076mGI44UI58J3Ncb66LXrhNpmXO/T4o76//v8U/9z/wP8TdfRVdi5rqib+iGN7vuj+cIxEOoLLxkjOiNWEg6ThKG8IayIUpeMbgcpKEz/OAcE7oMwKufe56lui7b6DOPzmoqufEkza2LIktI2dGRDKyVtuYClUaYulyO6yE40QZrM40zoPhp0xa+nCL/FF8iNsQnU0NZyUEuNFg0AQq590TikYqXv1Ei+EDfaIgvdgIFUZm0xOiOS5dVslwOo35dPgBx2bOiGVsXJBnh23qdyAiFTbmakZWZAQ5Mz6RLeNW3Pd4/Zk7fkotzeJjdJqs4r8+Qw2PrajQGBfnJC0zLI7rHrLSlp2LjtUraf9jYkOur5tZYCgQRtDAIA2Kw0lEfIODLi2ChTMd+cESHDUcnZmeJbw7nycAySDdGaWkOktSWMoYJ/LC6uLivFJJIuwwPHF5AoyfeF9bvHcJR5OQkcTn+8wjMjxBZ4z9dtgLFZEYDtKXoqwyP/uHdBkYR4b2tubfIJAdDIaDTNExGDrZrHbDPZohl0eD3Q0y2DMvcDHipTIYKNMri7xsDc8ywAfl5IRL65g8CwJJNMw8ReVHRneoX/7aoItJMEQn0gukKs3zkWkPHf12WH9ZSe4ez/q6ovE2qHgpAwbKDraD936yZwoPY2i0q7xY3eUa+GcOhNMA1PpQ4jrvcI7JbOF8JAav2JZOXWpexs4AsJ2zzengmcuZQSE5uXmFSPsYyedrM4nYAV2nI3fwsYqeOdXKkkosrKliQqWiZ7VMSKRWVsupnBEpOleUOsGVkuwq6qhu+LKaRzZzZixr/AbucNpALhh2ssPJmbKkMXuYPw86JvY7Eaptu6bpEefFw2RY2jB3w3hWrCXTmTqZwH5ihB15YYLj4NPKSfbfRJTMuqKD41mTgEUh8MQvPrTYv1s5uVWkuReM+NOt/EiXycNLhV6EJ1UdipiOKY7GzbprJN5sC4n36AvlKYh4hElmwYorXry7PmAYuMdeUagmc46qgwy3z0rCtIQUGCi7V2AoaLPBkrYF92UiYsIN9EMoq8zX/j5dYYyBratEA52O9NvXURpJk6wmtKjULM3Je81pdR2le5gelsvbm+NiewDP0dKMkQyj5c6dbOPEkThKA+dNwNhknp8p0Bac1/jZjfNfELfgMy76UTssJ9Dub+WbtbAKTC2h4eKouWnhdbQWh69IGF2vg3Jb7vUN5TStq1yXuezOZdfUn+WK9N984aGF+arJnneMOtdScjbTwyvI/knJIrgIuQPpjNbk9+KJ/pNvz+diLlWNBo3Px8aaQJdh7LZRsEBljMvVZWscjf8ZkhOShXzU6oA5yHXcxxFnpTZtmpCr6Na1LF8Roo3vVoQLnVqb9GzEY+46xJyAuSjBxJtHrPlWbO8zPmpOjXccKMFUy6avqYHn5w4zKAOW5qNkeMzZZcK5wPf9m4GLnYOkP3Tg5F7U5MoJeXxBHcJgFFD08abVF04OQAmwIHzg3pNrg1MSY2N42SYU+NiEkk4qroCN02tiA/FBMAI0VrNk4evU97lH3d7/DEESfsaZM+cJpAAmrU9M8yvRMH3vq70/HXfaLK/9hUVbcqK8U4C/TiRex6vmRhz+JFZP4tF/1qX8uqNuKj7dOrxlvHvuz+6B1QUb/5CuCRsSUDZQtPDsqCmRtZHYcGBoQBsgy5q4YO3aiRtcQTd/Pw1OOzEZnDw0G7x2riP3N0zIg9qClnp3wE+TsvBJ+DXSpYaX3M7E9Wv0i6n+O+5Jol1qqUsFbzIfmGY7fYFwX5ofgaBxKT4KW6NpbB6PAeB5bBqVHYIHGLwQNkwfWggWwhQfwA+w6Q3C5xk3MDBJ7yokrD6nz7gcDZNekq4c1WChQnMr6pZGoTzFq8JQAoJ8opi+SUUFpghRh7QjwjTW7ZMERPkEBVC8BVWOe6o13fTKurp7gHkDHjuEZx9QwIaEzKd0PTxDKoGn03RfmNysh/RvtPoXfvCAXdTexAA87G4JFY+IvmYGgNwbpUhE9tVsBrNkpOTbnWiSHkuiguqFg15ciWrCu8aJS1z9Oi+MFVWvbky5dzgtNcvE3D/V1LQu8ylKH5RO5fxzZ7XIUZCcCiwVBen+PIxqMrW4g0ur8n+3bNFt8Zf4eYq9jflr4E0amEPnMCVQ0lEgRhxi6caA5yKJJaefiAqt4aoOjZalTdgcptyckKBI0C5V0a6enUKl2cImZUSnVsvWaDqwKuWQSDSkVM98xx958+Pnu+drGuTW9OXcRDfDYO6eW5bYzTC4Q0xpy+TWRs0897z4eXk1N3dZ06356sWdlgXZ8lWMjwPetUE797RyCI/zD12wraLHpRuTpVZkLVqfcVrGptIZuxnQzr3TOPg7qZsvLHjL1OXqMmMs6MLpB+f9oBBSVKhLvvO+UwnJ3JGe0eReLvYngfADi3sB4y8X415WX+BOp+QufSQng9dq6fTaa7OV4rnRcYJsSI33N6JovXuGicS/9m6kIzn+4b32QKCfBPjQA8f2YtSxXPcVK43Pt9KOcVwxBK43ROcLLPSjLyWjvlI21qbNmv87HPFvzzsEeQmdmKTWRV50Gv240WZZJHVCrZAGO830gpk+XCHgPuA6fDJq437W7IxyLEqZS4/dUbtTaD98+0WddsmNz+wgKsSPb7W0FS+KwwhrxKubWIy6SCiv2bX6kvpC2JpQNGUVAfsD5bdWM1rd0PBL8wtWE0mLlZ0ikU7JYmli/jHAQaE4AHUataR6077EfZvBzf6lftPTHmOPcjIO43XGoX0xTO5Tv5IML5Yy7rtxEhWi3/Vd930067j1IyNJcjEB8WF7OAalxMN6XSNwvBeZOO1R/v2zdK1DKAr6GgNIdLEp1FmfB1SHv9imNtcvqugiHiN8zgIZIzgN58HI2Y5qx3vR1hnT6AQVL85djrg6/u3pNwxzswPHurNDOYmG0AJiHDvFV+0H8hDAihIatD1BTCbU9C7YMAUBYLEmD7+/fwFGbfoR9sh2LQaDhYANp0YMZKm/qaXLr4U0b+tns/u3NYescuv5bG3W8pSBUglJqQiSSoOi9/2qhUg1bgdsIPViRKDktO81/G/Rm6J+4hb7LeMoOPJoeatglcz0uMFEeArSx/uFLtbYkVDFOS+UN1C5JreZCEeVIRE/jn32UpBlIwB5kbt20PxL8rxG8BYtGE4COf1THjr09Z0usnZvrz8WH4zCuXnBCjz5CBrRCYer9wmfBJNRn+Y8QSNeftsggR9bsooutU7a/rFjJM+dG4Vue+dNM/+vGTEQeD+l0bPLHpoxZvI3W4KvIhTTKX/xi/g3pLVi0/bX5ZdwuWy1YvHyoTCCMJ/LzRfiuX92K5ZI1/CXwyzcE0hbCJux2M2E1RNZ47++hrPOJt7ulkfM/Mb0f7D/DKdkKLZjk8YVxkDmh2vUkWwfuzA6Baiyfrn0ON28JJ/RBIPEkJFIJH0wPJ1fC5o8THXsNVK4Jnz02oNqDxM082tDDevKg4Qa8mVCtrbFVZ1JQg8UaArykT8PExptrW0YoRhaR1rXtEnMwkeMfGZ5MPyE1ZBW/pMVN1R2jaG9S6+b4FRAHSdOdL2YjAUNreh6ua99x/GO52qcQds6WohBIgnIxEL7xH/oVY2uzGhWyjsXTqWaZl9xgsS+8TWKvXLNOAGzu05QNpdLfJx69NjDAQR2c83dyvUhFpslA+l7wZgAS0yIXHYbIcjgUdY3fGrqo3MeTtD5E3gxfKFYF/PS8VqMT1x4hSf9lOE96nfkbyewi/8UV7z8OZ/c+sIX5Xc4UWkSAAaoQcmv3Qdj8th9VTRmgP87CsOP6McMHthPkMXz8CuqA3QdZpk3M5BDfw2gyoY3HWFE3YjlTntJCSCowaNcNH1DXi1xBZfUFNoybYoBOm8WKEKMfdkhD5rygFO8Wa5Q5DiR3ayMlui4V/HmkMq8Wgdv5bCOoo0r5BjdjL9f5T+MEa4p4WZU4ccEdM8gRCqzjLRznUYia2BFoPkGpqNnJxH0gD2+04nvyRRvIsmHQv6gJH7YwQe8H+497+zVMrJdqZh3GN4v+/dBS1ur7U8Oc8G0ZRR/qmf6vg9DalyUzvXVyiiZvvf9kAmHZhXsPsbgIx39/C122Kdr2WShEUimZTnVIpQmcIBMHpkH0+g/P02Eo922zOb4yn1QuL+EbkqY4vWKHejtQ07LFg0kIxpOxUt0I4lG7UXuYledywDd8fFub0ZmfYZLGaScNwux2IVvSkjk4vk/p7KHECAKFYFARqBQYJu94oYkXOKMce4Q7J/8Xb3YK+mYGtQW1de0yMEYM23l44FbV6jyOCziieaSNNvfRTodOQvlrXD6mCN/a+od1zipcEz6Ddf+X06CN5z19q8LeOzjkf8Avc7amsuGIr+LUEUjaYG0l6MZh4nhhFSmRZBg3B01Goq6HpJCy4xJaaqRJKi0PPTwbiTpuzWunsDXqCOZv1++gSQttY5OPMfwL/uxDMN9hiaJLkusUxcGbWMyt8LRqUup7l/bOh+NayicgtOMcQsuE3zgrLcPLuAwT0b+A3R6S2suGvPx0u1x0KhZ9r55xNXKDf5Ywg8kng2+e/CusWcLv5rZdJkVLmCqySgwqWz5nVKc58PQtrOE+0a/H/NDs8jyb4AN5urB65Vj1X0QuLtAenBxRjW/9MGY7iciAhq6W4VBR+6GouDPiyNXkjDiPyZjcRN/px6Wdbdmp1qFX7+Go+g5S1+T4N9RmOHMVviDtFNoaDYO3jQK+auDvVfcja7pfQ8X8X9x7JAZ6guNm4/1+mMJwShcES9YQSBNA4dfPFPnE5D71Pv4dKo6eufY+PGQcUv/bnM4vcIVwl8TTRw++HCRBEdmYAj/aHhSEdVnoSL/15iGfy5+7LXdpHaTJil2ChqG4s45/0DI0fv4GnPadZQLTX56l01a/7fzuqCRdsAZxXnCdHzfEr6mwLd7r7ljcBTD3I4x2hhs0Gcc/abdb0ugu3+vzivXbF7GVrDl0fI2wXap6XODy/+rkXe/yv+42H9jpP9yMVp+lo3aVS8lqILljKSjCSTpAgkcdyi7CDms2XhsIhwJcmuih1WV8SsiqOD682ITEnBo1B/2MUTI7t/U5SaJWc875b9HCnxql/5QnmBpH/yrv9S+NSPrwWsqGSZ35dGr++aI3RXoiei4pePJw/W4H99EWHAdeSbCM2HMkaWXRDjZTfiSiRGBrR5VDflnfH8VnLGRNRsH2fSzNP7vSy650DLQlTrZZjQDjExpxjZBNCu5e3Ft3ezqSBnfxl0UdWE5tcjnGt04nN4Ajuvzq0q9l84iJYJd7arq9xgbQZf/sYYivn3o/ZjqhKffrv2977IZW5PH8DTnHvH6A65YKy07bAX6SLDPckaVwPLrAlGIoWK+leED2tQ7l3WmAp/aqgrcyq85+xcF/hyFvZLRCn9l2IWGWvDwYrjapiMZyUMM5v34Y8byH3zA7MKXHyvDB3frJSTckUwUqN83EncRyOUtHUG0V+C6THwAR86i4kcKZxYKhFU1b1oREF8Ao4Qf0iDqwd0i4Qws4OMwGh7Kn6H1kHB06wRsM3wCgcfxU5Dhb0YLs00YcR3xRSxQxAJBLJCtoWFsVRCgkMDKih0UQtOZSCGQypGVI7dGiq0xpQL6cEXok3KoT1lfVyYqbpOXmxPXJC6Csr4t2+SWsuBVOfSxeb0tsg2bbf7F7lpQR8VDynq6rA5XMjsXCF2PzHbospLtOtRFYFtfBSsnpPW6Z3aeOc4BDvKGt7zjPR/kY8wPr0jVN2luj3733zR/3bx4BfI/BdIgwPX8EHrewCHLaRS33d2NSeTa7VDsbDYEAn8tDkRBtcncjV1bHFE2WVboAJYBUTaZavKpUdHyfdxLLQeiOmCTya2B5UBUE2TBgF+ni8qPsUv7wU7mM9c+BH5jF7SfnfZcRITOwDJgZxP0GUEoA/zQFVhGs7MDRedCn59i+zJgZ1ehgglOZvKqRuB7I6sxJb/FNHrQYkzspAtNwJtMPyZqxGSxK5oKUe0smmfbmI12IfaL2qi5ZPY3EG4LQXoZfFLRe2ZaQyYVPjgjLk5n9VKM+LZxtfmsYOz9IKh8Ece+V7HfRreFr6LeOs7ktFG2CrKaz36UKQjtpoB1uAT1j+rMfVl1hcei4S29r00Y8a5+HiaG7fiQglMETOOST9PU8mrwPnHfZyzwO/pL2qvk1dbAlj9RllG1wTveJ6KIHEl9DWfRzWziTsgEk6yO37A2GmUZy7N0hWDvR2uc+S90ZMe1cY7r3z/8szWsKvT4zDyjY3qFt3gXjjgalK9EYhi8aozydv+Sx0MMrss4V0s41ZSOypMnIzhyLsS25rwCZ3SZWJJ+QdUkowzrHyX9jCw4jvDWwsHhMN7VB+R+0DTzHN5d7vf7p1w32EsyHfpHaBCW664R00acud3CmN5l7Ocwj6l6eSpfsoqdn4LN893mz9+2V63+9HnzeXe+Dg5x3qawPCjtnvz5dLtK/t9seNf8/HB7Ul4mxN2XxputF9wgrd7kGDeAX486x2RZLMOOO07okd4dL8emLR8uvfZCP+mcasd/WAciN3jtCLDi1WW0XwPIh5Bqd8mZj0ZX7CgMFlSwvgASjB2U7ZBlu1IMTZrZg2xIQEHBIE0XtuhyLshBca6FpR6H6NJ9Preuq+ZEzy+38eeksVSUH1SVN/J3j5+LRtnE2Sl6/ZTKdF96ouLtOTtt7A2n+r4anuIcrob2dcxGo6mDd7rHzSo5rNmjlROGTfCTpXLoj+T9MNSRr9BfPjXgbOoQfq8AkYGqLK1D3yG02ZyTUDVSgDFDZszMM1VcEKwPjgCnYQz6Fu6gn2+54T66KVM+2RyAGpZTp+MQ+lJqAOsSmSPYMlq2w9CUAJeD+Zh88+M3jkhEGlqIRXEL6jyrNzi5Wwp7JSm7HSvGURH3NzpSvm7bgipegvomYpYvAY6isxm9aeANzWcFsV0/IFKq0HWI8CVyksnCIb4wOOJcsBV9BM4zA1L0RXYb6lWBsXarRWr/zaGgwEZS1vkDPvLEF+nfTCifsmACFG8Tx3KkJCIGCPa91c8+NBbr57sF46T2QCs4EC52/sgzPsIwfZ5aRKo5Ys3evT0waQ06B5jVXkYB0+/tNhMTFvf6FmQXsaz1Axj8BTLEdbyH34MgINZq/yp8733N+7u35601RjuVYlES2aZnd53dZKW+Gy5v8YR+XRAh9NxedmP4vb4JFAWXjJdj21Qa31XSlNT4cVxNaZkUbeFpLtcW9qwgFWXGaumxN6mUCRPkO/x6AEX0BtR5ni2HZrTcsbFSZEGwTMIH90lBh4yPvP3YQWIoR6TPVJTaTtHvbWnV6VIWeS+O+bjl7hsEAVblt/RKq0WbzXhv8Sb5O3X92OoQ7hcHz6LcLeJt7mB1HHwSCZ1dgYyxKNO3QHnP06hStAF6tiOTwCjF47celTBIpwcONMAWnEKTM94jX8lhUJHPcw9g+MBbS+DO80WB3aLg35rZZ9uS6Od16R0p64MBvLt44x+ta5bILX2vrrsQ2myxupetUFyLw3N1Zu9hwWGfAbsv/ZPQvxnRHzrP+eal+I+lX9u/3O5+xxJmif0zmAVgrbKPpM8rkFdhP5ZKhdd/X/9D735LE82MWxmPASeO48CZ/3K9x6o9I+bURr/Azs0Sbv9dQZI4oQHjChfQsgKwlThZ/FMaAx6FYFhkZS3WZBOiiDWzLnw7Z+3ShQa82eioyvhcY93fA0zj484NOIz3+I0oKYki6veRYkgPdNlPBSQnTHfRQ5QdipxriXqacNQ/Gs8GRSHI0EdLpxjLs1RNdsN6N2VzlcG/QJRooGc0AtHmsqVt3b5JPS/N0NSuAcFq5O8FUcRm96o3Vr7HXDurDz6E6peyZ717zoUWvgVU7C1hKlqwd/wb8GJWb610VWzhpHlwpIq1/QK5/SJc/K4MaYtXFg/XTXHuXJIMyp6WcjuteSUrzd7AfUWQttUYhwYtw0jUuBvlTQIkP4CYE6Ry5WXVWpIjRqTxL7VKCcRS7oiclxa9Zx1fUWd3cdg7Bcu7lQocP7WrVHOXH/NGI62GFjr87r3kptr39EakplnONM4HX0QrWh3iEb1efYTa4pZAmhZ74mi30IMH2EaT99rCtK27jcEHHNtYqUUMMqAcRjnAYNNWnGZdIvz1IMNdLK3tatfVi56950tJu3v2pvL39Hpzo3dn6OokONtMgThihWGYy+js0tqJAlm640JPnLGK0eD1gM37lxGXp2wa5+bWPw4ho2MrmG+Xc1DfYyBF6UlHOC4F2mw4PFLnvyd89DiKQ8oht8RX05F5t4lukyj/58T16ddB/o/lJBBgHY+vLu/mTgpkowFV3q9TlukSjLr20mT2b5cQM7f/JQRGbS4VAuPxMZ8V5Sdd4Xog1PG+JvP86GCl7irEYzyYOkS9Bejk2JY1bMs60oFg91FwNJ9os+p0TOGWf82aXypCZr/odLqdoPFt6zbFF18yt/BJ72ylfqsX00sbe9Qp5KtOZmXE3Ym9KCbMHaAoDLZdZbZSrRgYCw4kW6jZK1/USsbOI2u9ss5dr2XIDE6DL7Laljp5HUYRnOiL+fXWg2enKJp29/Ip358mbOkSDa5GfFsUTToYh0sc77XzMOwBdRFlquGBIQaGrULQsslSnfForYlscM8hVbISIuYuw/QKFBc/VwsWL/rBJUwYlajhx65jy64glsowMAbXEi0NLb+ria6WK5wzsYnOG1msu8ZpzU5n9XB5sT/XXONEzspOX8g+rE5D19H1+iW5/DNbiq3Kje/wU28P+SPj7skqf+QVY/ZSWzzavVwXr9Q+rjkfV8iFnHyUkldS8l5ELH45clhEssGEQnPinOn616lF2GHTf7O7Gp+coqaYwk6W9u9bRX7WoVjJleObqUM0EhjbExN6HRfZqOlyDC469kkFnfHnOnjOOE0sANkGYiovNAZrK5jRIEd7OqaFjWerLWmArjMRZxnTp+peh8Ipv2/PlCzlT4Kj8hisqorTgnG0sCLqNaVwQHAO8RyMyMh0iN9yp3ITTwUsCAZf6tqe3iLs+JRKxcQITIODkE+YJdwJacRF7KLXE95QjZsVru3RoLiUEni06AHOlmzH++QCQi6Wx+hWow4augJHgPRHMoK1+2BlGSsNLjDzG8BM4ret+hRG+XI4kZcAW9N0pmRvZm4q4KjjMrpcMtLYVuF5dOQE0hv5Pptot5AdKX3wddo5vXxESvN4PEggPNlkYUrmBQ4ZeXao4E9EQ+yJi5VFoj2eHRswX9WGaJOZki1GinoFZLCREJH17Gd8BuBWCfXzfB8Y6liZAow2Ex0+jtNG+2meiUiMuWFF95ZzHnSc5oZ+QQBa1fEIQGnJ2JBv6yGlhm3TXdFRH7ZQokNnC/SiZ1DaKat8aXuki/lsBGFKdp5H19lFx/iaLpy1WKyzjOysMxGwqAkdbza0lUYaKJOMUKKAhCGhvEFIN9tyIcv0HsdxXn1w0X9yssyRkIA8F/gWBWHgHfC4GY9Tdai/jQOLIwW4ysjBEMqCmlYbeMO5IFc43GFNnF53fSzr9cJNlV2uZvi4vq0oECjl2fsRjMhJShWvzqcTpNR8DhqU7Eqc8pHyGnbsTcO99+rV/e0Wgx4QBTIrEVdYyRFgeFE5FotoFCeCi0XEPGxC1pmz7u9GUugjwoaudqCvonGEsNhO7XiCwqOBGfjBNI82Rn4cfxHEGOpQClOSC1Yr050S+cQE/ajRmLKgLO9cd06eNSYw5rADZE/Jfmsq7DFA2vfftAvWozTZBmJSLZa0IgqWAF5Qe04YmKY8gmdQB1EeNKRJlkFwOp6CzeY9P1pgr91OHWJuSHDKiVM/AGaP1NwGcBHn7OlcbjFrBeq9DLccSJIgwAp9w6+SDxHGEklsVRVRzhDB4k8lnKv3oDeRU0NeDCcwFrADK8bUpKmnrpgFpRFW5ZQCMc7k9PXih+6CXh7wrvlcQXS/E3rk0xuG4HxmAmsxuw4x1UpJV6HmzXhG86dOozkjSeRaICwdYPmWhuFSSF6XC74PyZ5SEHuK4HmfpSTjJ7kDsP20ZDu2ZP9RZ1ckY0QW6ynGDqvqxTAiCLVwnBBuFMA2Fp49IeM/N3us3w8mEBjVUXteEjlfcGs0y+D5y76Vu1O6F6j0miaPR1O4XBK69QrC6cgzXcEdNvEbziwc1W/1rKuq2nx0AEpaPmcDDsIMl4ROGckcbvbFEevplXU1xf4JLSt6rzbfsMAkxjEyLIsJUo4DMJBBVYsfb0St+H7ZEwcFtBSbWd1eoGKYE18w9UOkL2ilsynl85w043TGYeKAvrdqCmZlYGIjZMWMPksY2A/CzANumeG4zkbaukaBhtIEByr0oKgVEGc1yKyULe9kBtpmi0XI5EDGXSt4eFF2BWquepRs+Cvlr7jl+F4Vi9L6ZJa/khr+AcIMrYDm7LWu3PY54d7Yh1a/IZ8/n/AnuhI1DBKkxhBauLdCWTytp/rbyLUokKJ4GlJ4jjpW5OJXnPDs7wEJcsMwLZTer/rr1hXC99Y5Z5JQc24OtIbKhcxFY0mivG/pz081evx/OdfAHz7AL5i3z56eduBUb5UGN+9JbukFX2xrGeYxEcbEoTAqGI9VcCOZN5i0TIyZySlAZXismFUVMltVImd0GwfrQp7OeovneqK2t8LpDdSficudbfWI2Htw96DoyICzYBwqq+hQj4hkbOxyWyYuIbGmBOtaEsLcCIrzrWo9/Gp2REig6HjV1zcsQisS0Xhz6Il7HlKiRQLRxDSSNeEpCKkTTPK45Gtj6CXPhRaG+zH+F5CZtgPPzUMSCtvXmHyBCFYgMD28zlqo9oZ8PRkizbFBoJYNu53X4JMPE8RMIkJyrhjZk5F3PaAzrORrosmZjw3kg7A28MnsVRsJ4NCfM4hx0m82RtYPFwjJvxu7wisCf3uIpfyYs/RCy8xz92xPaKpH2dXiMWnsth8IwZymkzzFaGFmHO33lYut3dXX0aX1Eu/WCbaqmxsb3YUe8haKvHktutOSVcbBaYruYEChHIiwhziXSpqpCE3VzDw/y5DYajKiFTLLVve90Nlee5P3IJ0BcNzUmfaY1arNqdECdIg615Ly+ckyOAiWrcJiG6w4msOXnz8q6w021yjAQdd1rUVrU3LCLTZcLpT1cKbQBkn4zIBsEZkVFCCBnSj8dobn4nnxYm0F+5S1OaBbU+0nUWs3gR9jSAyNBgd98GAio1fjeOqfw2EbTEO1Jdsy+cUT/cMoE8Haicoa4bKkABCLj3rEtli/g0JoV5lDLmFyyWQX3oVuGLq9mnDRKr6unRNenZqCIOBberPZApfCxiwqP+haHcJNQZLdmevGMwtQmJDsKZVBLbS9WZnDIdxp4iheyLLOX6m4G3gsqzW5E4JbsBp/3WBxfrM0fbbnJId3ozA6Y/40utMreGYHGvhXDkhR+nutHP9KRsqQUEorxPW6u/gYzdhWa84rtrjaXWha8A6ndNVx/IW9ut4GmJic+oOvaCUmJJscQrPuB2vT2npb1dLYBGidPDxXeS0s+GwGLOfI2cIbElEqdkYoT7ai+sKiM+MghcG8aZedSbqw8pbQ50JfVRpq17L0RXOz8hXCV/QG6lVVmdYYlJzKjscm5h8ivmfBGuawW5S2Z2TWtpXOSKNrPrumeD+iCzyi5O7UxSkbDBcCzyJY76X07tENuGBSg+pgDEOoUnQOAeGqgoxgL2NVqseYfSaF4/yf1Ho0mlLX/2OFJiK3osHKMPac7BnVlWVQ1SoVRg8gnU99zbP91K1WK6+IMonJFjY9uTA8OqJdlhvVYMhzQZDM/drVPJTBqs7cbg2fU/PJrDbnunjqYa31h9lwwRyeKeULYGywCCO3C8Xn+coo/VckHzdKXDQZ/TeFtsY9P3rc9NqnVfIzbQbJTze7PDXG5GHcclnAY0qWdTcp6IgsmYl48hqZhaVBAbUDoZeaZ2RERqRxkRYcJ6RJMcN0J2CVIhSGEjUpYyA7/U1MeXNJ+z/EJdkLPWy1bNPSQZ+EyQCys+9BzgAla1IRtSEpsem215EsrscVWHmgbjG7qXvV6gy6HK/V+a3W0H1cbu0ll8ZxlCaHyZFQNpIaIsqwAjFnpcFtY7onJaiSdOxQiA3CBbQ7c+bhor7T29NzwlZr031caS3w9Y8lBvDRQrO1osZW5PsSVuYxpdvKD3zcrc0ldHyrsebNffL4HYQdIyrUTrGruhoo9zVI6BiTFZ3TFACStEz81O3HiJhMDUM5lqfVLC4VxsCoItAdEAT1Aqh+6gJcbC7U6+ac+IT7847ca7QXtHgKh+lCCj4z4u/YlUGNj4DZcEKB0j2FmXGullu2qpwWVDheCTyfz99H7bLiiy0zDHHosPEMs8iYKLNkjalDKK85S9gkA2VCJ1KTEohVTHF5kH8+3TUo0DlIwnluSBtRSzcppjDFdywGzsIUQCJBZN2Vq+UF4VnJYYwwfeMNa3EWb2fiRCkDe1l2NjR30nr04t7Y/CIfl2wczFcFUoPvBFayA9hxT5zpMPnfIzR6l1r/uVR9EAmpNYMLhJALWOXNU+soyQhjDdcOUQVSlsvA0qitpedYSuhkzJvHbHYmdCY0IxvAZ5P1Yu89BiswFM1Zy60Z7jvIUNK9FS2Smbj1ROvt1v8fDmZ6BjkXhEut5mWvK/z8UtNzKLFVc0m0YVM5OLM4EwPWYWZs4B+l9qXMQYRMfK8OewqnwKljn1m+2M9ojHljostwU5sylPCfFTF0kAiekKmcoORGKq0up7rNQcPY9IaGJRoVl+igqmuXqdoI3DMVdqbADWW1QeEuuWY6N4Dn1EteAn9lBRqgsN2URktuiY5IAQrDThag9roRE5Wdq6PVCjA4oxXSsxk/jWGygDALoSKGfvXOhxRN4oYUw8yHpuol0K1rLQqTy+pJkkhETDnE8wTdal1tlgb36lbX1o6OBw9EpAOacu2imQnEHHqQCy0Iwk2i7Ctm4329ws/w4gKl/36LOaXk/gboXowLhgWjOcE1+YV1yNGTUJBVqBrkTamR7s16eWWm1d+wegDZjnGKUFbM7V3GbIs3kd/qyMgnE31fnHPUYC4F1uwf09OFtcKXUsRHSzujhuv1Tq5i+cmnK6ewpn06m4Pvf70uLPfw6HV4C/uKqUPUhDm31OjJ8GCPUihFHb1Zd8MMq9WsRdBcMEMFZGpUVyVnY2pZ7FtSKAuYZvaGD3d0HoT08oW3lfxhTgWOPK+TDwbrrppO2mx56Lbf7OQdmr0JAfRC3CmdxSF+B7oAC0CLOJg29qsd+Tz1JGHu3+XjMaOqRuZ/4BtUsCgMEbD2W5JhdFaFXSSa90Vnjg8/gjerwQwLTVRB5OimzKPbRYqTnq/PPTsPv2yHHyf42GtrFS+J+JlmzaRqQ5c+oqsqtFFZR1elnz/pW9zZKDVgXIKoE03Yx0yw/J+mnzk727FPkmtEkDV8tNwYBnEcivPMtXDbgeVcrUm8Dv8UTOOpQ9CQCZeM1qPeZG65sWDnMaPZLw+X0HpMbyMnyyyh3TiwPMOJrDGn4btBu+pdXUpKkWLBxRtzx2F1cQa6jrwkijyv1hY+lyzGbwYDJ3mzse1fdBqYhkac6m2RRb/y9lSxIQNbvaQ+vFCsCPyjKPgiQ+ptOFgaSf8aBK9ZpMIXg2h03OcXR61u/Yvmax6vDVDxLauB1ddehjpf1tBUCdfXG3qmMKq2+T6HLczprnFFcJ44ljbVY00zez1IzcB/83QEG7uoA9mRH+IqMqBJxGrO3G/BSXCgooavy1VBKaq4clnMaLlOsT4fhU0xt0JJ2XcipF7Y7mbeTMO2pcysFvg355Jr3Ya0rxXzFrLxCX0oChU3UXR4Jh6oo0ZVIuLPQwvLBSUuHNQyKKMjhL5PHaLr2U1vuatTErGF2okC6ZKeFDAnG8MzvO65aJ8qbq6s4GPzBtDff/pmdFlx91RCM99a1IbDNh2ut2JzbrkyrZ0wBiPZieVrWGNBxdo4mq9DvPcB80Wl4nuC/ZYflbOwvGZ0l+f3GqKUNQY/GzIVyQwdzQTD/bwaLWOOac+z/9SeSpRQbzHu5dDqGd1Cvx6G82LBj2CWlrO3CcYDMvEoP21fQtn1OMKnebwfxaTn++F3FRp9gpjZL1d/l3eRNr1lkT8EP0zjd2DSXJyGWXP5ugcy1VGihbgHC5rn6a5rIUql63aqsxZwTXRmhq5D2U1rHKZL7bq9zUFxEYPQ0kgS0XsmWrobXudkqMNxIC3igecwQjoxSfRt15rwnPAWN3F7ZT60w2Ad2/4HZJj5GZbqYLjMYhw2hSzf8vGTJrHTKDZ53wdq7iMJkDIlI7uDK7mZ/aa522/YVXoPyop3Mo7si1vGvpxF7ZQkW4BfYA2c1wKMfbpv4FxmnQJyetizzWFP5/KeNfE1qzBGxI7khiX3u9CYoumqwcCqdMz31DkxHgPC6ldQtrhan9tz9IFJt+93H9XmJmZ2fqJWZ8z6TV+dPCY+tn8m2241DkP5/P5BEE8d1sc1kkQ6d4lKrTwgMRNG6Gbw9CWanza7V6hKdkxF16aH8k5SCRPqK0uPoUd3cBmbNl/zlwDcRzARJXqEuKtcK2mFy4Kp/60cPCCNIGKFKLakPy3pR2wz0NRLTTiDqiNl06K4hAgkLyBIMjQrUBl2QzSQFgRZHaMlPDB//fYLBmwfuzL9rSm391zR/6Oid9az1/+YYjtnVfwg9McJLlEDv+vR4QbIdHH+4kULDkRsAM80hI0JXu40cgBr3JhkmnOkHW1+YyZZmiq1frUTDaIiMtoRQf7ampI8iii/1pdspuEKg9e5F24nWOOu8HCesDXHPE8RMJ8IT7qanOEi4216R3hKraf0DtZIH1MUrvDw0R2ZWOMqaWrys0xJvpwhUTQ1eTfMMcmOD6jlAVVgue9bz4QkAeXXnm5UjYYvDjXc1OgFZckPWpcKerJ5omqkIXR6oTWwMxKpkDMp4hLYMsucIC4lSkTHlhmgGMyNrZX7xoFO504btkdktA23vZQ89mYHOucOIdNxr0KsKqwqOFElvsFqlOwSoXjkjFzoUqsHez2j/dntY47R3tEeNdbo2RRM4QXZWC1zsUrqV7g8Nv1yhWW6+6oY/rtp/CnZmbMDK//9KeQLwOqHSO4Jk/l9TKsUpSUrzcIsleukEgoYxeLnl6pe+/No+2EglfJcn0hpmKJvzWm3A0+0R0pWPq+FHUWDRcYuwVZYpOySXEjtEeiYiDBYAmvemucGsMXGQIt09oDlFOkeaiw32b4QOjY19KA57TQYxSqgl0XkclllCnwS3W8QAkHDF7eDumfut28R/wjuTMSOVlhcLtKwOGgPHkx3fCvE40ZMeDEennnGmiE/1YQRepiuN2izB1ZWyXoOo++Bx+eGGyyHhhMT8s73qwErZzspUuyeBg7j13fN8FVrrb6xw55HFWN7G27b65KYj6UdKesdTDu2MYDyMvaFq7xGuMeuwM7MPdY4ejTm+n49MdCklW91Zjb3o+xY1EbvcZButwrJQBAsOo998Sf0L5eVWOd4VvL5pGswkNQ5+ISHDVfZCB5PnTqLRnVaBbN03GAIjCGmAnNUogp62ZIiz5WpliHv2JIT8XWoIWtEAG+EYs0NicMoRv+2yMYKKe9x8czNMIHf/JzZFutjEiGQ2xwSO+pOZrqE35z/7/rDBacS6SPtFI6ixHM9q8sVcgvyHSwTH0fL4/B8zsiaKyiEd17uuwPie4tzyDxz1PrFC+bEMI7i7zstIwmTyHYcRSeab2BGPRTJS+HoDyQxlIbPHPt37MPKAVzp07tu2wzJV/i+5BMJ+33FRKoTKc9BcBKDUI0Us/0hQF9mDc420o2bY9a3hcMO5+7HcVReNSlY9pYhcLdf19Pe9yuLxkZ3I23WW7Hi1gBtJKS6sLzxUnftD62DeKXTrv9SU/nvI+PWfrK4YrpOHFxUsd1wcJsrOZXg4ffc03wGg7ersW/ed/FGeYL2TYjTQVD83OkpIx+g4MZT8OVVpqlzLuGyGPe15zIYlM4O7nb9rC9ufb8Wm45/mMcXN4M01QenG43Ttn1aOXSGc33/qERPFi9deOgP/cJx2qoyJ39bn4vbvylLQY6eqxxS7vc+BFIUsJTk+NDdDuCTp7b6kYVw6e7jxNE+r6t7kvlj19InEXRtZWGFJ5xldW8foAtRRyaejl/zPPwUUQRsvpibS7th89t28KUY/ZUZwkCH781KoizjsraHCNSdsh46Tu0fP7yC1OxUFY+9b0+Sl2EmNX1X65DQdmlXm9uVFMkzyQ+d37/+9fr/683r4w4vek/kiEoHZ8bjq5tM5DCNRYVO6tUTsf92w6/Mz5fagS/RRvbtROGb0Kh1mdGHfnsP179Wd87W3/aueYf139U/fbo9h+pZeZV8a2aJcybFKCo3TGlpG3qXePMUvIg6JZcYELGYL1OvstMfTh5CwclWXOpxnEnMEvVpwo/dji27jSdIj8CQUkIYp1zBk4A7kyw3kbpdksgTv6HmKX0RXgEOVmJghTB/ZK9voBE+NBc2l0O2eEChg08SpY+py3IFa1e9qbyO1kRcT2l9lryAkBfgdi+B0/vSLrgEu1wzTad6TbdajfxeEHGKBiBgyTTegS2+NShMq129n2KcpqG6fw6bkl+jz1CDHoQKskbQbJ4c9SZBBdY4Q9Z49c6+fZtT+9SDrcW1aW0vpnBEPHrnqdcuMGc1V+d7UTCoMXGH5NKHpBTkkPBxBjPcjcK2VHgYfntG039xyM/POTXsNB1efSIGoY/4wgmileuUnDeCiNpp9TEQH2uaYD45LPA/8s3vNUhGIZOcExK3L1WCh/lRmZHqDWpsacRNEMfyouAp6M/BUqOmX0eOP9MUJ1NekEdT3ORTwb9EeEu+OfRk9oZH8EbGO1rV7JcFpY73aiB2md3JsJu0y1PFIscuw2pqpUINzHRPNKm5/MSF7QCkRSWE2b0BKhj3AgoH/dz9Dx7fgV9L1Q0k4+IyFvLdVHU9Ty8BlpxRrwTxAGdPZGR3Ms5tQfFkwBOhgeORjKIwlRkgabTaZ6DUEzFeg7j3LMdFy50ozF/FEliLYDungHVKWbeZgwOOyVsgamCMFwQIPyaNM2MWawqgtQ3NxOoCAZV5ulLuSTaMDFPKqvNrtmWKuTgWmSFlkqhP1C3Lak5g0zJrU21fkkuZle4H/vR+4lmzn+LluG0RBWlbg84DrId9fOiX7S67OamaXjvd+BgojlWoaDLN/s1L9uwTnF3H94kwZeVwp5m0zAGlfS4oQks2tk7r4apO2WDUb1WcZrvpKhklNYIypEMo14XxpqpOpRdLCbHhEZam2Sj0Q/GEM4V/wQQE/1p6LKBnosa3F7j+VYbsgRyMYcHdnhMVr7m0oDb2gEIXSCBkY1jtdGH9ZsBYv3sQWU4Zsk6szB+0krRAaCXXivwULi/lbaN7NxVrc74mWLnKk+KT3OBcr8yxRr2rwJa5Xt93DU5wfH8BG2ui7mycS0TeGiyOlicfC9tEJ9bjsSMNBSOw6O9hqhSHY/x4QngeUvn4vmGg71J7Jxv5Zju952OJDhy7jJ0snZhMsL0PBImnju9SuyP1auzAptKwTx5vpYsO7VcUEW6PcocXk5eXIZtZiGfS4Ja1WSWhBHHccnN/8P7FE4ve9nZ9Zx4kGioP3ezusVoe33pi7QyP1h89+eVc+OrVIcOTCGcX9dZTLCJblU3+kS1vuPtIf4F8rryQwGgIRRsoLrgmpR5Ykwck6FuAV3Y1g8qemQOcUzZNQJrEIWQkuXIDleEsLT4Cr14/MUrn9fG9ewcLfirm/gkqhsX7Mozf3SGcSwey2NBLQ4dNQ2Sy2qy30721eu4YQmhCT5/SSx5bvYx1cdADx7s2F2RElZ6Dd6K1owKb7Z8RSDzYxrHLBZ7o7hK5o8eoHN599qSya2qauVrUJZXr5KFcBZ2DglF9KbKcqORMXlDUtXPxjOffhrfL7RDQup4dhkZj7h7szaMDNleFbs2ru05nESOmLGE87zqMOXW+FT222Yp0AIosZV4bz5iLo0on7aAjXu1aoXZMc7wvwRjhGJ8zgJWE2Ht7rFeTMCzCSdVN2r1ikYregoq+wpMgwtHwCULJzXkpW0FV0ZoO1JsSsdGxx3AyKA/tSiaNeJDfy+1wk3e9bSerhf0XrxBjAnyp2pkIu6rOzXeQGyJUqjGPd3mAw9ztx+tRp7xcX+SoeygitbLIn+q1QoWhyHDKZjmdvLZH69BJLWxMXnIesMM/2F8BoPhPSl4V4OQ1HtVTO11ZSxrHUIpMkGq3Cs/p3tfJZ22jlpg5qe7eeP7zAUCok9xsZhotm5JLqbJFlowsbP05CxGdd7iJuUjl5+ASLme9hRkiv5SPT+U09SbRBWX+Aa/vfqZxMjHFSnpqXStJJIUBN8+RzLStal7L5B26oWPlc+/hbhNpIfs68nwfSnno3yQx2vw7RKMJ3GqggYA2eFXMC6E/6L6XSDrjl2t/tWQZ+R9JepOLDx60jJkrZMPoT49kDHsOcPR34lpgZ710OazWPVI7UfKvEG57+DtSzz15Jxplh1vo8I198XNCfhTv0HvH7s69ukyV27qjNC/tk8RFk6EpdOwBTBSZI6OFw9B40mY52pdzsKQJRlLHeLFAKe1vEzezj7+PiVbR0V3efYL5DxCZu+hwebrk08WWcW/HJYwqTMu0AG5zDkPAzrS9dQEdKJvfssS21W00vgpV//i0/UZDru5nd1U7cof+nJAR91UZBvTprzDkDd/g8o2u0T7J/5FtUDVNfME6Q5xd4SlNuEuxlrxuYSGYY+EsC4UEUBKs3JcWwEExaqYFNJLaWKQ8OVWZHLNpkgqMSZpYcgmu9kFjq3O5UlptnIwEp226JTn5YUAI2FWbqftfofdV7Lox1PbDkLb3c6IBN30X9hzfLC27DIEb/KdO4ILI3BTwOnEdaZ11bgCY2k0v4PYrth2xbWGEHX4XMAYHduVuG3AwFpSeh1tad6A8Egvvjmi893RnG3s53Rjva4bYeD0VvBYQiuWX0FgrsEyHGpVGOMVy0XiXuasJnvz2fvbWhgu/gtE8a9Y++pK+iAXPhVm+joxH1jZgUKaaIfZ5lsPgUvatIqpE4MBvpCdddgrQ+LSzfiz7kMFOBmKno82mF8AAhTtGDtuHhIU9XD+M+zymOyJ2GDYi4OpqVChMVxo7rAbI9GTSZLpJebOXogXeG3u898Y2+1PBU120EyWAGoBxy8NDFjfL4kqZnWRSbRiFqVcYsQehxf3F+W6+vI4AMjk+o1tAtaOzDLIIx4WrBKEPFwUCZBLWeQmUvg5HOtRpin3jfMMJvHU+Y2VuCp0GjZ8rlK/UaUUXHznOKi1q0DQVdXzkFInBFHjUFIuP4nYbA5g5GbMPRvfCz/gzJ+Dj4uGqKvFhSxGrI8d7YuMmFAKohggkIsm0361Vw7zdI0Al/x9DvEX1N5ul4jnzB31Dk/kspSX0oGKVBmzF70tOorS3zlmatla30wBKFsGJImVgQtGE+VlMxhaTicHuVUAWR8EZo957EH8ZCzAe338LiK4baBK7ZUJoptMcZ+hFgaiqHgxGyVxr1jXNtj0tjrgTTnB0V8yLiVgsyzDrdHmeSiGavQoYEwBvlZhBehSFzYpdbzMFc0w8Hg03ihAgn76P0XIWG9fg2Olsjn1oLKyRtQNvvSAreAb3mh6lR9QeieRVpseUpWC+zQtxzhdF327MCgnfq4TwUYmp4FIseyLMiZGC/GH4vk12D7t3G427FXKoQowsL5Ae3ucJk0VbEQhVEtlvGEZf00q35zs7rf5V7OdLnqs0NOszmvf5qXUIDH5r/my4BPkRvM4O/Nh5JKeAwLNHLDSeK3NJI4EMkjIBSSSwZ5jrBMf3ujCtHKMpgnt6rjfZYodbSSfjYN5uMtu8s/Aw4MQQYub4S0WF6NUCVhV1qWFR07BS0DQUtAcCExoRnkcuCYWaBJgEVWdGoVDTp6o2wYowGLCdoG1n5nvsB4GJtxrjzo2LccfUGEOsIJjibmu6Zh0h4fSxhmWQaJLHH0wI9jEB8CMaP1bYAuXDU4m53HgeKt0GCt8modfjG+DRo9LRXnv4KA+FYk8AZdlIWgywVjjLJLSEfgBfQV9PaQIZl/Ftod1DfCMizIlbYmbzW3DI3l6VjE/AuUA5cd0Twzjp1cyj13IqfHhy4ackjyA6/IoBDcv0zKkZNM1BoaDTexfdbpsOzvu65QuvX9/45lAWlM3X8C32FRp8dOcRfD4zP6e9D6twgbC6YlGL91Ex3ITQLwGLqhn/HiCEPzk4YCQ8cCrpgaUa1GepMBzEps/GWFxrPsf9vuOUHRbzSWZJL0pyOPFk40qE8bUJf+gDOe60HHu0nATEtjMKwjgU0eFAePLiiXgNQDKsL2Xp+KKUV8CgiHOCMD6bkxCnLELYCQlrEXaWv9JD7ZI3dahiDS+fquLTp6qi7O/fe/ToNhk84V3okofYBOXDe8FlW2B4k4QqBBQI0jTUJDz64b3f3AukMM1UK5gwOb05y/XcU/er7jfdH7sh1z1+Qh9OD7oICx+cCDMfdMmz5Yf3DuDuwTH1LtB9vGVDWw/qOiajC7C5ng51tk4h3SFk+3iI/1uyYe4fuKaP47p9k+DWvyFe4d+3PCJd6aO11dL+mJsXIL9/JzGiQZcd3sYIx5NABJ4oRxgrCTcWC9AlbqfgJr3i0UM8yt/6aeKHwFc9OHbJeET2wXnj/RHdnbozQFTsPYyaps7WKVHnNcnraXrhQ9DZdEE999NQ25RVyTWIkS2IsKnXnLxhryF36ZVyZVnVxXHb1SpXYnOaKOa4YjFDuHIZsG0aAp3qRC/7ORbNP6dIxmPWk0pUu5RofB46iDKIMetQw/7azRJvjUQD/BMFqnUO67zNNHUNuvIt3bVdO4XaYLmNLyzyI7Z5e8WWVihBNEwXIMkB4SAPLnmVdDpYk3PZ3DIvi/m8nM32te1tLZ8PZkAqRSJCMJ3mSdCyGrR53qfqLJefyFl/JJwIAYGCexvKDpQxAKpBpcso4cKGoxfxZkzPxIQn1aODbHMTd5N6c5AYobu9ZpVk5EpY5NlQ78zdYNrHcNjUFCAJDb2GYspW3dLJItxl7V3Ht8a3lrePxfHZefu2cVQjw/1mc2gcHvaIMR5XlRhp50KkV0WoGo1Wb92eHI/9Ye0eF9RqO0d0/7JFmTBGLagryMtvvNYO3Z4rX4nyqMV67IQ1WDYFQHfmL5LJBE2dA3ar770f6jTcNItdCeTvubLQy+LKEi+TGPBiSJXDs81lMdEqmmVsG0vTEk2rrJlmvUi+XrE9+UnbnhimXylPi9k61tSZgM4cG2lMPgwC5PVdP2YmFT4/0nfd2Alw9v4L6o0CvyvBPVv9ZUw3sVGHcDA+uLT+TIRiT5AFS6W7bjSMpVkXTXfpGw0US8M0SWWRaYaDGuErJAyAL1uGOWnIM2yiETpBQYSy6alCg2trpXsAYpb8RjKQvCrRzVufGdJNCvIhFYavMJSZ41BAXog3Tcm+5SQACz4LnNl0X0tJsr33IZRYd+43PekOQx57cOyFjSbh3USOd292640w9MM8vDccViyLKcFSahtVjHy+kgJxBr/iyflxhX43/hwFEFSG4DFC2jY1prjdVVFB+XMMvzZOBGYYWp0Ya1S+sO+30QE7sx0ds5qSEKgs3ox52KmrooeapripYgkTW3/Whc0mje+JVV6R36Y7aTkjL7NpMZvOZsUUYdk4T8RMhvettw78dE7OTkSeCpfs69zusxXhYMzyohoqYADbR/sJv6tYdD1kjgnV1n/1p0iM/hK6QsyqIv6bvkSqHGkwTCYEISahZDJULdHypeKLYpxK51gJ95kQHGShIbYW1O+826NxDYpIJLYRP49Dl9vv9ZcDVxzbg0GzSxIDP1fS7PUYxi+3/cHE7flNi9qXNV8ZRU+iH0WNKGUKYuXjALwg6JkAAfe211c0VVsWFLFQUFRVysgyLxCE4nmpUIhwBMBnRGiFiaL6cmYq8XkqoOQsYlH/EvjgYzC7vDBkg7d3prPGBJpezG9cA4aRQkA/clzq2G0g2M4cPnq0bLrWqDeWRk00aoZRlEm1qCqkWK8L3Ebznm1I1RoYSEIkIjSMSa3uFxWqXcr+VwQoVtR0x2+FHwprAp0C+B4gO0pjmGotSkYz3HAmehoVPCl1UVqUtcVHq3GR/ryuxq+0my9uvjeuRRF8nfI28txu7F6Ju1OKcvO86djCGJSoyqzB9+vZGi+TdFrDeaKR5R8Xmk02GOZd+KPwx2FwY71ORAhFLa9cpv0KXX8nvil+LIKRiPlFZsqI1wxnUi9MGr8gVWeJPUULVJsm2Jn3uEvTnim/zy5GxXzH041rkPAM4Q3LuIvqVWqdfNxrx1koKZys1xEvVRsuZfkC3qUw/M5Avl4zG8ZEnmHkRYMxQtkUP53v5ZTxmlVEDG/I9RsCGuZFuql4sv+u+SrU8oO8uLhtRUVw1kWnOE3XIbHo9e9BIrGvafSGN8kFPFbhGYfDFCYNhBp2StdTnjc/g+b58Nvw95wJB1uE563nUSpptHpuU2nm0GBsLb8W6NBDOiCbd+6DbYrgJ9ahiaiAAHA6yw43+jsSyImi5beQhrbQ7dzT+yuPu+2m01y2bLHltuY4Vl5tNLJSmmyRbKsVLBK+KuE2YZqtie34DXWa37LSWXmmsXrWQZ/W80y+XyQv+yfYs6tuPi1zHnC2uFwrQGF0rhVxJixtt8IGlqsFG3uNcajk7v5wMFyO+uJIdg4GFcsqkURsFHJhBWu7FWh4JBGL3TurDUeTnIZfoSIOhVniyfBBSW53r92mJ5v8ofiqVFDWKMPiP/jVIEeB5umqHzo4C+64iO5PCvJxikuxSNs3y7/RoIbL4UHAkVMM8XqNiNYQn94Qg8F2lirT9Kz6fkQiDYbW5g0a954FUAnkT+Emcdaj3jbU7s5JtU1oq3RVaWH0q/pYc5aHgsIz5JHYo505wtmj8lbmCPP+ptuXXEHxnrSN7eHElhJ6cj4ro6Taa4XMTSu6Fa0YZyF/vnfBjzOIpCyDfNfzF5MXS/+5OL4s+b62Q6wBKWNctiYTIJweBs3QQ8LzHkGgJKHQMQEv/Mnzid+mWrHoYtqau7RxJZzSw+De4ZPb9KsZmLl4Qtm4mdHxudfz/0G/BfqlWzEPL3grAnQHnHwwf3F/uV93txEPbUUUnZHjuh4ABscUctwQZcUiZa4/6wF/QGpEe9O8Ga/hXzfKtVALjAHg6fXcR9815CFi/nmg/QIAj95PDAIAHh+mDP5a/3PqsTgQRAgAEGws0wHhX+AO3OrBGDJkdB+24pl/WyuKCGgM1+xVUJNabJbdDKTM1KJxJIgQT0nZ1puFimNDZeMLhEjq6m7uuS6RtQtNN0CFJgkNfLp7Q8jBtJHAzDEXqAZfgIuiGIXi44vHZxTBqITA8FMu+oLLx0uPDoOGI0mKWyLi7qdfRIih1TwUiykS0fO6kgEEE2hrMEBwRygJHphndiqw1IgnMAtLo2ZSTVpsYUS120rxfc+SBg0FJ1vg7vVqpNzpLEZzDBCBlZXjA4ZZxijKMlgi0hGsWgWIpGT1iDhRw3FvZMATyRSTTdWsXa3fAm4JuT9/42CFHBXbzRZgIMKoLuj0GhIKlEax08WUIvFBYJmrkKaUP0mTyQLxjkI74Y2AkDHiUqS66gxInYqk8XqSdO31zFwHljv363nKPj3zfP2IsECZcvUqTTbRJFMAFORChQLoeJSqqDQRja2iYogs6fY4UoAgWzRe1KuMb+uA6kqMg0q/JDfJ+Mk0BbZoim8DQGVRf00UBpjMq8lLpqz1Mvbkt89E1Yp5VGarAdkkID2IpMrkyIdZOalIP4itjzJIr01S9SInghmw3j2qsmy5TuzvCXiZExYRFROXkJSShoKGgYWDR0DsiAAgCAyBwuAIJAqNweLwBCKJTKHSRma+yWJzJu5GfYFQJJZIZXKFUkX1Rkv/Q9QbjCazxWpja2fv4Ojk7OLq5u7h6eXt4+tXpyZzo5I2dORUVJWUSRUUbVLpymc8ImJtFhckNJTc4kI5KVuEjJ4IYCUzbM8jkvBKGZY2aVwGwFjzgAwCu2jKvBmz5lyCuGnBoiyoN9CaFatgnrslhzBZkRLFSq2FVaFcpSrVpqhR6xmaBvUaNWtyiB9Xi2n4btxpWP8OgBZMH9IN07Id1/MZluMFUdJodXqD0WS22Nja2Ts4Ojm7uLq5e3ha8/HwWkqrlgNqXj0eja5bNVS338Te0eH31Fd3rbgv/Hf4L/yFBcz/NP6es6vVsRxiRV2xEX8TQJDRb/kfVLjGK0+0KiyutcNwGZwO1HNhxB/gj1ngXS81MApAiwAUBUAjQGFRwUHSn/I/Q+oZZnEhRyrsdu41f3KF+cnD8KbzS6ye/5/by91fsBxV0iemraUFlcoWdTGloYMrNI9EqsMbzh+LBQWDECwQBSBooZtGvroVtNdX1mvyp2HYJr8kBhr4AGhdLYUiNFyHoH3Ceg18zYadG7w0q8hMcEW9kPGu1aNZHowGl9YnMhZXXWSci+YsqMIw5lddeHProzk3YlY0M4xa50r3dFfpat+9zvpoRjyaXha1xaKpKVEXNcHpd9afrL9e762pZ7DBqfn8+XnxPWMgGROXdCaf0CM51APpdF9a3ZPbektu6g25rtdkqmnCQMwzNRxP8cbw86FfOgaOXxqtGztyPx5UDrcZ22Tlpt0cb/qvyMf041LrznhJt8cLujWe16vjOZ2sR1qtX9fdzoTBVzkrswkbL0z8P/YLVFtdJ/Yh1TvJYdFaowqePei1dVMw9ln63qefQnR+gc53DH1xPiUxK4V485HhfHESorTZfPOv/syzz4xK9r4mGEMzEMzC3EdKSfgp9+xp
--------------------------------------------------------------------------------
/deps/marked.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * marked - a markdown parser
3 | * Copyright (c) 2011-2021, Christopher Jeffrey. (MIT Licensed)
4 | * https://github.com/markedjs/marked
5 | */
6 | !function(e,u){"object"==typeof exports&&"undefined"!=typeof module?module.exports=u():"function"==typeof define&&define.amd?define(u):(e="undefined"!=typeof globalThis?globalThis:e||self).marked=u()}(this,function(){"use strict";function r(e,u){for(var t=0;te.length)&&(u=e.length);for(var t=0,n=new Array(u);t=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function t(e){return D[e]}var e,u=(function(u){function e(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}u.exports={defaults:e(),getDefaults:e,changeDefaults:function(e){u.exports.defaults=e}}}(e={exports:{}}),e.exports),n=/[&<>"']/,s=/[&<>"']/g,l=/[<>"']|&(?!#?\w+;)/,a=/[<>"']|&(?!#?\w+;)/g,D={"&":"&","<":"<",">":">",'"':""","'":"'"};var o=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function h(e){return e.replace(o,function(e,u){return"colon"===(u=u.toLowerCase())?":":"#"===u.charAt(0)?"x"===u.charAt(1)?String.fromCharCode(parseInt(u.substring(2),16)):String.fromCharCode(+u.substring(1)):""})}var p=/(^|[^\[])\^/g;var g=/[^\w:]/g,f=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var F={},A=/^[^:]+:\/*[^/]*$/,C=/^([^:]+:)[\s\S]*$/,d=/^([^:]+:\/*[^/]*)[\s\S]*$/;function E(e,u){F[" "+e]||(A.test(e)?F[" "+e]=e+"/":F[" "+e]=k(e,"/",!0));var t=-1===(e=F[" "+e]).indexOf(":");return"//"===u.substring(0,2)?t?u:e.replace(C,"$1")+u:"/"===u.charAt(0)?t?u:e.replace(d,"$1")+u:e+u}function k(e,u,t){var n=e.length;if(0===n)return"";for(var r=0;ru)t.splice(u);else for(;t.length>=1,e+=e;return t+e},S=u.defaults,T=k,I=y,R=m,Z=_;function q(e,u,t){var n=u.href,r=u.title?R(u.title):null,u=e[1].replace(/\\([\[\]])/g,"$1");return"!"!==e[0].charAt(0)?{type:"link",raw:t,href:n,title:r,text:u}:{type:"image",raw:t,href:n,title:r,text:R(u)}}var O=function(){function e(e){this.options=e||S}var u=e.prototype;return u.space=function(e){e=this.rules.block.newline.exec(e);if(e)return 1=t.length?e.slice(t.length):e}).join("\n")}(t,u[3]||"");return{type:"code",raw:t,lang:u[2]&&u[2].trim(),text:e}}},u.heading=function(e){var u=this.rules.block.heading.exec(e);if(u){var t=u[2].trim();return/#$/.test(t)&&(e=T(t,"#"),!this.options.pedantic&&e&&!/ $/.test(e)||(t=e.trim())),{type:"heading",raw:u[0],depth:u[1].length,text:t}}},u.nptable=function(e){e=this.rules.block.nptable.exec(e);if(e){var u={type:"table",header:I(e[1].replace(/^ *| *\| *$/g,"")),align:e[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:e[3]?e[3].replace(/\n$/,"").split("\n"):[],raw:e[0]};if(u.header.length===u.align.length){for(var t=u.align.length,n=0;n ?/gm,"");return{type:"blockquote",raw:u[0],text:e}}},u.list=function(e){e=this.rules.block.list.exec(e);if(e){for(var u,t,n,r,i,s,l=e[0],a=e[2],D=1g[1].length:n[1].length>=g[0].length||3/i.test(e[0])&&(u=!1),!t&&/^<(pre|code|kbd|script)(\s|>)/i.test(e[0])?t=!0:t&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(e[0])&&(t=!1),{type:this.options.sanitize?"text":"html",raw:e[0],inLink:u,inRawBlock:t,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):R(e[0]):e[0]}},u.link=function(e){var u=this.rules.inline.link.exec(e);if(u){var t=u[2].trim();if(!this.options.pedantic&&/^$/.test(t))return;e=T(t.slice(0,-1),"\\");if((t.length-e.length)%2==0)return}else{var n=Z(u[2],"()");-1$/.test(t)?n.slice(1):n.slice(1,-1):n)&&n.replace(this.rules.inline._escapes,"$1"),title:i&&i.replace(this.rules.inline._escapes,"$1")},u[0])}},u.reflink=function(e,u){if((t=this.rules.inline.reflink.exec(e))||(t=this.rules.inline.nolink.exec(e))){e=(t[2]||t[1]).replace(/\s+/g," ");if((e=u[e.toLowerCase()])&&e.href)return q(t,e,t[0]);var t=t[0].charAt(0);return{type:"text",raw:t,text:t}}},u.emStrong=function(e,u,t){void 0===t&&(t="");var n=this.rules.inline.emStrong.lDelim.exec(e);if(n&&(!n[3]||!t.match(/(?:[0-9A-Za-z\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BF\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54\uDFB0-\uDFCB\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEB8\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDD50-\uDD59\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2\uDFB0\uDFC0-\uDFD4]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD40-\uDD49\uDD4E\uDEC0-\uDEEB\uDEF0-\uDEF9]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD4B\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])/))){var r=n[1]||n[2]||"";if(!r||r&&(""===t||this.rules.inline.punctuation.exec(t))){var i,s=n[0].length-1,l=s,a=0,D="*"===n[0][0]?this.rules.inline.emStrong.rDelimAst:this.rules.inline.emStrong.rDelimUnd;for(D.lastIndex=0,u=u.slice(-1*e.length+s);null!=(n=D.exec(u));)if(i=n[1]||n[2]||n[3]||n[4]||n[5]||n[6])if(i=i.length,n[3]||n[4])l+=i;else if(!((n[5]||n[6])&&s%3)||(s+i)%3){if(!(0<(l-=i))){if(l+a-i<=0&&!u.slice(D.lastIndex).match(D)&&(i=Math.min(i,i+l+a)),Math.min(s,i)%2)return{type:"em",raw:e.slice(0,s+n.index+i+1),text:e.slice(1,s+n.index+i)};if(Math.min(s,i)%2==0)return{type:"strong",raw:e.slice(0,s+n.index+i+1),text:e.slice(2,s+n.index+i-1)}}}else a+=i}}},u.codespan=function(e){var u=this.rules.inline.code.exec(e);if(u){var t=u[2].replace(/\n/g," "),n=/[^ ]/.test(t),e=/^ /.test(t)&&/ $/.test(t);return n&&e&&(t=t.substring(1,t.length-1)),t=R(t,!0),{type:"codespan",raw:u[0],text:t}}},u.br=function(e){e=this.rules.inline.br.exec(e);if(e)return{type:"br",raw:e[0]}},u.del=function(e){e=this.rules.inline.del.exec(e);if(e)return{type:"del",raw:e[0],text:e[2]}},u.autolink=function(e,u){e=this.rules.inline.autolink.exec(e);if(e){var t,u="@"===e[2]?"mailto:"+(t=R(this.options.mangle?u(e[1]):e[1])):t=R(e[1]);return{type:"link",raw:e[0],text:t,href:u,tokens:[{type:"text",raw:t,text:t}]}}},u.url=function(e,u){var t,n,r,i;if(t=this.rules.inline.url.exec(e)){if("@"===t[2])r="mailto:"+(n=R(this.options.mangle?u(t[0]):t[0]));else{for(;i=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])[0],i!==t[0];);n=R(t[0]),r="www."===t[1]?"http://"+n:n}return{type:"link",raw:t[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}}},u.inlineText=function(e,u,t){e=this.rules.inline.text.exec(e);if(e){t=u?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):R(e[0]):e[0]:R(this.options.smartypants?t(e[0]):e[0]);return{type:"text",raw:e[0],text:t}}},e}(),y=w,_=x,w=v,x={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:y,table:y,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};x.def=_(x.def).replace("label",x._label).replace("title",x._title).getRegex(),x.bullet=/(?:[*+-]|\d{1,9}[.)])/,x.item=/^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/,x.item=_(x.item,"gm").replace(/bull/g,x.bullet).getRegex(),x.listItemStart=_(/^( *)(bull) */).replace("bull",x.bullet).getRegex(),x.list=_(x.list).replace(/bull/g,x.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+x.def.source+")").getRegex(),x._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",x._comment=/|$)/,x.html=_(x.html,"i").replace("comment",x._comment).replace("tag",x._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),x.paragraph=_(x._paragraph).replace("hr",x.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",x._tag).getRegex(),x.blockquote=_(x.blockquote).replace("paragraph",x.paragraph).getRegex(),x.normal=w({},x),x.gfm=w({},x.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n {0,3}([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n {0,3}\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),x.gfm.nptable=_(x.gfm.nptable).replace("hr",x.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",x._tag).getRegex(),x.gfm.table=_(x.gfm.table).replace("hr",x.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",x._tag).getRegex(),x.pedantic=w({},x.normal,{html:_("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?\\1> *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",x._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:y,paragraph:_(x.normal._paragraph).replace("hr",x.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",x.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});y={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:y,tag:"^comment|^[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",emStrong:{lDelim:/^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,rDelimAst:/\_\_[^_]*?\*[^_]*?\_\_|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,rDelimUnd:/\*\*[^*]*?\_[^*]*?\*\*|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:y,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\?@\\[\\]`^{|}~"};y.punctuation=_(y.punctuation).replace(/punctuation/g,y._punctuation).getRegex(),y.blockSkip=/\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g,y.escapedEmSt=/\\\*|\\_/g,y._comment=_(x._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),y.emStrong.lDelim=_(y.emStrong.lDelim).replace(/punct/g,y._punctuation).getRegex(),y.emStrong.rDelimAst=_(y.emStrong.rDelimAst,"g").replace(/punct/g,y._punctuation).getRegex(),y.emStrong.rDelimUnd=_(y.emStrong.rDelimUnd,"g").replace(/punct/g,y._punctuation).getRegex(),y._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,y._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,y._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,y.autolink=_(y.autolink).replace("scheme",y._scheme).replace("email",y._email).getRegex(),y._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,y.tag=_(y.tag).replace("comment",y._comment).replace("attribute",y._attribute).getRegex(),y._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,y._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,y._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,y.link=_(y.link).replace("label",y._label).replace("href",y._href).replace("title",y._title).getRegex(),y.reflink=_(y.reflink).replace("label",y._label).getRegex(),y.reflinkSearch=_(y.reflinkSearch,"g").replace("reflink",y.reflink).replace("nolink",y.nolink).getRegex(),y.normal=w({},y),y.pedantic=w({},y.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:_(/^!?\[(label)\]\((.*?)\)/).replace("label",y._label).getRegex(),reflink:_(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",y._label).getRegex()}),y.gfm=w({},y.normal,{escape:_(y.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\'+(t?e:H(e,!0))+"\n":"